Defining the Artifact Path
For an expanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact., the artifactArtifactA build or deployment result, such as a Docker container image or Java archive, produced by a software project. path and name define where the generated artifactArtifactA build or deployment result, such as a Docker container image or Java archive, produced by a software project. will be located and how it will be named.
Testing the artifact path
A guide to test the artifactArtifactA build or deployment result, such as a Docker container image or Java archive, produced by a software project. path can be found in the developer hub: Artifact Path
Defining the artifact path
To define the artifactArtifactA build or deployment result, such as a Docker container image or Java archive, produced by a software project. path and name we edit the {Expander}.xml file.
E.g. we can fix the path to match the test above with the following values:
<artifactName>$dataElement.name$Foo.java</artifactName>
<artifactPath>$module.rootDirectory$/$artifactSubFolders$/$dataElement.packageName;format="toPath"$</artifactPath>
The artifactName and artifactPath are small embedded templates similar to the other templates. They can make use of the following variables:
dataElement: Which is the composite of the target element, the name of this variable is based on the element type. (E.g. for a TaskElement expanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact., this would be taskElement)dataElementContext/expansionContext: A context object of type DataElementExpansionContext with extra information (generally not needed for regular expandersExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact.)program.rootDirectory: The root directory for the applicationApplicationThe overarching model container grouping all components, domain logic, and configurations for an enterprise solution..module.rootDirectory: The root directory for the component.artifactSubFolders: The sub-folders based on the layerLayerLogical separation of functionality within a single system/application, focused on code organization.-technology-sourceType settings (E.g. logic/gen/common/src)
Furthermore, you can use formats in the template as follows:
$dataElement.name;format="firstToLower"$
The formats available are:
firstToLower: converts the first character to lowerCasefirstToUpper: converts the first character to upperCaselower: converts all characters to lowerCaseupperconverts all characters to upperCasetoPath: converts all.characters to/kebab: converts camelCase to dashed lowercase
The location of the harvest files is also based on the artifactArtifactA build or deployment result, such as a Docker container image or Java archive, produced by a software project. path.
When harvestingHarvestingThe process of extracting and persisting custom code from anchors and ext directories back into source directories., the expanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. framework will render the artifactArtifactA build or deployment result, such as a Docker container image or Java archive, produced by a software project. path, but insert different values for the variables.
E.g. program.rootDirectory will now point to the harvest directory of the ApplicationApplicationThe overarching model container grouping all components, domain logic, and configurations for an enterprise solution.,
module.rootDirectory will point to the harvest directory of the Component and artifactSubFolders will not contain /gen/.
Standard applicationApplicationThe overarching model container grouping all components, domain logic, and configurations for an enterprise solution. models are build with ApplicationsApplicationThe overarching model container grouping all components, domain logic, and configurations for an enterprise solution. and Components, but other models might use other elements with similar roles. Program and Module are more general names for the same concepts.
Using OGNL for more complex logic
Using artifactModifiers is considered an advanced topic and should be used with care and only when absolutely necessary.
Sometimes, there are paths that cannot be represented with the resources available in the template.
In that case, there is the possibility to define <artifactModifiers> in the xml.
This contains an ognl definition of a map with key-value pairs which can be used in the artifactPath and artifactName.
E.g. to remove all vowels from the dataElement name:
<artifactModifiers>#{
'dataElementNoVowels' : dataElement.name.replaceAll('[aeiouy]', '')
}
</artifactModifiers>
<artifactName>$dataElementNoVowels$Foo.java</artifactName>
<artifactPath>$componentRoot.directory$/$artifactSubFolders$/$dataElement.packageName;format="toPath"$</artifactPath>
The artifactModifiers can use the same variables as the artifactPath.
Defining artifactPaths for locations outside the regular directories
In some cases you may need to define an artifactArtifactA build or deployment result, such as a Docker container image or Java archive, produced by a software project. path that is different from the standard path.
Important to know is that when using applicationRoot.directory in your artifactArtifactA build or deployment result, such as a Docker container image or Java archive, produced by a software project. path, harvest files will end up in the applicationApplicationThe overarching model container grouping all components, domain logic, and configurations for an enterprise solution.'s source directory.
To prevent this, you can define the directory for harvest and expansion separately.
First, create a separate class to define the new componentRoot.
package net.demo.foo;
import net.democritus.elements.ApplicationComposite;
import net.democritus.elements.DataElementComposite;
import java.util.Map;
import java.util.Objects;
public class MyCustomDirectories {
public static String getComponentRoot(Map<String, Object> data) {
boolean isHarvest = getProperty("isHarvest", data);
String applicationDirectory = getProperty("directory", getProperty("applicationRoot", data));
String componentDirectory = getProperty("directory", getProperty("componentRoot", data));
ApplicationComposite application = getProperty("application", data);
DataElementComposite dataElement = getProperty("dataElement", data);
return isHarvest ?
componentDirectory + "/foo" :
applicationDirectory + "/foo/src/app/" + application.getName().toLowerCase() + '/' + dataElement.getComponent().getName();
}
@SuppressWarnings("unchecked")
private static <T> T getProperty(String key, Map<String, Object> data) {
return (T) Objects.requireNonNull(data.get(key), "Property '" + key + "' not found. Available properties: " + data.keySet());
}
}
The class receives a map with the data from the artifactPathBuilder. This contains the variables mentioned above.
In addition to those we also use isHarvest, which is a boolean that is true only when deciding the harvest location.
We can use this value to decide to return either the component root directory for the expansion or the harvest files.
Next, we use this class in artifactModifiers to insert it into the artifactPath:
<artifactModifiers>#{
'myComponentRoot' : @net.demo.foo.MyCustomDirectories@getComponentRoot(#this)
}
</artifactModifiers>
<artifactName>$dataElement.name$Foo.java</artifactName>
<artifactPath>$myComponentRoot$/$artifactSubFolders$/$dataElement.packageName;format="toPath"$</artifactPath>
In addition to this, there are also some other variables to give fine-grained control in defining an artifactPath.
layerDir: The directory name for the layerType. (E.g logic)technologyDir: The directory name for the technology. (E.g common or ejb3)sourceDir: The directory name for the sourceType. (E.g src or js)genDir: Resolves togen/for the expansion path, and an empty string for the harvest pathexpansionRoot.directory: The root directory of the expansionscriptsRoot.directory: A directory for scripts which resolves to{expansionDirectory}/scripts