finished, tested and fixed initial impl

This commit is contained in:
Brian Long 2022-03-28 20:05:46 +01:00
parent 0541cf502b
commit 3d353cf6d5
20 changed files with 223 additions and 181 deletions

View File

@ -41,7 +41,7 @@
<dependency>
<groupId>com.inteligr8.alfresco</groupId>
<artifactId>aps-public-rest-api</artifactId>
<version>1.2.0</version>
<version>1.2.1</version>
<classifier>aps1</classifier>
</dependency>
<dependency>
@ -216,8 +216,7 @@
<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.basicAuth.mavenServerId>${aps-model.basicAuth.mavenServerId}</aps-model.basicAuth.mavenServerId>
<aps-model.appName>${aps-model.appName}</aps-model.appName>
</properties>
<pomIncludes>

View File

@ -12,10 +12,6 @@
<name>Deploy App Plugin Tests</name>
<properties>
<aps.app>FORMS Core</aps.app>
</properties>
<build>
<plugins>
<plugin>
@ -24,14 +20,46 @@
<version>@pom.version@</version>
<executions>
<execution>
<id>download-app</id>
<phase>validate</phase>
<id>download-unpack-app</id>
<phase>generate-sources</phase>
<goals>
<goal>download-app</goal>
<goal>unpack-app</goal>
</goals>
<configuration>
<reformat>true</reformat>
<normalize>true</normalize>
</configuration>
</execution>
<execution>
<id>translate-app</id>
<phase>compile</phase>
<goals>
<goal>translate-app</goal>
</goals>
<configuration>
<finalDirectory>${project.build.directory}/aps-dev</finalDirectory>
</configuration>
</execution>
<execution>
<id>pack-app</id>
<phase>package</phase>
<goals>
<goal>pack-app</goal>
</goals>
<configuration>
<unzipDirectory>${project.build.directory}/aps-dev</unzipDirectory>
<zipDirectory>${project.build.directory}/aps-test</zipDirectory>
</configuration>
</execution>
<execution>
<id>deploy-app</id>
<phase>package</phase>
<goals>
<goal>deploy-app</goal>
</goals>
<configuration>
<apsAppName>${aps.app}</apsAppName>
<zipDirectory>${project.build.directory}/aps-test</zipDirectory>
</configuration>
</execution>
</executions>

View File

@ -21,14 +21,14 @@
<executions>
<execution>
<id>download-app</id>
<phase>validate</phase>
<phase>generate-sources</phase>
<goals>
<goal>download-app</goal>
</goals>
</execution>
<execution>
<id>download-app-other</id>
<phase>validate</phase>
<phase>generate-sources</phase>
<goals>
<goal>download-app</goal>
</goals>

View File

@ -12,10 +12,6 @@
<name>Pack App Plugin Tests</name>
<properties>
<aps.app>FORMS Core</aps.app>
</properties>
<build>
<plugins>
<plugin>
@ -25,7 +21,7 @@
<executions>
<execution>
<id>download-unpack-app</id>
<phase>validate</phase>
<phase>generate-sources</phase>
<goals>
<goal>download-app</goal>
<goal>unpack-app</goal>
@ -36,11 +32,12 @@
</execution>
<execution>
<id>pack-app</id>
<phase>validate</phase>
<phase>package</phase>
<goals>
<goal>pack-app</goal>
</goals>
<configuration>
<zipDirectory>${basedir}</zipDirectory>
</configuration>
</execution>
</executions>
@ -56,7 +53,7 @@
<rules>
<requireFilesExist>
<files>
<file>${basedir}/src/main/app/${aps.app}.zip</file>
<file>${basedir}/${aps-model.appName}.zip</file>
</files>
</requireFilesExist>
</rules>

View File

@ -21,7 +21,7 @@
<executions>
<execution>
<id>download-unpack-app</id>
<phase>validate</phase>
<phase>generate-sources</phase>
<goals>
<goal>download-app</goal>
<goal>unpack-app</goal>
@ -33,7 +33,7 @@
</execution>
<execution>
<id>translate-app</id>
<phase>validate</phase>
<phase>compile</phase>
<goals>
<goal>translate-app</goal>
</goals>

View File

@ -21,7 +21,7 @@
<executions>
<execution>
<id>download-unpack-app</id>
<phase>validate</phase>
<phase>generate-sources</phase>
<goals>
<goal>download-app</goal>
<goal>unpack-app</goal>
@ -29,7 +29,7 @@
</execution>
<execution>
<id>unpack-app</id>
<phase>validate</phase>
<phase>process-sources</phase>
<goals>
<goal>unpack-app</goal>
</goals>

View File

@ -1,6 +1,8 @@
package com.inteligr8.maven.aps.modeling.goal;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.settings.Server;
import com.inteligr8.alfresco.activiti.ApsClientConfiguration;
import com.inteligr8.alfresco.activiti.ApsClientJerseyImpl;
@ -8,32 +10,26 @@ import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl;
public abstract class ApsAddressibleGoal extends DisablableGoal {
@Parameter( defaultValue = "${session}", readonly = true )
protected MavenSession session;
@Parameter( property = "aps-model.baseUrl", required = true, defaultValue = "http://localhost:8080/activiti-app" )
protected String activitiAppBaseUrl;
@Parameter( property = "aps-model.authType", required = true, defaultValue = "BASIC" )
protected String activitiAppAuthType;
@Parameter( property = "aps-model.basicAuth.username", required = false, defaultValue = "admin@app.activiti.com" )
protected String activitiAppAuthBasicUsername;
@Parameter( property = "aps-model.basicAuth.password", required = false, defaultValue = "admin" )
protected String activitiAppAuthBasicPassword;
@Parameter( property = "aps-model.basicAuth.mavenServerId", required = true, defaultValue = "aps" )
protected String activitiAppAuthBasicServerId;
@Parameter( property = "aps-model.oauth.code", required = false )
protected String oauthCode;
@Parameter( property = "aps-model.oauth.clientId", required = false )
protected String oauthClientId;
@Parameter( property = "aps-model.oauth.client.mavenServerId", required = false )
protected String oauthClientServerId;
@Parameter( property = "aps-model.oauth.clientSecret", required = false )
protected String oauthClientSecret;
@Parameter( property = "aps-model.oauth.username", required = false )
protected String oauthUsername;
@Parameter( property = "aps-model.oauth.password", required = false )
protected String oauthPassword;
@Parameter( property = "aps-model.oauth.mavenServerId", required = false )
protected String oauthServerId;
@Parameter( property = "aps-model.oauth.tokenUrl", required = false )
protected String oauthTokenUrl;
@ -47,21 +43,41 @@ public abstract class ApsAddressibleGoal extends DisablableGoal {
switch (this.activitiAppAuthType.toUpperCase()) {
case "BASIC":
this.getLog().info("Configuring APS with BASIC authentication");
this.getLog().debug("Username: " + this.activitiAppAuthBasicUsername);
config.setBasicAuthUsername(this.activitiAppAuthBasicUsername);
config.setBasicAuthPassword(this.activitiAppAuthBasicPassword);
Server creds = this.session.getSettings().getServer(this.activitiAppAuthBasicServerId);
if (this.activitiAppAuthBasicServerId != null && creds == null)
this.getLog().warn("The Maven configuration has no server '" + this.activitiAppAuthBasicServerId + "'; continuing with default credentials");
if (creds != null) {
this.getLog().debug("Username: " + creds.getUsername());
config.setBasicAuthUsername(creds.getUsername());
config.setBasicAuthPassword(creds.getPassword());
}
break;
case "OAUTH":
this.getLog().info("Configuring APS with OAuth authentication");
Server clientCreds = this.session.getSettings().getServer(this.oauthClientServerId);
Server oauthCreds = this.session.getSettings().getServer(this.oauthServerId);
if ((this.oauthClientServerId != null || this.oauthServerId != null) && clientCreds == null && oauthCreds == null)
this.getLog().warn("The Maven configuration has no server '" + this.oauthClientServerId + "' or '" + this.oauthServerId + "'; continuing without credentials");
this.getLog().debug("OAuth Code: " + this.oauthCode);
this.getLog().debug("OAuth Client ID: " + this.oauthClientId);
this.getLog().debug("OAuth Username: " + this.oauthUsername);
config.setOAuthAuthCode(this.oauthCode);
if (clientCreds != null) {
this.getLog().debug("OAuth Client ID: " + clientCreds.getUsername());
config.setOAuthClientId(clientCreds.getUsername());
config.setOAuthClientSecret(clientCreds.getPassword());
}
if (oauthCreds != null) {
this.getLog().debug("OAuth Username: " + oauthCreds.getUsername());
config.setOAuthUsername(oauthCreds.getUsername());
config.setOAuthPassword(oauthCreds.getPassword());
}
config.setOAuthTokenUrl(this.oauthTokenUrl);
config.setOAuthClientId(this.oauthClientId);
config.setOAuthClientSecret(this.oauthClientSecret);
config.setOAuthUsername(this.oauthUsername);
config.setOAuthPassword(this.oauthPassword);
break;
default:
throw new IllegalArgumentException("The 'activitiAppAuthType' configuration must be either 'Basic' or 'OAuth'");

View File

@ -5,12 +5,15 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.ws.rs.core.MediaType;
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.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart;
import com.inteligr8.alfresco.activiti.ApsPublicRestApiJerseyImpl;
import com.inteligr8.alfresco.activiti.model.AppDefinitionUpdateResultRepresentation;
@ -19,13 +22,14 @@ import com.inteligr8.alfresco.activiti.model.AppDefinitionUpdateResultRepresenta
@Component( role = org.apache.maven.plugin.Mojo.class )
public class DeployAppGoal extends ApsAppAccessibleGoal {
@Parameter( property = "sourceDirectory", required = true, defaultValue = "${project.build.directory}/aps/app" )
protected File sourceDirectory;
@Parameter( property = "aps-model.upload.directory", required = true, defaultValue = "${project.build.directory}/aps" )
protected File zipDirectory;
@Parameter( property = "publish", required = true, defaultValue = "false" )
protected boolean publish = false;
protected final int bufferSize = 128 * 1024;
private final MediaType zipMediaType = MediaType.valueOf("application/zip");
@Override
public void executeEnabled() throws MojoExecutionException, MojoFailureException {
@ -36,21 +40,21 @@ public class DeployAppGoal extends ApsAppAccessibleGoal {
try {
this.uploadApp(appId, sourceFile);
} catch (IOException ie) {
throw new MojoExecutionException("The downloaded APS App could not be unpacked", ie);
throw new MojoExecutionException("The APS App could not be uploaded", ie);
}
}
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);
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.sourceDirectory, this.apsAppName + ".zip");
File sourceFile = new File(this.zipDirectory, this.apsAppName + ".zip");
if (!sourceFile.exists()) {
throw new IllegalStateException("The App file does not exists in the 'sourceDirectory': " + sourceFile);
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);
}
@ -61,33 +65,31 @@ public class DeployAppGoal extends ApsAppAccessibleGoal {
private void uploadApp(Long appId, File appZip) throws IOException, MojoExecutionException {
ApsPublicRestApiJerseyImpl api = this.getApsApi();
FormDataContentDisposition cdisposition = FormDataContentDisposition.name("file")
.size(appZip.length())
.fileName(appZip.getName())
.build();
FileInputStream fistream = new FileInputStream(appZip);
BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize);
try {
FormDataMultiPart multipart = new FormDataMultiPart();
multipart.bodyPart(new StreamDataBodyPart("file", bistream, appZip.getName(), this.zipMediaType));
if (appId == null) {
if (this.publish) {
this.getLog().info("Uploading & publishing new APS App: " + this.apsAppName);
AppDefinitionUpdateResultRepresentation appDefUpdate = api.getAppDefinitionsJerseyApi().publishApp(bistream, cdisposition);
AppDefinitionUpdateResultRepresentation appDefUpdate = api.getAppDefinitionsJerseyApi().publishApp(multipart);
if (Boolean.TRUE.equals(appDefUpdate.getError()))
throw new MojoExecutionException(appDefUpdate.getErrorDescription());
} else {
this.getLog().info("Uploading new APS App: " + this.apsAppName);
api.getAppDefinitionsJerseyApi().import_(bistream, cdisposition);
api.getAppDefinitionsJerseyApi().importApp(multipart, true);
}
} else {
if (this.publish) {
this.getLog().info("Uploading, versioning, & publishing APS App: " + this.apsAppName);
AppDefinitionUpdateResultRepresentation appDefUpdate = api.getAppDefinitionsJerseyApi().publishApp(appId, bistream, cdisposition);
this.getLog().info("Uploading, versioning, & publishing APS App: " + this.apsAppName + " (" + appId + ")");
AppDefinitionUpdateResultRepresentation appDefUpdate = api.getAppDefinitionsJerseyApi().publishApp(appId, multipart);
if (Boolean.TRUE.equals(appDefUpdate.getError()))
throw new MojoExecutionException(appDefUpdate.getErrorDescription());
} else {
this.getLog().info("Uploading & versioning APS App: " + this.apsAppName);
api.getAppDefinitionsJerseyApi().import_(appId, bistream, cdisposition);
this.getLog().info("Uploading & versioning APS App: " + this.apsAppName + " (" + appId + ")");
api.getAppDefinitionsJerseyApi().importApp(appId, multipart, true);
}
}
} finally {

View File

@ -22,11 +22,11 @@ import org.codehaus.plexus.component.annotations.Component;
@Component( role = org.apache.maven.plugin.Mojo.class )
public class PackAppGoal extends ApsAppGoal {
@Parameter( property = "sourceDirectory", required = true, defaultValue = "${project.build.directory}/aps/app" )
protected File sourceDirectory;
@Parameter( property = "targetDirectory", required = true, defaultValue = "${project.build.directory}/aps/app" )
protected File targetDirectory;
@Parameter( property = "aps-model.app.directory", required = true, defaultValue = "${project.build.directory}/aps/app" )
protected File unzipDirectory;
@Parameter( property = "aps-model.upload.directory", required = true, defaultValue = "${project.build.directory}/aps" )
protected File zipDirectory;
protected final int bufferSize = 128 * 1024;
@ -45,17 +45,17 @@ public class PackAppGoal extends ApsAppGoal {
}
protected void 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);
if (!this.unzipDirectory.exists()) {
throw new IllegalStateException("The 'unzipDirectory' does not exist: " + this.unzipDirectory);
} else if (!this.unzipDirectory.isDirectory()) {
throw new IllegalStateException("The 'unzipDirectory' is not a directory: " + this.unzipDirectory);
}
}
protected File validateAppDirectory() {
File appDirectory = new File(this.sourceDirectory, this.apsAppName);
File appDirectory = new File(this.unzipDirectory, this.apsAppName);
if (!appDirectory.exists()) {
throw new IllegalStateException("The 'apsAppName' does not exist in the source directory: " + this.sourceDirectory);
throw new IllegalStateException("The 'apsAppName' does not exist in the source directory: " + this.unzipDirectory);
} else if (!appDirectory.isDirectory()) {
throw new IllegalStateException("The 'apsAppName' refers to a file and not a directory: " + appDirectory);
}
@ -64,19 +64,19 @@ public class PackAppGoal extends ApsAppGoal {
}
protected File validateTargetDirectory() {
if (!this.targetDirectory.exists()) {
this.getLog().debug("The 'targetDirectory' does not exist; creating: " + this.targetDirectory);
this.targetDirectory.mkdirs();
} else if (!this.targetDirectory.isDirectory()) {
throw new IllegalStateException("The 'targetDirectory' is not a directory: " + this.targetDirectory);
if (!this.zipDirectory.exists()) {
this.getLog().debug("The 'zipDirectory' does not exist; creating: " + this.zipDirectory);
this.zipDirectory.mkdirs();
} else if (!this.zipDirectory.isDirectory()) {
throw new IllegalStateException("The 'zipDirectory' is not a directory: " + this.zipDirectory);
}
File targetFile = new File(this.targetDirectory, this.apsAppName + ".zip");
File targetFile = new File(this.zipDirectory, this.apsAppName + ".zip");
if (targetFile.isDirectory()) {
throw new IllegalStateException("The App file is not a file: " + targetFile);
} else if (targetFile.exists()) {
this.getLog().debug("The App file in the 'targetDirectory' exists; deleting: " + targetFile);
this.getLog().debug("The App file in the 'zipDirectory' exists; deleting: " + targetFile);
targetFile.delete();
}
@ -92,6 +92,7 @@ public class PackAppGoal extends ApsAppGoal {
ZipOutputStream zostream = new ZipOutputStream(bostream);
try {
this.zipDirectory(appDirectory, null, zostream);
zostream.flush();
} finally {
zostream.close();
}
@ -118,7 +119,8 @@ public class PackAppGoal extends ApsAppGoal {
this.getLog().debug("Packing APS file: " + path);
ZipEntry zentry = new ZipEntry(path.toString());
// Activit App processing requires forward slashes (WOW)
ZipEntry zentry = new ZipEntry(path.toString().replace('\\', '/'));
zostream.putNextEntry(zentry);
try {
FileInputStream fistream = new FileInputStream(file);

View File

@ -4,12 +4,10 @@ import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.apache.maven.execution.MavenSession;
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.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.annotations.Component;
import com.inteligr8.maven.aps.modeling.crawler.ApsAppCrawler;
@ -19,12 +17,6 @@ import com.inteligr8.maven.aps.modeling.translator.ApsAppTranslator;
@Component( role = org.apache.maven.plugin.Mojo.class )
public class TranslateAppGoal extends ApsAppAccessibleGoal {
@Parameter( defaultValue = "${project}", readonly = true )
protected MavenProject project;
@Parameter( defaultValue = "${session}", readonly = true )
protected MavenSession session;
@Parameter( property = "aps-model.app.directory", required = true, defaultValue = "${project.build.directory}/aps/app" )
protected File unzipDirectory;

View File

@ -188,7 +188,7 @@ public class UnpackAppGoal extends ApsAppGoal {
case "json":
this.getLog().debug("Reformatting file: " + file);
Map<String, Object> json = ModelUtil.getInstance().readJsonAsMap(file);
ModelUtil.getInstance().writeJson(json, file);
ModelUtil.getInstance().writeJson(json, file, false);
break;
case "xml":
case "bpmn":

View File

@ -36,17 +36,18 @@ public class ApsAppJsonNormalizer implements ApsFileNormalizer {
ObjectNode jsonModel = (ObjectNode)_jsonModel;
int fields = jsonModel.size();
jsonModel.remove(Arrays.asList("createdBy", "createdByFullName", "lastUpdatedBy", "lastUpdatedByFullName", "lastUpdated"));
jsonModel.remove(Arrays.asList("lastUpdated"));
// jsonModel.remove(Arrays.asList("createdBy", "createdByFullName", "lastUpdatedBy", "lastUpdatedByFullName", "lastUpdated"));
if (jsonModel.size() < fields)
changed = true;
}
// sort the models for better 'diff' support
if (this.enableSorting)
ApsModelArrayNodeSorter.getInstance().sort(jsonModels, "name");
changed = ApsModelArrayNodeSorter.getInstance().sort(jsonModels, "name") || changed;
if (changed)
ModelUtil.getInstance().writeJson(descriptor, file);
ModelUtil.getInstance().writeJson(descriptor, file, this.enableSorting);
}
}

View File

@ -37,7 +37,7 @@ public class ApsProcessJsonNormalizer implements ApsFileNormalizer {
changed = ApsModelArrayNodeSorter.getInstance().sort(jsonChildShapes, "resourceId") || changed;
if (changed)
ModelUtil.getInstance().writeJson(jsonDescriptor, file);
ModelUtil.getInstance().writeJson(jsonDescriptor, file, this.enableSorting);
}
private ArrayNode getChildShapes(ObjectNode jsonDescriptor) {

View File

@ -2,7 +2,6 @@ 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;
@ -67,10 +66,14 @@ public class ApsAppJsonTranslator implements ApsFileTranslator {
}
}
int fields = jsonModel.size();
jsonModel.remove(Arrays.asList("version"));
if (jsonModel.size() < fields)
if (jsonModel.has("version")) {
jsonModel.put("version", 0);
changed = true;
}
// int fields = jsonModel.size();
// jsonModel.remove(Arrays.asList("version"));
// if (jsonModel.size() < fields)
// changed = true;
}
for (JsonNode _jsonIdentityInfo : descriptor.get("definition").get("publishIdentityInfo")) {
@ -90,11 +93,15 @@ public class ApsAppJsonTranslator implements ApsFileTranslator {
} else {
this.logger.trace("The organization '{}' ID does not change; leaving unchanged", fileOrgName);
}
if (jsonGroup.has("parentGroupId")) {
jsonGroup.remove("parentGroupName");
jsonGroup.put("parentGroupId", 0);
changed = true;
}
// if (jsonGroup.has("parentGroupId")) {
// jsonGroup.remove("parentGroupId");
// changed = true;
// }
} else {
this.logger.warn("The organization '{}' does not exist in APS", fileOrgName);
// FIXME create the organization
@ -102,7 +109,7 @@ public class ApsAppJsonTranslator implements ApsFileTranslator {
}
if (changed)
ModelUtil.getInstance().writeJson(descriptor, file);
ModelUtil.getInstance().writeJson(descriptor, file, false);
}
}

View File

@ -46,7 +46,7 @@ public class ApsFormJsonTranslator implements ApsFileTranslator {
}
if (changed)
ModelUtil.getInstance().writeJson(jsonDescriptor, file);
ModelUtil.getInstance().writeJson(jsonDescriptor, file, false);
}
}

View File

@ -25,7 +25,6 @@ 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 {
@ -106,6 +105,7 @@ public class ApsProcessBpmnTranslator implements ApsFileTranslator {
if (apsProcessId != null)
changed = this.setAttributeIfSet(definitionsElement, NAMESPACE_ACTIVITI_MODELER, "modelId", apsProcessId) || changed;
changed = this.removeAttributeIfSet(definitionsElement, NAMESPACE_ACTIVITI_MODELER, "modelVersion") || changed;
//changed = this.setAttributeIfSet(definitionsElement, NAMESPACE_ACTIVITI_MODELER, "modelVersion", "0") || changed;
return changed;
}
@ -200,17 +200,17 @@ public class ApsProcessBpmnTranslator implements ApsFileTranslator {
this.logger.trace("The form '{}' key does not change; leaving unchanged", formRefName);
}
CDATAFlexSection formRefIdData = (CDATAFlexSection)ModelUtil.getInstance().xpath(
CharacterData formRefIdData = (CharacterData)ModelUtil.getInstance().xpath(
taskElement,
"tns:extensionElements/modeler:form-reference-id",
ModelUtil.CDATA_FLEX);
if (formRefIdData == null)
throw new IllegalStateException("A form was detected in the task, but no form reference ID was found: " + taskElement.getAttribute("id"));
long formRefId = Long.parseLong(formRefIdData.getValue());
long formRefId = Long.parseLong(formRefIdData.getData());
if (apsFormId != formRefId) {
this.logger.debug("The form '{}' reference exists in APS with ID {}; changing model", formRefName, apsFormId);
formRefIdData.setValue(apsFormId.toString());
formRefIdData.setData(apsFormId.toString());
changed = true;
} else {
this.logger.trace("The form '{}' reference ID does not change; leaving unchanged", formRefName);
@ -244,14 +244,14 @@ public class ApsProcessBpmnTranslator implements ApsFileTranslator {
this.logger.trace("Found ID {} for the subprocess '{}' in the APS Process BPMN model", apsProcessId, subprocessName);
CDATAFlexSection subprocessIdData = (CDATAFlexSection)ModelUtil.getInstance().xpath(
CharacterData subprocessIdData = (CharacterData)ModelUtil.getInstance().xpath(
subprocessElement,
"tns:extensionElements/modeler:subprocess-id",
ModelUtil.CDATA_FLEX);
long subprocessId = Long.parseLong(subprocessIdData.getValue());
long subprocessId = Long.parseLong(subprocessIdData.getData());
if (apsProcessId != subprocessId) {
this.logger.debug("The process '{}' exists in APS with ID {}; changing model", subprocessName, apsProcessId);
subprocessIdData.setValue(apsProcessId.toString());
subprocessIdData.setData(apsProcessId.toString());
changed = true;
} else {
this.logger.trace("The process '{}' ID does not change; leaving unchanged", subprocessName);
@ -289,23 +289,37 @@ public class ApsProcessBpmnTranslator implements ApsFileTranslator {
boolean changed = false;
String conditionExpression = conditionExpressionCdata.getData();
Pattern formOutcomeInExpressionPattern = Pattern.compile("[^A-Za-z0-9]form([0-9]+)outcome[^A-Za-z0-9]");
StringBuilder newce = new StringBuilder();
int pos = 0;
Pattern formOutcomeInExpressionPattern = Pattern.compile("form([0-9]+)outcome");
Matcher matcher = formOutcomeInExpressionPattern.matcher(conditionExpression);
while (matcher.find()) {
newce.append(conditionExpression.substring(pos, matcher.start(1)));
long formId = Long.parseLong(matcher.group(1));
String formName = this.fileFormIndex.getValue(formId);
if (formName == null) {
this.logger.warn("The form ID '{}' does not exist in the form model files; ignoring", formId);
newce.append(formId);
} else {
Long apsFormId = this.apsFormIndex.getFirstKey(formName);
if (apsFormId == null) {
this.logger.warn("The form '{}' does not exist in APS; leaving unchanged", formName);
newce.append(formId);
} else {
conditionExpressionCdata.setData(apsFormId.toString());
newce.append(apsFormId);
changed = true;
}
}
pos = matcher.end(1);
}
newce.append(conditionExpression.substring(pos));
if (changed)
conditionExpressionCdata.setData(newce.toString());
return changed;
}

View File

@ -45,7 +45,7 @@ public class ApsProcessJsonTranslator implements ApsFileTranslator {
changed = this.translateSubprocesses(jsonDescriptor) || changed;
if (changed)
ModelUtil.getInstance().writeJson(jsonDescriptor, file);
ModelUtil.getInstance().writeJson(jsonDescriptor, file, false);
}
private boolean translateResourceId(ObjectNode jsonDescriptor, Long apsProcessId) {
@ -130,8 +130,8 @@ public class ApsProcessJsonTranslator implements ApsFileTranslator {
for (JsonNode jsonChildShape : this.getChildShapes(jsonDescriptor)) {
try {
JsonNode jsonConditionalSequenceFlow = (JsonNode)jsonChildShape.get("properties").get("conditionalsequenceflow");
changed = this.translateConditionalSequenceFlow(jsonConditionalSequenceFlow) || changed;
JsonNode jsonConditionalSequenceFlow = (JsonNode)jsonChildShape.get("properties").get("conditionsequenceflow");
changed = this.translateConditionSequenceFlow(jsonConditionalSequenceFlow) || changed;
JsonNode jsonFormRef = (JsonNode)jsonChildShape.get("properties").get("formreference");
changed = this.translateReference(jsonFormRef, this.apsFormIndex) || changed;
@ -143,7 +143,7 @@ public class ApsProcessJsonTranslator implements ApsFileTranslator {
return changed;
}
private boolean translateConditionalSequenceFlow(JsonNode jsonConditionalSequenceFlow) {
private boolean translateConditionSequenceFlow(JsonNode jsonConditionalSequenceFlow) {
if (jsonConditionalSequenceFlow == null || !jsonConditionalSequenceFlow.isObject())
return false;

View File

@ -27,7 +27,7 @@ import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.CDATASection;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@ -38,12 +38,10 @@ 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 {
public final static QName CDATA = QName.valueOf("inteligr8:xml:cdata");
public final static QName CDATA_FLEX = QName.valueOf("inteligr8:xml:cdata_or_element");
private final static ModelUtil INSTANCE = new ModelUtil();
@ -54,6 +52,7 @@ public class ModelUtil {
private final ObjectMapper om = new ObjectMapper();
private final ObjectMapper omsorted = new ObjectMapper();
private final DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
private final DocumentBuilder docBuilder;
private final XPathFactory xpathfactory = XPathFactory.newInstance();
@ -81,26 +80,28 @@ public class ModelUtil {
// makes Git handling a whole lot better
this.om.enable(SerializationFeature.INDENT_OUTPUT);
this.omsorted.enable(SerializationFeature.INDENT_OUTPUT);
// makes Git handling better between environment nuances
this.om.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);
this.om.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS);
this.omsorted.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);
this.omsorted.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS);
}
public void json(File inplaceFile) throws IOException {
public void json(File inplaceFile, boolean enableSorting) throws IOException {
JsonNode json = this.readJson(inplaceFile);
this.writeJson(json, inplaceFile);
this.writeJson(json, inplaceFile, enableSorting);
}
public void json(File sourceFile, File targetFile) throws IOException {
public void json(File sourceFile, File targetFile, boolean enableSorting) throws IOException {
FileInputStream fistream = new FileInputStream(sourceFile);
BufferedInputStream bistream = new BufferedInputStream(fistream, this.bufferSize);
try {
FileOutputStream fostream = new FileOutputStream(targetFile);
BufferedOutputStream bostream = new BufferedOutputStream(fostream, this.bufferSize);
try {
this.json(bistream, bostream);
this.json(bistream, bostream, enableSorting);
} finally {
bostream.close();
}
@ -109,10 +110,10 @@ public class ModelUtil {
}
}
public void json(InputStream istream, OutputStream ostream) throws IOException {
public void json(InputStream istream, OutputStream ostream, boolean enableSorting) throws IOException {
// FIXME stream it for lower memory/IO usage
JsonNode json = this.readJson(istream);
this.writeJson(json, ostream);
this.writeJson(json, ostream, enableSorting);
}
public JsonNode readJson(File file) throws IOException {
@ -167,32 +168,40 @@ public class ModelUtil {
return this.om.readValue(istream, Map.class);
}
public void writeJson(JsonNode json, File file) throws IOException {
public void writeJson(JsonNode json, File file, boolean enableSorting) throws IOException {
FileOutputStream fostream = new FileOutputStream(file);
BufferedOutputStream bostream = new BufferedOutputStream(fostream, this.bufferSize);
try {
this.writeJson(json, bostream);
this.writeJson(json, bostream, enableSorting);
} finally {
bostream.close();
}
}
public void writeJson(Map<String, Object> map, File file) throws IOException {
public void writeJson(Map<String, Object> map, File file, boolean enableSorting) throws IOException {
FileOutputStream fostream = new FileOutputStream(file);
BufferedOutputStream bostream = new BufferedOutputStream(fostream, this.bufferSize);
try {
this.writeJson(map, bostream);
this.writeJson(map, bostream, enableSorting);
} finally {
bostream.close();
}
}
public void writeJson(JsonNode json, OutputStream ostream) throws IOException {
this.om.writeValue(ostream, json);
public void writeJson(JsonNode json, OutputStream ostream, boolean enableSorting) throws IOException {
if (enableSorting) {
this.omsorted.writeValue(ostream, json);
} else {
this.om.writeValue(ostream, json);
}
}
public void writeJson(Map<String, Object> map, OutputStream ostream) throws IOException {
this.om.writeValue(ostream, map);
public void writeJson(Map<String, Object> map, OutputStream ostream, boolean enableSorting) throws IOException {
if (enableSorting) {
this.omsorted.writeValue(ostream, map);
} else {
this.om.writeValue(ostream, map);
}
}
@ -277,22 +286,23 @@ public class ModelUtil {
XPath xpath = this.xpathfactory.newXPath();
xpath.setNamespaceContext(new DomNamespaceContext(node));
boolean isFlex = returnType.equals(ModelUtil.CDATA_FLEX);
if (returnType.equals(ModelUtil.CDATA) || isFlex) {
if (returnType.equals(ModelUtil.CDATA_FLEX)) {
NodeList nodes = (NodeList)xpath.evaluate(xpathExpr, node, XPathConstants.NODESET);
Node anode = this.getFirstCDataSectionOrLastElement(nodes);
if (anode instanceof CDATASection) {
if (anode instanceof CharacterData) {
// nothing special
} else if (anode instanceof Element) {
Node anode2 = this.getFirstCDataSectionOrLastElement(anode.getChildNodes());
if (anode2 != null)
return anode = anode2;
if (anode2 == null)
return null;
if (!(anode2 instanceof CharacterData))
throw new IllegalStateException();
anode = anode2;
} else {
return null;
}
return isFlex ? new CDATAFlexSection(anode) : anode;
return anode;
} else {
return xpath.evaluate(xpathExpr, node, returnType);
}
@ -303,8 +313,8 @@ public class ModelUtil {
for (int n = 0; n < nodes.getLength(); n++) {
Node anode = nodes.item(n);
if (anode.getNodeType() == Node.CDATA_SECTION_NODE) {
return (CDATASection)anode;
if (anode instanceof CharacterData) {
return (CharacterData)anode;
} else if (anode.getNodeType() == Node.ELEMENT_NODE) {
element = (Element)anode;
}

View File

@ -1,31 +0,0 @@
package com.inteligr8.maven.aps.modeling.xml;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Node;
public class CDATAFlexSection {
private final Node node;
public CDATAFlexSection(Node node) {
this.node = node;
}
public String getValue() {
if (this.node instanceof CDATASection) {
return ((CDATASection)this.node).getData();
} else {
String value = this.node.getTextContent();
return value == null ? null : this.node.getTextContent().trim();
}
}
public void setValue(String value) {
if (this.node instanceof CDATASection) {
((CDATASection)this.node).setData(value);
} else {
this.node.setTextContent(value);
}
}
}

View File

@ -1,9 +1,14 @@
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:output indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
<xsl:value-of select="." disable-output-escaping="yes" />
<xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
</xsl:template>
</xsl:stylesheet>