added dynamic normalizer and reusable crawler

This commit is contained in:
Brian Long 2022-03-25 15:55:38 +01:00
parent 89a43457f4
commit 0541cf502b
18 changed files with 431 additions and 202 deletions

View File

@ -31,7 +31,7 @@
<goal>unpack-app</goal>
</goals>
<configuration>
<apsAppName>${aps.app}</apsAppName>
<normalize>true</normalize>
</configuration>
</execution>
<execution>
@ -41,8 +41,6 @@
<goal>pack-app</goal>
</goals>
<configuration>
<apsAppName>${aps.app}</apsAppName>
<targetDirectory>${basedir}/src/main/app</targetDirectory>
</configuration>
</execution>
</executions>

View File

@ -28,6 +28,7 @@
</goals>
<configuration>
<normalize>true</normalize>
<diffFriendly>true</diffFriendly>
</configuration>
</execution>
<execution>

View File

@ -0,0 +1,13 @@
package com.inteligr8.maven.aps.modeling.crawler;
public interface ApsAppCrawlable {
ApsFileTransformer getAppJsonTransformer();
ApsFileTransformer getProcessJsonTransformer();
ApsFileTransformer getProcessBpmnTransformer();
ApsFileTransformer getFormJsonTransformer();
}

View File

@ -0,0 +1,105 @@
package com.inteligr8.maven.aps.modeling.crawler;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ApsAppCrawler {
private final Logger logger = LoggerFactory.getLogger(ApsAppCrawler.class);
private final Pattern filenamePattern = Pattern.compile("([^/]+)-([0-9]+)\\.(json|bpmn20\\.xml)");
private final String appName;
private final File appDirectory;
private final File appDescriptor;
private final boolean failOnIntegrityViolation;
public ApsAppCrawler(String apsAppName, File apsAppDirectory, boolean failOnIntegrityViolation) {
this.appName = apsAppName;
this.appDirectory = apsAppDirectory;
this.failOnIntegrityViolation = failOnIntegrityViolation;
this.appDescriptor = this.validateDescriptor(appDirectory);
if (this.logger.isDebugEnabled())
this.logger.debug("APS App descriptor found: " + this.appDescriptor);
}
protected File validateDescriptor(File appDirectory) {
File appDescriptor = new File(appDirectory, this.appName + ".json");
if (!appDescriptor.exists())
throw new IllegalStateException("The APS App descriptor could not be found: " + appDescriptor);
if (!appDescriptor.isFile())
throw new IllegalStateException("The APS App descriptor is not a file: " + appDescriptor);
return appDescriptor;
}
public void execute(ApsAppCrawlable crawlable) throws IOException {
this.logger.info("Crawling APS App ...");
Map<String, ApsFileTransformer> processTransformers = new HashMap<>();
processTransformers.put("json", crawlable.getProcessJsonTransformer());
processTransformers.put("bpmn20.xml", crawlable.getProcessBpmnTransformer());
processTransformers.put("bpmn", crawlable.getProcessBpmnTransformer());
this.transform(crawlable.getAppJsonTransformer(), this.appDescriptor, this.appName, null);
this.crawlModels("form-models", crawlable.getFormJsonTransformer());
this.crawlModels("bpmn-models", processTransformers);
this.crawlModels("bpmn-subprocess-models", crawlable.getProcessJsonTransformer());
}
protected void crawlModels(String modelsDirectoryName, ApsFileTransformer transformer) throws IOException {
this.crawlModels(modelsDirectoryName, Collections.singletonMap("json", transformer));
}
protected void crawlModels(String modelsDirectoryName, Map<String, ApsFileTransformer> transformers) throws IOException {
File modelsDirectory = new File(this.appDirectory, modelsDirectoryName);
if (!modelsDirectory.exists()) {
this.logger.debug("APS model directory doesn't exist; no models to transform: {}", modelsDirectory);
return;
}
for (File modelFile : modelsDirectory.listFiles()) {
this.logger.trace("Transforming 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);
continue;
}
String ext = matcher.group(3);
ApsFileTransformer transformer = transformers.get(ext.toLowerCase());
if (transformer == null) {
this.logger.warn("The '{}' folder has a file with an unexpected extension; skipping: {}", modelsDirectoryName, modelFile);
continue;
}
String modelName = matcher.group(1);
Long modelId = new Long(matcher.group(2));
this.logger.trace("Transforming model {} ID: {}", modelName, modelId);
this.transform(transformer, modelFile, modelName, modelId);
}
}
private void transform(ApsFileTransformer transformer, File modelFile, String modelName, Long modelId) throws IOException {
try {
transformer.transformFile(modelFile, modelName, modelId);
} catch (IllegalArgumentException | IllegalStateException ie) {
if (this.failOnIntegrityViolation) {
throw ie;
} else {
this.logger.warn(ie.getMessage());
}
}
}
}

View File

@ -0,0 +1,10 @@
package com.inteligr8.maven.aps.modeling.crawler;
import java.io.File;
import java.io.IOException;
public interface ApsFileTransformer {
void transformFile(File file, String modelName, Long modelId) throws IOException;
}

View File

@ -12,6 +12,7 @@ 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;
import com.inteligr8.maven.aps.modeling.translator.ApsAppTranslator;
@Mojo( name = "translate-app", threadSafe = true )
@ -47,8 +48,11 @@ public class TranslateAppGoal extends ApsAppAccessibleGoal {
apsAppDirectory = newApsAppDirectory;
}
ApsAppTranslator translator = new ApsAppTranslator(this.apsAppName, apsAppDirectory, this.getApsApi(), true);
translator.execute();
ApsAppTranslator translator = new ApsAppTranslator(apsAppDirectory, this.getApsApi());
translator.buildIndexes();
ApsAppCrawler crawler = new ApsAppCrawler(this.apsAppName, apsAppDirectory, true);
crawler.execute(translator);
} catch (IOException ie) {
throw new MojoExecutionException("An I/O issue occurred", ie);
} catch (IllegalArgumentException iae) {

View File

@ -10,7 +10,6 @@ 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;
@ -26,10 +25,8 @@ 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.crawler.ApsAppCrawler;
import com.inteligr8.maven.aps.modeling.normalizer.ApsAppNormalizer;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
@Mojo( name = "unpack-app", threadSafe = true )
@ -45,9 +42,12 @@ public class UnpackAppGoal extends ApsAppGoal {
@Parameter( property = "aps-model.reformat", required = true, defaultValue = "true" )
protected boolean reformat = true;
@Parameter( property = "aps-model.normalize", required = true, defaultValue = "false" )
@Parameter( property = "aps-model.normalize" )
protected boolean normalize;
@Parameter( property = "aps-model.normalize.diffFriendly" )
protected boolean diffFriendly;
@Parameter( property = "aps-model.charset", required = true, defaultValue = "utf-8" )
protected String charsetName = "utf-8";
@ -72,6 +72,15 @@ public class UnpackAppGoal extends ApsAppGoal {
if (this.reformat)
this.reformatFiles(appDirectory);
if (this.normalize) {
try {
ApsAppNormalizer normalizer = new ApsAppNormalizer(this.diffFriendly);
ApsAppCrawler crawler = new ApsAppCrawler(this.apsAppName, appDirectory, true);
crawler.execute(normalizer);
} catch (IOException ie) {
throw new MojoExecutionException("An I/O issue occurred", ie);
}
}
}
protected void validate() {
@ -179,16 +188,12 @@ public class UnpackAppGoal extends ApsAppGoal {
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:
@ -201,96 +206,6 @@ public class UnpackAppGoal extends ApsAppGoal {
}
}
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)

View File

@ -0,0 +1,52 @@
package com.inteligr8.maven.aps.modeling.normalizer;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.inteligr8.maven.aps.modeling.util.ApsModelArrayNodeSorter;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
public class ApsAppJsonNormalizer implements ApsFileNormalizer {
private final Logger logger = LoggerFactory.getLogger(ApsAppJsonNormalizer.class);
private final boolean enableSorting;
public ApsAppJsonNormalizer(boolean enableSorting) {
this.enableSorting = enableSorting;
}
@Override
public void transformFile(File file, String modelName, Long modelId) throws IOException {
this.logger.debug("Normalizing App JSON file: {}", file);
boolean changed = false;
JsonNode descriptor = ModelUtil.getInstance().readJson(file);
ArrayNode jsonModels = (ArrayNode)descriptor.get("definition").get("models");
// remove system-level and non-functional fields from models
for (JsonNode _jsonModel : jsonModels) {
ObjectNode jsonModel = (ObjectNode)_jsonModel;
int fields = jsonModel.size();
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");
if (changed)
ModelUtil.getInstance().writeJson(descriptor, file);
}
}

View File

@ -0,0 +1,34 @@
package com.inteligr8.maven.aps.modeling.normalizer;
import com.inteligr8.maven.aps.modeling.crawler.ApsAppCrawlable;
import com.inteligr8.maven.aps.modeling.crawler.ApsFileTransformer;
public class ApsAppNormalizer implements ApsAppCrawlable {
private final boolean enableSorting;
public ApsAppNormalizer(boolean enableSorting) {
this.enableSorting = enableSorting;
}
@Override
public ApsFileTransformer getAppJsonTransformer() {
return new ApsAppJsonNormalizer(this.enableSorting);
}
@Override
public ApsFileTransformer getFormJsonTransformer() {
return new ApsFormJsonNormalizer();
}
@Override
public ApsFileTransformer getProcessJsonTransformer() {
return new ApsProcessJsonNormalizer(this.enableSorting);
}
@Override
public ApsFileTransformer getProcessBpmnTransformer() {
return new ApsProcessBpmnNormalizer();
}
}

View File

@ -0,0 +1,7 @@
package com.inteligr8.maven.aps.modeling.normalizer;
import com.inteligr8.maven.aps.modeling.crawler.ApsFileTransformer;
public interface ApsFileNormalizer extends ApsFileTransformer {
}

View File

@ -0,0 +1,19 @@
package com.inteligr8.maven.aps.modeling.normalizer;
import java.io.File;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ApsFormJsonNormalizer implements ApsFileNormalizer {
private final Logger logger = LoggerFactory.getLogger(ApsFormJsonNormalizer.class);
@Override
public void transformFile(File file, String modelName, Long modelId) throws IOException {
this.logger.debug("Normalizing Form JSON file: {}", file);
this.logger.trace("Nothing to normalize: {}", file);
}
}

View File

@ -0,0 +1,52 @@
package com.inteligr8.maven.aps.modeling.normalizer;
import java.io.File;
import java.io.IOException;
import javax.xml.transform.TransformerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
public class ApsProcessBpmnNormalizer implements ApsFileNormalizer {
private static final String NAMESPACE_ACTIVITI_MODELER = "http://activiti.com/modeler";
private final Logger logger = LoggerFactory.getLogger(ApsProcessBpmnNormalizer.class);
@Override
public void transformFile(File file, String modelName, Long modelId) throws IOException {
this.logger.debug("Normalizing Process BPMN file: {}", file);
boolean changed = false;
try {
Document bpmn = ModelUtil.getInstance().readXml(file);
Element definitionsElement = bpmn.getDocumentElement();
changed = this.removeAttributeIfSet(definitionsElement, NAMESPACE_ACTIVITI_MODELER, "exportDateTime") || changed;
changed = this.removeAttributeIfSet(definitionsElement, NAMESPACE_ACTIVITI_MODELER, "modelLastUpdated") || changed;
if (changed)
ModelUtil.getInstance().writeXml(bpmn, file);
} catch (TransformerException | SAXException e) {
throw new IllegalStateException("An XML issue occurred", e);
}
}
private boolean removeAttributeIfSet(Element element, String attrNamespace, String attrName) {
Attr attr = element.getAttributeNodeNS(attrNamespace, attrName);
if (attr == null)
return false;
element.removeAttributeNode(attr);
return true;
}
}

View File

@ -0,0 +1,50 @@
package com.inteligr8.maven.aps.modeling.normalizer;
import java.io.File;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.inteligr8.maven.aps.modeling.util.ApsModelArrayNodeSorter;
import com.inteligr8.maven.aps.modeling.util.ModelUtil;
public class ApsProcessJsonNormalizer implements ApsFileNormalizer {
private final Logger logger = LoggerFactory.getLogger(ApsProcessJsonNormalizer.class);
private final boolean enableSorting;
public ApsProcessJsonNormalizer(boolean enableSorting) {
this.enableSorting = enableSorting;
}
@Override
public void transformFile(File file, String modelName, Long modelId) throws IOException {
this.logger.debug("Normalizing Process JSON file: {}", file);
if (!this.enableSorting)
return;
boolean changed = false;
ObjectNode jsonDescriptor = ModelUtil.getInstance().readJson(file, ObjectNode.class);
ArrayNode jsonChildShapes = this.getChildShapes(jsonDescriptor);
changed = ApsModelArrayNodeSorter.getInstance().sort(jsonChildShapes, "resourceId") || changed;
if (changed)
ModelUtil.getInstance().writeJson(jsonDescriptor, file);
}
private ArrayNode getChildShapes(ObjectNode jsonDescriptor) {
JsonNode jsonChildShapes = jsonDescriptor.get("childShapes");
if (jsonChildShapes == null)
jsonChildShapes = jsonDescriptor.get("editorJson").get("childShapes");
return (ArrayNode)jsonChildShapes;
}
}

View File

@ -68,7 +68,7 @@ public class ApsAppJsonTranslator implements ApsFileTranslator {
}
int fields = jsonModel.size();
jsonModel.remove(Arrays.asList("version", "createdBy", "createdByFullName", "lastUpdatedBy", "lastUpdatedByFullName", "lastUpdated"));
jsonModel.remove(Arrays.asList("version"));
if (jsonModel.size() < fields)
changed = true;
}
@ -90,6 +90,11 @@ 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");
changed = true;
}
} else {
this.logger.warn("The organization '{}' does not exist in APS", fileOrgName);
// FIXME create the organization

View File

@ -2,7 +2,6 @@ package com.inteligr8.maven.aps.modeling.translator;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -20,18 +19,18 @@ 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.crawler.ApsAppCrawlable;
import com.inteligr8.maven.aps.modeling.crawler.ApsFileTransformer;
import com.inteligr8.maven.aps.modeling.util.Index;
public class ApsAppTranslator {
public class ApsAppTranslator implements ApsAppCrawlable {
private final Logger logger = LoggerFactory.getLogger(ApsAppTranslator.class);
private final Pattern filenamePattern = Pattern.compile("([^/]+)-([0-9]+)\\.(json|bpmn20\\.xml)");
private final ApsPublicRestApi api;
private final String appName;
private final File appDirectory;
private final File appDescriptor;
private final boolean failOnIntegrityViolation;
private boolean indexesBuilt = false;
private Map<String, Group> apsOrgIndex;
private Index<Long, String> apsFormIndex;
private Index<Long, String> apsProcessIndex;
@ -39,34 +38,15 @@ public class ApsAppTranslator {
private Index<Long, String> fileProcessIndex;
private Index<Long, String> fileSubprocessIndex;
public ApsAppTranslator(String apsAppName, File apsAppDirectory, ApsPublicRestApiJerseyImpl api, boolean failOnIntegrityViolation) {
public ApsAppTranslator(File apsAppDirectory, ApsPublicRestApiJerseyImpl api) {
this.api = api;
this.appName = apsAppName;
this.appDirectory = apsAppDirectory;
this.failOnIntegrityViolation = failOnIntegrityViolation;
this.appDescriptor = this.validateDescriptor(appDirectory);
if (this.logger.isDebugEnabled())
this.logger.debug("APS App descriptor found: " + this.appDescriptor);
}
protected File validateDescriptor(File appDirectory) {
File appDescriptor = new File(appDirectory, this.appName + ".json");
public synchronized void buildIndexes() throws IOException {
if (this.indexesBuilt)
return;
if (!appDescriptor.exists())
throw new IllegalStateException("The APS App descriptor could not be found: " + appDescriptor);
if (!appDescriptor.isFile())
throw new IllegalStateException("The APS App descriptor is not a file: " + appDescriptor);
return appDescriptor;
}
public void execute() throws IOException {
this.buildIndexes();
this.translate();
}
protected void buildIndexes() throws IOException {
this.logger.info("Building indexes ...");
long tenantId = this.findTenantId();
@ -89,6 +69,8 @@ public class ApsAppTranslator {
this.fileSubprocessIndex = this.buildFileIndex("bpmn-subprocess-models", this.apsProcessIndex, true);
this.logLarge("File subprocess models: {}", this.fileSubprocessIndex);
this.indexesBuilt = true;
}
private <K, V> void logLarge(String message, Map<K, V> map) {
@ -107,34 +89,47 @@ public class ApsAppTranslator {
}
}
protected void translate() throws IOException {
this.logger.info("Translating models ...");
@Override
public ApsFileTransformer getAppJsonTransformer() {
if (!this.indexesBuilt)
throw new IllegalStateException("The indexes are never built");
ApsFileTranslator descriptorTranslator = new ApsAppJsonTranslator(
return new ApsAppJsonTranslator(
this.apsOrgIndex,
this.apsProcessIndex,
this.fileProcessIndex);
ApsFileTranslator formTranslator = new ApsFormJsonTranslator(
}
@Override
public ApsFileTransformer getFormJsonTransformer() {
if (!this.indexesBuilt)
throw new IllegalStateException("The indexes are never built");
return new ApsFormJsonTranslator(
this.apsFormIndex);
ApsFileTranslator processTranslator = new ApsProcessJsonTranslator(
}
@Override
public ApsFileTransformer getProcessJsonTransformer() {
if (!this.indexesBuilt)
throw new IllegalStateException("The indexes are never built");
return new ApsProcessJsonTranslator(
this.apsProcessIndex,
this.apsOrgIndex,
this.apsFormIndex);
ApsFileTranslator bpmnTranslator = new ApsProcessBpmnTranslator(
}
@Override
public ApsFileTransformer getProcessBpmnTransformer() {
if (!this.indexesBuilt)
throw new IllegalStateException("The indexes are never built");
return new ApsProcessBpmnTranslator(
this.apsProcessIndex,
this.apsOrgIndex,
this.apsFormIndex,
this.fileFormIndex);
Map<String, ApsFileTranslator> processTranslators = new HashMap<>();
processTranslators.put("json", processTranslator);
processTranslators.put("bpmn20.xml", bpmnTranslator);
processTranslators.put("bpmn", bpmnTranslator);
this.translate(descriptorTranslator, this.appDescriptor, this.appName, null);
this.translateModels("form-models", formTranslator);
this.translateModels("bpmn-models", processTranslators);
this.translateModels("bpmn-subprocess-models", processTranslator);
}
protected Long findTenantId() {
@ -201,10 +196,15 @@ public class ApsAppTranslator {
fileModelIndex.put(fileModelId, modelName);
Set<Long> apsModelIds = apsModelIndex.getKeys(modelName);
if (apsModelIds == null || apsModelIds.isEmpty()) {
this.logger.debug("The model file '{}' has no corresponding model in APS; treating as new", modelFile.getName());
continue;
}
if (apsModelIds.size() > 1)
throw new IllegalStateException("An APS " + modelDirectory.getName() + " name was used multiple times: " + modelName);
if (renameFiles && !apsModelIds.isEmpty()) {
if (renameFiles) {
Long apsModelId = apsModelIds.iterator().next();
if (apsModelId != fileModelId) {
this.logger.debug("Renaming form model from '" + modelFile.getName() + "' to match APS form ID: " + apsModelId);
@ -218,52 +218,5 @@ public class ApsAppTranslator {
return fileModelIndex;
}
protected void translateModels(String modelsDirectoryName, ApsFileTranslator translator) throws IOException {
this.translateModels(modelsDirectoryName, Collections.singletonMap("json", translator));
}
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);
continue;
}
String ext = matcher.group(3);
ApsFileTranslator translator = translators.get(ext.toLowerCase());
if (translator == null) {
this.logger.warn("The '{}' folder has a file with an unexpected extension; skipping: {}", modelsDirectoryName, modelFile);
continue;
}
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);
}
}
private void translate(ApsFileTranslator translator, File modelFile, String modelName, Long modelId) throws IOException {
try {
translator.translateFile(modelFile, modelName, modelId);
} catch (IllegalArgumentException | IllegalStateException ie) {
if (this.failOnIntegrityViolation) {
throw ie;
} else {
this.logger.warn(ie.getMessage());
}
}
}
}

View File

@ -3,7 +3,14 @@ package com.inteligr8.maven.aps.modeling.translator;
import java.io.File;
import java.io.IOException;
public interface ApsFileTranslator {
import com.inteligr8.maven.aps.modeling.crawler.ApsFileTransformer;
public interface ApsFileTranslator extends ApsFileTransformer {
@Override
default void transformFile(File file, String modelName, Long modelId) throws IOException {
this.translateFile(file, modelName, modelId);
}
void translateFile(File file, String modelName, Long modelId) throws IOException;

View File

@ -103,10 +103,9 @@ public class ApsProcessBpmnTranslator implements ApsFileTranslator {
private boolean translateRootElement(Element definitionsElement, Long apsProcessId) {
boolean changed = false;
changed = this.setAttributeIfSet(definitionsElement, NAMESPACE_ACTIVITI_MODELER, "modelId", apsProcessId) || changed;
if (apsProcessId != null)
changed = this.setAttributeIfSet(definitionsElement, NAMESPACE_ACTIVITI_MODELER, "modelId", apsProcessId) || changed;
changed = this.removeAttributeIfSet(definitionsElement, NAMESPACE_ACTIVITI_MODELER, "modelVersion") || changed;
changed = this.removeAttributeIfSet(definitionsElement, NAMESPACE_ACTIVITI_MODELER, "exportDateTime") || changed;
changed = this.removeAttributeIfSet(definitionsElement, NAMESPACE_ACTIVITI_MODELER, "modelLastUpdated") || changed;
return changed;
}

View File

@ -49,6 +49,11 @@ public class ApsProcessJsonTranslator implements ApsFileTranslator {
}
private boolean translateResourceId(ObjectNode jsonDescriptor, Long apsProcessId) {
if (apsProcessId == null) {
this.logger.trace("The process is not in APS; treating as new");
return false;
}
ObjectNode resourceIdParentJson = jsonDescriptor;
JsonNode jsonResourceId = jsonDescriptor.get("resourceId");