/* * 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.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; import org.fosstrak.ale.exception.ECSpecValidationException; import org.fosstrak.ale.exception.ImplementationException; import org.fosstrak.ale.server.util.TagHelper; import org.fosstrak.ale.util.ECReportSetEnum; import org.fosstrak.ale.xsd.ale.epcglobal.ECFilterSpec; 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.ECTagStat.StatBlocks; 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 */ 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 { // get tag URI String tagURI = tag.getTagIDAsPureURI(); // check if the tag is a member of this report (use filter patterns and set spec) if (isMember(tagURI)) { LOG.debug("Event '" + tag + "' is member of report '" + name + "'"); // add tag to report addTagToReportGroup(tag); } } /** * 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 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 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); } } } } } /** * 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 { // 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()); } // 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()); } //ORANGE: check if we need to add user memory in the report ECReportOutputSpecExtension outputExtension = reportSpec.getOutput().getExtension(); if (outputExtension != null) { if (outputExtension.getFieldList() != null) { for (ECReportOutputFieldSpec outputFieldSpec : outputExtension.getFieldList().getField()) { String fieldName = outputFieldSpec.getFieldspec().getFieldname(); if (fieldName.equalsIgnoreCase("UserMemory") && outputFieldSpec.isIncludeFieldSpecInReport()) { addUserMemoryToReport(tag, groupMember,fieldName) ; } } } } //ORANGE End // add list member to group list List<ECReportGroupListMember> members = matchingGroup.getGroupList().getMember(); 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 + "'"); } /** * 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) { ECReportGroupListMemberExtension extension = new ECReportGroupListMemberExtension(); groupMember.setExtension(extension); extension.setStats(new Stats()); List<ECTagStat> ecTagStats = extension.getStats().getStat(); for (String profile : statProfileName) { 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.getReader()); 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; } }