added dynamic normalizer and reusable crawler
This commit is contained in:
parent
89a43457f4
commit
0541cf502b
@ -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>
|
||||
|
@ -28,6 +28,7 @@
|
||||
</goals>
|
||||
<configuration>
|
||||
<normalize>true</normalize>
|
||||
<diffFriendly>true</diffFriendly>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.inteligr8.maven.aps.modeling.crawler;
|
||||
|
||||
public interface ApsAppCrawlable {
|
||||
|
||||
ApsFileTransformer getAppJsonTransformer();
|
||||
|
||||
ApsFileTransformer getProcessJsonTransformer();
|
||||
|
||||
ApsFileTransformer getProcessBpmnTransformer();
|
||||
|
||||
ApsFileTransformer getFormJsonTransformer();
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.inteligr8.maven.aps.modeling.normalizer;
|
||||
|
||||
import com.inteligr8.maven.aps.modeling.crawler.ApsFileTransformer;
|
||||
|
||||
public interface ApsFileNormalizer extends ApsFileTransformer {
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user