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.ArrayList;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
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;
/**
* @author wafa.soubra@orange.com
*
*/
public class CaptureApp {
private int port;
private String epcisRepository;
private CaptureClient client = null;
/** ORANGE: the path to the properties file for the LLRPAdaptor. */
private static final String LLRPADAPTOR_CONFIG_FILE = "/LLRPAdaptorConfig.properties";
/** ORANGE: epcisUniqueTagInObjectEvent is the name of the boolean property.
* If true, it allows to get the User Memory of the tag and add it to the
* ObjectEvent of the capture application in the EPCIS.
* In this case, we generate an ObjectEvent per tag and store the User Memory
* of the tag in the extension of the ObjectEvent.
* If we want to store a list of User Memory, the model of the ObjectEventType
* must evolve to allow the storage of a list of User Memory like the list of tags.
**/
private static final String EPCIS_UNIQUE_TAG = "epcisUniqueTagInObjectEvent";
/** ORANGE: store the value of epcisUniqueTagInObjectEvent property.
* If true allows to store the User Memory of the tag in the ObjectEvent.
* In that case, each ObjectEvent will have a unique tag in the epcList.
*/
private static boolean epcisUniqueTag = false;
public CaptureApp(int port, String epcisRepository) {
this.port = port;
this.epcisRepository = epcisRepository;
}
private void handleReports(ECReports reports) throws IOException, JAXBException, ImplementationExceptionResponse, Exception {
System.out.println("Handling incomming reports");
// ORANGE:
initUniqueTagProperty();
if (epcisUniqueTag) {
handleReportsWithUserMemory(reports);
}
//ORANGE End
else {
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!");
}
}
}
/** ORANGE: retrieve and test the value of the property just to know if we want to store
* the User Memory in the ObjectEvent.
* @throws ImplementationExceptionResponse whenever an internal error occurs.
*
*/
private void initUniqueTagProperty () throws ImplementationExceptionResponse {
Properties props = new Properties();
//TODO : � remplacer Subscriber.class par CaptureApp.class
try {
props.load(Subscriber.class.getResourceAsStream(LLRPADAPTOR_CONFIG_FILE));
} catch (Exception e) {
throw new ImplementationExceptionResponse
("Error loading properties from Subscriber'" + LLRPADAPTOR_CONFIG_FILE + "'");
}
String uniqueTag = props.getProperty(EPCIS_UNIQUE_TAG);
if (uniqueTag != null) {
epcisUniqueTag = Boolean.valueOf(uniqueTag).booleanValue();
}
}
/**
* ORANGE: handle reports by extracting the epc and the user memory of the tag.
* For each tag, an ObjectEvent will be define containing these 2 informations.
* @param reports the ECReports
* @throws ImplementationException whenever an internal error occurs.
*/
private void handleReportsWithUserMemory(ECReports reports) throws IOException, JAXBException, Exception {
System.out.println("Handling incomming reports with User Memory");
List<ECReport> theReports = reports.getReports().getReport();
// collect all the tags
List<EPC> epcs = new LinkedList<EPC>();
// collect all the "user memory" containing the complete payload
List<String> userMemories = new ArrayList<String>();
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.getEpc() != null) {
epcs.add(member.getEpc());
String userMemory = null;
ECReportGroupListMemberExtension extension = member.getExtension();
if (extension!= null) {
// TODO : to test if it works
// on remplace
//String userMemory = member.getExtension().getFieldList().getField().get(0).getValue();
// par :
if (extension.getFieldList() != null) {
for (ECReportMemberField reportMemberField : extension.getFieldList().getField()) {
String fieldName = reportMemberField.getFieldspec().getFieldname();
//TODO : test if the field name contains "UserMemory"
if (fieldName.equalsIgnoreCase("UserMemory")) {
userMemory = reportMemberField.getValue();
}
}
}
}
LOG.debug (" User Memory = " + userMemory);
userMemories.add(userMemory);
}
}
}
}
}
}
}
if (epcs.size() == 0) {
System.out.println("no epc received - generating no event");
return;
}
captureObjectEvent (epcs, userMemories);
}
/** ORANGE: For each epc in the list, we create an ObjectEvent.
* The UserMemory corresponding to this epc will be stored in the Extension of the ObjectEvent.
* @param reports the ECReports
* @throws ImplementationException whenever an internal error occurs.
*/
private void captureObjectEvent (List<EPC> epcs, List<String> userMemories) throws IOException, JAXBException, Exception {
System.out.println("Begining Process of all the epc .........." );
int i = 0;
for (EPC epc : epcs) {
System.out.println ("Entering captureObjectEvent for One EPC");
// 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();
// Each ObjectEvent contains 1 EPC in the EPCList
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);
// get the user memory of the tag and store it in the extension of the objectEvent.
String userMemory = userMemories.get(i);
if (userMemory != null) {
DocumentImpl documentImpl = new DocumentImpl();
ElementNSImpl elementNSImpl = (ElementNSImpl)documentImpl.createElementNS("http://com.orange.pangoo/epcis/extension/", "userMemory");
TextImpl textImpl = (TextImpl)documentImpl.createTextNode(userMemory);
elementNSImpl.appendChild(textImpl);
objEvent.getAny().add(elementNSImpl);
// the code below doesn't work.
// elementNSImpl.setAttribute("payload", userMemory);
// ObjectEventExtensionType doesn't work either.
// ObjectEventExtensionType fieldExtension = new ObjectEventExtensionType();
//fieldExtension.getAny().add(elementNSImpl);
// fieldExtension.getOtherAttributes().put(new QName("http://pangoo.unique.namespace", "payload", "aaa"), userMemory);
//objEvent.setExtension(fieldExtension);
}
// 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);
// sending the xml document to the capture client
int httpResponseCode = client.capture(epcisDoc);
if (httpResponseCode != 200) {
System.out.println("The event could NOT be captured!");
}
System.out.println("Ending captureObjectEvent for One EPC");
// counter to get the next UserMemory for the next epc in the list
i=i+1;
}
System.out.println("Ending Process for all epc and user memory list in the ECREport !!!!!!!!!!!" );
}
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();
}
}