From an event notification from the Fosstrak Filtering and Collection server (ECReports) you can easily create an event for the EPCIS repository. You can either implement your own capturing application (My own Capturing App) or use the generic capturing application provided by fosstrak (Generic Capturing App).
The generic fosstrak capturing application tries to reduce the coding amount to an absolute minimum. Retrieval and de-serialization of ECReports is handled automatically for you, as well as the delivery of ECPIS documents to the EPCIS-repository. All you need to do, is to implement a set of jboss rules (drools) and adjust a few configuration files.
To execute the capturing application, you simply place the war-file into the webapps folder of your tomcat instance. The capturing application will deploy and start automatically.
We assume, that you already installed an instance of Apache Tomcat, the Fosstrak ALE and the Fosstrak EPCIS-repository!
There are two ways, how you can edit the configuration files for the capturing application. First: You deploy the war-file, modify the configuration files and then re-assemble the war-file. Second: You use 7-zip to open the archive and use the embedded text-editor to edit the configuration files within the war. Feel free to choose the variant you like to most.
# specifies how many event sinks are present in the configuration file. n=2 # configuration for capturing app 0 # unique port where the capturing app is listening for ECReports cap.0.port=9999 # unique name for the capturing app. cap.0.name=theFirstCaptureApp # url where to send the collected EPCIS-documents to cap.0.epcis=http://localhost:8080/epcis-repository-0.4.2/capture # configuration for capturing app 1 cap.1.port=9998 cap.1.name=theSecondCaptureApp cap.1.epcis=http://someOtherEPCISserverIP:8080/epcis-repository-0.4.2/capture # specifies the changeset file for this capturing app (in essence the rules...) cap.2.changeset=changeset-secondCaptureApp.xml
If you place your drools rules in the subfolder WEB-INF/classes/drools, you can simply copy one of existing directives within the changeset.xml and adjust it to your needs.
You can create custom-changeset-files and specify them for each capturing application in the configuration file captureapplication.properties. Please place the custom files in the folder WEB-INF/classes.
We will not cover how to program drools rules as there exists an excellent drools manual. However, we will give a few useful hints you need to obey to use the fosstrak capturing application.
// the global collector for all the EPCIS documents for further processing. global java.util.List epcisResults
// add an EPCIS-document to the capturing app. epcisResults.add(myEPCISdocument);
The code below shows you an example of a drools rule file (This rule is shipped together with the fosstrak capturing application). The rule retrieves all ECReports, extracts all the tags as hex-values in any contained report and dispatches them as a new EPCIS-document.
package org.fosstrak.capturingapp import org.fosstrak.capturingapp.util.Util; import org.fosstrak.ale.xsd.ale.epcglobal.ECReport; import org.fosstrak.ale.xsd.ale.epcglobal.ECReports; import org.fosstrak.ale.xsd.epcglobal.EPC; import org.fosstrak.capturingapp.util.SimpleEPCISDocument; import org.fosstrak.epcis.model.ActionType; import java.util.LinkedList; import function org.fosstrak.capturingapp.util.Util.extractEPC; // the global collector for all the EPCIS documents for further processing. global java.util.List epcisResults rule "Create EPCIS event from EPCs" dialect "java" when $reports : ECReports() $epcs : LinkedList( size > 0 ) from collect ( EPC() from extractEPC(Util.selectRawHex, $reports) ) then SimpleEPCISDocument simpleDocument = new SimpleEPCISDocument(); simpleDocument.addObjectEvent( $epcs, ActionType.ADD, "urn:fosstrak:demo:bizstep:testing", "urn:fosstrak:demo:disp:testing", "urn:fosstrak:demo:rp:1.1", "urn:fosstrak:demo:loc:1.1" ); epcisResults.add(simpleDocument.getDocument()); end
If you need more control on the drools session loading etc., the fosstrak capturing application provides an extendable API.
Incoming ECReports are processed by a number of so-called handlers. You can implement your own handler, pack it into a jar-file and place this jar-file into the library-folder of the capturing application (WEB-INF/lib). Each handler needs to implement the abstract class org.fosstrak.capturingapp.ECReportsHandler.java.
For a detailed explanation how to write your own handler, please refer to the JavaDoc of the class ECReportsHandler.java or use the default handler DefaultECReportHandler.
To load your custom handler at runtime, you need to specify the class-name of your handler in the capturing application properties file captureapplication.properties (If you omit the configuration, the fosstrak default handler will be loaded automatically).
n=1 # configuration for capturing app 0 with a custom handler and a custom changeset cap.0.port=9999 cap.0.name=theFirstCaptureApp cap.0.epcis=http://localhost:8080/epcis-repository-0.4.2/capture # custom changeset cap.0.changeset=myChangeset.xml # custom handler cap.0.handler=org.fosstrak.capturingapp.DefaultECReportHandler
This guide will explain the different steps that have to be taken to implement a capturing application from scratch. The capturing application discussed will retrieve an ECReports over the HTTP protocol. And generate an EPCIS Event through the ECPIS capture client.
The guide will omit error-handling to keep the documentation short. The complete example at the end of the guide will implement the whole error handling.
download the source code: CaptureApp.java
To run the capturing app you will need the following packages in your classpath:
First you need to open a Socket to retrieve the ECReports from the Filtering and Collection server.
// create a new server socket to retrieve ECReports ServerSocket ss = new ServerSocket(port); while (true) { // accept an incoming message Socket s = ss.accept(); // ... (more to come) }
After the server socket has been created and incoming messages get accepted by another socket, you have to read the http message from the socket. Therefor you create an InputStream and read the message. We throw away the http header as we are just interested into the xml content holding the ECReports.
// create a new server socket to retrieve ECReports ServerSocket ss = new ServerSocket(port); while (true) { // accept an incoming message Socket s = ss.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream())); String data = in.readLine(); String buf = ""; // ignore the http header data = in.readLine(); data = in.readLine(); data = in.readLine(); data = in.readLine(); while (data != null) { buf += data; data = in.readLine(); } // ... (more to come) }
After this step the ECReports are stored in the String buf. Now we have to deserialize the xml into an instance of an ECReports. Fosstrak offers you some helper methods that will do that job for you. You can find the whole serializer/deserializer methods in the package org.fosstrak.ale.util in the classes DeserializerUtil and SerializerUtil respectively.
For a detailed discussion of the serializer/deserializer utilties you can refer to the developers-guide Serializers and Deserializers.
The serializer/deserializer methods require the input as an InputStream, we therefor create a ByteArrayInputStream from buf.
// create a new server socket to retrieve ECReports ServerSocket ss = new ServerSocket(port); while (true) { // accept an incoming message Socket s = ss.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream())); String data = in.readLine(); String buf = ""; // ignore the http header data = in.readLine(); data = in.readLine(); data = in.readLine(); data = in.readLine(); while (data != null) { buf += data; data = in.readLine(); } // create a stream from the buf InputStream parseStream = new ByteArrayInputStream(buf.getBytes()); // parse the string through the serializer/deserializer utils. ECReports reports = DeserializerUtil.deserializeECReports(parseStream); if (reports != null) { // call the handler that will process the ECReports handleReports(reports); } }
To create an EPCIS Event the EPCIS capture client is used. This guide will not discuss the generation of the event itself but outline the steps that have to be taken to retrieve the epc tags from the ECReports.
In this example we extract all the epcs from the ECReports and put them collectively into one EPCIS event. Thatfor we store all the epcs into a list of epc.
List<ECReport> theReports = reports.getReports().getReport(); // collect all the tags List<EPC> epcs = new LinkedList<EPC>(); if (theReports != null) { for (ECReport report : theReports) { if (report.getGroup() != null) { for (ECReportGroup group : report.getGroup()) { if (group.getGroupList() != null) { for (ECReportGroupListMember member : group.getGroupList().getMember()) { if (member.getRawDecimal() != null) { epcs.add(member.getRawDecimal()); } } } } } } } if (epcs.size() == 0) { System.out.println("no epc received - generating no event"); return; }
After that step you have to create an EPCISDocumentType instance. Please refer to the users guide in the EPCIS documentation for a discussion. In this place we will just show you how to put the epcs we just extracted from the ECReports into the EPCISDocumentType.
// ... (more code in front) EPCListType epcList = new EPCListType(); // add the epcs for (EPC epc : epcs) { org.fosstrak.epcis.model.EPC nepc = new org.fosstrak.epcis.model.EPC(); nepc.setValue(epc.getValue()); epcList.getEpc().add(nepc); } objEvent.setEpcList(epcList); // ... (more code behind)
When you created the whole EPCISEvent and populated it with epc data, you are ready to call the capture-client.
EPCISDocumentType epcisDoc = new EPCISDocumentType(); // ... (code in between) // send the event to the repository int httpResponseCode = client.capture(epcisDoc); if (httpResponseCode != 200) { System.out.println("The event could NOT be captured!"); }
This section gives you an overview to the code for a whole captureApp.
download the source code: CaptureApp.java
import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.math.BigDecimal; import java.net.ServerSocket; import java.net.Socket; import java.text.DecimalFormat; import java.util.GregorianCalendar; import java.util.LinkedList; import java.util.List; import javax.xml.bind.JAXBException; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import org.fosstrak.ale.util.DeserializerUtil; import org.fosstrak.ale.xsd.ale.epcglobal.ECReport; import org.fosstrak.ale.xsd.ale.epcglobal.ECReportGroup; import org.fosstrak.ale.xsd.ale.epcglobal.ECReportGroupListMember; import org.fosstrak.ale.xsd.ale.epcglobal.ECReports; import org.fosstrak.ale.xsd.epcglobal.EPC; import org.fosstrak.epcis.captureclient.CaptureClient; import org.fosstrak.epcis.model.ActionType; import org.fosstrak.epcis.model.BusinessLocationType; import org.fosstrak.epcis.model.EPCISBodyType; import org.fosstrak.epcis.model.EPCISDocumentType; import org.fosstrak.epcis.model.EPCListType; import org.fosstrak.epcis.model.EventListType; import org.fosstrak.epcis.model.ObjectEventType; import org.fosstrak.epcis.model.ReadPointType; public class CaptureApp { private int port; private String epcisRepository; private CaptureClient client = null; public CaptureApp(int port, String epcisRepository) { this.port = port; this.epcisRepository = epcisRepository; } private void handleReports(ECReports reports) throws IOException, JAXBException { System.out.println("Handling incomming reports"); List<ECReport> theReports = reports.getReports().getReport(); // collect all the tags List<EPC> epcs = new LinkedList<EPC>(); if (theReports != null) { for (ECReport report : theReports) { if (report.getGroup() != null) { for (ECReportGroup group : report.getGroup()) { if (group.getGroupList() != null) { for (ECReportGroupListMember member : group.getGroupList().getMember()) { if (member.getRawDecimal() != null) { epcs.add(member.getRawDecimal()); } } } } } } } if (epcs.size() == 0) { System.out.println("no epc received - generating no event"); return; } // create the ecpis event ObjectEventType objEvent = new ObjectEventType(); // get the current time and set the eventTime XMLGregorianCalendar now = null; try { DatatypeFactory dataFactory = DatatypeFactory.newInstance(); now = dataFactory.newXMLGregorianCalendar(new GregorianCalendar()); objEvent.setEventTime(now); } catch (DatatypeConfigurationException e) { e.printStackTrace(); } // get the current time zone and set the eventTimeZoneOffset if (now != null) { int timezone = now.getTimezone(); int h = Math.abs(timezone / 60); int m = Math.abs(timezone % 60); DecimalFormat format = new DecimalFormat("00"); String sign = (timezone < 0) ? "-" : "+"; objEvent.setEventTimeZoneOffset(sign + format.format(h) + ":" + format.format(m)); } EPCListType epcList = new EPCListType(); // add the epcs for (EPC epc : epcs) { org.fosstrak.epcis.model.EPC nepc = new org.fosstrak.epcis.model.EPC(); nepc.setValue(epc.getValue()); epcList.getEpc().add(nepc); } objEvent.setEpcList(epcList); // set action objEvent.setAction(ActionType.ADD); // set bizStep objEvent.setBizStep("urn:fosstrak:demo:bizstep:testing"); // set disposition objEvent.setDisposition("urn:fosstrak:demo:disp:testing"); // set readPoint ReadPointType readPoint = new ReadPointType(); readPoint.setId("urn:fosstrak:demo:rp:1.1"); objEvent.setReadPoint(readPoint); // set bizLocation BusinessLocationType bizLocation = new BusinessLocationType(); bizLocation.setId("urn:fosstrak:demo:loc:1.1"); objEvent.setBizLocation(bizLocation); // create the EPCISDocument containing a single ObjectEvent EPCISDocumentType epcisDoc = new EPCISDocumentType(); EPCISBodyType epcisBody = new EPCISBodyType(); EventListType eventList = new EventListType(); eventList.getObjectEventOrAggregationEventOrQuantityEvent().add(objEvent); epcisBody.setEventList(eventList); epcisDoc.setEPCISBody(epcisBody); epcisDoc.setSchemaVersion(new BigDecimal("1.0")); epcisDoc.setCreationDate(now); int httpResponseCode = client.capture(epcisDoc); if (httpResponseCode != 200) { System.out.println("The event could NOT be captured!"); } } public void run() { client = new CaptureClient(epcisRepository); ServerSocket ss = null; try { ss = new ServerSocket(port); while(true) { try { Socket s = ss.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream())); String data = in.readLine(); String buf = ""; // ignore the http header data = in.readLine(); data = in.readLine(); data = in.readLine(); data = in.readLine(); while (data != null) { buf += data; data = in.readLine(); } System.out.println(buf); // create a stream from the buf InputStream parseStream = new ByteArrayInputStream(buf.getBytes()); // parse the string ECReports reports = DeserializerUtil.deserializeECReports(parseStream); if (reports != null) { handleReports(reports); } } catch (Exception e) { System.out.println("ERROR: " + e.getMessage()); } } } catch (IOException e1) { System.out.println(e1.getMessage()); } } public static void help() { System.out.println("You need to specify the port where to listen and the url of the epcis repository"); System.out.println("Example: "); } /** * starts the CaptureApp. * * @param args the first command line parameter is the TCP port. if omitted port 9999 is used. */ public static void main(String[] args) { CaptureApp client; int port; String epcisRepository; // check if args[0] is tcp-port // and args[1] is epcis repository if (args.length == 2){ port = Integer.parseInt(args[0]); epcisRepository = args[1]; client = new CaptureApp(port, epcisRepository); } else { help(); return; } client.run(); } }