From 9a05d6fb43619c2b0f53add97aac3c4c98d2ef80 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Fri, 31 Dec 2021 15:43:16 +0100 Subject: [PATCH] [New] XML import now supports more options: - failOnUpdate - add of elements - update of elements --- .../agent/impl/InMemoryElementListener.java | 33 +++++-- .../li/strolch/model/ModelStatistics.java | 95 ++++++++++++------- .../model/xml/XmlModelSaxFileReader.java | 42 ++++---- .../strolch/model/xml/XmlModelSaxReader.java | 2 +- .../model/xml/XmlModelSaxStreamReader.java | 3 +- .../li/strolch/rest/endpoint/Inspector.java | 27 ++++-- .../command/XmlExportModelCommand.java | 7 +- .../command/XmlImportModelCommand.java | 22 ++--- .../service/XmlImportModelArgument.java | 6 +- .../service/XmlImportModelService.java | 15 +-- 10 files changed, 153 insertions(+), 99 deletions(-) diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/InMemoryElementListener.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/InMemoryElementListener.java index cd726c03a..c4137fade 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/InMemoryElementListener.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/InMemoryElementListener.java @@ -16,10 +16,12 @@ package li.strolch.agent.impl; import java.text.MessageFormat; +import java.time.LocalDateTime; import java.util.Collections; import java.util.Set; import li.strolch.exception.StrolchException; +import li.strolch.model.ModelStatistics; import li.strolch.model.Order; import li.strolch.model.Resource; import li.strolch.model.activity.Activity; @@ -31,6 +33,9 @@ import li.strolch.persistence.api.StrolchTransaction; */ public class InMemoryElementListener implements StrolchElementListener { + private final StrolchTransaction tx; + private final ModelStatistics statistics; + private boolean addOrders; private boolean addResources; private boolean addActivities; @@ -43,10 +48,10 @@ public class InMemoryElementListener implements StrolchElementListener { private boolean failOnUpdate; - private StrolchTransaction tx; - public InMemoryElementListener(StrolchTransaction tx) { this.tx = tx; + this.statistics = new ModelStatistics(); + this.statistics.startTime = LocalDateTime.now(); this.addResources = true; this.addOrders = true; @@ -139,6 +144,10 @@ public class InMemoryElementListener implements StrolchElementListener { this.failOnUpdate = failOnUpdate; } + public ModelStatistics getStatistics() { + return this.statistics; + } + @Override public void notifyResource(Resource resource) { if (!this.resourceTypes.isEmpty() && !this.resourceTypes.contains(resource.getType())) @@ -150,12 +159,15 @@ public class InMemoryElementListener implements StrolchElementListener { Resource current = this.tx.getResourceBy(resource.getType(), resource.getId()); resource.setVersion(current.getVersion()); this.tx.update(resource); + this.statistics.nrOfResourcesUpdated++; } else if (this.failOnUpdate) { - throw new StrolchException(MessageFormat - .format("Resource {0} already exists and updating is disallowed!", resource.getLocator())); + throw new StrolchException( + MessageFormat.format("Resource {0} already exists and updating is disallowed!", + resource.getLocator())); } } else if (this.addResources) { this.tx.add(resource); + this.statistics.nrOfResources++; } // else ignore } @@ -171,12 +183,14 @@ public class InMemoryElementListener implements StrolchElementListener { Order current = this.tx.getOrderBy(order.getType(), order.getId()); order.setVersion(current.getVersion()); this.tx.update(order); + this.statistics.nrOfOrdersUpdated++; } else if (failOnUpdate) { - throw new StrolchException(MessageFormat - .format("Order {0} already exists and updating is disallowed!", order.getLocator())); + throw new StrolchException(MessageFormat.format("Order {0} already exists and updating is disallowed!", + order.getLocator())); } } else if (this.addOrders) { this.tx.add(order); + this.statistics.nrOfOrders++; } // else ignore } @@ -192,12 +206,15 @@ public class InMemoryElementListener implements StrolchElementListener { Activity current = this.tx.getActivityBy(activity.getType(), activity.getId()); activity.setVersion(current.getVersion()); this.tx.update(activity); + this.statistics.nrOfActivitiesUpdated++; } else if (failOnUpdate) { - throw new StrolchException(MessageFormat - .format("Activity {0} already exists and updating is disallowed!", activity.getLocator())); + throw new StrolchException( + MessageFormat.format("Activity {0} already exists and updating is disallowed!", + activity.getLocator())); } } else if (this.addActivities) { this.tx.add(activity); + this.statistics.nrOfActivities++; } // else ignore } diff --git a/li.strolch.model/src/main/java/li/strolch/model/ModelStatistics.java b/li.strolch.model/src/main/java/li/strolch/model/ModelStatistics.java index 126aadfe3..12d8b2412 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/ModelStatistics.java +++ b/li.strolch.model/src/main/java/li/strolch/model/ModelStatistics.java @@ -17,10 +17,14 @@ package li.strolch.model; import static li.strolch.utils.helper.StringHelper.NULL; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.Date; import com.google.gson.JsonObject; import li.strolch.utils.helper.StringHelper; +import li.strolch.utils.iso8601.ISO8601; import li.strolch.utils.iso8601.ISO8601FormatFactory; /** @@ -28,40 +32,43 @@ import li.strolch.utils.iso8601.ISO8601FormatFactory; */ public class ModelStatistics { - public Date startTime; + public LocalDateTime startTime; public long durationNanos; public long nrOfResources; + public long nrOfResourcesUpdated; public long nrOfOrders; + public long nrOfOrdersUpdated; public long nrOfActivities; + public long nrOfActivitiesUpdated; - /** - * @return the nrOfOrders - */ - public long getNrOfOrders() { - return this.nrOfOrders; - } - - /** - * @return the nrOfResources - */ public long getNrOfResources() { return this.nrOfResources; } - /** - * @return the nrOfResources + nrOfOrders - */ - public long getNrOfElements() { - return this.nrOfOrders + this.nrOfResources; + public long getNrOfResourcesUpdated() { + return nrOfResourcesUpdated; + } + + public long getNrOfOrders() { + return this.nrOfOrders; + } + + public long getNrOfOrdersUpdated() { + return nrOfOrdersUpdated; } - /** - * @return the nrOfActivities - */ public long getNrOfActivities() { return this.nrOfActivities; } + public long getNrOfActivitiesUpdated() { + return nrOfActivitiesUpdated; + } + + public long getNrOfElements() { + return this.nrOfResources + this.nrOfOrders + this.nrOfActivities; + } + /** * Adds the statistics of the other statistics to this statistics instance * @@ -69,38 +76,56 @@ public class ModelStatistics { * further statistics to add to this {@link ModelStatistics} */ public void add(ModelStatistics statistics) { - this.nrOfOrders += statistics.nrOfOrders; this.nrOfResources += statistics.nrOfResources; + this.nrOfResourcesUpdated += statistics.nrOfResourcesUpdated; + this.nrOfOrders += statistics.nrOfOrders; + this.nrOfOrdersUpdated += statistics.nrOfOrdersUpdated; this.nrOfActivities += statistics.nrOfActivities; + this.nrOfActivitiesUpdated += statistics.nrOfActivitiesUpdated; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append(getClass().getSimpleName()); - builder.append(" [startTime="); - builder.append(this.startTime == null ? NULL : ISO8601FormatFactory.getInstance().formatDate(this.startTime)); - builder.append(", durationNanos="); + builder.append(",\n- startTime="); + builder.append(this.startTime == null ? + NULL : + this.startTime.toLocalTime().truncatedTo(ChronoUnit.SECONDS).toString()); + builder.append(",\n- duration="); builder.append(StringHelper.formatNanoDuration(this.durationNanos)); - builder.append(", nrOfResources="); - builder.append(this.nrOfResources); - builder.append(", nrOfOrders="); - builder.append(this.nrOfOrders); - builder.append(", nrOfActivities="); - builder.append(this.nrOfActivities); - builder.append("]"); + + if (this.nrOfResourcesUpdated == 0) + builder.append(",\n- Resources=").append(this.nrOfResources); + else + builder.append(",\n- Resources: added=").append(this.nrOfResources).append(" updated=") + .append(this.nrOfResourcesUpdated); + + if (this.nrOfOrdersUpdated == 0) + builder.append(",\n- Orders=").append(this.nrOfOrders); + else + builder.append(",\n- Orders: added=").append(this.nrOfOrders).append(" updated=") + .append(this.nrOfOrdersUpdated); + + if (this.nrOfActivitiesUpdated == 0) + builder.append(",\n- Activities=").append(this.nrOfActivities); + else + builder.append(",\n- Activities: added=").append(this.nrOfActivities).append(" updated=") + .append(this.nrOfActivitiesUpdated); return builder.toString(); } public JsonObject toJson() { JsonObject json = new JsonObject(); - json.addProperty("startTime", - this.startTime == null ? NULL : ISO8601FormatFactory.getInstance().formatDate(this.startTime)); + json.addProperty("startTime", this.startTime == null ? NULL : ISO8601.toString(this.startTime)); json.addProperty("durationNanos", durationNanos); - json.addProperty("nrOfResources", nrOfResources); - json.addProperty("nrOfOrders", nrOfOrders); - json.addProperty("nrOfActivities", nrOfActivities); + json.addProperty("resourcesAdded", nrOfResources); + json.addProperty("resourcesUpdated", nrOfResourcesUpdated); + json.addProperty("ordersAdded", nrOfOrders); + json.addProperty("ordersUpdated", nrOfOrdersUpdated); + json.addProperty("activitiesAdded", nrOfActivities); + json.addProperty("activitiesUpdated", nrOfActivitiesUpdated); return json; } diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxFileReader.java b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxFileReader.java index 82b8a5b36..0f9e16772 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxFileReader.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxFileReader.java @@ -15,10 +15,13 @@ */ package li.strolch.model.xml; +import static li.strolch.utils.helper.StringHelper.*; + import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.File; import java.text.MessageFormat; +import java.time.LocalDateTime; import java.util.Date; import li.strolch.exception.StrolchException; @@ -32,14 +35,9 @@ import org.xml.sax.SAXException; */ public class XmlModelSaxFileReader extends XmlModelSaxReader { - private File modelFile; - private boolean allowInclude; + private final File modelFile; + private final boolean allowInclude; - /** - * @param listener - * @param modelFile - * @param allowInclude - */ public XmlModelSaxFileReader(StrolchElementListener listener, File modelFile, boolean allowInclude) { super(listener); this.modelFile = modelFile; @@ -49,36 +47,30 @@ public class XmlModelSaxFileReader extends XmlModelSaxReader { @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - switch (qName) { - - case Tags.INCLUDE_FILE: - + if (!Tags.INCLUDE_FILE.equals(qName)) { + super.startElement(uri, localName, qName, attributes); + } else { if (!this.allowInclude) { String msg = "ModelFile {0} has includes which are disabled for this parse invocation!"; - throw new IllegalArgumentException( - MessageFormat.format(msg, this.modelFile.getAbsolutePath())); //$NON-NLS-1$ + throw new IllegalArgumentException(MessageFormat.format(msg, this.modelFile.getAbsolutePath())); } String includeFileS = attributes.getValue(Tags.FILE); - if (StringHelper.isEmpty(includeFileS)) { + if (isEmpty(includeFileS)) { throw new IllegalArgumentException( - MessageFormat.format("The attribute {0} is missing for IncludeFile!", Tags.FILE)); //$NON-NLS-1$ + MessageFormat.format("The attribute {0} is missing for IncludeFile!", Tags.FILE)); } File includeFile = new File(this.modelFile.getParentFile(), includeFileS); if (!includeFile.exists() || !includeFile.canRead()) { - String msg = "The IncludeFile does not exist, or is not readable. Source model: {0} with IncludeFile: {1}"; //$NON-NLS-1$ + String msg = "The IncludeFile does not exist, or is not readable. Source model: {0} with IncludeFile: {1}"; msg = MessageFormat.format(msg, this.modelFile.getAbsolutePath(), includeFileS); throw new IllegalArgumentException(msg); } - XmlModelSaxFileReader handler = new XmlModelSaxFileReader(this.listener, includeFile, this.allowInclude); + XmlModelSaxFileReader handler = new XmlModelSaxFileReader(this.listener, includeFile, true); handler.parseFile(); this.statistics.add(handler.statistics); - - break; - default: - super.startElement(uri, localName, qName, attributes); } } @@ -86,7 +78,7 @@ public class XmlModelSaxFileReader extends XmlModelSaxReader { try { long startNanos = System.nanoTime(); - this.statistics.startTime = new Date(); + this.statistics.startTime = LocalDateTime.now(); SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); @@ -95,13 +87,13 @@ public class XmlModelSaxFileReader extends XmlModelSaxReader { long endNanos = System.nanoTime(); this.statistics.durationNanos = endNanos - startNanos; - String msg = "SAX parsed model file {0} took {1}"; //$NON-NLS-1$ + String msg = "SAX parsed model file {0} took {1}"; logger.info(MessageFormat.format(msg, this.modelFile.getAbsolutePath(), - StringHelper.formatNanoDuration(this.statistics.durationNanos))); + formatNanoDuration(this.statistics.durationNanos))); } catch (Exception e) { - String msg = "Parsing of {0} failed due to internal error: {1}"; //$NON-NLS-1$ + String msg = "Parsing of {0} failed due to internal error: {1}"; throw new StrolchException(MessageFormat.format(msg, this.modelFile.getAbsolutePath(), e.getMessage()), e); } } diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxReader.java b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxReader.java index f5052e4ce..726a35497 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxReader.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxReader.java @@ -53,7 +53,7 @@ public class XmlModelSaxReader extends DefaultHandler { private GroupedParameterizedElement parameterizedElement; private TextParameter textParam; - private Deque activityStack; + private final Deque activityStack; private ParameterBag pBag; private StrolchTimedState> state; private PolicyDefs policies; diff --git a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxStreamReader.java b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxStreamReader.java index 978ba5f0a..323ddb463 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxStreamReader.java +++ b/li.strolch.model/src/main/java/li/strolch/model/xml/XmlModelSaxStreamReader.java @@ -25,6 +25,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.text.MessageFormat; +import java.time.LocalDateTime; import java.util.Date; import li.strolch.exception.StrolchException; @@ -85,7 +86,7 @@ public class XmlModelSaxStreamReader extends XmlModelSaxReader { try { long startNanos = System.nanoTime(); - this.statistics.startTime = new Date(); + this.statistics.startTime = LocalDateTime.now(); SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java index 77e6b24bc..d897f78d2 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java @@ -993,7 +993,16 @@ public class Inspector { @Produces(MediaType.APPLICATION_XML) @Consumes(MediaType.APPLICATION_XML) @Path("{realm}/import") - public Response importAsXml(@Context HttpServletRequest request, @PathParam("realm") String realm, String data) { + public Response importAsXml(@Context HttpServletRequest request, // + @PathParam("realm") String realm, // + @QueryParam("failOnUpdate") boolean failOnUpdate, // + @QueryParam("addResources") boolean addResources, // + @QueryParam("addOrders") boolean addOrders, // + @QueryParam("addActivities") boolean addActivities, // + @QueryParam("updateResources") boolean updateResources, // + @QueryParam("updateOrders") boolean updateOrders, // + @QueryParam("updateActivities") boolean updateActivities, // + String data) { Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE); @@ -1010,12 +1019,16 @@ public class Inspector { arg.modelFileName = tempFile.getAbsolutePath(); arg.allowInclude = false; arg.external = true; - arg.addOrders = true; - arg.addResources = true; - arg.updateOrders = true; - arg.updateResources = true; - arg.orderTypes = Collections.emptySet(); - arg.resourceTypes = Collections.emptySet(); + arg.failOnUpdate = failOnUpdate; + arg.addResources = addResources; + arg.addOrders = addOrders; + arg.addActivities = addActivities; + arg.updateResources = updateResources; + arg.updateOrders = updateOrders; + arg.updateActivities = updateActivities; + arg.orderTypes = emptySet(); + arg.resourceTypes = emptySet(); + arg.activityTypes = emptySet(); arg.realm = realm; XmlImportModelResult svcResult = getServiceHandler().doService(cert, svc, arg); diff --git a/li.strolch.service/src/main/java/li/strolch/command/XmlExportModelCommand.java b/li.strolch.service/src/main/java/li/strolch/command/XmlExportModelCommand.java index b19c3bd30..b38f4d3a1 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/XmlExportModelCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/XmlExportModelCommand.java @@ -23,6 +23,7 @@ import java.io.FilenameFilter; import java.io.OutputStream; import java.nio.file.Files; import java.text.MessageFormat; +import java.time.LocalDateTime; import java.util.Date; import java.util.HashSet; import java.util.List; @@ -106,7 +107,7 @@ public class XmlExportModelCommand extends Command { long start = System.nanoTime(); this.statistics = new ModelStatistics(); - this.statistics.startTime = new Date(); + this.statistics.startTime = LocalDateTime.now(); String exportName = fileName.substring(0, fileName.indexOf(XML_FILE_SUFFIX)); @@ -320,7 +321,7 @@ public class XmlExportModelCommand extends Command { } /** - * @param multiFile + * */ public void setMultiFile(boolean multiFile) { this.multiFile = multiFile; @@ -382,7 +383,7 @@ public class XmlExportModelCommand extends Command { } /** - * @param overwrite + * */ public void setOverwrite(boolean overwrite) { this.overwrite = overwrite; diff --git a/li.strolch.service/src/main/java/li/strolch/command/XmlImportModelCommand.java b/li.strolch.service/src/main/java/li/strolch/command/XmlImportModelCommand.java index bb9f06708..20c1ac175 100644 --- a/li.strolch.service/src/main/java/li/strolch/command/XmlImportModelCommand.java +++ b/li.strolch.service/src/main/java/li/strolch/command/XmlImportModelCommand.java @@ -16,6 +16,8 @@ package li.strolch.command; import java.io.File; +import java.time.Instant; +import java.time.ZoneId; import java.util.Set; import li.strolch.agent.impl.InMemoryElementListener; @@ -31,6 +33,7 @@ import li.strolch.utils.dbc.DBC; public class XmlImportModelCommand extends Command { // input + private boolean failOnUpdate; private File modelFile; private boolean addOrders; private boolean addResources; @@ -46,10 +49,6 @@ public class XmlImportModelCommand extends Command { private ModelStatistics statistics; private boolean allowInclude; - /** - * @param container - * @param tx - */ public XmlImportModelCommand(StrolchTransaction tx) { super(tx); } @@ -64,6 +63,7 @@ public class XmlImportModelCommand extends Command { InMemoryElementListener elementListener = new InMemoryElementListener(tx()); + elementListener.setFailOnUpdate(this.failOnUpdate); elementListener.setAddOrders(this.addOrders); elementListener.setAddResources(this.addResources); elementListener.setAddActivities(this.addActivities); @@ -74,10 +74,12 @@ public class XmlImportModelCommand extends Command { elementListener.setResourceTypes(this.resourceTypes); elementListener.setActivityTypes(this.activityTypes); + long start = System.nanoTime(); XmlModelSaxFileReader handler = new XmlModelSaxFileReader(elementListener, this.modelFile, this.allowInclude); handler.parseFile(); - this.statistics = handler.getStatistics(); + this.statistics = elementListener.getStatistics(); + this.statistics.durationNanos = System.nanoTime() - start; } @Override @@ -85,16 +87,14 @@ public class XmlImportModelCommand extends Command { logger.warn("Not undoing import of file " + this.modelFile); } - /** - * @param modelFileName - */ + public void setFailOnUpdate(boolean failOnUpdate) { + this.failOnUpdate = failOnUpdate; + } + public void setModelFile(File modelFileName) { this.modelFile = modelFileName; } - /** - * @param allowInclude - */ public void setAllowInclude(boolean allowInclude) { this.allowInclude = allowInclude; } diff --git a/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelArgument.java b/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelArgument.java index 519732ce6..c2f576362 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelArgument.java +++ b/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelArgument.java @@ -22,6 +22,7 @@ import li.strolch.service.api.ServiceArgument; public class XmlImportModelArgument extends ServiceArgument { public String modelFileName; + public boolean failOnUpdate = false; public boolean external = false; public boolean allowInclude = true; public boolean addOrders = true; @@ -39,7 +40,10 @@ public class XmlImportModelArgument extends ServiceArgument { StringBuilder builder = new StringBuilder(); builder.append("XmlImportModelArgument [ "); - builder.append("external="); + builder.append("failOnUpdate="); + builder.append(this.failOnUpdate); + + builder.append(", external="); builder.append(this.external); builder.append(", allowInclude="); diff --git a/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelService.java b/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelService.java index 10b94667a..e4fe9e1af 100644 --- a/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelService.java +++ b/li.strolch.service/src/main/java/li/strolch/service/XmlImportModelService.java @@ -75,6 +75,7 @@ public class XmlImportModelService extends AbstractService