/*
*
* Copyright (C) 2014 KAIST
* @author Janggwan Im <limg00n@kaist.ac.kr>
*
* Copyright (C) 2007 ETH Zurich
*
* This file is part of Fosstrak (www.fosstrak.org).
*
* Fosstrak is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* Fosstrak 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Fosstrak; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package org.fosstrak.ale.server;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.log4j.Logger;
import org.fosstrak.ale.exception.ECSpecValidationException;
import org.fosstrak.ale.exception.ImplementationException;
import org.fosstrak.ale.server.tm.SymbolicField;
import org.fosstrak.ale.server.tm.SymbolicFieldRepo;
import org.fosstrak.ale.server.util.TagFormatHelper;
import org.fosstrak.ale.server.util.TagHelper;
import org.fosstrak.ale.util.ECReportSetEnum;
import org.fosstrak.ale.xsd.ale.epcglobal.ECFilterListMember;
import org.fosstrak.ale.xsd.ale.epcglobal.ECFilterListMember.PatList;
import org.fosstrak.ale.xsd.ale.epcglobal.ECFilterSpec;
import org.fosstrak.ale.xsd.ale.epcglobal.ECFilterSpecExtension;
import org.fosstrak.ale.xsd.ale.epcglobal.ECFilterSpecExtension.FilterList;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReaderStat;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReaderStat.Sightings;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReport;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportGroup;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportGroupCount;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportGroupList;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportGroupListMember;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportGroupListMemberExtension;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportGroupListMemberExtension.FieldList;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportGroupListMemberExtension.Stats;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportMemberField;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportOutputFieldSpec;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportOutputSpecExtension;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportSpec;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportSpecExtension;
import org.fosstrak.ale.xsd.ale.epcglobal.ECSightingStat;
import org.fosstrak.ale.xsd.ale.epcglobal.ECTagStat;
import org.fosstrak.ale.xsd.ale.epcglobal.ECTagTimestampStat;
import org.fosstrak.ale.xsd.ale.epcglobal.ECTagStat.StatBlocks;
import org.fosstrak.ale.xsd.epcglobal.EPC;
import org.fosstrak.tdt.TDTEngine;
/**
* This class represents a report.
* It filters and groups tags, add them to the report and build ec reports.
*
* @author regli
* @author swieland
* @author wafa.soubra@orange.com
* @author Janggwan Im
*/
public class Report {
/** logger. */
private static final Logger LOG = Logger.getLogger(Report.class);
/** name of this report. */
private final String name;
/** current event cycle delivers tags. */
private final EventCycle currentEventCycle;
/** patterns of tags which are included in this report. */
private final Set<Pattern> includePatterns = new HashSet<Pattern>();
/** patterns of tags which are excluded from this report. */
private final Set<Pattern> excludePatterns = new HashSet<Pattern>();
/** patterns to group the tags of this report. */
private final Set<Pattern> groupPatterns = new HashSet<Pattern>();
/** type of this report (current, additions or deletions). */
private String reportType;
/** ec report. */
private ECReport report;
/** ec report specification. */
private ECReportSpec reportSpec;
/**
* Constructor set parameters, read specifiaction and initializes patterns.
*
* @param reportSpec defines how the report should be generated
* @param currentEventCycle this report belongs to
* @throws ImplementationException if an implementation exception occurs
*/
public Report(ECReportSpec reportSpec, EventCycle currentEventCycle) throws ImplementationException {
// set name
name = reportSpec.getReportName();
LOG.debug("Create report '" + name + "'");
// create ECReport
report = new ECReport();
// set ECReport name
report.setReportName(name);
// set type
reportType = reportSpec.getReportSet().getSet();
// set ECReportSpec
this.reportSpec = reportSpec;
// set currentEventCycle
this.currentEventCycle = currentEventCycle;
// init patterns
initFilterPatterns();
initGroupPatterns();
}
/**
* This method adds a tag to the report.
*
* @param tag to add
* @throws ECSpecValidationException if the tag is invalid
* @throws ImplementationException if an implementation exception occurs
*/
public void addTag(Tag tag) throws ECSpecValidationException, ImplementationException {
TDTEngine tdt = TagHelper.getTDTEngine();
// get tag URI
String tagURI = tag.getTagIDAsTagURI();//.getTagIDAsPureURI();
boolean isMember = true;
if(this.reportSpec.getFilterSpec() != null) {
ECFilterSpec filterSpec = this.reportSpec.getFilterSpec();
if(filterSpec.getIncludePatterns() != null || filterSpec.getExcludePatterns() != null) {
isMember = isMember && isMember(tagURI);
}
if(filterSpec.getExtension() != null) {
ECFilterSpecExtension filterSpecExtension = filterSpec.getExtension();
if(filterSpecExtension.getFilterList() != null) {
List<ECFilterListMember> filterListMembers = filterSpecExtension.getFilterList().getFilter();
for(ECFilterListMember filterListMember : filterListMembers) {
// represent the user memory to binary format
String usermemInBinary = tag.getUserMemory();
if(usermemInBinary != null) {
usermemInBinary = usermemInBinary.replaceAll("\\s", "");
usermemInBinary = new StringBuilder("f").append(usermemInBinary).toString(); //usermem = "f".concat(usermem);
usermemInBinary = tdt.hex2bin(usermemInBinary);
usermemInBinary = usermemInBinary.substring(4);
}
if(filterListMember.getFieldspec() != null) {
String fieldName = filterListMember.getFieldspec().getFieldname();
if(fieldName.equals("epc")) {
// check if the tag is a member of this report (use filter patterns and set spec)
isMember = isMember && isMember(tagURI);
} else if(fieldName.equalsIgnoreCase("killPwd")) {
//TODO : killPwd fieldname
// same as "@0.32"
// datatype : "uint", format: "hex"
System.out.println("fieldname \"killPwd\": access to reserved bank is not implemented");
} else if(fieldName.equalsIgnoreCase("accessPwd")) {
//TODO : accessPwd fieldname
// same as "@0.32.32"
// datatype : "uint", format: "hex"
System.out.println("fieldname \"accessPwd\": access to reserved bank is not implemented");
} else if(fieldName.equalsIgnoreCase("epcBank")) {
// return the contents of epc bank
// datatype: "bits", format: "hex"
String fieldValue = tag.getEpcBank();
} else if(fieldName.equalsIgnoreCase("tidBank")) {
// TODO: fieldname "tidBank"
// return the contents of tid bank
// datatype: "bits", format: "hex"
System.out.println("fieldname \"tidBank\": access to tid bank is not implemented");
} else if(fieldName.equalsIgnoreCase("userBank")) {
// return the contents of user memory bank
// datatype: "bits", format: "hex"
String fieldValue = tag.getUserMemory();
isMember = computeMembership(isMember, filterListMember,
fieldValue);
} else if(fieldName.equalsIgnoreCase("afi")) {
// TODO: application family identifier
// same as "@1.8.24"
// datatype: "uint", format: "hex"
String fieldValue = processEpcBank(tag, tdt, 8,
24, "uint", "hex");
isMember = computeMembership(isMember, filterListMember,
fieldValue);
} else if(fieldName.equalsIgnoreCase("nsi")) {
// TODO: Numbering System Identifier (NSI)
// same as "@1.9.23"
// datatype: "uint", format: "hex"
String fieldValue = processEpcBank(tag, tdt, 9,
23, "uint", "hex");
isMember = computeMembership(isMember, filterListMember,
fieldValue);
} else if (fieldName.startsWith("@")) {
// TODO: fieldnames start with "@"
// datatype: "uint", format: "hex"
String[] part = fieldName.substring(1).split("\\.");
int bank = Integer.parseInt(part[0]);
int length = Integer.parseInt(part[1]);
int offset = Integer.parseInt(part[2]);
String datatype = "uint";
String format = "hex";
if(bank == 0) {
System.out.println("Access to bank "+bank+" is not supported.");
} else if(bank == 1) {
String fieldValue = processEpcBank(tag, tdt, length,
offset, datatype, format);
isMember = computeMembership(isMember, filterListMember,
fieldValue);
} else if(bank == 2) {
System.out.println("Access to bank "+bank+" is not supported.");
} else if(bank == 3) {
String fieldValue = processUserbank(tdt, usermemInBinary, length,
offset, datatype, format);
isMember = computeMembership(isMember, filterListMember,
fieldValue);
} else {
System.out.println("field "+fieldName+" not found");
}
} else {
// TODO: symbolic fieldnames
// datatype: "uint", format: "hex"
SymbolicField symbolicField = SymbolicFieldRepo.getInstance().getSymbolicField(fieldName);
if(symbolicField != null) {
int bank = symbolicField.getBank();
int length = symbolicField.getLength();
int offset = symbolicField.getOffset();
String datatype = symbolicField.getDataType() != null? symbolicField.getDataType(): "uint";
String format = symbolicField.getFormat() != null? symbolicField.getFormat(): "hex";
if(bank == 0) {
System.out.println("Access to bank "+bank+" is not supported.");
} else if(bank == 1) {
String fieldValue = processEpcBank(tag, tdt, length,
offset, datatype, format);
isMember = computeMembership(isMember, filterListMember,
fieldValue);
} else if(bank == 2) {
System.out.println("Access to bank "+bank+" is not supported.");
} else if(bank == 3) {
String fieldValue = processUserbank(tdt, usermemInBinary, length,
offset, datatype, format);
isMember = computeMembership(isMember, filterListMember,
fieldValue);
} else {
System.out.println("field "+fieldName+" not found");
}
} else {
LOG.debug("There is no such symbolic fieldname "+fieldName+". skip processing userdata of this tag");
}
}
}
}
}
}
}
if(isMember) {
LOG.debug("Event '" + tag + "' is member of report '" + name + "'");
// add tag to report
addTagToReportGroup(tag);
}
}
private boolean computeMembership(boolean isMember,
ECFilterListMember filterListMember, String fieldValue) {
for(String pat : filterListMember.getPatList().getPat()) {
if(filterListMember.getIncludeExclude().equalsIgnoreCase("include")) {
isMember = isMember && pat.equals(fieldValue);
} else {
isMember = isMember && !pat.equals(fieldValue);
}
}
return isMember;
}
/**
* this method is for compatibility reasons such that eg ReportTest is not broken.
* @param tag to add
* @throws ECSpecValidationException if the tag is invalid
* @throws ImplementationException if an implementation exception occurs
*/
public void addTag(org.fosstrak.reader.rprm.core.msg.notification.TagType tag) throws ECSpecValidationException, ImplementationException {
Tag newtag = new Tag();
newtag.setTagID(tag.getTagID());
newtag.setTagIDAsPureURI(tag.getTagIDAsPureURI());
addTag(newtag);
}
/**
* helper method to display tags that were added or deleted.
* @param reportTags a map holding the tags that were either added or deleted.
*/
private void writeTraceInformation(Map<String, Tag> reportTags) {
String out = '\n' + "+++++++++++++++++++++++++++++++++++++++++++++++++++++" + '\n';
out += '\t' + "eventcycle " + currentEventCycle.getName() + '\n';
out += '\t' + "round " + currentEventCycle.getRounds() + '\n';
if (reportTags == null) {
out += '\t' + "no tags" + '\n';
out += "+++++++++++++++++++++++++++++++++++++++++++++++++++++" + '\n';
LOG.info(out);
return;
}
for (Tag tag : reportTags.values()) {
out += '\t' + tag.getTagIDAsPureURI() + '\n';
}
out += "+++++++++++++++++++++++++++++++++++++++++++++++++++++" + '\n';
LOG.trace(out);
}
/**
* This method returns the new ec report.
*
* @return ec report
* @throws ECSpecValidationException if a tag is invalid
* @throws ImplementationException if an implementation exception occurs
*/
public ECReport getECReport() throws ECSpecValidationException, ImplementationException {
Set<Tag> currentCycleTags = currentEventCycle.getTags();
Set<Tag> lastCycleTags = currentEventCycle.getLastEventCycleTags();
//generate new ECReport
if (ECReportSetEnum.isSameECReportSet(ECReportSetEnum.ADDITIONS, reportType)) {
// get additional tags
Map<String, Tag> reportTags = new HashMap<String, Tag>();
// add tags from current EventCycle
for (Tag tag : currentCycleTags) {
reportTags.put(tag.getTagIDAsPureURI(), tag);
}
// remove tags from last EventCycle
if (lastCycleTags != null) {
for (Tag tag : lastCycleTags) {
reportTags.remove(tag.getTagIDAsPureURI());
}
}
for (Tag tag : reportTags.values()) {
addTag(tag);
}
//writeDebugInformation(reportTags);
} else if (ECReportSetEnum.isSameECReportSet(ECReportSetEnum.CURRENT, reportType)) {
// get tags from current EventCycle
for (Tag tag : currentCycleTags) {
addTag(tag);
}
} else if (ECReportSetEnum.isSameECReportSet(ECReportSetEnum.DELETIONS, reportType)) {
// get removed tags
Map<String, Tag> reportTags = new HashMap<String, Tag>();
// add tags from last EventCycle
if (lastCycleTags != null) {
for (Tag tag : lastCycleTags) {
reportTags.put(tag.getTagIDAsPureURI(), tag);
}
}
// remove tags from current EventCycle
for (Tag tag : currentCycleTags) {
reportTags.remove(tag.getTagIDAsPureURI());
}
// add tags to report with filtering
for (Tag tag : reportTags.values()) {
addTag(tag);
}
if (LOG.isTraceEnabled()) {
writeTraceInformation(reportTags);
}
} else {
LOG.info("unknown reportType: " + reportType);
}
if (reportSpec.isReportIfEmpty() || !isEmpty()) {
ECReport temp = report;
report = new ECReport();
report.setReportName(name);
return temp;
} else {
report = new ECReport();
report.setReportName(name);
return null;
}
}
//
// private methods
//
/**
* This method initializes the filter patterns on the basis of the ec report specification.
*/
private void initFilterPatterns() {
LOG.debug("Init filter patterns");
// get filter spec
ECFilterSpec filterSpec = reportSpec.getFilterSpec();
if (filterSpec != null) {
// add ECIncludePatterns from spec to includePatterns set
if(filterSpec.getIncludePatterns() != null) {
List<String> ecIncludePatterns = filterSpec.getIncludePatterns().getIncludePattern();
if (ecIncludePatterns != null) {
for (String pattern : ecIncludePatterns) {
try {
includePatterns.add(new Pattern(pattern, PatternUsage.FILTER));
} catch (ECSpecValidationException e) {
LOG.debug("Specification Validation Exception: ", e);
}
}
}
}
// add ECExcludePatterns from spec to excludePatterns set
if(filterSpec.getExcludePatterns() != null) {
List<String> ecExcludePatterns = filterSpec.getExcludePatterns().getExcludePattern();
if (ecExcludePatterns != null) {
for (String pattern : ecExcludePatterns) {
try {
excludePatterns.add(new Pattern(pattern, PatternUsage.FILTER));
} catch (ECSpecValidationException e) {
LOG.debug("Specification Validation Exception: ", e);
}
}
}
}
ECFilterSpecExtension filterSpecExt = filterSpec.getExtension();
if(filterSpecExt != null) {
FilterList filterList = filterSpecExt.getFilterList();
if(filterList != null) {
List<ECFilterListMember> filterListMembers = filterList.getFilter();
for(ECFilterListMember m : filterListMembers) {
if(m.getFieldspec() != null && m.getFieldspec().getFieldname().equalsIgnoreCase("epc")) {
if(m.getIncludeExclude().equalsIgnoreCase("INCLUDE")) {
PatList plist = m.getPatList();
if(plist != null) {
List<String> patStrs = plist.getPat();
for(String s : patStrs) {
try {
includePatterns.add(new Pattern(s, PatternUsage.FILTER));
} catch (ECSpecValidationException e) {
LOG.debug("Specification Validation Exception: ", e);
}
}
}
} else if(m.getIncludeExclude().equalsIgnoreCase("EXCLUDE")) {
PatList plist = m.getPatList();
if(plist != null) {
List<String> patStrs = plist.getPat();
for(String s : patStrs) {
try {
excludePatterns.add(new Pattern(s, PatternUsage.FILTER));
} catch (ECSpecValidationException e) {
LOG.debug("Specification Validation Exception: ", e);
}
}
}
}
}
}
}
}
}
}
/**
* This method initializes the group patterns on the basis of the ec report specification.
*/
private void initGroupPatterns() {
LOG.debug("Init group patterns");
if (reportSpec.getGroupSpec() != null) {
// get group spec
List<String> groupSpec = reportSpec.getGroupSpec().getPattern();
// add ECGroupPatterns from spec to groupPatterns set
for (String pattern : groupSpec) {
try {
groupPatterns.add(new Pattern(pattern, PatternUsage.GROUP));
} catch (ECSpecValidationException e) {
LOG.debug("Specification Validation Exception: ", e);
}
}
}
}
/**
* This method checks on the basis of the filter patterns if the specified tag could be a member of this report.
*
* @param tagURI to check for possible membership
* @return true if the tag could be a member of this report and false otherwise
* @throws ECSpecValidationException if the tag is invalid
* @throws ImplementationException if an implementation exception occurs
*/
private boolean isMember(String tagURI) throws ECSpecValidationException, ImplementationException {
if (ECReportSetEnum.isSameECReportSet(ECReportSetEnum.ADDITIONS, reportType)) {
// if report type is additions the tag is only a member if it wasn't a member of the last event cycle
Set<Tag> tags = currentEventCycle.getLastEventCycleTags();
if (tags != null) {
for (Tag tag : tags) {
if (tag.getTagIDAsPureURI().equals(tagURI)) {
return false;
}
}
}
}
// check if tagURI is member of an exclude pattern
for (Pattern pattern : excludePatterns) {
if (pattern.isMember(tagURI)) {
return false;
}
}
// check if there are include patterns specified
if (includePatterns.size() == 0) {
return true;
} else {
// check if tagURI is a member of an include pattern
for (Pattern pattern : includePatterns) {
if (pattern.isMember(tagURI)) {
return true;
}
}
return false;
}
}
/**
* This method adds a tag to the matching group of the report.
*
* @param tag to add
* @throws ECSpecValidationException if the tag is invalid
* @throws ImplementationException if an implementation exception occurs
*/
private void addTagToReportGroup(Tag tag) throws ImplementationException, ECSpecValidationException {
try {
// get tag URI
String tagURI = tag.getTagIDAsTagURI();//.getTagIDAsPureURI();
// if this one is null, try something different to compense crashes...
if (null == tagURI) {
tagURI = TagHelper.getTDTEngine().bin2hex(tag.getTagAsBinary());
}
// get group name (use group patterns)
String groupName = getGroupName(tagURI);
LOG.debug("The group name for tag '" + tagURI + "' is '" + groupName + "'");
// get matching group
ECReportGroup matchingGroup = null;
List<ECReportGroup> groups = report.getGroup();
//if (groups == null) {
if (groups.isEmpty()) {
matchingGroup = null;
} else {
for (ECReportGroup group : groups) {
if (groupName == null) {
if (group.getGroupName() == null) {
matchingGroup = group;
}
} else {
if (groupName.equals(group.getGroupName())) {
matchingGroup = group;
}
}
}
}
// create group if group does not already exist
if (matchingGroup == null) {
LOG.debug("Group '" + groupName + "' does not already exist, create it");
// create group
matchingGroup = new ECReportGroup();
// set name
matchingGroup.setGroupName(groupName);
// set count
if (reportSpec.getOutput().isIncludeCount()) {
ECReportGroupCount groupCount = new ECReportGroupCount();
groupCount.setCount(0);
matchingGroup.setGroupCount(groupCount);
}
// create and set group list
matchingGroup.setGroupList(new ECReportGroupList());
// add to groups
report.getGroup().add(matchingGroup);
}
// create group list member
ECReportGroupListMember groupMember = new ECReportGroupListMember();
TDTEngine tdt = TagHelper.getTDTEngine();
// RAW DECIMAL
if (TagHelper.isReportOutputSpecIncludeRawDecimal(reportSpec.getOutput())) {
TagHelper.addTagAsRawDecimal(tdt, groupMember, tag);
}
// TAG ENCODING
if (TagHelper.isReportOutputSpecIncludeTagEncoding(reportSpec.getOutput())) {
TagHelper.addTagAsTagEncoding(tdt, groupMember, tag);
}
// RAW HEX
if (TagHelper.isReportOutputSpecIncludeRawHex(reportSpec.getOutput())) {
TagHelper.addTagAsRawHex(tdt, groupMember, tag);
}
// EPC
if (TagHelper.isReportOutputSpecIncludeEPC(reportSpec.getOutput())) {
TagHelper.addTagAsEPC(tdt, groupMember, tag);
}
// check if we need to add tag stats
ECReportSpecExtension ecReportSpecExtension = reportSpec.getExtension();
if ((null != ecReportSpecExtension) &&
(null != ecReportSpecExtension.getStatProfileNames())) {
LOG.debug("adding stat profile");
addStatProfiles(
tag,
groupMember,
ecReportSpecExtension.getStatProfileNames().getStatProfileName(),
reportType);
}
//ORANGE: check if we need to add user memory in the report
ECReportOutputSpecExtension outputExtension = reportSpec.getOutput().getExtension();
if (outputExtension != null) {
if(groupMember.getExtension() == null) {
ECReportGroupListMemberExtension extension = new ECReportGroupListMemberExtension();
groupMember.setExtension(extension);
}
ECReportGroupListMemberExtension extension = groupMember.getExtension();
if (outputExtension.getFieldList() != null) {
extension.setFieldList(new FieldList());
List<ECReportMemberField> ecReportMemberFields = extension.getFieldList().getField();
// represent the user memory to binary format
String usermemInBinary = tag.getUserMemory();
if(usermemInBinary != null) {
usermemInBinary = usermemInBinary.replaceAll("\\s", "");
usermemInBinary = new StringBuilder("f").append(usermemInBinary).toString(); //usermem = "f".concat(usermem);
usermemInBinary = tdt.hex2bin(usermemInBinary);
usermemInBinary = usermemInBinary.substring(4);
for (ECReportOutputFieldSpec outputFieldSpec : outputExtension.getFieldList().getField()) {
if(outputFieldSpec.getFieldspec() != null) {
if(outputFieldSpec.getFieldspec().getFieldname() != null) {
String fieldName = outputFieldSpec.getFieldspec().getFieldname();
if (fieldName.equalsIgnoreCase("UserMemory") && outputFieldSpec.isIncludeFieldSpecInReport()) {
ECReportMemberField ecReportMemberField = new ECReportMemberField();
ecReportMemberField.setName(fieldName);
ecReportMemberField.setValue(tag.getUserMemory());
ecReportMemberFields.add(ecReportMemberField);
} else if(fieldName.equalsIgnoreCase("epc")) {
// default datatype: "epc"
// default format: "epc-tag"
ECReportMemberField ecReportMemberField = new ECReportMemberField();
ecReportMemberField.setName(fieldName);
try {
String bin = TagHelper.getBinaryRepresentation(tag);
if (null != bin) {
final String converted = TagHelper.convert_to_TAG_ENCODING(tag.getTagLength(), tag.getFilter(), tag.getCompanyPrefixLength(), bin, tdt);
ecReportMemberField.setValue(converted);
}
} catch (Exception ex) {
LOG.error("caught exception during tag transformation: ", ex);
}
ecReportMemberFields.add(ecReportMemberField);
}
else if(fieldName.equalsIgnoreCase("killPwd")) {
//TODO : killPwd fieldname
throw new ImplementationException("fieldname \"killPwd\": access to reserved bank is not implemented");
/*
ECReportMemberField ecReportMemberField = new ECReportMemberField();
ecReportMemberField.setName(fieldName);
ecReportMemberField.setValue(null);
// same as "@0.32"
field.setBank(0);
field.setLength(32);
field.setOffset(0);
field.setDataType("uint");
field.setFormat("hex");
ecReportMemberFields.add(ecReportMemberField);
*/
} else if(fieldName.equalsIgnoreCase("accessPwd")) {
//TODO : accessPwd fieldname
throw new ImplementationException("fieldname \"accessPwd\": access to reserved bank is not implemented");
/*
ECReportMemberField field = new ECReportMemberField();
field.setName(fieldName);
// same as "@0.32.32"
field.setBank(0);
field.setLength(32);
field.setOffset(32);
field.setDataType("uint");
field.setFormat("hex");
*/
} else if(fieldName.equalsIgnoreCase("epcBank")) {
// return the contents of epc bank
// datatype: "bits", format: "hex"
ECReportMemberField ecReportMemberField = new ECReportMemberField();
ecReportMemberField.setName(fieldName);
ecReportMemberField.setValue(tag.getEpcBank());
ecReportMemberFields.add(ecReportMemberField);
} else if(fieldName.equalsIgnoreCase("tidBank")) {
// TODO: fieldname "tidBank"
// return the contents of tid bank
// datatype: "bits", format: "hex"
throw new ImplementationException("fieldname \"tidBank\": access to tid bank is not implemented");
} else if(fieldName.equalsIgnoreCase("userBank")) {
// return the contents of user memory bank
// datatype: "bits", format: "hex"
ECReportMemberField ecReportMemberField = new ECReportMemberField();
ecReportMemberField.setName(fieldName);
ecReportMemberField.setValue(tag.getUserMemory()); // tag.getUserMemory() is already hex string, no need to convert
ecReportMemberFields.add(ecReportMemberField);
} else if(fieldName.equalsIgnoreCase("afi")) {
// TODO: application family identifier
// same as "@1.8.24"
// datatype: "uint", format: "hex"
ECReportMemberField ecReportMemberField = new ECReportMemberField();
ecReportMemberField.setName(fieldName);
String fieldValue = processEpcBank(tag, tdt, 8,
24, "uint", "hex");
ecReportMemberField.setValue(fieldValue);
ecReportMemberFields.add(ecReportMemberField);
//throw new ImplementationException("fieldname \"afi\": application family identifier (afi) is not implemented");
} else if(fieldName.equalsIgnoreCase("nsi")) {
// TODO: Numbering System Identifier (NSI)
// same as "@1.9.23"
// datatype: "uint", format: "hex"
ECReportMemberField ecReportMemberField = new ECReportMemberField();
ecReportMemberField.setName(fieldName);
String fieldValue = processEpcBank(tag, tdt, 9,
23, "uint", "hex");
ecReportMemberField.setValue(fieldValue);
ecReportMemberFields.add(ecReportMemberField);
//throw new ImplementationException("fieldname \"nsi\": Numbering System Identifier (NSI) is not implemented");
} else if (fieldName.startsWith("@")) {
// TODO: fieldnames start with "@"
// datatype: "uint", format: "hex"
String[] part = fieldName.substring(1).split("\\.");
int bank = Integer.parseInt(part[0]);
int length = Integer.parseInt(part[1]);
int offset = Integer.parseInt(part[2]);
String datatype = "uint";
String format = "hex";
ECReportMemberField ecReportMemberField = new ECReportMemberField();
ecReportMemberField.setName(fieldName);
if(bank == 0) {
throw new ImplementationException("Access to bank "+bank+" is not supported.");
} else if(bank == 1) {
String fieldValue = processEpcBank(tag, tdt, length,
offset, datatype, format);
ecReportMemberField.setValue(fieldValue);
} else if(bank == 2) {
throw new ImplementationException("Access to bank "+bank+" is not supported.");
} else if(bank == 3) {
String fieldValue = processUserbank(tdt, usermemInBinary, length,
offset, datatype, format);
ecReportMemberField.setValue(fieldValue);
} else {
throw new ImplementationException("bank "+bank+" does not exist.");
}
ecReportMemberFields.add(ecReportMemberField);
} else {
// TODO: symbolic fieldnames
// datatype: "uint", format: "hex"
ECReportMemberField field = new ECReportMemberField();
field.setName(fieldName);
// user-defined symbolic field name
String epc_tag = TagHelper.convert_to_TAG_ENCODING(tag.getTagLength(), tag.getFilter(), tag.getCompanyPrefixLength(), tag.getTagAsBinary(), tdt);
/*
Map<String,SymbolicField> symbolicFields = SymbolicFieldRepo.getInstance().findSymbolicFieldMap(epc_tag);
if(symbolicFields == null) {
throw new ImplementationException("symbolic field does not exist for the epc "+epc_tag);
}
SymbolicField symbolicField = symbolicFields.get(fieldName);
*/
SymbolicField symbolicField = SymbolicFieldRepo.getInstance().getSymbolicField(fieldName);
if(symbolicField != null) {
int bank = symbolicField.getBank();
int length = symbolicField.getLength();
int offset = symbolicField.getOffset();
String datatype = symbolicField.getDataType() != null? symbolicField.getDataType(): "uint";
String format = symbolicField.getFormat() != null? symbolicField.getFormat(): "hex";
ECReportMemberField ecReportMemberField = new ECReportMemberField();
ecReportMemberField.setName(fieldName);
if(bank == 0) {
throw new ImplementationException("Access to bank "+bank+" is not supported.");
} else if(bank == 1) {
String fieldValue = processEpcBank(tag, tdt, length,
offset, datatype, format);
ecReportMemberField.setValue(fieldValue);
} else if(bank == 2) {
throw new ImplementationException("Access to bank "+bank+" is not supported.");
} else if(bank == 3) {
String fieldValue = processUserbank(tdt, usermemInBinary, length,
offset, datatype, format);
ecReportMemberField.setValue(fieldValue);
} else {
throw new ImplementationException("bank "+bank+" does not exist.");
}
ecReportMemberFields.add(ecReportMemberField);
} else {
LOG.debug("There is no such symbolic fieldname "+fieldName+". skip processing userdata of this tag");
}
}
}
}
}
}
}
}
//ORANGE End
// add list member to group list
List<ECReportGroupListMember> members = matchingGroup.getGroupList().getMember();
if(groupMember.getEpc() != null && groupMember.getEpc().getValue() == null) {
LOG.debug("Tag '" + tagURI + "' failed to convert '" + groupName + "' of report '" + name + "'");
return;
}
// if there exists ECReportGroupListMember with the same EPCs in the group, we need to deal with this
// this is because same tags are read from different origin readers.
// a tag set in EventCycle did not treat duplicate tags because they are different origins
// FIXME current solution is inefficient. Try to find the better solution. (maybe in the tag set in EventCycle, or Tag.equals method)
boolean exist = false;
for(ECReportGroupListMember m : members) {
if(m.getEpc() != null && groupMember.getEpc() != null && m.getEpc().getValue().equals(groupMember.getEpc().getValue())) {
exist = true;
}
if(m.getTag() != null && groupMember.getTag() != null && m.getTag().getValue().equals(groupMember.getTag().getValue())) {
exist = true;
}
if(m.getRawDecimal() != null && groupMember.getRawDecimal() != null && m.getRawDecimal().getValue().equals(groupMember.getRawDecimal().getValue())) {
exist = true;
}
if(m.getRawHex() != null && groupMember.getRawHex() != null && m.getRawHex().getValue().equals(groupMember.getRawHex().getValue())) {
exist = true;
}
if(exist) {
if(m.getExtension() == null) {
break;
}
if(m.getExtension().getStats() != null) {
break;
}
for(ECTagStat tagstat : m.getExtension().getStats().getStat()) {
if(tagstat.getStatBlocks() == null) {
break;
}
ECReaderStat readerstat = new ECReaderStat();
readerstat.setReaderName(groupMember.getExtension().getStats().getStat().get(0).getStatBlocks().getStatBlock().get(0).getReaderName());
tagstat.getStatBlocks().getStatBlock().add(readerstat);
}
break;
//m.getExtension().getStats().getStat().get(0).getStatBlocks().getStatBlock().get(0).getReaderName();
//groupMember.getExtension().getStats().getStat().get(0).getStatBlocks().getStatBlock().get(0).getReaderName();
}
}
if(!exist) {
members.add(groupMember);
// increment group counter
if (reportSpec.getOutput().isIncludeCount()) {
matchingGroup.getGroupCount().setCount(matchingGroup.getGroupCount().getCount() + 1);
}
LOG.debug("Tag '" + tagURI + "' successfully added to group '" + groupName + "' of report '" + name + "'");
}
} catch(Exception e) {
e.printStackTrace();
}
}
private String processEpcBank(Tag tag, TDTEngine tdt, int length, int offset,
String datatype, String format)
throws ImplementationException {
String epcBankInBinary = tag.getEpcBank();
epcBankInBinary = epcBankInBinary.replaceAll("\\s", "");
epcBankInBinary = new StringBuilder("f").append(epcBankInBinary).toString(); //epcBankInBinary = "f".concat(epcBankInBinary);
epcBankInBinary = tdt.hex2bin(epcBankInBinary);
epcBankInBinary = epcBankInBinary.substring(4);
String fieldValueInBinary = epcBankInBinary.substring(offset, offset+length);
if(datatype.equalsIgnoreCase("uint")) {
// only "decimal" and "hex" are valid for "uint"
if(format.equalsIgnoreCase("decimal")) {
return tdt.bin2dec(fieldValueInBinary);
} else if(format.equalsIgnoreCase("hex")) {
return tdt.bin2hex(fieldValueInBinary);
} else {
// error, but include binary as the field value
return fieldValueInBinary;
}
} else if (datatype.equalsIgnoreCase("bits")){
// only "hex" format is valid for the datatype "bits"
if(format.equalsIgnoreCase("hex")) {
return tdt.bin2hex(fieldValueInBinary);
}
} else if (datatype.equalsIgnoreCase("iso-15962-string")){
throw new ImplementationException("fieldname whose datatype is 'iso-15962-string' is not supported.");
} else {
throw new ImplementationException("fieldname whose datatype is "+datatype+" is not supported.");
}
throw new ImplementationException ("cannot process epc bank");
}
private String processUserbank(TDTEngine tdt, String usermemInBinary,
int length,
int offset,
String datatype,
String format)
throws ImplementationException {
String fieldValueInBinary = usermemInBinary.substring(offset, offset+length);
if(datatype.equalsIgnoreCase("uint")) {
// only "decimal" and "hex" are valid for "uint"
if(format.equalsIgnoreCase("decimal")) {
return tdt.bin2dec(fieldValueInBinary);
} else if(format.equalsIgnoreCase("hex")) {
return tdt.bin2hex(fieldValueInBinary);
} else {
// error, but include binary as the field value
return fieldValueInBinary;
}
} else if (datatype.equalsIgnoreCase("bits")){
// only "hex" format is valid for the datatype "bits"
if(format.equalsIgnoreCase("hex")) {
return tdt.bin2hex(fieldValueInBinary);
}
} else if (datatype.equalsIgnoreCase("iso-15962-string")){
throw new ImplementationException("fieldname whose datatype is 'iso-15962-string' is not supported.");
} else {
throw new ImplementationException("fieldname whose datatype is "+datatype+" is not supported.");
}
throw new ImplementationException("cannot process userbank");
}
/**
* for each statistics profile name add the respective statistics profile.
* @param tag the tag holding information the statistics.
* @param groupMember the group member where to add the statistics.
* @param statProfileName a list of statistic profile names.
*/
private void addStatProfiles(Tag tag, ECReportGroupListMember groupMember,
List<String> statProfileName, String reportType) {
ECReportGroupListMemberExtension extension =
new ECReportGroupListMemberExtension();
groupMember.setExtension(extension);
extension.setStats(new Stats());
List<ECTagStat> ecTagStats = extension.getStats().getStat();
for (String profile : statProfileName) {
if(profile.equalsIgnoreCase("TagTimestamps")) {
ECTagTimestampStat ecTagTimestampStat = new ECTagTimestampStat();
ecTagStats.add(ecTagTimestampStat);
ecTagTimestampStat.setProfile(profile);
ecTagTimestampStat.setStatBlocks(new StatBlocks());
try {
GregorianCalendar gregorianCalendar = new GregorianCalendar();
gregorianCalendar.setTime(new Date(tag.getTimestamp()));
XMLGregorianCalendar xmlGrogerianCalendar = null;
xmlGrogerianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(gregorianCalendar);
// TODO: firstSightingTime is dependent on ReportSetSpec
ecTagTimestampStat.setFirstSightingTime(xmlGrogerianCalendar);
ecTagTimestampStat.setLastSightingTime(xmlGrogerianCalendar);
} catch (DatatypeConfigurationException e) {
LOG.debug("timestamp is not valid. timestamp inclusion skipped");
}
} else {
LOG.debug("adding stat profile: " + profile);
ECTagStat ecTagStat = new ECTagStat();
ecTagStats.add(ecTagStat);
ecTagStat.setProfile(profile);
ecTagStat.setStatBlocks(new StatBlocks());
ECReaderStat readerStat = new ECReaderStat();
ecTagStat.getStatBlocks().getStatBlock().add(readerStat);
readerStat.setReaderName(tag.getOrigin());
readerStat.setSightings(new Sightings());
readerStat.getSightings().getSighting().add(new ECSightingStat());
}
}
}
/**
* ORANGE: Gets the value of the user memory and added to the generated report.
*
* @param tag the tag holding information of user memory.
* @param groupMember the group member where to add the user memory.
* @param fieldName the field name "UserMemory".
*/
private void addUserMemoryToReport (Tag tag, ECReportGroupListMember groupMember, String fieldName) {
ECReportGroupListMemberExtension extension = new ECReportGroupListMemberExtension();
groupMember.setExtension(extension);
extension.setFieldList(new FieldList());
List<ECReportMemberField> ecReportMemberFields = extension.getFieldList().getField();
ECReportMemberField ecReportMemberField = new ECReportMemberField();
ecReportMemberFields.add(ecReportMemberField);
ecReportMemberField.setName(fieldName);
ecReportMemberField.setValue(tag.getUserMemory());
}
/**
* This method get the matching group of this report for the specified tag.
*
* @param tagURI to search group for
* @return group name
* @throws ECSpecValidationException if the tag is invalid
* @throws ImplementationException if an implementation exception occurs
*/
private String getGroupName(String tagURI) throws ImplementationException, ECSpecValidationException {
for (Pattern pattern : groupPatterns) {
if (pattern.isMember(tagURI)) {
return pattern.getGroupName(tagURI);
}
}
return null;
}
/**
* This method indicates if the report contains any tags.
*
* @return true if the report is empty and false otherwise
*/
private boolean isEmpty() {
List<ECReportGroup> groups = report.getGroup();
if (groups != null) {
for (ECReportGroup group : groups) {
ECReportGroupList groupList = group.getGroupList();
if (groupList.getMember().size() > 0) {
return false;
}
}
}
return true;
}
}