/*
* Copyright (C) 2014 KAIST
* @author Wondeuk Yoon <wdyoon@resl.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.cc;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.fosstrak.ale.exception.CCSpecValidationException;
import org.fosstrak.ale.exception.ECSpecValidationException;
import org.fosstrak.ale.exception.ImplementationException;
import org.fosstrak.ale.server.Pattern;
import org.fosstrak.ale.server.PatternUsage;
import org.fosstrak.ale.server.Tag;
import org.fosstrak.ale.server.Tag.OpReportResult;
import org.fosstrak.ale.server.util.TagHelper;
import org.fosstrak.alecc.util.CCReportSetEnum;
import org.fosstrak.ale.xsd.ale.epcglobal.CCCmdReport;
import org.fosstrak.ale.xsd.ale.epcglobal.CCCmdReport.TagReports;
import org.fosstrak.ale.xsd.ale.epcglobal.CCCmdSpec;
import org.fosstrak.ale.xsd.ale.epcglobal.CCCmdSpec.StatProfileNames;
import org.fosstrak.ale.xsd.ale.epcglobal.CCFilterSpec;
import org.fosstrak.ale.xsd.ale.epcglobal.CCOpReport;
import org.fosstrak.ale.xsd.ale.epcglobal.CCOpSpec;
import org.fosstrak.ale.xsd.ale.epcglobal.CCTagReport;
import org.fosstrak.ale.xsd.ale.epcglobal.CCTagReport.OpReports;
import org.fosstrak.ale.xsd.ale.epcglobal.CCTagReport.Stats;
import org.fosstrak.ale.xsd.ale.epcglobal.CCTagStat;
import org.fosstrak.ale.xsd.ale.epcglobal.CCTagStat.StatBlocks;
import org.fosstrak.ale.xsd.ale.epcglobal.ECFilterListMember;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReaderStat;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReaderStat.Sightings;
import org.fosstrak.ale.xsd.ale.epcglobal.ECSightingStat;
import org.fosstrak.tdt.TDTException;
/**
* This class represents a report.
* It filters and groups tags, add them to the report and build cc reports.
*
* @author regli
* @author swieland
* @author wafa.soubra@orange.com
* @author Wondeuk Yoon
*/
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 CommandCycle currentCommandCycle;
/** report generator which contains this command cycle. */
private final ReportsGenerator generator;
/** 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>();
/** type of this report (current). */
private String reportType;
/** cc report. */
private CCCmdReport report;
/** cc report specification. */
private CCCmdSpec reportSpec;
private Hashtable<Integer, CCOpSpec> OpSpecTable = new Hashtable<Integer, CCOpSpec>();
/**
* 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
* @throws CCSpecValidationException
*/
public Report(CCCmdSpec reportSpec, CommandCycle currentCommandCycle, ReportsGenerator generator) throws ImplementationException, CCSpecValidationException {
// set ReportGenerator
this.generator = generator;
this.OpSpecTable = generator.getOpSpecTable();
// set name
name = reportSpec.getName();
LOG.debug("Create report '" + name + "'");
// create CCReport
report = new CCCmdReport();
// set CCReport name
report.setCmdSpecName(name);
// set TagReports
report.setTagReports(new TagReports());
// set type
reportType = "CURRENT";
// set CCReportSpec
this.reportSpec = reportSpec;
// set currentCommandCycle
this.currentCommandCycle = currentCommandCycle;
// init patterns
initFilterPatterns();
}
/**
* This method adds a tag to the report.
*
* @param tag to add
* @throws CCSpecValidationException if the tag is invalid
* @throws ImplementationException if an implementation exception occurs
*/
public void addTag(Tag tag) throws CCSpecValidationException, ImplementationException {
try {
String epcInTagFormat = TagHelper.convert_to_TAG_ENCODING(tag.getTagLength(), tag.getFilter(), tag.getCompanyPrefixLength(), tag.getTagAsBinary(), TagHelper.getTDTEngine());
// check if the tag is a member of this report (use filter patterns and set spec)
if(isMember(epcInTagFormat)) {
LOG.debug("Command '" + tag + "' is member of report '" + name + "'");
// add tag to report
addTagToCCTag(tag);
}
} catch (ECSpecValidationException e) {
e.printStackTrace();
throw new CCSpecValidationException(e);
} catch (TDTException e) {
LOG.debug("Tag "+TagHelper.getTDTEngine().bin2hex(tag.getTagAsBinary())+" cannot be converted. skip this tag.");
return;
}
}
/**
* this method is for compatibility reasons such that eg ReportTest is not broken.
* @param tag to add
* @throws CCSpecValidationException 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 CCSpecValidationException, ImplementationException {
Tag newtag = new Tag();
newtag.setTagID(tag.getTagID());
newtag.setTagIDAsPureURI(tag.getTagIDAsPureURI());
addTag(newtag);
}
/**
* This method returns the new cc report.
*
* @return cc report
* @throws CCSpecValidationException if a tag is invalid
* @throws ImplementationException if an implementation exception occurs
*/
public CCCmdReport getCCCmdReport() throws CCSpecValidationException, ImplementationException {
Set<Tag> currentCycleTags = currentCommandCycle.getTags();
//generate new CCReport
if (CCReportSetEnum.isSameCCReportSet(CCReportSetEnum.CURRENT, reportType)) {
// get tags from current CommandCycle
for (Tag tag : currentCycleTags) {
addTag(tag);
}
} else {
LOG.info("unknown reportType: " + reportType);
}
if (reportSpec.isReportIfEmpty() || !isEmpty()) {
CCCmdReport temp = report;
report = new CCCmdReport();
// set TagReports
report.setTagReports(new TagReports());
List<CCTagReport> listTagReport = report.getTagReports().getTagReport();
listTagReport = new ArrayList<CCTagReport>();
report.setCmdSpecName(name);
return temp;
} else {
report = new CCCmdReport();
// set TagReports
report.setTagReports(new TagReports());
List<CCTagReport> listTagReport = report.getTagReports().getTagReport();
listTagReport = new ArrayList<CCTagReport>();
report.setCmdSpecName(name);
return null;
}
}
//
// private methods
//
/**
* This method initializes the filter patterns on the basis of the cc report specification.
* @throws CCSpecValidationException
*/
private void initFilterPatterns() throws CCSpecValidationException {
LOG.debug("Init filter patterns");
// get filter spec
CCFilterSpec CCFilterSpec = reportSpec.getFilterSpec();
if (CCFilterSpec != null)
{
List<ECFilterListMember> filterSpec = reportSpec.getFilterSpec().getFilterList().getFilter();
if (!filterSpec.isEmpty()) {
for (ECFilterListMember filter : filterSpec)
{
// add CCIncludePatterns from spec to includePatterns set
if (filter.getIncludeExclude().equals("INCLUDE"))
{
for (String pattern : filter.getPatList().getPat())
{
try {
includePatterns.add(new Pattern(pattern, PatternUsage.FILTER));
} catch (ECSpecValidationException e) {
LOG.debug("Specification Validation Exception: ", e);
}
}
}
// add CCExcludePatterns from spec to excludePatterns set
if (filter.getIncludeExclude().equals("EXCLUDE"))
{
for (String pattern : filter.getPatList().getPat())
{
try {
excludePatterns.add(new Pattern(pattern, PatternUsage.FILTER));
} 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 CCSpecValidationException if the tag is invalid
* @throws ImplementationException if an implementation exception occurs
*/
private boolean isMember(String tagURI) throws ECSpecValidationException, ImplementationException {
// 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 CCSpecValidationException if the tag is invalid
* @throws ImplementationException if an implementation exception occurs
*/
private void addTagToCCTag(Tag tag) throws ImplementationException, ECSpecValidationException {
// get tag URI
String tagURI = tag.getTagIDAsPureURI();
// if this one is null, try something different to compense crashes...
if (null == tagURI) {
//tagURI = TagHelper.getTDTEngine().bin2hex(tag.getTagAsBinary());
LOG.debug("Transformation to EPC-pure was failed (in LLRPAdapter.java). skip this tag.");
return;
}
// skip if tagURI is not a member of the CCFilter
String epcInTagFormat = TagHelper.convert_to_TAG_ENCODING(tag.getTagLength(), tag.getFilter(), tag.getCompanyPrefixLength(), tag.getTagAsBinary(), TagHelper.getTDTEngine());
List<CCTagReport> listTagReport = report.getTagReports().getTagReport();
CCTagReport tagReport = new CCTagReport();
tagReport.setId(epcInTagFormat);
// check if we need to add tag stats
StatProfileNames ProfileNames = reportSpec.getStatProfileNames();
if ((null != ProfileNames)) {
LOG.debug("adding stat profile");
addStatProfiles(
tag,
tagReport,
ProfileNames.getStatProfileName());
}
//Add OpReport.
if (OpSpecTable != null) {
if (!OpSpecTable.isEmpty()) {
OpReports temp = new OpReports();
System.out.println("#############" + tag.getopresult().size());
for (OpReportResult opresult : tag.getopresult())
{
if (opresult.OpSpecID >= 1000)
{
if (opresult.OpResult == 0)
{
if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("READ"))
{
CCOpReport e = new CCOpReport();
e.setData(opresult.Data);
e.setOpStatus("SUCCESS");
temp.getOpReport().add(e);
}
else if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("WRITE"))
{
CCOpReport e = new CCOpReport();
e.setData(OpSpecTable.get(opresult.OpSpecID).getDataSpec().getData());
e.setOpStatus("SUCCESS");
temp.getOpReport().add(e);
}
else
{
CCOpReport e = new CCOpReport();
e.setOpStatus("SUCCESS");
temp.getOpReport().add(e);
}
}
else if (opresult.OpResult == 1)
{
if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("READ"))
{
CCOpReport e = new CCOpReport();
e.setData(opresult.Data);
e.setOpStatus("Tag_Memory_Overrun_Error");
temp.getOpReport().add(e);
}
else if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("WRITE"))
{
CCOpReport e = new CCOpReport();
e.setData(OpSpecTable.get(opresult.OpSpecID).getDataSpec().getData());
e.setOpStatus("Tag_Memory_Overrun_Error");
temp.getOpReport().add(e);
}
else
{
CCOpReport e = new CCOpReport();
e.setOpStatus("Tag_Memory_Overrun_Error");
temp.getOpReport().add(e);
}
}
else if (opresult.OpResult == 2)
{
if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("READ"))
{
CCOpReport e = new CCOpReport();
e.setData(opresult.Data);
e.setOpStatus("Tag_Memory_Locked_Error");
temp.getOpReport().add(e);
}
else if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("WRITE"))
{
CCOpReport e = new CCOpReport();
e.setData(OpSpecTable.get(opresult.OpSpecID).getDataSpec().getData());
e.setOpStatus("Tag_Memory_Locked_Error");
temp.getOpReport().add(e);
}
else
{
CCOpReport e = new CCOpReport();
e.setOpStatus("Tag_Memory_Locked_Error");
temp.getOpReport().add(e);
}
}
else if (opresult.OpResult == 3)
{
if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("READ"))
{
CCOpReport e = new CCOpReport();
e.setData(opresult.Data);
e.setOpStatus("Insufficient_Power");
temp.getOpReport().add(e);
}
else if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("WRITE"))
{
CCOpReport e = new CCOpReport();
e.setData(OpSpecTable.get(opresult.OpSpecID).getDataSpec().getData());
e.setOpStatus("Insufficient_Power");
temp.getOpReport().add(e);
}
else
{
CCOpReport e = new CCOpReport();
e.setOpStatus("Insufficient_Power");
temp.getOpReport().add(e);
}
}
else if (opresult.OpResult == 4)
{
if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("READ"))
{
CCOpReport e = new CCOpReport();
e.setData(opresult.Data);
e.setOpStatus("Nonspecific_Tag_Error");
temp.getOpReport().add(e);
}
else if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("WRITE"))
{
CCOpReport e = new CCOpReport();
e.setData(OpSpecTable.get(opresult.OpSpecID).getDataSpec().getData());
e.setOpStatus("Nonspecific_Tag_Error");
temp.getOpReport().add(e);
}
else
{
CCOpReport e = new CCOpReport();
e.setOpStatus("Nonspecific_Tag_Error");
temp.getOpReport().add(e);
}
}
else if (opresult.OpResult == 5)
{
if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("READ"))
{
CCOpReport e = new CCOpReport();
e.setData(opresult.Data);
e.setOpStatus("No_Response_From_Tag");
temp.getOpReport().add(e);
}
else if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("WRITE"))
{
CCOpReport e = new CCOpReport();
e.setData(OpSpecTable.get(opresult.OpSpecID).getDataSpec().getData());
e.setOpStatus("No_Response_From_Tag");
temp.getOpReport().add(e);
}
else
{
CCOpReport e = new CCOpReport();
e.setOpStatus("No_Response_From_Tag");
temp.getOpReport().add(e);
}
}
else if (opresult.OpResult == 6)
{
if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("READ"))
{
CCOpReport e = new CCOpReport();
e.setData(opresult.Data);
e.setOpStatus("Nonspecific_Reader_Error");
temp.getOpReport().add(e);
}
else if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("WRITE"))
{
CCOpReport e = new CCOpReport();
e.setData(OpSpecTable.get(opresult.OpSpecID).getDataSpec().getData());
e.setOpStatus("Nonspecific_Reader_Error");
temp.getOpReport().add(e);
}
else
{
CCOpReport e = new CCOpReport();
e.setOpStatus("Nonspecific_Reader_Error");
temp.getOpReport().add(e);
}
}
else
{
if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("READ"))
{
CCOpReport e = new CCOpReport();
e.setData(opresult.Data);
e.setOpStatus("FAIL");
temp.getOpReport().add(e);
}
else if (OpSpecTable.get(opresult.OpSpecID).getOpType().equals("WRITE"))
{
CCOpReport e = new CCOpReport();
e.setData(OpSpecTable.get(opresult.OpSpecID).getDataSpec().getData());
e.setOpStatus("FAIL");
temp.getOpReport().add(e);
}
else
{
CCOpReport e = new CCOpReport();
e.setOpStatus("FAIL");
temp.getOpReport().add(e);
}
}
}
}
tagReport.setOpReports(temp);
}
}
//ORANGE End
if (tagReport.getOpReports().getOpReport().size() > 0) {
boolean exist = false;
for (CCTagReport temp : listTagReport) {
if (temp.getId().equals(tagReport.getId())) {
exist = true;
for(CCOpReport opr : tagReport.getOpReports().getOpReport()) {
temp.getOpReports().getOpReport().add(opr);
}
}
}
if(!exist) listTagReport.add(tagReport);
}
LOG.debug("Tag '" + tagURI + "' successfully added to group '" + epcInTagFormat + "' of report '" + name + "'");
}
/**
* 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, CCTagReport tagMember, List<String> statProfileName) {
tagMember.setStats(new Stats());
List<CCTagStat> ccTagStats = tagMember.getStats().getStat();
for (String profile : statProfileName) {
LOG.debug("adding stat profile: " + profile);
CCTagStat ccTagStat = new CCTagStat();
ccTagStats.add(ccTagStat);
ccTagStat.setProfile(profile);
ccTagStat.setStatBlocks(new StatBlocks());
ECReaderStat readerStat = new ECReaderStat();
ccTagStat.getStatBlocks().getStatBlock().add(readerStat);
readerStat.setReaderName(tag.getReader());
readerStat.setSightings(new Sightings());
readerStat.getSightings().getSighting().add(new ECSightingStat());
}
}
/**
* This method indicates if the report contains any tags.
*
* @return true if the report is empty and false otherwise
*/
private boolean isEmpty() {
List<CCTagReport> TagReports = report.getTagReports().getTagReport();
if(TagReports.size()>0) return false;
return true;
}
}