diff --git a/pom.xml b/pom.xml
index 0686a37..e3c7aa0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,7 +51,7 @@
com.inteligr8.alfresco
aps-public-rest-api
- 2.0.11
+ 2.0.14
com.inteligr8.alfresco
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/crawler/ApsTemplateCrawlable.java b/src/main/java/com/inteligr8/maven/aps/modeling/crawler/ApsTemplateCrawlable.java
new file mode 100644
index 0000000..d5b101e
--- /dev/null
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/crawler/ApsTemplateCrawlable.java
@@ -0,0 +1,31 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+package com.inteligr8.maven.aps.modeling.crawler;
+
+/**
+ * An interface for APS template export transformation implementations.
+ *
+ * An APS template is a JSON file.
+ *
+ * @author brian@inteligr8.com
+ */
+public interface ApsTemplateCrawlable {
+
+ /**
+ * @return A file transformer for APS template JSON files.
+ */
+ ApsFileTransformer getTemplateJsonTransformer();
+
+}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/crawler/ApsTemplateCrawler.java b/src/main/java/com/inteligr8/maven/aps/modeling/crawler/ApsTemplateCrawler.java
new file mode 100644
index 0000000..8374c65
--- /dev/null
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/crawler/ApsTemplateCrawler.java
@@ -0,0 +1,74 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+package com.inteligr8.maven.aps.modeling.crawler;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A class that implements a APS App export crawler. The crawler does not
+ * directly perform any transformations. Those are handled through a callback.
+ *
+ * @author brian@inteligr8.com
+ */
+public class ApsTemplateCrawler {
+
+ private final Logger logger = LoggerFactory.getLogger(ApsTemplateCrawler.class);
+ private final File templateDirectory;
+ private final boolean failOnIntegrityViolation;
+
+ /**
+ * @param apsAppName A name for the APS App.
+ * @param apsAppDirectory A directory to the unpacked APS App export.
+ * @param failOnIntegrityViolation true to fail on file integrity issues; false to log warnings.
+ */
+ public ApsTemplateCrawler(File apsTemplateDirectory, boolean failOnIntegrityViolation) {
+ this.templateDirectory = apsTemplateDirectory;
+ this.failOnIntegrityViolation = failOnIntegrityViolation;
+ }
+
+ /**
+ * @param crawlable A crawlable implementation; the callback for potential transformations.
+ * @throws IOException A file access exception occurred.
+ */
+ public void execute(ApsTemplateCrawlable crawlable) throws IOException {
+ this.logger.info("Crawling APS templates ...");
+
+ this.crawlTemplates(crawlable.getTemplateJsonTransformer());
+ }
+
+ protected void crawlTemplates(ApsFileTransformer transformer) throws IOException {
+ for (File templateFile : this.templateDirectory.listFiles()) {
+ if (!templateFile.getName().endsWith(".json"))
+ continue;
+
+ this.logger.trace("Transforming template: {}", templateFile);
+
+ try {
+ transformer.transformFile(templateFile, null, null);
+ } catch (IllegalArgumentException | IllegalStateException ie) {
+ if (this.failOnIntegrityViolation) {
+ throw ie;
+ } else {
+ this.logger.warn(ie.getMessage());
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAddressibleGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAddressibleGoal.java
index dfac7bc..bb11769 100644
--- a/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAddressibleGoal.java
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAddressibleGoal.java
@@ -14,6 +14,8 @@
*/
package com.inteligr8.maven.aps.modeling.goal;
+import java.util.List;
+
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.settings.Server;
@@ -21,6 +23,7 @@ import org.apache.maven.settings.Server;
import com.inteligr8.alfresco.activiti.ApsClientJerseyConfiguration;
import com.inteligr8.alfresco.activiti.ApsClientJerseyImpl;
import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl;
+import com.inteligr8.alfresco.activiti.model.Tenant;
/**
* This class adds APS addressbility to extending goals.
@@ -128,5 +131,20 @@ public abstract class ApsAddressibleGoal extends DisablableGoal {
return this.api;
}
+
+ /**
+ * This method makes the appropriate service calls to find the first APS
+ * tenant ID from the configured APS service.
+ *
+ * This method does not cache the result.
+ *
+ * @return An APS tenant ID; null only if there are no tenants.
+ */
+ protected Long findTenantId() {
+ List tenants = this.getApsApi().getAdminApi().getTenants();
+ if (tenants == null || tenants.isEmpty())
+ return null;
+ return tenants.iterator().next().getId();
+ }
}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppAccessibleGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppAddressibleGoal.java
similarity index 98%
rename from src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppAccessibleGoal.java
rename to src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppAddressibleGoal.java
index b67fe2c..ae22f7d 100644
--- a/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppAccessibleGoal.java
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppAddressibleGoal.java
@@ -36,7 +36,7 @@ import com.inteligr8.alfresco.activiti.model.Tenant;
*
* @author brian@inteligr8.com
*/
-public abstract class ApsAppAccessibleGoal extends ApsAddressibleGoal {
+public abstract class ApsAppAddressibleGoal extends ApsAddressibleGoal {
@Parameter( property = "aps-model.appName", required = true )
protected String apsAppName;
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsTemplateAddressibleGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsTemplateAddressibleGoal.java
new file mode 100644
index 0000000..a5cd759
--- /dev/null
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsTemplateAddressibleGoal.java
@@ -0,0 +1,162 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+package com.inteligr8.maven.aps.modeling.goal;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.apache.maven.plugins.annotations.Parameter;
+
+import com.inteligr8.activiti.model.ResultList;
+import com.inteligr8.alfresco.activiti.model.BaseTemplateLight;
+import com.inteligr8.alfresco.activiti.model.DocumentTemplateLight;
+import com.inteligr8.alfresco.activiti.model.EmailTemplateLight;
+
+/**
+ * This class adds the APS App name to APS addressibility to extending goals.
+ *
+ * Only use this class if your goal needs both the APS name and an APS service
+ * client. You can use `ApsAppGoal` or `ApsAddressibleGoal` if you only need
+ * one of those capabilities.
+ *
+ * @author brian@inteligr8.com
+ */
+public abstract class ApsTemplateAddressibleGoal extends ApsAddressibleGoal {
+
+ public enum TemplateType {
+ SystemEmail,
+ CustomEmail,
+ Document
+ }
+
+ @Parameter( property = "aps-model.documentTemplateNames", defaultValue = ".*" )
+ protected String apsDocumentTemplateNames;
+ @Parameter( property = "aps-model.systemEmailTemplateNames", defaultValue = ".*" )
+ protected String apsSystemEmailTemplateNames;
+ @Parameter( property = "aps-model.customEmailTemplateNames", defaultValue = ".*" )
+ protected String apsCustomEmailTemplateNames;
+
+ protected Map> findTemplates() {
+ Long tenantId = this.findTenantId();
+ return this.findTemplates(tenantId);
+ }
+
+ protected Map> findTemplates(Long tenantId) {
+ Map> templates = new HashMap<>(32);
+
+ Map systemEmailTemplateNames = this.findSystemEmailTemplates(tenantId);
+ if (systemEmailTemplateNames != null && !systemEmailTemplateNames.isEmpty())
+ templates.put(TemplateType.SystemEmail, systemEmailTemplateNames);
+
+ Map customEmailTemplateNames = this.findCustomEmailTemplates(tenantId);
+ if (customEmailTemplateNames != null && !customEmailTemplateNames.isEmpty())
+ templates.put(TemplateType.CustomEmail, customEmailTemplateNames);
+
+ Map docTemplateNames = this.findDocumentTemplates(tenantId);
+ if (docTemplateNames != null && !docTemplateNames.isEmpty())
+ templates.put(TemplateType.Document, docTemplateNames);
+
+ return templates;
+ }
+
+ protected Map findSystemEmailTemplates(Long tenantId) {
+ this.getLog().debug("Searching for all APS System Email Templates");
+
+ List matchingPatterns = this.buildPatterns(this.apsSystemEmailTemplateNames);
+ Map map = new HashMap<>();
+
+ ResultList templates = this.getApsApi().getTemplatesApi().getSystemEmailTemplates(tenantId);
+ for (EmailTemplateLight template : templates.getData()) {
+ for (Pattern pattern : matchingPatterns) {
+ if (pattern.matcher(template.getName()).matches())
+ map.put(template.getName(), template);
+ }
+ }
+
+ this.getLog().debug("Found APS System Email Templates: " + map.size());
+
+ return map;
+ }
+
+ protected Map findCustomEmailTemplates(Long tenantId) {
+ this.getLog().debug("Searching for all APS Custom Email Templates");
+
+ List matchingPatterns = this.buildPatterns(this.apsCustomEmailTemplateNames);
+ Map map = new HashMap<>();
+ int pageSize = 50;
+ int page = 1;
+
+ ResultList templates = this.getApsApi().getTemplatesApi().getCustomEmailTemplates(null, (page-1) * pageSize, pageSize, null, tenantId);
+ while (!templates.getData().isEmpty()) {
+ for (EmailTemplateLight template : templates.getData()) {
+ for (Pattern pattern : matchingPatterns) {
+ if (pattern.matcher(template.getName()).matches())
+ map.put(template.getName(), template);
+ }
+ }
+
+ page++;
+ templates = this.getApsApi().getTemplatesApi().getCustomEmailTemplates(null, (page-1) * pageSize, pageSize, null, tenantId);
+ }
+
+ this.getLog().debug("Found APS Custom Email Templates: " + map.size());
+
+ return map;
+ }
+
+ protected Map findDocumentTemplates(Long tenantId) {
+ List matchingPatterns = this.buildPatterns(this.apsDocumentTemplateNames);
+ Map map = new HashMap<>();
+ int pageSize = 50;
+ int page = 1;
+
+ ResultList templates = this.getApsApi().getTemplatesApi().getDocumentTemplates(null, (page-1) * pageSize, pageSize, null, tenantId);
+ while (!templates.getData().isEmpty()) {
+ for (DocumentTemplateLight template : templates.getData()) {
+ for (Pattern pattern : matchingPatterns) {
+ if (pattern.matcher(template.getName()).matches())
+ map.put(template.getName(), template);
+ }
+ }
+
+ page++;
+ templates = this.getApsApi().getTemplatesApi().getDocumentTemplates(null, (page-1) * pageSize, pageSize, null, tenantId);
+ }
+
+ this.getLog().debug("Found APS Document Templates: " + map.size());
+
+ return map;
+ }
+
+ private List buildPatterns(String regexes) {
+ if (regexes == null)
+ return Collections.emptyList();
+
+ List patterns = new LinkedList<>();
+
+ for (String regex : regexes.split(",")) {
+ regex = regex.trim();
+ if (regex.length() > 0)
+ patterns.add(Pattern.compile(regex));
+ }
+
+ return patterns;
+ }
+
+}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/DownloadAppGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/DownloadAppGoal.java
index d37f73b..3d1b174 100644
--- a/src/main/java/com/inteligr8/maven/aps/modeling/goal/DownloadAppGoal.java
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/DownloadAppGoal.java
@@ -37,7 +37,7 @@ import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl;
*/
@Mojo( name = "download-app", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
-public class DownloadAppGoal extends ApsAppAccessibleGoal {
+public class DownloadAppGoal extends ApsAppAddressibleGoal {
@Parameter( property = "aps-model.download.directory", required = true, defaultValue = "${project.build.directory}/aps" )
protected File zipDirectory;
@@ -65,7 +65,7 @@ public class DownloadAppGoal extends ApsAppAccessibleGoal {
this.getLog().debug("Creating APS Apps directory: " + this.zipDirectory);
this.zipDirectory.mkdirs();
} else if (!this.zipDirectory.isDirectory()) {
- throw new IllegalStateException("The 'targetDirectory' refers to a file and not a directory");
+ throw new IllegalStateException("The 'zipDirectory' refers to a file and not a directory");
}
}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/DownloadTemplateGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/DownloadTemplateGoal.java
new file mode 100644
index 0000000..d9be23c
--- /dev/null
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/DownloadTemplateGoal.java
@@ -0,0 +1,127 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+package com.inteligr8.maven.aps.modeling.goal;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.codehaus.plexus.component.annotations.Component;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.inteligr8.alfresco.activiti.model.BaseTemplateLight;
+import com.inteligr8.alfresco.activiti.model.DocumentTemplateLight;
+import com.inteligr8.alfresco.activiti.model.EmailTemplate;
+import com.inteligr8.maven.aps.modeling.normalizer.ApsTemplateJsonNormalizer;
+import com.inteligr8.maven.aps.modeling.util.ModelUtil;
+
+/**
+ * A class that implements an APS service download goal.
+ *
+ * This goal will simply download the APS templates with the specified names
+ * from the specified APS service.
+ *
+ * @author brian@inteligr8.com
+ */
+@Mojo( name = "download-template", threadSafe = true )
+@Component( role = org.apache.maven.plugin.Mojo.class )
+public class DownloadTemplateGoal extends ApsTemplateAddressibleGoal {
+
+ @Parameter( property = "aps-model.download.directory", required = true, defaultValue = "${project.build.directory}/aps" )
+ protected File templateDirectory;
+
+ @Parameter( property = "aps-model.normalize" )
+ protected boolean normalize;
+
+ @Parameter( property = "aps-model.normalize.diffFriendly" )
+ protected boolean diffFriendly;
+
+ @Override
+ public void executeEnabled() throws MojoExecutionException, MojoFailureException {
+ this.validateTargetDirectory();
+
+ Long tenantId = this.findTenantId();
+
+ try {
+ Map> templates = this.findTemplates(tenantId);
+ for (TemplateType ttype : templates.keySet()) {
+ this.getLog().debug("Downloading templates: " + ttype);
+
+ for (Entry template : templates.get(ttype).entrySet()) {
+ switch (ttype) {
+ case Document:
+ ObjectNode djson = ModelUtil.getInstance().readPojo(template.getValue());
+ File dfile = new File(this.templateDirectory, template.getValue().getId() + ".doc-template.json");
+ ModelUtil.getInstance().writeJson(djson, dfile, this.diffFriendly);
+ if (this.normalize)
+ new ApsTemplateJsonNormalizer(this.diffFriendly).normalizeFile(dfile, null);
+
+ File dfilebin = new File(this.templateDirectory, template.getValue().getId() + ".doc-template.docx");
+
+ Response response = this.getApsApi().getTemplatesApi().getDocumentTemplate((DocumentTemplateLight) template.getValue());
+ try {
+ InputStream istream = (InputStream) response.getEntity();
+ try {
+ FileUtils.copyInputStreamToFile(istream, dfilebin);
+ } finally {
+ istream.close();
+ }
+ } finally {
+ response.close();
+ }
+ break;
+ case CustomEmail:
+ EmailTemplate etemplate = this.getApsApi().getTemplatesApi().getCustomEmailTemplate(template.getValue().getId(), tenantId);
+ ObjectNode ejson = ModelUtil.getInstance().readPojo(etemplate);
+ File efile = new File(this.templateDirectory, template.getValue().getId() + ".custom-email-template.json");
+ ModelUtil.getInstance().writeJson(ejson, efile, this.diffFriendly);
+ if (this.normalize)
+ new ApsTemplateJsonNormalizer(this.diffFriendly).normalizeFile(efile, null);
+
+ break;
+ case SystemEmail:
+ EmailTemplate stemplate = this.getApsApi().getTemplatesApi().getSystemEmailTemplate(template.getValue().getName(), tenantId);
+ ObjectNode sjson = ModelUtil.getInstance().readPojo(stemplate);
+ File sfile = new File(this.templateDirectory, template.getValue().getName() + ".system-email-template.json");
+ ModelUtil.getInstance().writeJson(sjson, sfile, this.diffFriendly);
+ if (this.normalize)
+ new ApsTemplateJsonNormalizer(this.diffFriendly).normalizeFile(sfile, null);
+ }
+ }
+ }
+ } catch (IOException ie) {
+ throw new MojoExecutionException("The downloaded APS templates could not be saved", ie);
+ }
+ }
+
+ protected void validateTargetDirectory() {
+ if (!this.templateDirectory.exists()) {
+ this.getLog().debug("Creating APS template directory: " + this.templateDirectory);
+ this.templateDirectory.mkdirs();
+ } else if (!this.templateDirectory.isDirectory()) {
+ throw new IllegalStateException("The 'templateDirectory' refers to a file and not a directory");
+ }
+ }
+
+}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/PublishAppGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/PublishAppGoal.java
index 5541a17..7803c16 100644
--- a/src/main/java/com/inteligr8/maven/aps/modeling/goal/PublishAppGoal.java
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/PublishAppGoal.java
@@ -35,7 +35,7 @@ import com.inteligr8.alfresco.activiti.model.AppDefinitionPublishRepresentation;
*/
@Mojo( name = "publish-app", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
-public class PublishAppGoal extends ApsAppAccessibleGoal {
+public class PublishAppGoal extends ApsAppAddressibleGoal {
@Parameter( property = "aps-model.publish.comment", required = true, defaultValue = "Automated by 'aps-model-maven-plugin'" )
protected String comment;
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/TranslateAppGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/TranslateAppGoal.java
index e305016..742377e 100644
--- a/src/main/java/com/inteligr8/maven/aps/modeling/goal/TranslateAppGoal.java
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/TranslateAppGoal.java
@@ -33,7 +33,7 @@ import com.inteligr8.maven.aps.modeling.translator.ApsAppTranslator;
* This goal will translate all the JSON and XML files in an APS App to match
* the environment referenced by the specified APS App. This relies on all APS
* model elements (apps, processes, and forms) to have unique names. The names
- * of those mdoel elements are used to remap IDs between environments.
+ * of those model elements are used to remap IDs between environments.
*
* APS does not enforce a unique name constraint. But it is good practice to
* avoid using the same name anyhow. This plugin will just make you do it. It
@@ -43,7 +43,7 @@ import com.inteligr8.maven.aps.modeling.translator.ApsAppTranslator;
*/
@Mojo( name = "translate-app", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
-public class TranslateAppGoal extends ApsAppAccessibleGoal {
+public class TranslateAppGoal extends ApsAppAddressibleGoal {
@Parameter( property = "aps-model.app.directory", required = true, defaultValue = "${project.build.directory}/aps/app" )
protected File unzipDirectory;
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/TranslateTemplateGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/TranslateTemplateGoal.java
new file mode 100644
index 0000000..4b24f8b
--- /dev/null
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/TranslateTemplateGoal.java
@@ -0,0 +1,95 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+package com.inteligr8.maven.aps.modeling.goal;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.codehaus.plexus.component.annotations.Component;
+
+import com.inteligr8.maven.aps.modeling.crawler.ApsTemplateCrawler;
+import com.inteligr8.maven.aps.modeling.translator.ApsTemplateTranslator;
+
+/**
+ * A class that implements an APS template translation goal.
+ *
+ * This goal will translate all the JSON template files to match the
+ * environment referenced by the specified APS service. This relies on all APS
+ * templates having unique names. The names of those templates are used to
+ * remap IDs between environments.
+ *
+ * @author brian@inteligr8.com
+ */
+@Mojo( name = "translate-template", threadSafe = true )
+@Component( role = org.apache.maven.plugin.Mojo.class )
+public class TranslateTemplateGoal extends ApsAddressibleGoal {
+
+ @Parameter( property = "aps-model.template.directory", required = true, defaultValue = "${project.build.directory}/aps" )
+ protected File templateDirectory;
+
+ @Parameter( property = "aps-model.translatedTemplate.directory", required = false, defaultValue = "${project.build.directory}/aps" )
+ protected File finalDirectory;
+
+ @Parameter( property = "aps-model.translate.overwrite", required = true, defaultValue = "true" )
+ protected boolean overwrite = true;
+
+ @Parameter( property = "aps-model.translate.charset", required = true, defaultValue = "utf-8" )
+ protected String charsetName = "utf-8";
+
+ @Override
+ public void executeEnabled() throws MojoExecutionException, MojoFailureException {
+ this.validateApsTemplateDirectory();
+ this.validateTargetDirectory();
+
+ try {
+ if (!this.templateDirectory.equals(this.finalDirectory)) {
+ FileUtils.copyDirectory(this.templateDirectory, this.finalDirectory);
+ }
+
+ ApsTemplateTranslator translator = new ApsTemplateTranslator(this.getApsApi());
+ translator.buildIndexes();
+
+ ApsTemplateCrawler crawler = new ApsTemplateCrawler(this.finalDirectory, true);
+ crawler.execute(translator);
+ } catch (IOException ie) {
+ throw new MojoExecutionException("An I/O issue occurred", ie);
+ } catch (IllegalArgumentException iae) {
+ throw new MojoExecutionException("The input is not supported", iae);
+ } catch (IllegalStateException ise) {
+ throw new MojoExecutionException("The state of system is not supported", ise);
+ }
+ }
+
+ protected void validateApsTemplateDirectory() throws MojoExecutionException {
+ if (!this.templateDirectory.exists())
+ throw new MojoExecutionException("The 'templateDirectory' does not exist: " + this.templateDirectory);
+ if (!this.templateDirectory.isDirectory())
+ throw new MojoExecutionException("The 'templateDirectory' is not a directory: " + this.templateDirectory);
+ }
+
+ protected void validateTargetDirectory() throws MojoExecutionException {
+ if (!this.finalDirectory.exists()) {
+ this.finalDirectory.mkdirs();
+ } else if (!this.finalDirectory.isDirectory()) {
+ throw new MojoExecutionException("The 'finalDirectory' is not a directory: " + this.finalDirectory);
+ }
+ }
+
+}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/UploadAppGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/UploadAppGoal.java
index 9396a6a..4dce552 100644
--- a/src/main/java/com/inteligr8/maven/aps/modeling/goal/UploadAppGoal.java
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/UploadAppGoal.java
@@ -42,7 +42,7 @@ import com.inteligr8.alfresco.activiti.model.FileMultipartJersey;
*/
@Mojo( name = "upload-app", threadSafe = true )
@Component( role = org.apache.maven.plugin.Mojo.class )
-public class UploadAppGoal extends ApsAppAccessibleGoal {
+public class UploadAppGoal extends ApsAppAddressibleGoal {
@Parameter( property = "aps-model.upload.directory", required = true, defaultValue = "${project.build.directory}/aps" )
protected File zipDirectory;
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/UploadTemplateGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/UploadTemplateGoal.java
new file mode 100644
index 0000000..5ffc08c
--- /dev/null
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/UploadTemplateGoal.java
@@ -0,0 +1,118 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+package com.inteligr8.maven.aps.modeling.goal;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.text.ParseException;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.codehaus.plexus.component.annotations.Component;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.inteligr8.alfresco.activiti.model.DocumentTemplateLight;
+import com.inteligr8.alfresco.activiti.model.EmailTemplate;
+import com.inteligr8.alfresco.activiti.model.FileMultipartJersey;
+import com.inteligr8.maven.aps.modeling.util.ModelUtil;
+
+/**
+ * A class that implements an APS service upload goal.
+ *
+ * This goal will simply upload the APS templates within the specified template
+ * directory to the specified APS service. Any IDs specified in the uploaded
+ * templates must match existing IDs for them to properly version. That is the
+ * main purpose of this plugin and can be achieved using the
+ * 'translate-template' goal.
+ *
+ * @author brian@inteligr8.com
+ */
+@Mojo( name = "upload-template", threadSafe = true )
+@Component( role = org.apache.maven.plugin.Mojo.class )
+public class UploadTemplateGoal extends ApsAddressibleGoal {
+
+ @Parameter( property = "aps-model.upload.directory", required = true, defaultValue = "${project.build.directory}/aps" )
+ protected File templateDirectory;
+
+ protected final int bufferSize = 128 * 1024;
+
+ @Override
+ public void executeEnabled() throws MojoExecutionException, MojoFailureException {
+ this.validateSourceDirectory();
+
+ Long tenantId = this.findTenantId();
+
+ for (File file : this.templateDirectory.listFiles()) {
+ if (!file.getName().endsWith(".json")) {
+ this.getLog().debug("Ignoring file: " + file.getName());
+ continue;
+ }
+
+ try {
+ if (file.getName().endsWith(".doc-template.json")) {
+ DocumentTemplateLight template = ModelUtil.getInstance().writePojo(ModelUtil.getInstance().readJsonAsMap(file), DocumentTemplateLight.class);
+
+ File docxfile = new File(file.getParent(), file.getName().substring(0, file.getName().length() - ".json".length()) + ".docx");
+ if (!docxfile.exists())
+ throw new FileNotFoundException("The file, '" + docxfile.getName() + "' was expected and not found");
+
+ FileInputStream fistream = new FileInputStream(docxfile);
+ BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize);
+ try {
+ FileMultipartJersey multipart = FileMultipartJersey.from(docxfile.getName(), bistream);
+ if (template.getId() == null) {
+ this.getApsApi().getTemplatesJerseyApi().createDocumentTemplate(tenantId, multipart);
+ } else {
+ this.getApsApi().getTemplatesJerseyApi().updateDocumentTemplate(template.getId(), tenantId, multipart);
+ }
+ } finally {
+ bistream.close();
+ fistream.close();
+ }
+ } else if (file.getName().endsWith(".custom-email-template.json")) {
+ EmailTemplate template = ModelUtil.getInstance().writePojo(ModelUtil.getInstance().readJsonAsMap(file), EmailTemplate.class);
+ if (template.getId() == null) {
+ this.getApsApi().getTemplatesJerseyApi().createCustomEmailTemplate(template);
+ } else {
+ this.getApsApi().getTemplatesJerseyApi().updateCustomEmailTemplate(template.getId(), template);
+ }
+ } else if (file.getName().endsWith(".system-email-template.json")) {
+ EmailTemplate template = ModelUtil.getInstance().writePojo(ModelUtil.getInstance().readJsonAsMap(file), EmailTemplate.class);
+ this.getApsApi().getTemplatesJerseyApi().updateSystemEmailTemplate(template.getName(), template);
+ }
+ } catch (JsonProcessingException jpe) {
+ throw new MojoExecutionException("The APS templates JSON files could not be parsed", jpe);
+ } catch (IOException ie) {
+ throw new MojoExecutionException("The APS templates could not be uploaded", ie);
+ } catch (ParseException pe) {
+ throw new MojoFailureException("This should never happen", pe);
+ }
+ }
+ }
+
+ protected void validateSourceDirectory() {
+ if (!this.templateDirectory.exists()) {
+ throw new IllegalStateException("The 'templateDirectory' does not exist: " + this.templateDirectory);
+ } else if (!this.templateDirectory.isDirectory()) {
+ throw new IllegalStateException("The 'templateDirectory' is not a directory: " + this.templateDirectory);
+ }
+ }
+
+}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/normalizer/ApsTemplateJsonNormalizer.java b/src/main/java/com/inteligr8/maven/aps/modeling/normalizer/ApsTemplateJsonNormalizer.java
new file mode 100644
index 0000000..659fd18
--- /dev/null
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/normalizer/ApsTemplateJsonNormalizer.java
@@ -0,0 +1,73 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+package com.inteligr8.maven.aps.modeling.normalizer;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.inteligr8.maven.aps.modeling.util.ModelUtil;
+
+/**
+ * This class implements an APS template JSON configuration file normalizer.
+ *
+ * This will remove the 'created' date of each defined template.
+ *
+ * @author brian@inteligr8.com
+ */
+public class ApsTemplateJsonNormalizer implements ApsFileNormalizer {
+
+ private final Logger logger = LoggerFactory.getLogger(ApsTemplateJsonNormalizer.class);
+
+ private final boolean enableSorting;
+
+ /**
+ * This constructor initializes the default normalizer with or without
+ * sorting.
+ *
+ * The sorting feature is available for a better "diff" experience. If
+ * you intend to commit the APS App configurations to Git, you will want to
+ * enable sorting.
+ *
+ * @param enableSorting true to re-order JSON objects; false to keep as-is.
+ */
+ public ApsTemplateJsonNormalizer(boolean enableSorting) {
+ this.enableSorting = enableSorting;
+ }
+
+ @Override
+ public void normalizeFile(File file, String _unused) throws IOException {
+ this.logger.debug("Normalizing template JSON file: {}", file);
+
+ ObjectNode templateJson = (ObjectNode) ModelUtil.getInstance().readJson(file);
+ boolean changed = this.transformModel(templateJson);
+
+ if (changed)
+ ModelUtil.getInstance().writeJson(templateJson, file, this.enableSorting);
+ }
+
+ private boolean transformModel(ObjectNode jsonModel) {
+ this.logger.trace("Removing excess template meta-data: {}", jsonModel.get("name"));
+
+ int fields = jsonModel.size();
+ jsonModel.remove(Arrays.asList("created", "createdBy"));
+ return jsonModel.size() < fields;
+ }
+
+}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/normalizer/ApsTemplateNormalizer.java b/src/main/java/com/inteligr8/maven/aps/modeling/normalizer/ApsTemplateNormalizer.java
new file mode 100644
index 0000000..b839983
--- /dev/null
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/normalizer/ApsTemplateNormalizer.java
@@ -0,0 +1,48 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+package com.inteligr8.maven.aps.modeling.normalizer;
+
+import com.inteligr8.maven.aps.modeling.crawler.ApsFileTransformer;
+import com.inteligr8.maven.aps.modeling.crawler.ApsTemplateCrawlable;
+
+/**
+ * This class defines an APS template normalizer.
+ *
+ * @author brian@inteligr8.com
+ */
+public class ApsTemplateNormalizer implements ApsTemplateCrawlable {
+
+ private final boolean enableSorting;
+
+ /**
+ * This constructor initializes the default normalizer with or without
+ * sorting.
+ *
+ * The sorting feature is available for a better "diff" experience. If
+ * you intend to commit the APS template configurations to Git, you will
+ * want to enable sorting.
+ *
+ * @param enableSorting true to re-order JSON objects; false to keep as-is.
+ */
+ public ApsTemplateNormalizer(boolean enableSorting) {
+ this.enableSorting = enableSorting;
+ }
+
+ @Override
+ public ApsFileTransformer getTemplateJsonTransformer() {
+ return new ApsTemplateJsonNormalizer(this.enableSorting);
+ }
+
+}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsTemplateJsonTranslator.java b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsTemplateJsonTranslator.java
new file mode 100644
index 0000000..716ea0b
--- /dev/null
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsTemplateJsonTranslator.java
@@ -0,0 +1,90 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+package com.inteligr8.maven.aps.modeling.translator;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.inteligr8.maven.aps.modeling.util.Index;
+import com.inteligr8.maven.aps.modeling.util.ModelUtil;
+
+/**
+ * This class implements an APS template JSON configuration file translator.
+ *
+ * @author brian@inteligr8.com
+ */
+public class ApsTemplateJsonTranslator implements ApsFileTranslator {
+
+ private final Logger logger = LoggerFactory.getLogger(ApsTemplateJsonTranslator.class);
+ private final Index apsDocumentTemplateIndex;
+ private final Index apsCustomEmailTemplateIndex;
+
+ /**
+ * This constructor initializes the default translator.
+ *
+ * @param api An APS API reference.
+ */
+ public ApsTemplateJsonTranslator(
+ Index apsDocumentTemplateIndex,
+ Index apsCustomEmailTemplateIndex) {
+ this.apsDocumentTemplateIndex = apsDocumentTemplateIndex;
+ this.apsCustomEmailTemplateIndex = apsCustomEmailTemplateIndex;
+ }
+
+ @Override
+ public void translateFile(File file, String _unsued1, Long _unused2) throws IOException {
+ this.logger.debug("Translating JSON file: {}", file);
+
+ boolean changed = false;
+
+ ObjectNode json = (ObjectNode) ModelUtil.getInstance().readJson(file);
+
+ boolean isDocumentTemplate = json.get("mimeType") != null;
+ String templateName = json.get("name").asText();
+ this.logger.trace("Found template name '{}' in APS template file: {}", templateName, file);
+
+ Long oldTemplateId = null;
+ if (json.hasNonNull("id")) {
+ oldTemplateId = json.get("id").asLong();
+ this.logger.trace("Found template ID '{}' in APS template file: {}", oldTemplateId, file);
+ }
+
+ Long newTemplateId = null;
+ if (isDocumentTemplate) {
+ newTemplateId = this.apsDocumentTemplateIndex.getFirstKey(templateName);
+ } else {
+ newTemplateId = this.apsCustomEmailTemplateIndex.getFirstKey(templateName);
+ }
+
+ if (newTemplateId == null) {
+ // new template; remove the key completely
+ json.remove("id");
+ changed = true;
+ } else if (newTemplateId.equals(oldTemplateId)) {
+ // unchanged; nothing to do
+ } else {
+ json.put("id", newTemplateId);
+ changed = true;
+ }
+
+ if (changed)
+ ModelUtil.getInstance().writeJson(json, file, false);
+ }
+
+}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsTemplateTranslator.java b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsTemplateTranslator.java
new file mode 100644
index 0000000..df5deb6
--- /dev/null
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsTemplateTranslator.java
@@ -0,0 +1,149 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+package com.inteligr8.maven.aps.modeling.translator;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.inteligr8.activiti.model.ResultList;
+import com.inteligr8.alfresco.activiti.ApsPublicRestApi;
+import com.inteligr8.alfresco.activiti.model.BaseTemplateLight;
+import com.inteligr8.alfresco.activiti.model.Tenant;
+import com.inteligr8.maven.aps.modeling.crawler.ApsFileTransformer;
+import com.inteligr8.maven.aps.modeling.crawler.ApsTemplateCrawlable;
+import com.inteligr8.maven.aps.modeling.util.Index;
+
+/**
+ * This class defines an APS App package translator.
+ *
+ * An APS App package is a ZIP file that contains multiple files in a
+ * predictable folder hierachy with predictable file names. It is effectively
+ * an APS App interchange format specification.
+ *
+ * A package must have at least a single configuration file at the root of the
+ * ZIP package in the JSON format. It must be named the APS App name. That
+ * file will then reference all the model elements contained in the ZIP. Any
+ * model elements not referenced will simply be ignored by APS and by this
+ * plugin.
+ *
+ * This class has methods that provide translator for all the various model
+ * elements in an APS App package.
+ *
+ * @author brian@inteligr8.com
+ */
+public class ApsTemplateTranslator implements ApsTemplateCrawlable {
+
+ private final Logger logger = LoggerFactory.getLogger(ApsTemplateTranslator.class);
+ private final ApsPublicRestApi api;
+
+ private boolean indexesBuilt = false;
+ private Index apsDocumentTemplateIndex;
+ private Index apsCustomEmailTemplateIndex;
+
+ public ApsTemplateTranslator(ApsPublicRestApi api) {
+ this.api = api;
+ }
+
+ /**
+ * This method initializes the data required from the APS Service for the
+ * function of this class.
+ *
+ * @throws IOException A network I/O related issue occurred.
+ */
+ public synchronized void buildIndexes() throws IOException {
+ if (this.indexesBuilt)
+ return;
+
+ this.logger.info("Building indexes ...");
+
+ long tenantId = this.findTenantId();
+ this.logger.debug("APS tenant ID: {}", tenantId);
+
+ this.apsDocumentTemplateIndex = this.buildApsDocumentTemplateIndex(tenantId);
+ this.logLarge("APS document templates: {}", this.apsDocumentTemplateIndex);
+
+ this.apsCustomEmailTemplateIndex = this.buildApsCustomEmailTemplateIndex(tenantId);
+ this.logLarge("APS custom email templates: {}", this.apsCustomEmailTemplateIndex);
+
+ this.indexesBuilt = true;
+ }
+
+ private void logLarge(String message, Index index) {
+ if (this.logger.isTraceEnabled()) {
+ this.logger.trace(message, index);
+ } else {
+ this.logger.debug(message, index.valueSet());
+ }
+ }
+
+ @Override
+ public ApsFileTransformer getTemplateJsonTransformer() {
+ if (!this.indexesBuilt)
+ throw new IllegalStateException("The indexes are never built");
+
+ return new ApsTemplateJsonTranslator(
+ this.apsDocumentTemplateIndex,
+ this.apsCustomEmailTemplateIndex);
+ }
+
+ protected Long findTenantId() {
+ List tenants = this.api.getAdminApi().getTenants();
+ return (tenants == null || tenants.isEmpty()) ? null : tenants.iterator().next().getId();
+ }
+
+ protected Index buildApsDocumentTemplateIndex(Long tenantId) {
+ int perPage = 50;
+ int page = 1;
+
+ ResultList extends BaseTemplateLight> templates = this.api.getTemplatesApi().getDocumentTemplates(null, (page-1)*perPage, perPage, null, tenantId);
+ Index index = new Index<>(templates.getTotal() / 2, false);
+
+ while (!templates.getData().isEmpty()) {
+ this.logger.debug("APS document templates found: {}-{} out of {}", templates.getStart(), (templates.getStart() + templates.getSize()), templates.getTotal());
+
+ for (BaseTemplateLight template : templates.getData())
+ index.put(template.getId(), template.getName());
+
+ page++;
+ templates = this.api.getTemplatesApi().getDocumentTemplates(null, (page-1)*perPage, perPage, null, tenantId);
+ }
+
+ return index;
+ }
+
+ protected Index buildApsCustomEmailTemplateIndex(Long tenantId) {
+ int perPage = 50;
+ int page = 1;
+
+ ResultList extends BaseTemplateLight> templates = this.api.getTemplatesApi().getCustomEmailTemplates(null, (page-1)*perPage, perPage, null, tenantId);
+ Index index = new Index<>(templates.getTotal() / 2, false);
+
+ while (!templates.getData().isEmpty()) {
+ this.logger.debug("APS document templates found: {}-{} out of {}", templates.getStart(), (templates.getStart() + templates.getSize()), templates.getTotal());
+
+ for (BaseTemplateLight template : templates.getData())
+ index.put(template.getId(), template.getName());
+
+ page++;
+ templates = this.api.getTemplatesApi().getCustomEmailTemplates(null, (page-1)*perPage, perPage, null, tenantId);
+ }
+
+ return index;
+ }
+
+}
diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/util/ModelUtil.java b/src/main/java/com/inteligr8/maven/aps/modeling/util/ModelUtil.java
index 00ef5f0..0844eb5 100644
--- a/src/main/java/com/inteligr8/maven/aps/modeling/util/ModelUtil.java
+++ b/src/main/java/com/inteligr8/maven/aps/modeling/util/ModelUtil.java
@@ -52,6 +52,8 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.inteligr8.maven.aps.modeling.xml.DomNamespaceContext;
/**
@@ -73,8 +75,8 @@ public class ModelUtil {
- private final ObjectMapper om = new ObjectMapper();
- private final ObjectMapper omsorted = new ObjectMapper();
+ private final ObjectMapper om = new ObjectMapper().registerModule(new JavaTimeModule());
+ private final ObjectMapper omsorted = new ObjectMapper().registerModule(new JavaTimeModule());
private final DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
private final DocumentBuilder docBuilder;
private final XPathFactory xpathfactory = XPathFactory.newInstance();
@@ -296,6 +298,28 @@ public class ModelUtil {
public Map readJsonAsMap(InputStream istream) throws IOException {
return this.om.readValue(istream, Map.class);
}
+
+ /**
+ * This method reads/parses a Java POJO.
+ *
+ * @param o A Java POJO.
+ * @return A JSON node (array, object, or value).
+ * @throws IOException A stream I/O issue occurred.
+ */
+ public ObjectNode readPojo(Object o) {
+ return this.om.convertValue(o, ObjectNode.class);
+ }
+
+ /**
+ * This method reads/parses a Java POJO.
+ *
+ * @param o A Java POJO.
+ * @return A Java POJO as a map.
+ */
+ @SuppressWarnings("unchecked")
+ public Map readPojoAsMap(Object o) {
+ return this.om.convertValue(o, Map.class);
+ }
/**
* This method formats/writes JSON to the specified file.
@@ -384,6 +408,20 @@ public class ModelUtil {
this.om.writeValue(ostream, map);
}
}
+
+ /**
+ * This method formats/writes a Java POJO of the specified type using the
+ * specified map.
+ *
+ * @param The class of the type to create.
+ * @param map A Java map.
+ * @param type A Java class to create.
+ * @return A Java POJO instance.
+ * @throws IOException A file I/O issue occurred.
+ */
+ public T writePojo(Map map, Class type) throws IOException {
+ return this.om.convertValue(map, type);
+ }