/*
* 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.readers;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.fosstrak.ale.exception.ImplementationException;
import org.fosstrak.ale.exception.ValidationException;
import org.fosstrak.ale.server.ALEApplicationContext;
import org.fosstrak.ale.server.Tag;
import org.fosstrak.ale.server.readers.gen.LogicalReaders;
import org.fosstrak.ale.xsd.ale.epcglobal.CCOpSpec;
import org.fosstrak.ale.xsd.ale.epcglobal.CCSpec;
import org.fosstrak.ale.xsd.ale.epcglobal.LRSpec;
/**
* represents a compositeReader that is a composition of different logicalreaders.
* @author swieland
*
*/
public class CompositeReader extends LogicalReader implements Observer {
/** logger. */
private static final Logger LOG = Logger.getLogger(CompositeReader.class);
/** logical readers within the composite reader. */
private final java.util.Map<String, LogicalReader> logicalReaders = new HashMap<String, LogicalReader>();;
/**
* constructor for the composite reader.
*/
public CompositeReader() {
super();
}
/**
* initializes a Composite Reader. this method must be called befor the Reader can
* be used.
* @param name the name for the reader encapsulated by this reader.
* @param aspec the specification that describes the current reader.
* @throws ImplementationException whenever an internal error occurs.
*/
public void initialize(String name, LRSpec aspec) throws ImplementationException {
super.initialize(name, aspec);
// create the sub parts by calling the factory method
if(aspec.getReaders() != null) {
List<String> readers = aspec.getReaders().getReader();
for (String reader : readers) {
LOG.debug(String.format("retrieving reader part %s", reader));
// just retrieve the reader from the LogicalReaderManager
LogicalReader logicalReader = logicalReaderManager.getLogicalReader(reader);
// add the reader to the observable
logicalReader.addObserver(this);
logicalReaders.put(logicalReader.getName(), logicalReader);
}
}
}
/**
* unregister this compositeReader from its observables.
*/
public void unregisterAsObserver() {
for (LogicalReader reader : logicalReaders.values()) {
LOG.debug("undefining observer " + readerName + " on reader " + reader.getName());
reader.deleteObserver(this);
}
}
/**
* implements the update-method for the observer-pattern for events.
* @param o the observed object
* @param arg the arguments passed by the observable
*/
public void update(Observable o, Object arg) {
// deliver tags only if the reader is not suspended
if (isStarted()) {
if (arg instanceof Tag) {
setChanged();
Tag tag = (Tag) arg;
tag.setReader(getName());
tag.addTrace(getName());
notifyObservers(tag);
} else if (arg instanceof List) {
LOG.debug("processing multiple tags");
// process multiple tags at once
@SuppressWarnings("unchecked")
List<Tag> tagList = (List<Tag>) arg;
for (Tag tag : tagList) {
tag.setReader(getName());
tag.addTrace(getName());
}
setChanged();
notifyObservers(tagList);
}
}
}
/**
* add a logicalReader to the composite.
* @param reader a logicalReader (baseReader or CompositeReader)
*/
public void addReader(LogicalReader reader) {
reader.addObserver(this);
logicalReaders.put(reader.getName(), reader);
return;
}
/**
* removes a given reader from the composite.
* @param reader a logicalReader (baseReader or CompositeReader).
*/
public void removeReader(LogicalReader reader) {
reader.deleteObserver(this);
logicalReaders.remove(reader.getName());
return;
}
/**
* checks if the composite reader contains the given reader.
* @param readerName the name of the reader to check.
* @return true if contained, false otherwise.
*/
public boolean containsReader(String readerName) {
return logicalReaders.containsKey(readerName);
}
/**
* this method changes the specification of a reader.
* @param aspec an LRSpec containing the changes for the reader
* @throws ImplementationException whenever an internal error occurs
* @throws ValidationException
*/
@Override
public synchronized void update(LRSpec aspec) throws ImplementationException, ValidationException {
//TODO
//LogicalReaderManager lrm = (LogicalReaderManager) ALEApplicationContext.getBean(LogicalReaderManager.class);
//lrm.getLogicalReaderNames();
// get a lock on the logicalReaders
synchronized (logicalReaders) {
// test whether we need to update the reader or just the properties
// this can be done by comparing the readers with the readers in the new LRSpec
List<String> readers = aspec.getReaders().getReader();
// set the new spec
setLRSpec(aspec);
if (!CollectionUtils.isEqualCollection(readers, logicalReaders.keySet())) {
// as there are changes in the readers, we
// need to stop this compositeReader, update the
// components and then restart again
LOG.debug("updating readers in CompositeReader " + readerName);
// stop the reader
stop();
// remove all readers first
for (LogicalReader reader : logicalReaders.values()) {
reader.deleteObserver(this);
}
logicalReaders.clear();
// fill in the new readers
for (String reader : readers) {
LogicalReader logicalReader = logicalReaderManager.getLogicalReader(reader);
logicalReader.addObserver(this);
logicalReaders.put(reader, logicalReader);
}
start();
}
// update the LRProperties
LOG.debug("updating LRProperties in CompositeReader " + readerName);
notifyAll();
}
}
/**
* starts all components of a composite reader.
*/
@Override
public synchronized void start() {
setStarted();
}
/**
* stops all components of a composite reader.
*/
@Override
public synchronized void stop() {
setStopped();
}
@Override
public void ADDACCESSSPECfromCCSpec(CCSpec ccspec, Hashtable<Integer, CCOpSpec> OpSpecTable) {
for (LogicalReader reader : logicalReaders.values()) {
LOG.debug("Add AccessSpec derived by CCSpec into" + readerName + " on reader " + reader.getName());
reader.ADDACCESSSPECfromCCSpec(ccspec, OpSpecTable);
}
}
@Override
public void DELETEACCESSSPEC()
{
for (LogicalReader reader : logicalReaders.values()) {
LOG.debug("Delete AccessSpec3 from" + readerName + " on reader " + reader.getName());
reader.DELETEACCESSSPEC();
}
}
@Override
public void recoveryACCESSSPEC3() {
for (LogicalReader reader : logicalReaders.values()) {
LOG.debug("Recover AccessSpec3 into" + readerName + " on reader " + reader.getName());
reader.recoveryACCESSSPEC3();
}
}
}