[New] XML import now supports more options:

- failOnUpdate
- add of elements
- update of elements
This commit is contained in:
Robert von Burg 2021-12-31 15:43:16 +01:00
parent 8003bd9bef
commit 9a05d6fb43
10 changed files with 153 additions and 99 deletions

View File

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

View File

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

View File

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

View File

@ -53,7 +53,7 @@ public class XmlModelSaxReader extends DefaultHandler {
private GroupedParameterizedElement parameterizedElement;
private TextParameter textParam;
private Deque<Activity> activityStack;
private final Deque<Activity> activityStack;
private ParameterBag pBag;
private StrolchTimedState<? extends IValue<?>> state;
private PolicyDefs policies;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -75,6 +75,7 @@ public class XmlImportModelService extends AbstractService<XmlImportModelArgumen
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
command = new XmlImportModelCommand(tx);
command.setFailOnUpdate(arg.failOnUpdate);
command.setModelFile(modelFile);
command.setAllowInclude(arg.allowInclude);
command.setAddOrders(arg.addOrders);
@ -87,18 +88,18 @@ public class XmlImportModelService extends AbstractService<XmlImportModelArgumen
command.setResourceTypes(arg.resourceTypes);
command.setActivityTypes(arg.activityTypes);
tx.addCommand(command);
command.validate();
command.doCommand();
tx.commitOnClose();
}
ModelStatistics statistics = command.getStatistics();
String durationS = StringHelper.formatNanoDuration(statistics.durationNanos);
logger.info(MessageFormat
.format("Loading XML Model file {0} for realm {1} took {2}.", modelFile.getName(), //$NON-NLS-1$
arg.realm, durationS));
logger.info(MessageFormat.format("Loaded {0} Orders", statistics.nrOfOrders)); //$NON-NLS-1$
logger.info(MessageFormat.format("Loaded {0} Resources", statistics.nrOfResources)); //$NON-NLS-1$
logger.info(MessageFormat.format("Loaded {0} Activities", statistics.nrOfActivities)); //$NON-NLS-1$
logger.info(MessageFormat.format("Loading XML Model file {0} for realm {1} took {2}.", modelFile.getName(),
arg.realm, durationS));
logger.info(MessageFormat.format("Loaded {0} Orders", statistics.nrOfOrders));
logger.info(MessageFormat.format("Loaded {0} Resources", statistics.nrOfResources));
logger.info(MessageFormat.format("Loaded {0} Activities", statistics.nrOfActivities));
return new XmlImportModelResult(statistics);
}