major refactoring with testing; not done

This commit is contained in:
Brian Long 2022-03-24 20:20:36 +01:00
parent da06f5adc9
commit 89a43457f4
32 changed files with 939 additions and 387 deletions

16
pom.xml
View File

@ -184,6 +184,7 @@
<goals><goal>jar</goal></goals>
<configuration>
<show>public</show>
<skip>true</skip>
</configuration>
</execution>
</executions>
@ -212,6 +213,13 @@
<goal>run</goal>
</goals>
<configuration>
<properties>
<aps-model.baseUrl>${aps-model.baseUrl}</aps-model.baseUrl>
<aps-model.authType>${aps-model.authType}</aps-model.authType>
<aps-model.basicAuth.username>${aps-model.basicAuth.username}</aps-model.basicAuth.username>
<aps-model.basicAuth.password>${aps-model.basicAuth.password}</aps-model.basicAuth.password>
<aps-model.appName>${aps-model.appName}</aps-model.appName>
</properties>
<pomIncludes>
<pomInclude>${run-it}/pom.xml</pomInclude>
</pomIncludes>
@ -224,6 +232,14 @@
</profile>
</profiles>
<repositories>
<repository>
<id>inteligr8-releases</id>
<name>Inteligr8 Releases</name>
<url>https://repos.inteligr8.com/nexus/repository/inteligr8-public</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>inteligr8-releases</id>

View File

@ -12,10 +12,6 @@
<name>Download App Plugin Tests</name>
<properties>
<aps.app>FORMS Core</aps.app>
</properties>
<build>
<plugins>
<plugin>
@ -29,9 +25,6 @@
<goals>
<goal>download-app</goal>
</goals>
<configuration>
<apsAppName>${aps.app}</apsAppName>
</configuration>
</execution>
<execution>
<id>download-app-other</id>
@ -40,8 +33,7 @@
<goal>download-app</goal>
</goals>
<configuration>
<apsAppName>${aps.app}</apsAppName>
<targetDirectory>${basedir}/src/main/app</targetDirectory>
<zipDirectory>${basedir}/src/main/aps</zipDirectory>
</configuration>
</execution>
</executions>
@ -57,8 +49,8 @@
<rules>
<requireFilesExist>
<files>
<file>${project.build.directory}/app/${aps.app}.zip</file>
<file>${basedir}/src/main/app/${aps.app}.zip</file>
<file>${project.build.directory}/aps/${aps-model.appName}.zip</file>
<file>${basedir}/src/main/aps/${aps-model.appName}.zip</file>
</files>
</requireFilesExist>
</rules>

View File

@ -12,10 +12,6 @@
<name>Translate App Plugin Tests</name>
<properties>
<aps.app>FORMS Core</aps.app>
</properties>
<build>
<plugins>
<plugin>
@ -31,7 +27,7 @@
<goal>unpack-app</goal>
</goals>
<configuration>
<apsAppName>${aps.app}</apsAppName>
<normalize>true</normalize>
</configuration>
</execution>
<execution>
@ -41,8 +37,7 @@
<goal>translate-app</goal>
</goals>
<configuration>
<apsAppName>${aps.app}</apsAppName>
<targetDirectory>${basedir}/src/main/app</targetDirectory>
<finalDirectory>${basedir}/src/main/aps/app</finalDirectory>
</configuration>
</execution>
</executions>
@ -58,7 +53,7 @@
<rules>
<requireFilesExist>
<files>
<file>${basedir}/src/main/app/${aps.app}/${aps.app}.json</file>
<file>${basedir}/src/main/aps/app/${aps-model.appName}/${aps-model.appName}.json</file>
</files>
</requireFilesExist>
</rules>

View File

@ -12,10 +12,6 @@
<name>Unpack App Plugin Tests</name>
<properties>
<aps.app>FORMS Core</aps.app>
</properties>
<build>
<plugins>
<plugin>
@ -30,9 +26,6 @@
<goal>download-app</goal>
<goal>unpack-app</goal>
</goals>
<configuration>
<apsAppName>${aps.app}</apsAppName>
</configuration>
</execution>
<execution>
<id>unpack-app</id>
@ -41,8 +34,7 @@
<goal>unpack-app</goal>
</goals>
<configuration>
<apsAppName>${aps.app}</apsAppName>
<targetDirectory>${basedir}/src/main/app</targetDirectory>
<unzipDirectory>${basedir}/src/main/aps/app</unzipDirectory>
</configuration>
</execution>
</executions>
@ -58,8 +50,8 @@
<rules>
<requireFilesExist>
<files>
<file>${project.build.directory}/app/${aps.app}/${aps.app}.json</file>
<file>${basedir}/src/main/app/${aps.app}/${aps.app}.json</file>
<file>${project.build.directory}/aps/app/${aps-model.appName}/${aps-model.appName}.json</file>
<file>${basedir}/src/main/aps/app/${aps-model.appName}/${aps-model.appName}.json</file>
</files>
</requireFilesExist>
</rules>

View File

@ -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<Tenant> 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;
}
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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<Tenant> tenants = this.getApsApi().getAdminApi().getTenants();
if (tenants == null || tenants.isEmpty())
return null;
return tenants.iterator().next().getId();
}
protected Map<String, Long> findAppNameIds() {
ApsPublicRestApiJerseyImpl api = this.getApsApi();
Map<String, Long> 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<String, Long> 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;
}
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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;
}

View File

@ -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");
}
}

View File

@ -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();

View File

@ -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 = "aps-model.app.directory", required = true, defaultValue = "${project.build.directory}/aps/app" )
protected File unzipDirectory;
@Parameter( property = "sourceDirectory", required = true, defaultValue = "${project.build.directory}/app" )
protected File sourceDirectory;
@Parameter( property = "aps-model.translatedApp.directory", required = false, defaultValue = "${project.build.directory}/aps/app" )
protected File finalDirectory;
@Parameter( property = "targetDirectory", required = false, defaultValue = "${project.build.directory}/app" )
protected File targetDirectory;
@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;

View File

@ -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<String, Object> 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<String, Object> jsonMap) {
boolean changed = false;
try {
List<Map<String, Object>> jsonModels = (List<Map<String, Object>>)this.mapGetsListMaps(jsonMap, "definition", "models");
changed = ApsModelListMapSorter.getInstance().sort(jsonModels, "name") || changed;
} catch (ClassCastException cce) {
// suppress
} catch (NullPointerException npe) {
// suppress
}
try {
List<Map<String, Object>> jsonChildShapes = (List<Map<String, Object>>)this.mapGetsListMaps(jsonMap, "childShapes");
changed = ApsModelListMapSorter.getInstance().sort(jsonChildShapes, "resourceId") || changed;
} catch (ClassCastException cce) {
// suppress
} catch (NullPointerException npe) {
// suppress
}
try {
List<Map<String, Object>> jsonChildShapes = (List<Map<String, Object>>)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> T mapGets(Map<String, ?> map, Class<T> returnType, String... keys) {
for (int i = 0; i < keys.length - 1; i++)
map = (Map<String, ?>)map.get(keys[i]);
return (T)map.get(keys[keys.length-1]);
}
@SuppressWarnings("unchecked")
private <T> List<T> mapGetsList(Map<String, ?> map, Class<T> listType, String... keys) {
for (int i = 0; i < keys.length - 1; i++)
map = (Map<String, ?>)map.get(keys[i]);
return (List<T>)map.get(keys[keys.length-1]);
}
@SuppressWarnings("unchecked")
private List<Map<String, Object>> mapGetsListMaps(Map<String, ?> map, String... keys) {
for (int i = 0; i < keys.length - 1; i++)
map = (Map<String, ?>)map.get(keys[i]);
return (List<Map<String, Object>>)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();
}
}

View File

@ -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 {
@ -33,9 +36,8 @@ public class ApsAppJsonTranslator implements ApsFileTranslator {
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
}
}

View File

@ -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 <K, V> void logLarge(String message, Map<K, V> map) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(message, map);
} else {
this.logger.debug(message, map.keySet());
}
}
private <K, V> void logLarge(String message, Index<K, V> 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<Long, String> 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<Long, String> map = new Index<>(results.getSize().intValue(), false);
@ -143,6 +162,8 @@ 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);
@ -157,19 +178,25 @@ public class ApsAppTranslator {
}
protected Index<Long, String> buildFileIndex(File modelDirectory, Index<Long, String> 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<Long, String> 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<String, ApsFileTranslator> 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);
}
}

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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));
}
}

View File

@ -0,0 +1,23 @@
package com.inteligr8.maven.aps.modeling.util;
import java.util.List;
import java.util.Map;
public class ApsModelListMapSorter extends ListMapSorter<String, Object> {
private static ApsModelListMapSorter INSTANCE = new ApsModelListMapSorter();
public static ApsModelListMapSorter getInstance() {
return INSTANCE;
}
protected ApsModelListMapSorter() {
}
public boolean sort(List<Map<String, Object>> jsonArrayAsMap, String jsonObjectFieldName) {
return this.sort(jsonArrayAsMap, new MapComparator<String, Object>(jsonObjectFieldName));
}
}

View File

@ -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<JsonNode> 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;
}
}

View File

@ -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<K, V> {
return this.forwardMap.get(key);
}
public Set<K> keySet() {
return this.forwardMap.keySet();
}
public Set<V> valueSet() {
return this.reverseMap.keySet();
}
public Set<K> getKeys(V value) {
return this.reverseMap.get(value);
}

View File

@ -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<K, V> {
public boolean sort(List<Map<K, V>> listOfMaps, Comparator<Map<K, V>> comparator) {
if (listOfMaps.isEmpty())
return false;
boolean sorted = false;
boolean changed = false;
int index = 0;
Map<K, V> map = listOfMaps.get(index);
// simple bubble sort
while (!sorted) {
sorted = true;
int nextIndex = index + 1;
// forward bubble
while (nextIndex < listOfMaps.size()) {
Map<K, V> 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<K, V> 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;
}
}

View File

@ -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<K, V> implements Comparator<Map<K, V>> {
//private final Logger logger = LoggerFactory.getLogger(ArrayOfObjectNodeComparator.class);
private final List<K> keys;
public MapComparator(@SuppressWarnings("unchecked") K... keys) {
this(Arrays.asList(keys));
}
public MapComparator(List<K> keys) {
this.keys = keys;
}
@Override
public int compare(Map<K, V> m1, Map<K, V> 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;
}
}

View File

@ -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 extends JsonNode> T readJson(File file, Class<T> type) throws IOException {
public <T> T readJson(File file, Class<T> type) throws IOException {
FileInputStream fistream = new FileInputStream(file);
BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize);
try {
@ -140,14 +129,44 @@ public class ModelUtil {
}
}
public <T> List<T> 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<String, Object> 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 extends JsonNode> T readJson(InputStream istream, Class<T> type) throws IOException {
public <T> T readJson(InputStream istream, Class<T> type) throws IOException {
return this.om.readValue(istream, type);
}
@SuppressWarnings("unchecked")
public <T> List<T> readJsonAsList(InputStream istream) throws IOException {
return this.om.readValue(istream, List.class);
}
@SuppressWarnings("unchecked")
public Map<String, Object> 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<String, Object> 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<String, Object> map, OutputStream ostream) throws IOException {
this.om.writeValue(ostream, map);
}
public void xml(File inplaceFile) throws IOException, SAXException, TransformerException {

View File

@ -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<JsonNode> {
//private final Logger logger = LoggerFactory.getLogger(ArrayOfObjectNodeComparator.class);
private final List<String> objectFieldNames;
public ObjectNodeComparator(String... objectFieldNames) {
this(Arrays.asList(objectFieldNames));
}
public ObjectNodeComparator(List<String> 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;
}
}

View File

@ -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;

View File

@ -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;