diff --git a/pom.xml b/pom.xml index 0088d9a..ce55cfa 100644 --- a/pom.xml +++ b/pom.xml @@ -184,6 +184,7 @@ jar public + true @@ -212,6 +213,13 @@ run + + ${aps-model.baseUrl} + ${aps-model.authType} + ${aps-model.basicAuth.username} + ${aps-model.basicAuth.password} + ${aps-model.appName} + ${run-it}/pom.xml @@ -223,6 +231,14 @@ + + + + inteligr8-releases + Inteligr8 Releases + https://repos.inteligr8.com/nexus/repository/inteligr8-public + + diff --git a/src/it/download-app/pom.xml b/src/it/download-app/pom.xml index 6f4c9dd..e3d8f43 100644 --- a/src/it/download-app/pom.xml +++ b/src/it/download-app/pom.xml @@ -12,10 +12,6 @@ Download App Plugin Tests - - FORMS Core - - @@ -29,9 +25,6 @@ download-app - - ${aps.app} - download-app-other @@ -40,8 +33,7 @@ download-app - ${aps.app} - ${basedir}/src/main/app + ${basedir}/src/main/aps @@ -57,8 +49,8 @@ - ${project.build.directory}/app/${aps.app}.zip - ${basedir}/src/main/app/${aps.app}.zip + ${project.build.directory}/aps/${aps-model.appName}.zip + ${basedir}/src/main/aps/${aps-model.appName}.zip diff --git a/src/it/translate-app/pom.xml b/src/it/translate-app/pom.xml index 0d70c2a..0c0bc72 100644 --- a/src/it/translate-app/pom.xml +++ b/src/it/translate-app/pom.xml @@ -12,10 +12,6 @@ Translate App Plugin Tests - - FORMS Core - - @@ -31,7 +27,7 @@ unpack-app - ${aps.app} + true @@ -41,8 +37,7 @@ translate-app - ${aps.app} - ${basedir}/src/main/app + ${basedir}/src/main/aps/app @@ -58,7 +53,7 @@ - ${basedir}/src/main/app/${aps.app}/${aps.app}.json + ${basedir}/src/main/aps/app/${aps-model.appName}/${aps-model.appName}.json diff --git a/src/it/unpack-app/pom.xml b/src/it/unpack-app/pom.xml index 085b737..df47b5b 100644 --- a/src/it/unpack-app/pom.xml +++ b/src/it/unpack-app/pom.xml @@ -12,10 +12,6 @@ Unpack App Plugin Tests - - FORMS Core - - @@ -30,9 +26,6 @@ download-app unpack-app - - ${aps.app} - unpack-app @@ -41,8 +34,7 @@ unpack-app - ${aps.app} - ${basedir}/src/main/app + ${basedir}/src/main/aps/app @@ -58,8 +50,8 @@ - ${project.build.directory}/app/${aps.app}/${aps.app}.json - ${basedir}/src/main/app/${aps.app}/${aps.app}.json + ${project.build.directory}/aps/app/${aps-model.appName}/${aps-model.appName}.json + ${basedir}/src/main/aps/app/${aps-model.appName}/${aps-model.appName}.json diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/ApsAppAccessibleGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/ApsAppAccessibleGoal.java deleted file mode 100644 index d59ff31..0000000 --- a/src/main/java/com/inteligr8/maven/aps/modeling/ApsAppAccessibleGoal.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.inteligr8.maven.aps.modeling; - -import java.util.List; - -import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl; -import com.inteligr8.alfresco.activiti.api.ModelsApi.ModelType; -import com.inteligr8.alfresco.activiti.model.Datum; -import com.inteligr8.alfresco.activiti.model.ResultListDataRepresentation; -import com.inteligr8.alfresco.activiti.model.Tenant; - -public abstract class ApsAppAccessibleGoal extends ApsAddressibleGoal { - - protected Long findTenantId() { - List tenants = this.getApsApi().getAdminApi().getTenants(); - if (tenants == null || tenants.isEmpty()) - return null; - return tenants.iterator().next().getId(); - } - - protected Long findAppByName(String appName) { - ApsPublicRestApiJerseyImpl api = this.getApsApi(); - - this.getLog().debug("Searching for APS App with name: " + appName); - ResultListDataRepresentation results = api.getModelsApi().get(null, null, ModelType.App.getId(), null); - this.getLog().debug("Found " + results.getTotal() + " APS Apps"); - for (Datum datum : results.getData()) { - String name = (String)datum.getAdditionalProperties().get("name"); - if (name.equals(appName)) { - Number id = (Number)datum.getAdditionalProperties().get("id"); - this.getLog().info("Found APS App ID: " + id); - return id == null ? null : id.longValue(); - } - } - - return null; - } - -} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/UnpackAppGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/UnpackAppGoal.java deleted file mode 100644 index ed755e0..0000000 --- a/src/main/java/com/inteligr8/maven/aps/modeling/UnpackAppGoal.java +++ /dev/null @@ -1,186 +0,0 @@ -package com.inteligr8.maven.aps.modeling; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -import javax.xml.transform.TransformerException; - -import org.apache.commons.io.IOUtils; -import org.apache.maven.plugin.AbstractMojo; -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 org.xml.sax.SAXException; - -@Mojo( name = "unpack-app", threadSafe = true ) -@Component( role = org.apache.maven.plugin.Mojo.class ) -public class UnpackAppGoal extends AbstractMojo { - - @Parameter( property = "apsAppName", required = true ) - protected String apsAppName; - - @Parameter( property = "sourceDirectory", required = true, defaultValue = "${project.build.directory}/app" ) - protected File sourceDirectory; - - @Parameter( property = "targetDirectory", required = true, defaultValue = "${project.build.directory}/app" ) - protected File targetDirectory; - - @Parameter( property = "charset", required = true, defaultValue = "utf-8" ) - protected String charsetName = "utf-8"; - - @Parameter( property = "skip", required = true, defaultValue = "false" ) - protected boolean skip = false; - - private final int bufferSize = 128 * 1024; - - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - File sourceFile = this.validateSourceDirectory(); - - this.validateTargetDirectory(); - File appDirectory = this.validateAppDirectory(); - this.getLog().debug("Clearing directory: " + appDirectory); - this.clearDirectory(appDirectory); - - try { - this.unpack(sourceFile, appDirectory); - } catch (IOException ie) { - throw new MojoExecutionException("The downloaded APS App could not be unpacked", ie); - } - - this.normalizeFiles(appDirectory); - } - - protected File validateSourceDirectory() { - if (!this.sourceDirectory.exists()) { - throw new IllegalStateException("The 'sourceDirectory' does not exist: " + this.sourceDirectory); - } else if (!this.sourceDirectory.isDirectory()) { - throw new IllegalStateException("The 'sourceDirectory' is not a directory: " + this.sourceDirectory); - } - - File sourceFile = new File(this.sourceDirectory, this.apsAppName + ".zip"); - - if (!sourceFile.exists()) { - throw new IllegalStateException("The App file does not exists in the 'sourceDirectory': " + sourceFile); - } else if (!sourceFile.isFile()) { - throw new IllegalStateException("The App file is not a file: " + sourceFile); - } - - return sourceFile; - } - - protected void validateTargetDirectory() { - if (!this.targetDirectory.exists()) { - this.getLog().debug("Creating APS Apps directory: " + this.targetDirectory); - this.targetDirectory.mkdirs(); - } else if (!this.targetDirectory.isDirectory()) { - throw new IllegalStateException("The 'apsAppsDirectory' refers to a file and not a directory: " + this.targetDirectory); - } - } - - protected File validateAppDirectory() { - File appDirectory = new File(this.targetDirectory, this.apsAppName); - if (!appDirectory.exists()) { - this.getLog().debug("Creating APS App directory: " + appDirectory); - appDirectory.mkdirs(); - } else if (!appDirectory.isDirectory()) { - throw new IllegalStateException("The 'apsAppsDirectory' has a file where nothing or a directory is expected: " + appDirectory); - } - - return appDirectory; - } - - private void unpack(File appZip, File targetDirectory) throws IOException { - FileInputStream fistream = new FileInputStream(appZip); - BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize); - try { - ZipInputStream zistream = new ZipInputStream(bistream); - try { - for (ZipEntry zentry = zistream.getNextEntry(); zentry != null; zentry = zistream.getNextEntry()) { - try { - String path = zentry.getName(); - if (!zentry.isDirectory()) { - this.getLog().debug("Unzipping path: " + zentry.getName()); - this.unzipToPath(zistream, Paths.get(path), targetDirectory); - } - } finally { - zistream.closeEntry(); - } - } - } finally { - zistream.close(); - } - } finally { - bistream.close(); - } - } - - private void unzipToPath(InputStream istream, Path relativePath, File targetDirectory) throws IOException { - Path path = targetDirectory.toPath().resolve(relativePath); - Path folderPath = path.getParent(); - Files.createDirectories(folderPath); - - FileOutputStream fostream = new FileOutputStream(path.toFile()); - BufferedOutputStream bostream = new BufferedOutputStream(fostream); - try { - IOUtils.copy(istream, bostream); - } finally { - bostream.close(); - } - } - - private void clearDirectory(File directory) { - for (File file : directory.listFiles()) { - if (file.isDirectory()) - this.clearDirectory(file); - file.delete(); - } - } - - private void normalizeFiles(File directory) throws MojoFailureException { - for (File file : directory.listFiles()) { - if (file.isDirectory()) { - this.normalizeFiles(file); - } else { - String ext = this.getFileExtension(file); - - try { - switch (ext) { - case "json": - ModelUtil.getInstance().json(file); - break; - case "xml": - case "bpmn": - ModelUtil.getInstance().xml(file); - break; - default: - file.delete(); - } - } catch (TransformerException | SAXException | IOException e) { - throw new MojoFailureException("The following file faild to be reformatted: " + file, e); - } - } - } - } - - private String getFileExtension(File file) { - int lastdot = file.getName().lastIndexOf('.'); - if (lastdot < 0) - return null; - - return file.getName().substring(lastdot+1).toLowerCase(); - } - -} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/ApsAddressibleGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAddressibleGoal.java similarity index 65% rename from src/main/java/com/inteligr8/maven/aps/modeling/ApsAddressibleGoal.java rename to src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAddressibleGoal.java index 5da59ff..5141963 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/ApsAddressibleGoal.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAddressibleGoal.java @@ -1,47 +1,47 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.goal; -import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugins.annotations.Parameter; import com.inteligr8.alfresco.activiti.ApsClientConfiguration; import com.inteligr8.alfresco.activiti.ApsClientJerseyImpl; import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl; -public abstract class ApsAddressibleGoal extends AbstractMojo { +public abstract class ApsAddressibleGoal extends DisablableGoal { - @Parameter( property = "activitiAppBaseUrl", required = true, defaultValue = "http://localhost:8080/activiti-app" ) + @Parameter( property = "aps-model.baseUrl", required = true, defaultValue = "http://localhost:8080/activiti-app" ) protected String activitiAppBaseUrl; - @Parameter( property = "activitiAppAuth", required = true, defaultValue = "BASIC" ) + @Parameter( property = "aps-model.authType", required = true, defaultValue = "BASIC" ) protected String activitiAppAuthType; - @Parameter( property = "activitiAppBasicUsername", required = false, defaultValue = "admin" ) + @Parameter( property = "aps-model.basicAuth.username", required = false, defaultValue = "admin@app.activiti.com" ) protected String activitiAppAuthBasicUsername; - @Parameter( property = "activitiAppBasicPassword", required = false, defaultValue = "admin" ) + @Parameter( property = "aps-model.basicAuth.password", required = false, defaultValue = "admin" ) protected String activitiAppAuthBasicPassword; - @Parameter( property = "oAuthCode", required = false ) + @Parameter( property = "aps-model.oauth.code", required = false ) protected String oauthCode; - @Parameter( property = "oAuthClientId", required = false ) + @Parameter( property = "aps-model.oauth.clientId", required = false ) protected String oauthClientId; - @Parameter( property = "oAuthClientSecret", required = false ) + @Parameter( property = "aps-model.oauth.clientSecret", required = false ) protected String oauthClientSecret; - @Parameter( property = "oAuthUsername", required = false ) + @Parameter( property = "aps-model.oauth.username", required = false ) protected String oauthUsername; - @Parameter( property = "oAuthPassword", required = false ) + @Parameter( property = "aps-model.oauth.password", required = false ) protected String oauthPassword; - @Parameter( property = "oAuthTokenUrl", required = false ) + @Parameter( property = "aps-model.oauth.tokenUrl", required = false ) protected String oauthTokenUrl; private ApsPublicRestApiJerseyImpl api; public ApsClientConfiguration getApsClientConfiguration() { + this.getLog().debug("Configuring APS to URL: " + this.activitiAppBaseUrl); ApsClientConfiguration config = new ApsClientConfiguration(); config.setBaseUrl(this.activitiAppBaseUrl); switch (this.activitiAppAuthType.toUpperCase()) { @@ -64,7 +64,7 @@ public abstract class ApsAddressibleGoal extends AbstractMojo { config.setOAuthPassword(this.oauthPassword); break; default: - throw new IllegalArgumentException("The 'activitiAppAuth' configuration must be either 'Basic' or 'OAuth'"); + throw new IllegalArgumentException("The 'activitiAppAuthType' configuration must be either 'Basic' or 'OAuth'"); } return config; diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppAccessibleGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppAccessibleGoal.java new file mode 100644 index 0000000..489852a --- /dev/null +++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppAccessibleGoal.java @@ -0,0 +1,57 @@ +package com.inteligr8.maven.aps.modeling.goal; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; + +import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl; +import com.inteligr8.alfresco.activiti.api.ModelsApi.ModelType; +import com.inteligr8.alfresco.activiti.model.Datum; +import com.inteligr8.alfresco.activiti.model.ResultListDataRepresentation; +import com.inteligr8.alfresco.activiti.model.Tenant; + +public abstract class ApsAppAccessibleGoal extends ApsAddressibleGoal { + + @Parameter( property = "aps-model.appName", required = true ) + protected String apsAppName; + + protected Long findTenantId() { + List tenants = this.getApsApi().getAdminApi().getTenants(); + if (tenants == null || tenants.isEmpty()) + return null; + return tenants.iterator().next().getId(); + } + + protected Map findAppNameIds() { + ApsPublicRestApiJerseyImpl api = this.getApsApi(); + + Map apps = new HashMap<>(16); + + this.getLog().debug("Searching for all APS Apps"); + ResultListDataRepresentation results = api.getModelsApi().get("everyone", null, ModelType.App.getId(), null); + this.getLog().debug("Found " + results.getTotal() + " APS Apps"); + for (Datum datum : results.getData()) { + String name = (String)datum.getAdditionalProperties().get("name"); + Number id = (Number)datum.getAdditionalProperties().get("id"); + apps.put(name, id.longValue()); + } + + return apps; + } + + protected Long findAppId() throws MojoExecutionException { + return this.findAppIdByName(this.apsAppName); + } + + protected Long findAppIdByName(String appName) throws MojoExecutionException { + Map apps = this.findAppNameIds(); + Long appId = apps.get(this.apsAppName); + if (appId == null) + throw new MojoExecutionException("The APS App '' could not be found; valid apps: " + apps.keySet()); + return appId; + } + +} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppGoal.java new file mode 100644 index 0000000..e60b081 --- /dev/null +++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsAppGoal.java @@ -0,0 +1,10 @@ +package com.inteligr8.maven.aps.modeling.goal; + +import org.apache.maven.plugins.annotations.Parameter; + +public abstract class ApsAppGoal extends DisablableGoal { + + @Parameter( property = "aps-model.appName", required = true ) + protected String apsAppName; + +} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/ApsInfoGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsInfoGoal.java similarity index 85% rename from src/main/java/com/inteligr8/maven/aps/modeling/ApsInfoGoal.java rename to src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsInfoGoal.java index 07b8d01..d3764d5 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/ApsInfoGoal.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/ApsInfoGoal.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.goal; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -12,7 +12,7 @@ import com.inteligr8.alfresco.activiti.model.AppVersion; public class ApsInfoGoal extends ApsAddressibleGoal { @Override - public void execute() throws MojoExecutionException, MojoFailureException { + public void executeEnabled() throws MojoExecutionException, MojoFailureException { AppVersion version = this.getApsApi() .getAppVersionApi() .get(); diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/DeployAppGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/DeployAppGoal.java similarity index 89% rename from src/main/java/com/inteligr8/maven/aps/modeling/DeployAppGoal.java rename to src/main/java/com/inteligr8/maven/aps/modeling/goal/DeployAppGoal.java index 07eee07..1a7d87e 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/DeployAppGoal.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/DeployAppGoal.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.goal; import java.io.BufferedInputStream; import java.io.File; @@ -19,26 +19,21 @@ import com.inteligr8.alfresco.activiti.model.AppDefinitionUpdateResultRepresenta @Component( role = org.apache.maven.plugin.Mojo.class ) public class DeployAppGoal extends ApsAppAccessibleGoal { - @Parameter( property = "apsAppName", required = true ) - protected String apsAppName; - - @Parameter( property = "sourceDirectory", required = true, defaultValue = "${project.build.directory}/app" ) + @Parameter( property = "sourceDirectory", required = true, defaultValue = "${project.build.directory}/aps/app" ) protected File sourceDirectory; @Parameter( property = "publish", required = true, defaultValue = "false" ) protected boolean publish = false; - @Parameter( property = "skip", required = true, defaultValue = "false" ) - protected boolean skip = false; - protected final int bufferSize = 128 * 1024; @Override - public void execute() throws MojoExecutionException, MojoFailureException { + public void executeEnabled() throws MojoExecutionException, MojoFailureException { File sourceFile = this.validateSourceDirectory(); + Long appId = this.findAppId(); + try { - Long appId = this.findAppByName(this.apsAppName); this.uploadApp(appId, sourceFile); } catch (IOException ie) { throw new MojoExecutionException("The downloaded APS App could not be unpacked", ie); diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/DisablableGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/DisablableGoal.java new file mode 100644 index 0000000..ba1c368 --- /dev/null +++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/DisablableGoal.java @@ -0,0 +1,29 @@ +package com.inteligr8.maven.aps.modeling.goal; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Parameter; + +public abstract class DisablableGoal extends AbstractMojo { + + @Parameter( property = "aps-model.skip", required = true, defaultValue = "false" ) + protected boolean skip = false; + + protected boolean isEnabled() { + return !this.skip; + } + + protected boolean isDisabled() { + return this.skip; + } + + @Override + public final void execute() throws MojoExecutionException, MojoFailureException { + if (this.isEnabled()) + this.executeEnabled(); + } + + public abstract void executeEnabled() throws MojoExecutionException, MojoFailureException; + +} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/DownloadAppGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/DownloadAppGoal.java similarity index 61% rename from src/main/java/com/inteligr8/maven/aps/modeling/DownloadAppGoal.java rename to src/main/java/com/inteligr8/maven/aps/modeling/goal/DownloadAppGoal.java index ce95e70..3b7001b 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/DownloadAppGoal.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/DownloadAppGoal.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.goal; import java.io.File; import java.io.IOException; @@ -16,23 +16,17 @@ import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl; @Component( role = org.apache.maven.plugin.Mojo.class ) public class DownloadAppGoal extends ApsAppAccessibleGoal { - @Parameter( property = "apsAppName", required = true ) - protected String apsAppName; - - @Parameter( property = "targetDirectory", required = true, defaultValue = "${project.build.directory}/app" ) - protected File targetDirectory; - - @Parameter( property = "skip", required = true, defaultValue = "false" ) - protected boolean skip = false; + @Parameter( property = "aps-model.download.directory", required = true, defaultValue = "${project.build.directory}/aps" ) + protected File zipDirectory; @Override - public void execute() throws MojoExecutionException, MojoFailureException { + public void executeEnabled() throws MojoExecutionException, MojoFailureException { this.validateTargetDirectory(); - long appId = this.findAppByName(this.apsAppName); + Long appId = this.findAppId(); File appZip = this.downloadApp(appId); - File toAppZip = new File(this.targetDirectory, this.apsAppName + ".zip"); + File toAppZip = new File(this.zipDirectory, this.apsAppName + ".zip"); if (toAppZip.exists()) toAppZip.delete(); @@ -44,10 +38,10 @@ public class DownloadAppGoal extends ApsAppAccessibleGoal { } protected void validateTargetDirectory() { - if (!this.targetDirectory.exists()) { - this.getLog().debug("Creating APS Apps directory: " + this.targetDirectory); - this.targetDirectory.mkdirs(); - } else if (!this.targetDirectory.isDirectory()) { + if (!this.zipDirectory.exists()) { + 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"); } } diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/PackAppGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/PackAppGoal.java similarity index 89% rename from src/main/java/com/inteligr8/maven/aps/modeling/PackAppGoal.java rename to src/main/java/com/inteligr8/maven/aps/modeling/goal/PackAppGoal.java index fb24f77..2db4965 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/PackAppGoal.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/PackAppGoal.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.goal; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -12,7 +12,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.apache.commons.io.IOUtils; -import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Mojo; @@ -21,24 +20,18 @@ import org.codehaus.plexus.component.annotations.Component; @Mojo( name = "pack-app", threadSafe = true ) @Component( role = org.apache.maven.plugin.Mojo.class ) -public class PackAppGoal extends AbstractMojo { +public class PackAppGoal extends ApsAppGoal { - @Parameter( property = "apsAppName", required = true ) - protected String apsAppName; - - @Parameter( property = "sourceDirectory", required = true, defaultValue = "${project.build.directory}/app" ) + @Parameter( property = "sourceDirectory", required = true, defaultValue = "${project.build.directory}/aps/app" ) protected File sourceDirectory; - @Parameter( property = "targetDirectory", required = true, defaultValue = "${project.build.directory}/app" ) + @Parameter( property = "targetDirectory", required = true, defaultValue = "${project.build.directory}/aps/app" ) protected File targetDirectory; - @Parameter( property = "skip", required = true, defaultValue = "false" ) - protected boolean skip = false; - protected final int bufferSize = 128 * 1024; @Override - public void execute() throws MojoExecutionException, MojoFailureException { + public void executeEnabled() throws MojoExecutionException, MojoFailureException { this.validateSourceDirectory(); File appDirectory = this.validateAppDirectory(); diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/TranslateAppGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/TranslateAppGoal.java similarity index 59% rename from src/main/java/com/inteligr8/maven/aps/modeling/TranslateAppGoal.java rename to src/main/java/com/inteligr8/maven/aps/modeling/goal/TranslateAppGoal.java index faa79ba..5f8a178 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/TranslateAppGoal.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/TranslateAppGoal.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.goal; import java.io.File; import java.io.IOException; @@ -12,6 +12,8 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.component.annotations.Component; +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 { @@ -22,26 +24,20 @@ public class TranslateAppGoal extends ApsAppAccessibleGoal { @Parameter( defaultValue = "${session}", readonly = true ) protected MavenSession session; - @Parameter( property = "apsAppName", required = true ) - protected String apsAppName; - - @Parameter( property = "sourceDirectory", required = true, defaultValue = "${project.build.directory}/app" ) - protected File sourceDirectory; + @Parameter( property = "aps-model.app.directory", required = true, defaultValue = "${project.build.directory}/aps/app" ) + protected File unzipDirectory; - @Parameter( property = "targetDirectory", required = false, defaultValue = "${project.build.directory}/app" ) - protected File targetDirectory; + @Parameter( property = "aps-model.translatedApp.directory", required = false, defaultValue = "${project.build.directory}/aps/app" ) + protected File finalDirectory; - @Parameter( property = "overwrite", required = true, defaultValue = "true" ) + @Parameter( property = "aps-model.translate.overwrite", required = true, defaultValue = "true" ) protected boolean overwrite = true; - @Parameter( property = "charset", required = true, defaultValue = "utf-8" ) + @Parameter( property = "aps-model.translate.charset", required = true, defaultValue = "utf-8" ) protected String charsetName = "utf-8"; - @Parameter( property = "skip", required = true, defaultValue = "false" ) - protected boolean skip = false; - @Override - public void execute() throws MojoExecutionException, MojoFailureException { + public void executeEnabled() throws MojoExecutionException, MojoFailureException { File apsAppDirectory = this.validateApsAppDirectory(); File newApsAppDirectory = this.validateTargetDirectory(); @@ -63,34 +59,34 @@ public class TranslateAppGoal extends ApsAppAccessibleGoal { } protected File validateApsAppDirectory() throws MojoExecutionException { - if (!this.sourceDirectory.exists()) - throw new MojoExecutionException("The 'sourceDirectory' does not exist: " + this.sourceDirectory); - if (!this.sourceDirectory.isDirectory()) - throw new MojoExecutionException("The 'sourceDirectory' is not a directory: " + this.sourceDirectory); + if (!this.unzipDirectory.exists()) + throw new MojoExecutionException("The 'unzipDirectory' does not exist: " + this.unzipDirectory); + if (!this.unzipDirectory.isDirectory()) + throw new MojoExecutionException("The 'unzipDirectory' is not a directory: " + this.unzipDirectory); - File appDirectory = new File(this.sourceDirectory, this.apsAppName); + File appDirectory = new File(this.unzipDirectory, this.apsAppName); if (!appDirectory.exists()) - throw new MojoExecutionException("The 'apsAppName' does not exist in the 'apsAppsDirectory': " + appDirectory); + throw new MojoExecutionException("The 'apsAppName' does not exist in the 'unzipDirectory': " + appDirectory); if (!appDirectory.isDirectory()) - throw new MojoExecutionException("The 'apsAppName' is not a directory in the 'apsAppsDirectory': " + appDirectory); + throw new MojoExecutionException("The 'apsAppName' is not a directory in the 'unzipDirectory': " + appDirectory); return appDirectory; } protected File validateTargetDirectory() throws MojoExecutionException { - if (!this.targetDirectory.exists()) { - this.targetDirectory.mkdirs(); - } else if (!this.targetDirectory.isDirectory()) { - throw new MojoExecutionException("The 'targetDirectory' is not a directory: " + this.targetDirectory); + if (!this.finalDirectory.exists()) { + this.finalDirectory.mkdirs(); + } else if (!this.finalDirectory.isDirectory()) { + throw new MojoExecutionException("The 'finalDirectory' is not a directory: " + this.finalDirectory); } - File appDirectory = new File(this.targetDirectory, this.apsAppName); + File appDirectory = new File(this.finalDirectory, this.apsAppName); if (!appDirectory.exists()) { appDirectory.mkdirs(); } else if (!appDirectory.isDirectory()) { - throw new MojoExecutionException("The 'apsAppName' is not a directory in the 'targetDirectory': " + appDirectory); + throw new MojoExecutionException("The 'apsAppName' is not a directory in the 'finalDirectory': " + appDirectory); } return appDirectory; diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/goal/UnpackAppGoal.java b/src/main/java/com/inteligr8/maven/aps/modeling/goal/UnpackAppGoal.java new file mode 100644 index 0000000..d597d4e --- /dev/null +++ b/src/main/java/com/inteligr8/maven/aps/modeling/goal/UnpackAppGoal.java @@ -0,0 +1,302 @@ +package com.inteligr8.maven.aps.modeling.goal; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import javax.xml.transform.TransformerException; + +import org.apache.commons.io.IOUtils; +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 org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.inteligr8.maven.aps.modeling.util.ApsModelArrayNodeSorter; +import com.inteligr8.maven.aps.modeling.util.ApsModelListMapSorter; +import com.inteligr8.maven.aps.modeling.util.ModelUtil; + +@Mojo( name = "unpack-app", threadSafe = true ) +@Component( role = org.apache.maven.plugin.Mojo.class ) +public class UnpackAppGoal extends ApsAppGoal { + + @Parameter( property = "aps-model.download.directory", required = true, defaultValue = "${project.build.directory}/aps" ) + protected File zipDirectory; + + @Parameter( property = "aps-model.app.directory", required = true, defaultValue = "${project.build.directory}/aps/app" ) + protected File unzipDirectory; + + @Parameter( property = "aps-model.reformat", required = true, defaultValue = "true" ) + protected boolean reformat = true; + + @Parameter( property = "aps-model.normalize", required = true, defaultValue = "false" ) + protected boolean normalize; + + @Parameter( property = "aps-model.charset", required = true, defaultValue = "utf-8" ) + protected String charsetName = "utf-8"; + + private final int bufferSize = 128 * 1024; + + @Override + public void executeEnabled() throws MojoExecutionException, MojoFailureException { + this.validate(); + + File sourceFile = this.validateSourceDirectory(); + + this.validateTargetDirectory(); + File appDirectory = this.validateAppDirectory(); + this.getLog().debug("Clearing directory: " + appDirectory); + this.clearDirectory(appDirectory); + + try { + this.unpack(sourceFile, appDirectory); + } catch (IOException ie) { + throw new MojoExecutionException("The downloaded APS App could not be unpacked", ie); + } + + if (this.reformat) + this.reformatFiles(appDirectory); + } + + protected void validate() { + if (this.normalize && !this.reformat) { + this.getLog().warn("The reformat option is disabled, but normalization is enabled; enabling reformat anyway"); + this.reformat = true; + } + } + + protected File validateSourceDirectory() { + if (!this.zipDirectory.exists()) { + throw new IllegalStateException("The 'zipDirectory' does not exist: " + this.zipDirectory); + } else if (!this.zipDirectory.isDirectory()) { + throw new IllegalStateException("The 'zipDirectory' is not a directory: " + this.zipDirectory); + } + + File sourceFile = new File(this.zipDirectory, this.apsAppName + ".zip"); + + if (!sourceFile.exists()) { + throw new IllegalStateException("The App file does not exists in the 'zipDirectory': " + sourceFile); + } else if (!sourceFile.isFile()) { + throw new IllegalStateException("The App file is not a file: " + sourceFile); + } + + return sourceFile; + } + + protected void validateTargetDirectory() { + if (!this.unzipDirectory.exists()) { + this.getLog().debug("Creating unzip directory: " + this.unzipDirectory); + this.unzipDirectory.mkdirs(); + } else if (!this.unzipDirectory.isDirectory()) { + throw new IllegalStateException("The 'unzipDirectory' refers to a file and not a directory: " + this.unzipDirectory); + } + } + + protected File validateAppDirectory() { + File appDirectory = new File(this.unzipDirectory, this.apsAppName); + if (!appDirectory.exists()) { + this.getLog().debug("Creating APS App directory: " + appDirectory); + appDirectory.mkdirs(); + } else if (!appDirectory.isDirectory()) { + throw new IllegalStateException("The 'apsAppsDirectory' has a file where nothing or a directory is expected: " + appDirectory); + } + + return appDirectory; + } + + private void unpack(File appZip, File targetDirectory) throws IOException { + FileInputStream fistream = new FileInputStream(appZip); + BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize); + try { + ZipInputStream zistream = new ZipInputStream(bistream); + try { + for (ZipEntry zentry = zistream.getNextEntry(); zentry != null; zentry = zistream.getNextEntry()) { + try { + String path = zentry.getName(); + if (!zentry.isDirectory()) { + this.getLog().debug("Unzipping path: " + zentry.getName()); + this.unzipToPath(zistream, Paths.get(path), targetDirectory); + } + } finally { + zistream.closeEntry(); + } + } + } finally { + zistream.close(); + } + } finally { + bistream.close(); + } + } + + private void unzipToPath(InputStream istream, Path relativePath, File targetDirectory) throws IOException { + Path path = targetDirectory.toPath().resolve(relativePath); + Path folderPath = path.getParent(); + Files.createDirectories(folderPath); + + FileOutputStream fostream = new FileOutputStream(path.toFile()); + BufferedOutputStream bostream = new BufferedOutputStream(fostream); + try { + IOUtils.copy(istream, bostream); + } finally { + bostream.close(); + } + } + + private void clearDirectory(File directory) { + for (File file : directory.listFiles()) { + if (file.isDirectory()) + this.clearDirectory(file); + file.delete(); + } + } + + private void reformatFiles(File directory) throws MojoFailureException { + for (File file : directory.listFiles()) { + if (file.isDirectory()) { + this.reformatFiles(file); + } else { + String ext = this.getFileExtension(file); + + try { + switch (ext) { + case "json": + this.getLog().debug("Reformatting file: " + file); + Map json = ModelUtil.getInstance().readJsonAsMap(file); + if (this.normalize) + this.normalizeJson(json); + ModelUtil.getInstance().writeJson(json, file); + break; + case "xml": + case "bpmn": + this.getLog().debug("Reformatting file: " + file); + Document xml = ModelUtil.getInstance().readXml(file); + if (this.normalize) + this.normalizeXml(xml); + ModelUtil.getInstance().writeXml(xml, file); + break; + default: + file.delete(); + } + } catch (TransformerException | SAXException | IOException e) { + throw new MojoFailureException("The following file faild to be reformatted: " + file, e); + } + } + } + } + + private boolean normalizeJson(Map jsonMap) { + boolean changed = false; + + try { + List> jsonModels = (List>)this.mapGetsListMaps(jsonMap, "definition", "models"); + changed = ApsModelListMapSorter.getInstance().sort(jsonModels, "name") || changed; + } catch (ClassCastException cce) { + // suppress + } catch (NullPointerException npe) { + // suppress + } + + try { + List> jsonChildShapes = (List>)this.mapGetsListMaps(jsonMap, "childShapes"); + changed = ApsModelListMapSorter.getInstance().sort(jsonChildShapes, "resourceId") || changed; + } catch (ClassCastException cce) { + // suppress + } catch (NullPointerException npe) { + // suppress + } + + try { + List> jsonChildShapes = (List>)this.mapGetsListMaps(jsonMap, "editorJson", "childShapes"); + changed = ApsModelListMapSorter.getInstance().sort(jsonChildShapes, "resourceId") || changed; + } catch (ClassCastException cce) { + // suppress + } catch (NullPointerException npe) { + // suppress + } + + return changed; + } + + @SuppressWarnings("unchecked") + private T mapGets(Map map, Class returnType, String... keys) { + for (int i = 0; i < keys.length - 1; i++) + map = (Map)map.get(keys[i]); + return (T)map.get(keys[keys.length-1]); + } + + @SuppressWarnings("unchecked") + private List mapGetsList(Map map, Class listType, String... keys) { + for (int i = 0; i < keys.length - 1; i++) + map = (Map)map.get(keys[i]); + return (List)map.get(keys[keys.length-1]); + } + + @SuppressWarnings("unchecked") + private List> mapGetsListMaps(Map map, String... keys) { + for (int i = 0; i < keys.length - 1; i++) + map = (Map)map.get(keys[i]); + return (List>)map.get(keys[keys.length-1]); + } + + private boolean normalizeJson(JsonNode json) { + boolean changed = false; + + try { + ArrayNode jsonModels = (ArrayNode)json.get("definition").get("models"); + changed = ApsModelArrayNodeSorter.getInstance().sort(jsonModels, "name") || changed; + } catch (ClassCastException cce) { + // suppress + } catch (NullPointerException npe) { + // suppress + } + + try { + ArrayNode jsonChildShapes = (ArrayNode)json.get("childShapes"); + changed = ApsModelArrayNodeSorter.getInstance().sort(jsonChildShapes, "resourceId") || changed; + } catch (ClassCastException cce) { + // suppress + } catch (NullPointerException npe) { + // suppress + } + + try { + ArrayNode jsonChildShapes = (ArrayNode)json.get("editorJson").get("childShapes"); + changed = ApsModelArrayNodeSorter.getInstance().sort(jsonChildShapes, "resourceId") || changed; + } catch (ClassCastException cce) { + // suppress + } catch (NullPointerException npe) { + // suppress + } + + return changed; + } + + private void normalizeXml(Document xml) { + } + + private String getFileExtension(File file) { + int lastdot = file.getName().lastIndexOf('.'); + if (lastdot < 0) + return null; + + return file.getName().substring(lastdot+1).toLowerCase(); + } + +} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/ApsAppJsonTranslator.java b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsAppJsonTranslator.java similarity index 86% rename from src/main/java/com/inteligr8/maven/aps/modeling/ApsAppJsonTranslator.java rename to src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsAppJsonTranslator.java index 6b947a5..a514bac 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/ApsAppJsonTranslator.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsAppJsonTranslator.java @@ -1,7 +1,8 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.translator; import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.Map; import org.slf4j.Logger; @@ -10,6 +11,8 @@ import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.inteligr8.alfresco.activiti.model.Group; +import com.inteligr8.maven.aps.modeling.util.Index; +import com.inteligr8.maven.aps.modeling.util.ModelUtil; public class ApsAppJsonTranslator implements ApsFileTranslator { @@ -32,10 +35,9 @@ public class ApsAppJsonTranslator implements ApsFileTranslator { @Override public void translateFile(File file, String modelName, Long modelId) throws IOException { this.logger.debug("Translating JSON file: {}", file); - - JsonNode descriptor = ModelUtil.getInstance().readJson(file); - + boolean changed = false; + JsonNode descriptor = ModelUtil.getInstance().readJson(file); for (JsonNode _jsonModel : descriptor.get("definition").get("models")) { ObjectNode jsonModel = (ObjectNode)_jsonModel; @@ -64,6 +66,11 @@ public class ApsAppJsonTranslator implements ApsFileTranslator { this.logger.trace("The process '{}' ID does not change; leaving unchanged", fileProcessName); } } + + int fields = jsonModel.size(); + jsonModel.remove(Arrays.asList("version", "createdBy", "createdByFullName", "lastUpdatedBy", "lastUpdatedByFullName", "lastUpdated")); + if (jsonModel.size() < fields) + changed = true; } for (JsonNode _jsonIdentityInfo : descriptor.get("definition").get("publishIdentityInfo")) { @@ -77,14 +84,14 @@ public class ApsAppJsonTranslator implements ApsFileTranslator { long apsOrgId = this.apsOrgIndex.get(fileOrgName).getId(); if (fileOrgId != apsOrgId) { - this.logger.debug("The organziation '{}' exists in APS with ID {}; changing descriptor", fileOrgName, apsOrgId); + this.logger.debug("The organization '{}' exists in APS with ID {}; changing descriptor", fileOrgName, apsOrgId); jsonGroup.put("id", apsOrgId); changed = true; } else { this.logger.trace("The organization '{}' ID does not change; leaving unchanged", fileOrgName); } } else { - this.logger.warn("The organziation '{}' does not exist in APS", fileOrgName); + this.logger.warn("The organization '{}' does not exist in APS", fileOrgName); // FIXME create the organization } } diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/ApsAppTranslator.java b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsAppTranslator.java similarity index 82% rename from src/main/java/com/inteligr8/maven/aps/modeling/ApsAppTranslator.java rename to src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsAppTranslator.java index 424d94e..17bbbd9 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/ApsAppTranslator.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsAppTranslator.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.translator; import java.io.File; import java.io.IOException; @@ -13,18 +13,20 @@ import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.inteligr8.alfresco.activiti.ApsPublicRestApi; import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl; import com.inteligr8.alfresco.activiti.api.ModelsApi.ModelType; import com.inteligr8.alfresco.activiti.model.Datum; import com.inteligr8.alfresco.activiti.model.Group; import com.inteligr8.alfresco.activiti.model.ResultListDataRepresentation; import com.inteligr8.alfresco.activiti.model.Tenant; +import com.inteligr8.maven.aps.modeling.util.Index; public class ApsAppTranslator { private final Logger logger = LoggerFactory.getLogger(ApsAppTranslator.class); private final Pattern filenamePattern = Pattern.compile("([^/]+)-([0-9]+)\\.(json|bpmn20\\.xml)"); - private final ApsPublicRestApiJerseyImpl api; + private final ApsPublicRestApi api; private final String appName; private final File appDirectory; private final File appDescriptor; @@ -71,22 +73,38 @@ public class ApsAppTranslator { this.logger.debug("APS App tenant ID: {}", tenantId); this.apsOrgIndex = this.buildApsGroupMap(tenantId); - this.logger.debug("APS App organizations: {}", this.apsOrgIndex); + this.logLarge("APS App organizations: {}", this.apsOrgIndex); this.apsProcessIndex = this.buildApsModelIndex(ModelType.Process); - this.logger.debug("APS process models: {}", this.apsProcessIndex); + this.logLarge("APS process models: {}", this.apsProcessIndex); this.apsFormIndex = this.buildApsModelIndex(ModelType.Form); - this.logger.debug("APS form models: {}", this.apsFormIndex); + this.logLarge("APS form models: {}", this.apsFormIndex); this.fileFormIndex = this.buildFileIndex("form-models", this.apsFormIndex, true); - this.logger.debug("File form models: {}", this.fileFormIndex); + this.logLarge("File form models: {}", this.fileFormIndex); this.fileProcessIndex = this.buildFileIndex("bpmn-models", this.apsProcessIndex, true); - this.logger.debug("File process models: {}", this.fileProcessIndex); + this.logLarge("File process models: {}", this.fileProcessIndex); this.fileSubprocessIndex = this.buildFileIndex("bpmn-subprocess-models", this.apsProcessIndex, true); - this.logger.debug("File subprocess models: {}", this.fileSubprocessIndex); + this.logLarge("File subprocess models: {}", this.fileSubprocessIndex); + } + + private void logLarge(String message, Map map) { + if (this.logger.isTraceEnabled()) { + this.logger.trace(message, map); + } else { + this.logger.debug(message, map.keySet()); + } + } + + private void logLarge(String message, Index index) { + if (this.logger.isTraceEnabled()) { + this.logger.trace(message, index); + } else { + this.logger.debug(message, index.valueSet()); + } } protected void translate() throws IOException { @@ -134,7 +152,8 @@ public class ApsAppTranslator { } protected Index buildApsModelIndex(ModelType modelType) { - ResultListDataRepresentation results = this.api.getModelsApi().get(null, null, modelType.getId(), null); + ResultListDataRepresentation results = this.api.getModelsApi().get("everyone", null, modelType.getId(), null); + this.logger.debug("APS {} models found: {} out of {}", modelType, results.getSize(), results.getTotal()); Index map = new Index<>(results.getSize().intValue(), false); @@ -143,11 +162,13 @@ public class ApsAppTranslator { Number defId = (Number)datum.getAdditionalProperties().get("id"); String defName = (String)datum.getAdditionalProperties().get("name"); map.put(defId.longValue(), defName); + + // FIXME add paging support } } catch (IllegalArgumentException iae) { throw new IllegalStateException("This goal does not support the current state of APS", iae); } - + return map; } @@ -157,19 +178,25 @@ public class ApsAppTranslator { } protected Index buildFileIndex(File modelDirectory, Index apsModelIndex, boolean renameFiles) { - if (!modelDirectory.exists()) + if (!modelDirectory.exists()) { + this.logger.debug("APS model directory doesn't exist; creating empty index: {}", modelDirectory); return new Index<>(0, false); + } + if (!modelDirectory.isDirectory()) throw new IllegalStateException("The APS model directory is actually a file: " + modelDirectory); Index fileModelIndex = new Index<>(apsModelIndex.size(), false); for (File modelFile : modelDirectory.listFiles()) { + this.logger.trace("Building index for model file: {}", modelFile); + Matcher matcher = this.filenamePattern.matcher(modelFile.getName()); String modelName = matcher.replaceFirst("$1"); String modelIdStr = matcher.replaceFirst("$2"); String modelExt = matcher.replaceFirst("$3"); long fileModelId = Long.parseLong(modelIdStr); + this.logger.trace("Building index for model {} ID: {}", modelName, fileModelId); fileModelIndex.put(fileModelId, modelName); @@ -184,7 +211,7 @@ public class ApsAppTranslator { File newModelFile = new File(modelFile.getParentFile(), modelName + "-" + apsModelId + "." + modelExt); modelFile.renameTo(newModelFile); } else { - this.logger.debug("The APS model '{}' and corresponding model file have matching IDs", modelName); + this.logger.debug("The APS model '{}' and corresponding model file '{}' have matching IDs", modelName, modelFile.getName()); } } } @@ -198,7 +225,14 @@ public class ApsAppTranslator { protected void translateModels(String modelsDirectoryName, Map translators) throws IOException { File modelsDirectory = new File(this.appDirectory, modelsDirectoryName); + if (!modelsDirectory.exists()) { + this.logger.debug("APS model directory doesn't exist; no models to translate: {}", modelsDirectory); + return; + } + for (File modelFile : modelsDirectory.listFiles()) { + this.logger.trace("Translating model: {}", modelFile); + Matcher matcher = this.filenamePattern.matcher(modelFile.getName()); if (!matcher.find()) { this.logger.warn("The '{}' folder has a file with an unexpected filename format; skipping: {}", modelsDirectoryName, modelFile); @@ -214,6 +248,8 @@ public class ApsAppTranslator { String modelName = matcher.group(1); Long modelId = new Long(matcher.group(2)); + this.logger.trace("Translating model {} ID: {}", modelName, modelId); + this.translate(translator, modelFile, modelName, modelId); } } diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/ApsFileTranslator.java b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsFileTranslator.java similarity index 76% rename from src/main/java/com/inteligr8/maven/aps/modeling/ApsFileTranslator.java rename to src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsFileTranslator.java index 80d4862..b400a68 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/ApsFileTranslator.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsFileTranslator.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.translator; import java.io.File; import java.io.IOException; diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/ApsFormJsonTranslator.java b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsFormJsonTranslator.java similarity index 91% rename from src/main/java/com/inteligr8/maven/aps/modeling/ApsFormJsonTranslator.java rename to src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsFormJsonTranslator.java index 1d9228a..91b853a 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/ApsFormJsonTranslator.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsFormJsonTranslator.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.translator; import java.io.File; import java.io.IOException; @@ -8,6 +8,8 @@ import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.inteligr8.maven.aps.modeling.util.Index; +import com.inteligr8.maven.aps.modeling.util.ModelUtil; public class ApsFormJsonTranslator implements ApsFileTranslator { diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/ApsProcessBpmnTranslator.java b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsProcessBpmnTranslator.java similarity index 95% rename from src/main/java/com/inteligr8/maven/aps/modeling/ApsProcessBpmnTranslator.java rename to src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsProcessBpmnTranslator.java index 61966ca..5a6a688 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/ApsProcessBpmnTranslator.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsProcessBpmnTranslator.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.translator; import java.io.File; import java.io.IOException; @@ -16,13 +16,16 @@ import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Attr; -import org.w3c.dom.CDATASection; +import org.w3c.dom.CharacterData; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.inteligr8.alfresco.activiti.model.Group; +import com.inteligr8.maven.aps.modeling.util.Index; +import com.inteligr8.maven.aps.modeling.util.ModelUtil; +import com.inteligr8.maven.aps.modeling.xml.CDATAFlexSection; public class ApsProcessBpmnTranslator implements ApsFileTranslator { @@ -72,7 +75,7 @@ public class ApsProcessBpmnTranslator implements ApsFileTranslator { changed = this.translateTaskForm(formKeyElement) || changed; } - NodeList subprocessElements = ModelUtil.getInstance().xpath(definitionsElement, "//subProcess"); + NodeList subprocessElements = ModelUtil.getInstance().xpath(definitionsElement, "//tns:subProcess"); for (int n = 0; n < subprocessElements.getLength(); n++) { Element subprocessElement = (Element)subprocessElements.item(n); changed = this.translateSubprocess(subprocessElement) || changed; @@ -84,9 +87,9 @@ public class ApsProcessBpmnTranslator implements ApsFileTranslator { changed = this.translateConditionDefinition(conditionDefinitionElement) || changed; } - NodeList conditionExpressions = ModelUtil.getInstance().xpath(definitionsElement, "//conditionExpression/text()"); + NodeList conditionExpressions = ModelUtil.getInstance().xpath(definitionsElement, "//tns:conditionExpression/text()"); for (int n = 0; n < conditionExpressions.getLength(); n++) { - CDATASection conditionExpression = (CDATASection)conditionExpressions.item(n); + CharacterData conditionExpression = (CharacterData)conditionExpressions.item(n); changed = this.translateConditionExpression(conditionExpression) || changed; } @@ -146,7 +149,7 @@ public class ApsProcessBpmnTranslator implements ApsFileTranslator { if (apsOrgId != orgId) { this.logger.debug("The organization '{}' exists in APS with ID {}; changing model", groupName, apsOrgId); groupNameElement = (Element)groupNameElement.getOwnerDocument().renameNode(groupNameElement, - groupNameElement.getNamespaceURI(), "group-info-name-" + apsOrgId); + groupNameElement.getNamespaceURI(), "modeler:group-info-name-" + apsOrgId); changed = true; } else { this.logger.trace("The organization '{}' ID does not change; leaving unchanged", groupName); @@ -282,7 +285,7 @@ public class ApsProcessBpmnTranslator implements ApsFileTranslator { return changed; } - private boolean translateConditionExpression(CDATASection conditionExpressionCdata) throws XPathExpressionException { + private boolean translateConditionExpression(CharacterData conditionExpressionCdata) throws XPathExpressionException { this.logger.trace("Translating condition expression for outcome form elements: {}", conditionExpressionCdata.getParentNode().getParentNode().getAttributes().getNamedItem("id")); boolean changed = false; diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/ApsProcessJsonTranslator.java b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsProcessJsonTranslator.java similarity index 92% rename from src/main/java/com/inteligr8/maven/aps/modeling/ApsProcessJsonTranslator.java rename to src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsProcessJsonTranslator.java index f61b020..25f1bcf 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/ApsProcessJsonTranslator.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/translator/ApsProcessJsonTranslator.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.translator; import java.io.File; import java.io.IOException; @@ -11,6 +11,8 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.inteligr8.alfresco.activiti.model.Group; +import com.inteligr8.maven.aps.modeling.util.Index; +import com.inteligr8.maven.aps.modeling.util.ModelUtil; public class ApsProcessJsonTranslator implements ApsFileTranslator { @@ -47,13 +49,23 @@ public class ApsProcessJsonTranslator implements ApsFileTranslator { } private boolean translateResourceId(ObjectNode jsonDescriptor, Long apsProcessId) { + ObjectNode resourceIdParentJson = jsonDescriptor; + JsonNode jsonResourceId = jsonDescriptor.get("resourceId"); + if (jsonResourceId == null || jsonResourceId.isNull()) { + JsonNode jsonEditorJson = jsonDescriptor.get("editorJson"); + if (jsonEditorJson != null && jsonEditorJson.isObject()) { + resourceIdParentJson = (ObjectNode)jsonEditorJson; + jsonResourceId = jsonEditorJson.get("resourceId"); + } + } + if (jsonResourceId == null || jsonResourceId.isNull()) { this.logger.trace("The process 'resourceId' is not defined; leaving unchanged", apsProcessId); return false; } else if (jsonResourceId.asLong() != apsProcessId) { this.logger.debug("The process is found in APS with ID {}; changing 'resourceId' in descriptor", apsProcessId); - jsonDescriptor.put("resourceId", apsProcessId); + resourceIdParentJson.put("resourceId", apsProcessId); return true; } else { this.logger.trace("The process ID {} does not change; leaving unchanged", apsProcessId); diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/util/ApsModelArrayNodeSorter.java b/src/main/java/com/inteligr8/maven/aps/modeling/util/ApsModelArrayNodeSorter.java new file mode 100644 index 0000000..11c49c3 --- /dev/null +++ b/src/main/java/com/inteligr8/maven/aps/modeling/util/ApsModelArrayNodeSorter.java @@ -0,0 +1,22 @@ +package com.inteligr8.maven.aps.modeling.util; + +import com.fasterxml.jackson.databind.node.ArrayNode; + +public class ApsModelArrayNodeSorter extends ArrayNodeObjectSorter { + + private static ApsModelArrayNodeSorter INSTANCE = new ApsModelArrayNodeSorter(); + + public static ApsModelArrayNodeSorter getInstance() { + return INSTANCE; + } + + + + protected ApsModelArrayNodeSorter() { + } + + public boolean sort(ArrayNode arrayNode, String jsonObjectFieldName) { + return this.sort(arrayNode, new ObjectNodeComparator(jsonObjectFieldName)); + } + +} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/util/ApsModelListMapSorter.java b/src/main/java/com/inteligr8/maven/aps/modeling/util/ApsModelListMapSorter.java new file mode 100644 index 0000000..212a048 --- /dev/null +++ b/src/main/java/com/inteligr8/maven/aps/modeling/util/ApsModelListMapSorter.java @@ -0,0 +1,23 @@ +package com.inteligr8.maven.aps.modeling.util; + +import java.util.List; +import java.util.Map; + +public class ApsModelListMapSorter extends ListMapSorter { + + private static ApsModelListMapSorter INSTANCE = new ApsModelListMapSorter(); + + public static ApsModelListMapSorter getInstance() { + return INSTANCE; + } + + + + protected ApsModelListMapSorter() { + } + + public boolean sort(List> jsonArrayAsMap, String jsonObjectFieldName) { + return this.sort(jsonArrayAsMap, new MapComparator(jsonObjectFieldName)); + } + +} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/util/ArrayNodeObjectSorter.java b/src/main/java/com/inteligr8/maven/aps/modeling/util/ArrayNodeObjectSorter.java new file mode 100644 index 0000000..b68297e --- /dev/null +++ b/src/main/java/com/inteligr8/maven/aps/modeling/util/ArrayNodeObjectSorter.java @@ -0,0 +1,82 @@ +package com.inteligr8.maven.aps.modeling.util; + +import java.util.Comparator; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; + +public class ArrayNodeObjectSorter { + + private static ArrayNodeObjectSorter INSTANCE = new ArrayNodeObjectSorter(); + + public static ArrayNodeObjectSorter getInstance() { + return INSTANCE; + } + + + + protected ArrayNodeObjectSorter() { + } + + public boolean sort(ArrayNode arrayNode, Comparator comparator) { + if (arrayNode.isEmpty()) + return false; + + boolean sorted = false; + boolean changed = false; + int index = 0; + JsonNode node = arrayNode.get(index); + + // simple bubble sort + while (!sorted) { + sorted = true; + int nextIndex = index + 1; + + // forward bubble + while (nextIndex < arrayNode.size()) { + JsonNode nextNode = arrayNode.get(nextIndex); + int c = comparator.compare(node, nextNode); + + if (c == 0) { + node = nextNode; + } else if (c < 0) { + node = nextNode; + } else { + arrayNode.insert(index, arrayNode.remove(nextIndex)); + sorted = false; + changed = true; + } + + index = nextIndex; + nextIndex = index + 1; + } + + if (sorted) + break; + sorted = true; + nextIndex = index - 1; + + // reverse bubble + while (nextIndex >= 0) { + JsonNode nextNode = arrayNode.get(nextIndex); + int c = comparator.compare(nextNode, node); + + if (c == 0) { + node = nextNode; + } else if (c < 0) { + node = nextNode; + } else { + arrayNode.insert(nextIndex, arrayNode.remove(index)); + sorted = false; + changed = true; + } + + index = nextIndex; + nextIndex = index - 1; + } + } + + return changed; + } + +} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/Index.java b/src/main/java/com/inteligr8/maven/aps/modeling/util/Index.java similarity index 93% rename from src/main/java/com/inteligr8/maven/aps/modeling/Index.java rename to src/main/java/com/inteligr8/maven/aps/modeling/util/Index.java index 6eb7f79..631e37f 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/Index.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/util/Index.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.util; import java.util.HashMap; import java.util.HashSet; @@ -33,6 +33,14 @@ public class Index { return this.forwardMap.get(key); } + public Set keySet() { + return this.forwardMap.keySet(); + } + + public Set valueSet() { + return this.reverseMap.keySet(); + } + public Set getKeys(V value) { return this.reverseMap.get(value); } diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/util/ListMapSorter.java b/src/main/java/com/inteligr8/maven/aps/modeling/util/ListMapSorter.java new file mode 100644 index 0000000..ae8b909 --- /dev/null +++ b/src/main/java/com/inteligr8/maven/aps/modeling/util/ListMapSorter.java @@ -0,0 +1,70 @@ +package com.inteligr8.maven.aps.modeling.util; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +public class ListMapSorter { + + public boolean sort(List> listOfMaps, Comparator> comparator) { + if (listOfMaps.isEmpty()) + return false; + + boolean sorted = false; + boolean changed = false; + int index = 0; + Map map = listOfMaps.get(index); + + // simple bubble sort + while (!sorted) { + sorted = true; + int nextIndex = index + 1; + + // forward bubble + while (nextIndex < listOfMaps.size()) { + Map nextMap = listOfMaps.get(nextIndex); + int c = comparator.compare(map, nextMap); + + if (c == 0) { + map = nextMap; + } else if (c < 0) { + map = nextMap; + } else { + listOfMaps.add(index, listOfMaps.remove(nextIndex)); + sorted = false; + changed = true; + } + + index = nextIndex; + nextIndex = index + 1; + } + + if (sorted) + break; + sorted = true; + nextIndex = index - 1; + + // reverse bubble + while (nextIndex >= 0) { + Map nextMap = listOfMaps.get(nextIndex); + int c = comparator.compare(nextMap, map); + + if (c == 0) { + map = nextMap; + } else if (c < 0) { + map = nextMap; + } else { + listOfMaps.add(nextIndex, listOfMaps.remove(index)); + sorted = false; + changed = true; + } + + index = nextIndex; + nextIndex = index - 1; + } + } + + return changed; + } + +} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/util/MapComparator.java b/src/main/java/com/inteligr8/maven/aps/modeling/util/MapComparator.java new file mode 100644 index 0000000..b5ebec1 --- /dev/null +++ b/src/main/java/com/inteligr8/maven/aps/modeling/util/MapComparator.java @@ -0,0 +1,49 @@ +package com.inteligr8.maven.aps.modeling.util; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +public class MapComparator implements Comparator> { + + //private final Logger logger = LoggerFactory.getLogger(ArrayOfObjectNodeComparator.class); + private final List keys; + + public MapComparator(@SuppressWarnings("unchecked") K... keys) { + this(Arrays.asList(keys)); + } + + public MapComparator(List keys) { + this.keys = keys; + } + + @Override + public int compare(Map m1, Map m2) { + for (K key : keys) { + V value1 = m1.get(key); + V value2 = m2.get(key); + + if (value1 == null && value2 == null) + continue; + + if (value1 == null) + return 1; + if (value2 == null) + return -1; + if (!value1.getClass().equals(value2.getClass())) + return 0; + + if (value1 instanceof Boolean) { + return Boolean.compare((Boolean)value1, (Boolean)value2); + } if (value1 instanceof Number) { + return Double.compare(((Number)value1).doubleValue(), ((Number)value2).doubleValue()); + } if (value1 instanceof String) { + return ((String)value1).compareTo((String)value2); + } + } + + return 0; + } + +} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/ModelUtil.java b/src/main/java/com/inteligr8/maven/aps/modeling/util/ModelUtil.java similarity index 84% rename from src/main/java/com/inteligr8/maven/aps/modeling/ModelUtil.java rename to src/main/java/com/inteligr8/maven/aps/modeling/util/ModelUtil.java index 2e1f7b6..38bed1d 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/ModelUtil.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/util/ModelUtil.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.util; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -8,6 +8,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.List; +import java.util.Map; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; @@ -36,6 +38,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.inteligr8.maven.aps.modeling.xml.CDATAFlexSection; +import com.inteligr8.maven.aps.modeling.xml.DomNamespaceContext; public class ModelUtil { @@ -85,23 +89,8 @@ public class ModelUtil { public void json(File inplaceFile) throws IOException { - JsonNode json; - - FileInputStream fistream = new FileInputStream(inplaceFile); - BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize); - try { - json = this.readJson(bistream); - } finally { - bistream.close(); - } - - FileOutputStream fostream = new FileOutputStream(inplaceFile); - BufferedOutputStream bostream = new BufferedOutputStream(fostream, this.bufferSize); - try { - this.writeJson(json, bostream); - } finally { - bostream.close(); - } + JsonNode json = this.readJson(inplaceFile); + this.writeJson(json, inplaceFile); } public void json(File sourceFile, File targetFile) throws IOException { @@ -130,7 +119,7 @@ public class ModelUtil { return this.readJson(file, JsonNode.class); } - public T readJson(File file, Class type) throws IOException { + public T readJson(File file, Class type) throws IOException { FileInputStream fistream = new FileInputStream(file); BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize); try { @@ -140,14 +129,44 @@ public class ModelUtil { } } + public List readJsonAsList(File file) throws IOException { + FileInputStream fistream = new FileInputStream(file); + BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize); + try { + return this.readJsonAsList(bistream); + } finally { + bistream.close(); + } + } + + public Map readJsonAsMap(File file) throws IOException { + FileInputStream fistream = new FileInputStream(file); + BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize); + try { + return this.readJsonAsMap(bistream); + } finally { + bistream.close(); + } + } + public JsonNode readJson(InputStream istream) throws IOException { return this.om.readTree(istream); } - public T readJson(InputStream istream, Class type) throws IOException { + public T readJson(InputStream istream, Class type) throws IOException { return this.om.readValue(istream, type); } + @SuppressWarnings("unchecked") + public List readJsonAsList(InputStream istream) throws IOException { + return this.om.readValue(istream, List.class); + } + + @SuppressWarnings("unchecked") + public Map readJsonAsMap(InputStream istream) throws IOException { + return this.om.readValue(istream, Map.class); + } + public void writeJson(JsonNode json, File file) throws IOException { FileOutputStream fostream = new FileOutputStream(file); BufferedOutputStream bostream = new BufferedOutputStream(fostream, this.bufferSize); @@ -158,10 +177,24 @@ public class ModelUtil { } } + public void writeJson(Map map, File file) throws IOException { + FileOutputStream fostream = new FileOutputStream(file); + BufferedOutputStream bostream = new BufferedOutputStream(fostream, this.bufferSize); + try { + this.writeJson(map, bostream); + } finally { + bostream.close(); + } + } + public void writeJson(JsonNode json, OutputStream ostream) throws IOException { this.om.writeValue(ostream, json); } + public void writeJson(Map map, OutputStream ostream) throws IOException { + this.om.writeValue(ostream, map); + } + public void xml(File inplaceFile) throws IOException, SAXException, TransformerException { diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/util/ObjectNodeComparator.java b/src/main/java/com/inteligr8/maven/aps/modeling/util/ObjectNodeComparator.java new file mode 100644 index 0000000..729639c --- /dev/null +++ b/src/main/java/com/inteligr8/maven/aps/modeling/util/ObjectNodeComparator.java @@ -0,0 +1,58 @@ +package com.inteligr8.maven.aps.modeling.util; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +import com.fasterxml.jackson.databind.JsonNode; + +public class ObjectNodeComparator implements Comparator { + + //private final Logger logger = LoggerFactory.getLogger(ArrayOfObjectNodeComparator.class); + private final List objectFieldNames; + + public ObjectNodeComparator(String... objectFieldNames) { + this(Arrays.asList(objectFieldNames)); + } + + public ObjectNodeComparator(List objectFieldNames) { + this.objectFieldNames = objectFieldNames; + } + + @Override + public int compare(JsonNode o1, JsonNode o2) { + if (!o1.isObject()) + return -1; + if (!o2.isObject()) + return 1; + + for (String objectFieldName : objectFieldNames) { + JsonNode value1 = o1.get(objectFieldName); + JsonNode value2 = o2.get(objectFieldName); + + if (value1 == null && value2 == null) + continue; + + if (value1 == null) + return 1; + if (value2 == null) + return -1; + if (!value1.getNodeType().equals(value2.getNodeType())) + return 0; + + switch (value1.getNodeType()) { + case BOOLEAN: + return Boolean.compare(value1.asBoolean(), value2.asBoolean()); + case NUMBER: + return Double.compare(value1.asDouble(), value2.asDouble()); + case STRING: + return value1.asText().compareTo(value2.asText()); + default: + return 0; + } + } + + return 0; + } + +} diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/CDATAFlexSection.java b/src/main/java/com/inteligr8/maven/aps/modeling/xml/CDATAFlexSection.java similarity index 93% rename from src/main/java/com/inteligr8/maven/aps/modeling/CDATAFlexSection.java rename to src/main/java/com/inteligr8/maven/aps/modeling/xml/CDATAFlexSection.java index 195b7ba..c0f5397 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/CDATAFlexSection.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/xml/CDATAFlexSection.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.xml; import org.w3c.dom.CDATASection; import org.w3c.dom.Node; diff --git a/src/main/java/com/inteligr8/maven/aps/modeling/DomNamespaceContext.java b/src/main/java/com/inteligr8/maven/aps/modeling/xml/DomNamespaceContext.java similarity index 97% rename from src/main/java/com/inteligr8/maven/aps/modeling/DomNamespaceContext.java rename to src/main/java/com/inteligr8/maven/aps/modeling/xml/DomNamespaceContext.java index 09e0aef..4c9872d 100644 --- a/src/main/java/com/inteligr8/maven/aps/modeling/DomNamespaceContext.java +++ b/src/main/java/com/inteligr8/maven/aps/modeling/xml/DomNamespaceContext.java @@ -1,4 +1,4 @@ -package com.inteligr8.maven.aps.modeling; +package com.inteligr8.maven.aps.modeling.xml; import java.util.Collections; import java.util.Iterator;