[New] Implemented an XmlModelDefaultHandler to parse a model file

Now we can parse a big file containing multiple types of objects. It is
also supported to include files by using the <IncludeFile file="" />
element.

Including tests
This commit is contained in:
Robert von Burg 2013-11-21 18:17:35 +01:00
parent 7289dccdfc
commit d3353062b9
16 changed files with 475 additions and 7 deletions

View File

@ -17,5 +17,8 @@ public class Tags {
public static final String RESOURCE = "Resource";
public static final String ORDER = "Order";
public static final String PARAMETER_BAG = "ParameterBag";
public static final String STROLCH_MODEL = "StrolchModel";
public static final String INCLUDE_FILE = "IncludeFile";
public static final String FILE = "file";
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2012, Robert von Burg
*
* All rights reserved.
*
* This file is part of the XXX.
*
* XXX is free software: you can redistribute
* it and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* XXX is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XXX. If not, see
* <http://www.gnu.org/licenses/>.
*/
package li.strolch.model.xml;
import li.strolch.model.Order;
import li.strolch.model.Resource;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
public interface StrolchElementListener {
public void notifyResource(Resource resource);
public void notifyOrder(Order order);
}

View File

@ -0,0 +1,256 @@
/*
* Copyright (c) 2012, Robert von Burg
*
* All rights reserved.
*
* This file is part of the XXX.
*
* XXX is free software: you can redistribute
* it and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* XXX is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XXX. If not, see
* <http://www.gnu.org/licenses/>.
*/
package li.strolch.model.xml;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Date;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import li.strolch.exception.StrolchException;
import li.strolch.model.Order;
import li.strolch.model.ParameterBag;
import li.strolch.model.Resource;
import li.strolch.model.State;
import li.strolch.model.Tags;
import li.strolch.model.parameter.BooleanParameter;
import li.strolch.model.parameter.DateParameter;
import li.strolch.model.parameter.FloatParameter;
import li.strolch.model.parameter.IntegerParameter;
import li.strolch.model.parameter.LongParameter;
import li.strolch.model.parameter.Parameter;
import li.strolch.model.parameter.StringListParameter;
import li.strolch.model.parameter.StringParameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import ch.eitchnet.utils.helper.StringHelper;
import ch.eitchnet.utils.iso8601.ISO8601FormatFactory;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
public class XmlModelDefaultHandler extends DefaultHandler {
private static final Logger logger = LoggerFactory.getLogger(XmlModelDefaultHandler.class);
private StrolchElementListener listener;
private File modelFile;
private Resource resource;
private Order order;
private ParameterBag pBag;
private XmlModelStatistics statistics;
public XmlModelDefaultHandler(StrolchElementListener listener, File modelFile) {
this.listener = listener;
this.modelFile = modelFile;
this.statistics = new XmlModelStatistics();
}
/**
* @return the statistics
*/
public XmlModelStatistics getStatistics() {
return this.statistics;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// TODO split each root object into its own file
switch (qName) {
case Tags.STROLCH_MODEL:
break;
case Tags.RESOURCE:
String resId = attributes.getValue(Tags.ID);
String resName = attributes.getValue(Tags.NAME);
String resType = attributes.getValue(Tags.TYPE);
Resource resource = new Resource(resId, resName, resType);
this.resource = resource;
break;
case Tags.ORDER:
String orderId = attributes.getValue(Tags.ID);
String orderName = attributes.getValue(Tags.NAME);
String orderType = attributes.getValue(Tags.TYPE);
String orderDateS = attributes.getValue(Tags.DATE);
String orderStateS = attributes.getValue(Tags.STATE);
Order order = new Order(orderId, orderName, orderType);
if (orderDateS != null) {
Date orderDate = ISO8601FormatFactory.getInstance().getDateFormat().parse(orderDateS);
order.setDate(orderDate);
}
if (orderDateS != null) {
State orderState = State.valueOf(orderStateS);
order.setState(orderState);
}
this.order = order;
break;
case Tags.PARAMETER_BAG:
String pBagId = attributes.getValue(Tags.ID);
String pBagName = attributes.getValue(Tags.NAME);
String pBagType = attributes.getValue(Tags.TYPE);
ParameterBag pBag = new ParameterBag(pBagId, pBagName, pBagType);
this.pBag = pBag;
break;
case Tags.PARAMETER:
String paramId = attributes.getValue(Tags.ID);
String paramName = attributes.getValue(Tags.NAME);
String paramType = attributes.getValue(Tags.TYPE);
String paramValue = attributes.getValue(Tags.VALUE);
String paramHiddenS = attributes.getValue(Tags.HIDDEN);
boolean paramHidden = paramHiddenS == null ? false : StringHelper.parseBoolean(paramHiddenS);
String paramUom = attributes.getValue(Tags.UOM);
String paramInterpretation = attributes.getValue(Tags.INTERPRETATION);
Parameter<?> param;
switch (paramType) {
case StringParameter.TYPE:
param = new StringParameter(paramId, paramName, paramValue);
break;
case IntegerParameter.TYPE:
param = new IntegerParameter(paramId, paramName, IntegerParameter.parseFromString(paramValue));
break;
case BooleanParameter.TYPE:
param = new BooleanParameter(paramId, paramName, BooleanParameter.parseFromString(paramValue));
break;
case LongParameter.TYPE:
param = new LongParameter(paramId, paramName, LongParameter.parseFromString(paramValue));
break;
case DateParameter.TYPE:
param = new DateParameter(paramId, paramName, DateParameter.parseFromString(paramValue));
break;
case StringListParameter.TYPE:
param = new StringListParameter(paramId, paramName, StringListParameter.parseFromString(paramValue));
break;
case FloatParameter.TYPE:
param = new FloatParameter(paramId, paramName, FloatParameter.parseFromString(paramValue));
break;
default:
throw new UnsupportedOperationException(MessageFormat.format(
"Parameters of type {0} are not supported!", paramType)); //$NON-NLS-1$
}
param.setHidden(paramHidden);
param.setUom(paramUom);
param.setInterpretation(paramInterpretation);
this.pBag.addParameter(param);
break;
case Tags.INCLUDE_FILE:
String includeFileS = attributes.getValue(Tags.FILE);
if (StringHelper.isEmpty(includeFileS))
throw new IllegalArgumentException(MessageFormat.format(
"The attribute {0} is missing for IncludeFile!", Tags.FILE)); //$NON-NLS-1$
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$
msg = MessageFormat.format(msg, this.modelFile.getName(), includeFileS);
throw new IllegalArgumentException(msg);
}
XmlModelDefaultHandler handler = new XmlModelDefaultHandler(this.listener, includeFile);
handler.parseFile();
this.statistics.nrOfOrders += handler.statistics.nrOfOrders;
this.statistics.nrOfResources += handler.statistics.nrOfResources;
break;
default:
throw new IllegalArgumentException(MessageFormat.format("The element ''{0}'' is unhandled!", qName)); //$NON-NLS-1$
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
switch (qName) {
case Tags.STROLCH_MODEL:
break;
case Tags.RESOURCE:
this.listener.notifyResource(this.resource);
this.statistics.nrOfResources++;
this.resource = null;
break;
case Tags.ORDER:
this.listener.notifyOrder(this.order);
this.statistics.nrOfOrders++;
this.order = null;
break;
case Tags.PARAMETER_BAG:
this.pBag = null;
break;
case Tags.PARAMETER:
break;
case Tags.INCLUDE_FILE:
break;
default:
throw new IllegalArgumentException(MessageFormat.format("The element ''{0}'' is unhandled!", qName)); //$NON-NLS-1$
}
}
public void parseFile() {
try {
long startNanos = System.nanoTime();
this.statistics.startTime = new Date();
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
sp.parse(this.modelFile, this);
long endNanos = System.nanoTime();
this.statistics.durationNanos = endNanos - startNanos;
String msg = "SAX parsed model file {0} took {1}"; //$NON-NLS-1$
logger.info(MessageFormat.format(msg, this.modelFile.getAbsolutePath(),
StringHelper.formatNanoDuration(this.statistics.durationNanos)));
} catch (ParserConfigurationException | SAXException | IOException e) {
String msg = "Parsing failed due to internal error: {0}"; //$NON-NLS-1$
throw new StrolchException(MessageFormat.format(msg, e.getMessage()), e);
}
}
public static class XmlModelStatistics {
public Date startTime;
public long durationNanos;
public int nrOfResources;
public int nrOfOrders;
}
}

View File

@ -1,4 +1,4 @@
package li.strolch.test.model;
package li.strolch.model.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

View File

@ -19,7 +19,7 @@
* along with li.strolch.model. If not, see
* <http://www.gnu.org/licenses/>.
*/
package li.strolch.test.model;
package li.strolch.model.test;
import java.util.ArrayList;
import java.util.Date;

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2012, Robert von Burg
*
* All rights reserved.
*
* This file is part of the XXX.
*
* XXX is free software: you can redistribute
* it and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* XXX is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XXX. If not, see
* <http://www.gnu.org/licenses/>.
*/
package li.strolch.model.test;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import li.strolch.model.Order;
import li.strolch.model.Resource;
import li.strolch.model.xml.StrolchElementListener;
import li.strolch.model.xml.XmlModelDefaultHandler;
import li.strolch.model.xml.XmlModelDefaultHandler.XmlModelStatistics;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.eitchnet.utils.helper.StringHelper;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
@SuppressWarnings("nls")
public class XmlModelDefaultHandlerTest {
private static final Logger logger = LoggerFactory.getLogger(XmlModelDefaultHandlerTest.class);
@Test
public void shouldParseXmlModelFile() {
final Map<String, Resource> resourceMap = new HashMap<>();
final Map<String, Order> orderMap = new HashMap<>();
File file = new File("src/test/resources/data/StrolchModel.xml");
StrolchElementListener listener = new StrolchElementListener() {
@Override
public void notifyResource(Resource resource) {
resourceMap.put(resource.getId(), resource);
}
@Override
public void notifyOrder(Order order) {
orderMap.put(order.getId(), order);
}
};
XmlModelDefaultHandler handler = new XmlModelDefaultHandler(listener, file);
handler.parseFile();
assertEquals(3, resourceMap.size());
assertEquals(3, orderMap.size());
XmlModelStatistics statistics = handler.getStatistics();
logger.info("Parsing took " + StringHelper.formatNanoDuration(statistics.durationNanos));
assertEquals(3, statistics.nrOfOrders);
assertEquals(3, statistics.nrOfResources);
}
}

View File

@ -1,8 +1,10 @@
package li.strolch.model.timedstate;
package li.strolch.model.test.timedstate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import li.strolch.model.timedstate.ITimedState;
import li.strolch.model.timedstate.TimedState;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValueChange;
import li.strolch.model.timevalue.impl.DoubleValue;

View File

@ -1,4 +1,4 @@
package li.strolch.model.timevalue;
package li.strolch.model.test.timevalue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@ -7,6 +7,9 @@ import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.SortedSet;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.IValueChange;
import li.strolch.model.timevalue.impl.DoubleValue;
import li.strolch.model.timevalue.impl.TimeVariable;
import li.strolch.model.timevalue.impl.ValueChange;

View File

@ -1,4 +1,4 @@
package li.strolch.model.timevalue;
package li.strolch.model.test.timevalue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@ -8,6 +8,9 @@ import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.IValueChange;
import li.strolch.model.timevalue.impl.IntegerValue;
import li.strolch.model.timevalue.impl.TimeVariable;
import li.strolch.model.timevalue.impl.ValueChange;

View File

@ -1,4 +1,4 @@
package li.strolch.model.timevalue;
package li.strolch.model.test.timevalue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@ -10,6 +10,9 @@ import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.IValueChange;
import li.strolch.model.timevalue.impl.AString;
import li.strolch.model.timevalue.impl.StringSetValue;
import li.strolch.model.timevalue.impl.TimeVariable;

View File

@ -1,10 +1,11 @@
package li.strolch.model.timevalue;
package li.strolch.model.test.timevalue;
import static org.junit.Assert.assertEquals;
import java.util.HashSet;
import java.util.Set;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.impl.AString;
import li.strolch.model.timevalue.impl.DoubleValue;
import li.strolch.model.timevalue.impl.IntegerValue;

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<StrolchModel>
<Order Id="@test1" Name="Test Order" Type="Order">
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
</ParameterBag>
</Order>
<Resource Id="@test1" Name="Test Resource" Type="Resource">
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
</ParameterBag>
</Resource>
<IncludeFile file="resources/Resources.xml" />
<IncludeFile file="orders/Orders.xml" />
</StrolchModel>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<StrolchModel>
<IncludeFile file="Templates.xml" />
<Order Id="MyTestOrder" Name="Test Name" Type="TestType" Date="2013-11-20T07:42:57.699+01:00" State="CREATED">
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
</ParameterBag>
</Order>
</StrolchModel>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<StrolchModel>
<Order Id="Template" Name="MyTestOrder Template" Type="MyTestOrder">
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
</ParameterBag>
</Order>
</StrolchModel>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<StrolchModel>
<IncludeFile file="Templates.xml" />
<Resource Id="MyTestResource" Name="Test Name" Type="TestType">
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
</ParameterBag>
</Resource>
</StrolchModel>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<StrolchModel>
<Resource Id="TestType" Name="TestType Template" Type="Template">
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
</ParameterBag>
</Resource>
</StrolchModel>