From a1ca29ae1d3f244912b0d5f3d5667540ceb6eb6f Mon Sep 17 00:00:00 2001 From: MansourD <96188427+mdukhan@users.noreply.github.com> Date: Wed, 11 May 2022 12:50:43 +0300 Subject: [PATCH] 1511 enable custom template set group ids for lookup (#1525) * #1511 added new method to read properties in ConfigurationFinder.java new TemplateSetConfiguration Class to save properties new test cases in ConfigurationFinderTest.java * #1511 fixed logic in method readTemplateSetConfiguration in ConfigurationFinder added hideTemplates variable in TemplateSetConfiguration completed 2 out of 3 tests cases * #1511 corrected CheckTemplateSetConfiguration logic in ConfigurationFinder.java Test cases Correction for CheckTemplateSetConfiguration in ConfigurationFinderTest.java New Constants for the new properties created in ConfigurationConstants.java CheckTemplateSetConfiguration Called in load function in CobiGenPropertiesReader.java * #1511 canceled the method call in load properties in CobiGenPropertiesReader.java * #1511 written Documentation Modified the properties function to read properties corrected tests * #1511 documentation correction * #1511 Documentation correction * #1511 Documentation Correction * #1511 requested changes * #1511 requested changes #2 * #1511 requested changes 2 * #1511 requested changes * #1511 fix defaultGroupId logic --- .../api/constants/ConfigurationConstants.java | 25 +++++ .../impl/config/TemplateSetConfiguration.java | 95 +++++++++++++++++++ .../generator/GenerationProcessorImpl.java | 2 +- .../impl/util/ConfigurationFinder.java | 48 +++++++++- .../config/ConfigurationFinderTest.java | 68 +++++++++++++ .../emptyConfigProperties/config.properties | 2 + .../validConfigProperties/config.properties | 4 + .../cobigen-core_configuration.asciidoc | 56 +++++++---- 8 files changed, 280 insertions(+), 20 deletions(-) create mode 100644 cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/TemplateSetConfiguration.java create mode 100644 cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/config/ConfigurationFinderTest.java create mode 100644 cobigen/cobigen-core/src/test/resources/testdata/unittest/config/properties/emptyConfigProperties/config.properties create mode 100644 cobigen/cobigen-core/src/test/resources/testdata/unittest/config/properties/validConfigProperties/config.properties diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java index b906646a69..39c21357cd 100644 --- a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java @@ -71,6 +71,31 @@ public class ConfigurationConstants { */ public static final String CONFIG_PROPERTY_TEMPLATE_SETS_PATH = "template-sets"; + /** + * Name of configuration key to be able to configure multiple (comma separated) groupIds + */ + public static final String CONFIG_PROPERTY_TEMPLATE_SETS_GROUPIDS = "template-sets.groupIds"; + + /** + * Name of configuration key to allow snapshots of template-sets to be offered + */ + public static final String CONFIG_PROPERTY_TEMPLATE_SETS_SNAPSHOTS = "template-sets.allow-snapshots"; + + /** + * Name of configuration key to disable by default querying of default public groupIds + */ + public static final String CONFIG_PROPERTY_TEMPLATE_SETS_DISABLE_LOOKUP = "template-sets.disable-default-lookup"; + + /** + * Name of configuration key to hide very specific template sets + */ + public static final String CONFIG_PROPERTY_TEMPLATE_SETS_HIDE = "template-sets.hide"; + + /** + * Default (public) cobigen GroupId + */ + public static final String CONFIG_PROPERTY_TEMPLATE_SETS_DEFAULT_GROUPID = "com.devonfw.cobigen.templates"; + // cobigen configuration environment variables /** Name of the environment variable pointing to cobigen configuration file */ diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/TemplateSetConfiguration.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/TemplateSetConfiguration.java new file mode 100644 index 0000000000..e21c4e6533 --- /dev/null +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/TemplateSetConfiguration.java @@ -0,0 +1,95 @@ +package com.devonfw.cobigen.impl.config; + +import java.util.List; + +/** + * mdukhan This Class is used to set specific properties if not found, or save them if correctly found. These properties + * are groupIds, allowSnapshots and hideTemplates. + */ +public class TemplateSetConfiguration { + + /** variable for template-set artifacts */ + private List groupIds; + + /** allow snapshots of template-sets */ + private boolean allowSnapshots; + + /** variable to hide very specific template sets or versions of template sets */ + private List hideTemplates; + + /** + * The constructor. load properties from a given source + * + * @param groupIds + * @param allowSnapshots + * @param hideTemplates + */ + public TemplateSetConfiguration(List groupIds, boolean allowSnapshots, List hideTemplates) { + + super(); + this.groupIds = groupIds; + this.allowSnapshots = allowSnapshots; + this.hideTemplates = hideTemplates; + } + + /** + * return a list of the saved groupIds + * + * @return groupIds + */ + public List getGroupIds() { + + return this.groupIds; + } + + /** + * set a list of the groupIds from a source + * + * @param groupIds new value of {@link #getgroupIds}. + */ + public void setGroupIds(List groupIds) { + + this.groupIds = groupIds; + } + + /** + * return a boolean which states if specific Snapshots should be allowed. + * + * @return allowSnapshots + */ + public boolean isAllowSnapshots() { + + return this.allowSnapshots; + } + + /** + * set a value on the snapshot + * + * @param allowSnapshots new value of {@link #getallowSnapshots}. + */ + public void setAllowSnapshots(boolean allowSnapshots) { + + this.allowSnapshots = allowSnapshots; + } + + /** + * return a list of the saved templates to be hidden + * + * @return hideTemplates + */ + public List getHideTemplates() { + + return this.hideTemplates; + } + + /** + * set a list of the HideTemplate from a source + * + * @param hideTemplates new value of {@link #gethideTemplates}. + */ + public void setHideTemplates(List hideTemplates) { + + this.hideTemplates = hideTemplates; + } + +} \ No newline at end of file diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/generator/GenerationProcessorImpl.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/generator/GenerationProcessorImpl.java index 4a2029fb50..982981827e 100644 --- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/generator/GenerationProcessorImpl.java +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/generator/GenerationProcessorImpl.java @@ -562,7 +562,7 @@ private void writeBrokenPatchFile(String targetCharset, File tmpOriginalFile, St } /** - * Builds the model for he given input. + * Builds the model for the given input. * * @param triggerInterpreter {@link TriggerInterpreter} to be used * @param trigger activated {@link Trigger} diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationFinder.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationFinder.java index 1ab6ebab41..56bae9e30e 100644 --- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationFinder.java +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationFinder.java @@ -7,6 +7,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Properties; import java.util.stream.Collectors; @@ -15,9 +18,10 @@ import org.slf4j.LoggerFactory; import com.devonfw.cobigen.api.constants.ConfigurationConstants; -import com.devonfw.cobigen.api.exception.CobiGenRuntimeException; +import com.devonfw.cobigen.api.exception.InvalidConfigurationException; import com.devonfw.cobigen.api.util.CobiGenPaths; import com.devonfw.cobigen.api.util.TemplatesJarUtil; +import com.devonfw.cobigen.impl.config.TemplateSetConfiguration; /** * Utilities related to the cobigen configurations including: @@ -29,6 +33,45 @@ public class ConfigurationFinder { /** Logger instance */ private static final Logger LOG = LoggerFactory.getLogger(ConfigurationFinder.class); + /** + * load properties from .properties file into TemplateSetConfiguration if found valid properties otherwise load + * default values + * + * @param path to a .properties file + * @return TemplateSetConfiguration instance + */ + public static TemplateSetConfiguration loadTemplateSetConfigurations(Path path) { + + Properties props = new Properties(); + try { + props = readConfigurationFile(path); + } catch (InvalidConfigurationException e) { + LOG.info("This path {} is invalid. The default Config values will be loaded instead.", path); + } + + String groupId = ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_GROUPIDS; + String snapshot = ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_SNAPSHOTS; + String hide = ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_HIDE; + String disableLookup = ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_DISABLE_LOOKUP; + String defaultGroupId = ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_DEFAULT_GROUPID; + + List groupIdsList = (props.getProperty(groupId) != null) + ? Arrays.asList(props.getProperty(groupId).split(",")) + : new ArrayList<>(); + // Creating a new ArrayList object which can be modified and prevents UnsupportedOperationException. + List groupIds = new ArrayList<>(groupIdsList); + if (props.getProperty(disableLookup) == null || props.getProperty(disableLookup).equals("false")) + if (!groupIds.contains(defaultGroupId)) + groupIds.add(defaultGroupId); + + boolean useSnapshots = props.getProperty(snapshot) == null || props.getProperty(snapshot).equals("false") ? false + : true; + List hiddenIds = (props.getProperty(hide) != null) ? Arrays.asList(props.getProperty(hide).split(",")) + : new ArrayList<>(); + + return new TemplateSetConfiguration(groupIds, useSnapshots, hiddenIds); + } + /** * The method finds location of templates. It could be CobiGen_Templates folder or a template artifact * @@ -96,6 +139,7 @@ private static Path getTemplatesFolderLocation(Path cobigenHome, Path configFile * This is a helper method to read a given cobigen configuration file * * @param cobigenConfigFile cobigen configuration file + * @throws InvalidConfigurationException if the file isn't present or the path is invalid * @return Properties containing configuration */ private static Properties readConfigurationFile(Path cobigenConfigFile) { @@ -109,7 +153,7 @@ private static Properties readConfigurationFile(Path cobigenConfigFile) { props.load(strReader); } } catch (IOException e) { - throw new CobiGenRuntimeException("An error occured while reading the config file " + cobigenConfigFile, e); + throw new InvalidConfigurationException("An error occured while reading the config file " + cobigenConfigFile, e); } return props; } diff --git a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/config/ConfigurationFinderTest.java b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/config/ConfigurationFinderTest.java new file mode 100644 index 0000000000..993dc19078 --- /dev/null +++ b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/config/ConfigurationFinderTest.java @@ -0,0 +1,68 @@ +package com.devonfw.cobigen.unittest.config; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.Test; + +import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.impl.config.TemplateSetConfiguration; +import com.devonfw.cobigen.impl.util.ConfigurationFinder; + +/** + * mdukhan Class to test the method loadTemplateSetConfigurations in ConfigurationFinder + * + */ +public class ConfigurationFinderTest { + + /** + * Test loadTemplateSetConfigurations Method in ConfigurationFinder if invalid properties found, to load the default + * values. + */ + @Test + public void emptyConfigurationTest() { + + Path emptyConfiguration = Paths + .get("src/test/resources/testdata/unittest/config/properties/emptyConfigProperties/config.properties"); + TemplateSetConfiguration conf = ConfigurationFinder.loadTemplateSetConfigurations(emptyConfiguration); + + assertThat(conf.getGroupIds()).contains(ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_DEFAULT_GROUPID); + assertThat(conf.getHideTemplates()).isEmpty(); + assertThat(conf.isAllowSnapshots()).isFalse(); + } + + /** + * Test loadTemplateSetConfigurations Method in ConfigurationFinder if valid properties found, to load these valid + * properties correctly. + */ + @Test + public void validConfigurationTest() { + + Path validConfiguration = Paths + .get("src/test/resources/testdata/unittest/config/properties/validConfigProperties/config.properties"); + TemplateSetConfiguration conf = ConfigurationFinder.loadTemplateSetConfigurations(validConfiguration); + + assertThat(conf.getGroupIds()).containsSequence("devonfw-cobigen-bla", "abcd", "blablob", + ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_DEFAULT_GROUPID); + assertThat(conf.isAllowSnapshots()).isTrue(); + assertThat(conf.getHideTemplates()).contains("com.devonfw(:test-artifact(:3.2.1-SNAPSHOT))"); + } + + /** + * Test loadTemplateSetConfigurations Method in ConfigurationFinder if file *.properties not found , to load the + * default values. + * + */ + @Test + public void invalidPathTest() { + + Path invalidPath = Paths.get("path/which/does/not/exist"); + TemplateSetConfiguration conf = ConfigurationFinder.loadTemplateSetConfigurations(invalidPath); + + assertThat(conf.getGroupIds()).contains(ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_DEFAULT_GROUPID); + assertThat(conf.getHideTemplates()).isEmpty(); + assertThat(conf.isAllowSnapshots()).isFalse(); + } +} diff --git a/cobigen/cobigen-core/src/test/resources/testdata/unittest/config/properties/emptyConfigProperties/config.properties b/cobigen/cobigen-core/src/test/resources/testdata/unittest/config/properties/emptyConfigProperties/config.properties new file mode 100644 index 0000000000..5fb0428181 --- /dev/null +++ b/cobigen/cobigen-core/src/test/resources/testdata/unittest/config/properties/emptyConfigProperties/config.properties @@ -0,0 +1,2 @@ +foo=foo +bar=bar \ No newline at end of file diff --git a/cobigen/cobigen-core/src/test/resources/testdata/unittest/config/properties/validConfigProperties/config.properties b/cobigen/cobigen-core/src/test/resources/testdata/unittest/config/properties/validConfigProperties/config.properties new file mode 100644 index 0000000000..1ddf59d538 --- /dev/null +++ b/cobigen/cobigen-core/src/test/resources/testdata/unittest/config/properties/validConfigProperties/config.properties @@ -0,0 +1,4 @@ +template-sets.groupIds=devonfw-cobigen-bla,abcd,blablob +template-sets.allow-snapshots=true +template-sets.disable-default-lookup=false +template-sets.hide=com.devonfw(:test-artifact(:3.2.1-SNAPSHOT)) \ No newline at end of file diff --git a/documentation/cobigen-core_configuration.asciidoc b/documentation/cobigen-core_configuration.asciidoc index f226e0e0c3..45a502f008 100644 --- a/documentation/cobigen-core_configuration.asciidoc +++ b/documentation/cobigen-core_configuration.asciidoc @@ -12,7 +12,7 @@ The actual configuration of CobiGen is maintained by a single folder or jar. The 1. A configuration jar or directory, which is passed to CobiGen by the Maven or Eclipse integration or any other program using the CobiGen programming interface: 1.1. the Maven integration allows to configure a jar dependency to be included in the currently running classpath _(of interest for link:cobigen-maven_configuration#plugin-injection-since-v3[maven configuration]_ -1.2. the Eclipse integration allows to specify a `CobiGen_Templates` project in the eclipse workspace +1.2. the Eclipse integration allows to specify a `CobiGen_Templates` project in the eclipse workspace 2. The file `$cghome/.cobigen` exists and the property `templates` is set to a valid configuration (e.g. `templates=C:\project\ide\conf\templates` or `templates=C:\project\ide\conf\templates.jar`) _Hint: Check for log entry like `Value of property templates in $cghome/.cobigen is invalid` to identify an invalid configuration which is not taken up as expected_ 3. The folder `$cghome/templates/CobiGen_Templates` exists 4. The lexicographical sorted first configuration jar of the following path pattern `$cghome/templates/templates-([^-]+)-(\\d+\\.?)+.jar` if exists (e.g. `templates-devon4j-2020.04.001`) @@ -39,8 +39,8 @@ The context configuration (`context.xml`) always has the following root structur .Context Configuration ```xml - ... @@ -68,7 +68,7 @@ As children of the `` node you can define different triggers. By defin === Matcher Node -A trigger will be activated if its matchers hold the following formula: +A trigger will be activated if its matchers hold the following formula: `!(NOT || ... || NOT) && AND && ... && AND && (OR || ... || OR)` @@ -85,7 +85,7 @@ Whereas NOT/AND/OR describes the `accumulationType` of a _matcher_ (see below) a * The attribute `value` might contain any information necessary for processing the _matcher's_ functionality. Have a look at the relevant plug-in's documentation for more detail. * The attribute `accumulationType` _(optional)_ specifies how the matcher will influence the trigger activation. Valid values are: ** OR (default): if any matcher of accumulation type OR _matches_, the trigger will be activated as long as there are no further matchers with different accumulation types -** AND: if any matcher with AND accumulation type does _not match_, the trigger will _not_ be activated +** AND: if any matcher with AND accumulation type does _not match_, the trigger will _not_ be activated ** NOT: if any matcher with NOT accumulation type _matches_, the trigger will _not_ be activated === Variable Assignment Node @@ -96,8 +96,8 @@ Finally, a `` node can have multiple `` nodes as ch .Complete Configuration Pattern ```xml - @@ -121,8 +121,8 @@ Such a container might be a package, which encloses multiple types or---more gen .`ContainerMatcher` Declaration ```xml - @@ -161,8 +161,8 @@ To get an intuition of the idea, the following will initially describe the first .Extensive Templates Configuration ```xml - ... @@ -214,18 +214,18 @@ The second configuration style for template meta-data is driven by initially sca .Example of Template-scan configuration ```xml - ``` -You can specify multiple `` nodes for different `templatePaths` and different `templateNamePrefixes`. +You can specify multiple `` nodes for different `templatePaths` and different `templateNamePrefixes`. * The `name` can be specified to later on reference the templates found by a template-scan within an xref:increment-node[increment]. _(since `cobigen-core-v2.1.`)_ -* The `templatePath` specifies the relative path from the `templates.xml` to the root folder from which the template scan should be performed. +* The `templatePath` specifies the relative path from the `templates.xml` to the root folder from which the template scan should be performed. * The `templateNamePrefix` _(optional)_ defines a common id prefix, which will be added to all found and automatically configured templates. * The `destinationPath` defines the root folder all found templates should be generated to, whereas the root folder will be a prefix for all found and automatically configured templates. @@ -295,7 +295,7 @@ _(Since version 4.1.0)_ An special case of `` is the external However, if we want to reference an increment that it is not defined inside our `templates.xml` (an increment defined for another trigger), then we can use external `incrementRef` as shown below: -```xml +```xml @@ -306,7 +306,7 @@ The ref string is split using as delimiter `::`. The first part of the string, i == Java Template Logic _since `cobigen-core-3.0.0` which is included in the Eclipse and Maven Plugin since version 2.0.0_ -In addition, it is possible to implement more complex template logic by custom Java code. To enable this feature, you can simply import the the `CobiGen_Templates` by clicking on _Adapt Templates_, turn it into a simple maven project (if it is not already) and implement any Java logic in the common maven layout (e.g. in the source folder `src/main/java`). Each Java class will be instantiated by CobiGen for each generation process. Thus, you can even store any state within a Java class instance during generation. However, there is currently no guarantee according to the template processing order. +In addition, it is possible to implement more complex template logic by custom Java code. To enable this feature, you can simply import the the `CobiGen_Templates` by clicking on _Adapt Templates_, turn it into a simple maven project (if it is not already) and implement any Java logic in the common maven layout (e.g. in the source folder `src/main/java`). Each Java class will be instantiated by CobiGen for each generation process. Thus, you can even store any state within a Java class instance during generation. However, there is currently no guarantee according to the template processing order. As a consequence, you have to implement your Java classes with a public default (non-parameter) constructor to be used by any template. Methods of the implemented Java classes can be called within templates by the simple standard FreeMarker expression for calling Bean methods: `SimpleType.methodName(param1)`. Until now, CobiGen will shadow multiple types with the same simple name non-deterministically. So please prevent yourself from that situation. @@ -335,6 +335,28 @@ folder Let the `cobigen.properties` file contain the line `relocate=../sub2/${cwd}`. Given that, the relative destination path of `Template.java.ftl` will be resolved to `folder/sub2/Template.java`. Compare `xref:templatescan-node[template scan]` configuration for more information about basic path resolution. The `relocate` property specifies a relative path from the location of the `cobigen.properties`. The `${cwd}` placeholder will contain the remaining relative path from the `cobigen.properties` location to the template file. In this basic example it just contains `Template.java.ftl`, but it may even be any relative path including sub-folders of sub1 and its templates. Given the `relocate` feature, you can even step out of the root path, which in general is the project/maven module the input is located in. This enables template designers to even address, e.g., maven modules located next to the module the input is coming from. +=== Custom template-set groupIds for lookup + +You can specify template-sets so that it can provide custom template-sets and even restrict the teams to ask for default templates provided by CobiGen. There are `four` custom template-sets attributes: + +* `template-sets.groupIds`: Search for template-set artifacts by that configuration key +configure multiple (comma separated) `groupIds`. By default, (public) CobiGen `groupId` will be used. + +* `template-sets.allow-snapshots`: Allow snapshots of template-sets to be offered for template-set development purposes. By default, no snapshots should be queried. + +* `template-sets.disable-default-lookup`: Disable by default querying of default public `groupIds` configured in CobiGen. + +* `template-sets.hide:` Hide very specific template sets or versions of template sets. + +* An example of how such a configuration should look like: + +``` +template-sets.groupIds=com.devonfw.cobigen.templates,jaxen,jakarta.xml.bind +template-sets.allow-snapshots=true +template-sets.disable-default-lookup=false +template-sets.hide=com.devonfw(:test-artifact(:3.2.1-SNAPSHOT)) +``` + == Basic Template Model In addition to what is served by the different model builders of the different plug-ins, CobiGen provides a minimal model based on context variables as well as CobiGen properties. The following model is independent of the input format and will be served as a template model all the time: