/* * 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.impl; import java.util.Map; import javax.annotation.PostConstruct; import org.apache.log4j.Logger; import org.fosstrak.ale.exception.DuplicateNameException; import org.fosstrak.ale.exception.DuplicateSubscriptionException; import org.fosstrak.ale.exception.ECSpecValidationException; import org.fosstrak.ale.exception.ImplementationException; import org.fosstrak.ale.exception.InvalidURIException; import org.fosstrak.ale.exception.NoSuchNameException; import org.fosstrak.ale.exception.NoSuchSubscriberException; import org.fosstrak.ale.exception.SecurityException; import org.fosstrak.ale.server.ALE; import org.fosstrak.ale.server.ALESettings; import org.fosstrak.ale.server.ReportsGenerator; import org.fosstrak.ale.server.ReportsGeneratorState; import org.fosstrak.ale.server.ac.ALEACImpl; import org.fosstrak.ale.server.impl.type.InputGeneratorProvider; import org.fosstrak.ale.server.impl.type.ReportsGeneratorsProvider; import org.fosstrak.ale.server.persistence.RemoveConfig; import org.fosstrak.ale.server.persistence.WriteConfig; import org.fosstrak.ale.server.readers.LogicalReaderManager; import org.fosstrak.ale.server.readers.rp.InputGenerator; import org.fosstrak.ale.xsd.ale.epcglobal.ECReports; import org.fosstrak.ale.xsd.ale.epcglobal.ECSpec; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * This class represents the application level events interface. * All ale operations are executed by this class. * * @author regli * @author swieland * @author haennimi * @author benoit.plomion@orange.com */ @Service("ale") public class ALEImpl implements ALE { /** * logger. */ private static final Logger LOG = Logger.getLogger(ALEImpl.class); private String authScope = "ALE"; @Autowired private ALEACImpl aleac; public ALEACImpl getAleac() { return aleac; } public void setAleac(ALEACImpl aleac) { this.aleac = aleac; } /** * set of input generators which deliver the tag event inputs. */ private InputGeneratorProvider inputGenerators = new InputGeneratorProvider(); private ReportsGeneratorsProvider reportGeneratorsProvider = new ReportsGeneratorsProvider(); /** * indicates if the ale is ready or not. */ private boolean isReady = false; /** * prefix for name of report generators which are created by immediate command. */ private static final String REPORT_GENERATOR_NAME_PREFIX = "ReportGenerator_"; /** * index for name of report generator which are created by immediate command. */ private long nameCounter = 0; @Autowired() private LogicalReaderManager logicalReaderManager; // autowired private RemoveConfig persistenceRemoveAPI; // autowired private WriteConfig persistenceWriteAPI; // autowired private ALESettings aleSettings; /** * setup the ALE directly after the construction of the bean.<br/> * <strong>NOTICE:</strong> Do not depend on initializer methods of other autowired components (like logical reader manager) * as the order of the initializer methods on the injected beans is not preset -> thus, the * injected bean might already be present in the ale, but not initialized (call postconstruct) yet. */ @PostConstruct() public void initialize() { LOG.debug("initializing ALE."); if (isReady) { LOG.debug("ALE already initialized - abort instruction."); return; } isReady = false; reportGeneratorsProvider.clear(); inputGenerators.clear(); isReady = true; LOG.info("ALE initialized"); } @Override() public boolean isReady() { return isReady; } @Override() public void define(String specName, ECSpec spec) throws DuplicateNameException, ECSpecValidationException, ImplementationException, SecurityException { aleac.checkAccess(authScope, Thread.currentThread().getStackTrace()[1].getMethodName()); if (reportGeneratorsProvider.containsKey(specName)) { LOG.debug("spec already defined: " + specName); throw new DuplicateNameException("ECSpec already defined with name: " + specName); } reportGeneratorsProvider.put(specName, reportGeneratorsProvider.createNewReportGenerator(specName, spec)); persistenceWriteAPI.writeECSpec(specName, spec); } @Override() public void undefine(String specName) throws NoSuchNameException, ImplementationException, SecurityException { aleac.checkAccess(authScope, Thread.currentThread().getStackTrace()[1].getMethodName()); throwNoSuchNameExceptionIfNoSuchSpec(specName); ReportsGeneratorImpl current = (ReportsGeneratorImpl)reportGeneratorsProvider.get(specName); if(current.isStateRequested()) current.stop(); /* ReportsGeneratorState state = current.getState(); if(state != ReportsGeneratorState.UNREQUESTED) { throw new ImplementationException("Eventcycle "+specName+" is not currently UNREQUESTED"); } */ reportGeneratorsProvider.remove(specName); persistenceRemoveAPI.removeECSpec(specName); } @Override() public ECSpec getECSpec(String specName) throws NoSuchNameException, SecurityException { aleac.checkAccess(authScope, Thread.currentThread().getStackTrace()[1].getMethodName()); throwNoSuchNameExceptionIfNoSuchSpec(specName); return reportGeneratorsProvider.get(specName).getSpec(); } @Override() public String[] getECSpecNames() throws SecurityException { aleac.checkAccess(authScope, Thread.currentThread().getStackTrace()[1].getMethodName()); return reportGeneratorsProvider.keySet().toArray(new String[0]); } @Override() public void subscribe(String specName, String notificationURI) throws NoSuchNameException, InvalidURIException, DuplicateSubscriptionException, SecurityException { aleac.checkAccess(authScope, Thread.currentThread().getStackTrace()[1].getMethodName()); throwNoSuchNameExceptionIfNoSuchSpec(specName); reportGeneratorsProvider.get(specName).subscribe(notificationURI); persistenceWriteAPI.writeECSpecSubscriber(specName, notificationURI); } @Override() public void unsubscribe(String specName, String notificationURI) throws NoSuchNameException, NoSuchSubscriberException, InvalidURIException, SecurityException { aleac.checkAccess(authScope, Thread.currentThread().getStackTrace()[1].getMethodName()); throwNoSuchNameExceptionIfNoSuchSpec(specName); reportGeneratorsProvider.get(specName).unsubscribe(notificationURI); persistenceRemoveAPI.removeECSpecSubscriber(specName, notificationURI); } @Override() public ECReports poll(String specName) throws NoSuchNameException, SecurityException { aleac.checkAccess(authScope, Thread.currentThread().getStackTrace()[1].getMethodName()); throwNoSuchNameExceptionIfNoSuchSpec(specName); return poll(reportGeneratorsProvider.get(specName)); } @Override() public ECReports immediate(ECSpec spec) throws ECSpecValidationException, ImplementationException, SecurityException { aleac.checkAccess(authScope, Thread.currentThread().getStackTrace()[1].getMethodName()); try { return poll(reportGeneratorsProvider.createNewReportGenerator(getNextReportGeneratorName(), spec)); } catch (NoSuchNameException e) { throw new ImplementationException("immediate failed"); } } @Override() public String[] getSubscribers(String specName) throws NoSuchNameException, SecurityException { aleac.checkAccess(authScope, Thread.currentThread().getStackTrace()[1].getMethodName()); throwNoSuchNameExceptionIfNoSuchSpec(specName); return reportGeneratorsProvider.get(specName).getSubscribers().toArray(new String[0]); } @Override() public final String getStandardVersion() { LOG.debug("getStandardVersion"); return aleSettings.getAleStandardVersion(); } @Override() public final String getVendorVersion() { LOG.debug("getVendorVersion"); return aleSettings.getVendorVersion(); } @Override() public void close() { LOG.info("Close ALE."); // remove input generators for (InputGenerator inputGenerator : inputGenerators) { inputGenerator.remove(); } } private ECReports poll(ReportsGenerator reportGenerator) throws NoSuchNameException { ECReports reports = null; reportGenerator.poll(); try { synchronized (reportGenerator) { reports = reportGenerator.getPollReports(); while (reports == null) { reportGenerator.wait(); reports = reportGenerator.getPollReports(); } } } catch (InterruptedException e) { LOG.debug("got interrupted."); } return reports; } /** * This method returns a name for a report generator which is created by a immediate command. * * @return name for input generator */ private String getNextReportGeneratorName() { return REPORT_GENERATOR_NAME_PREFIX + (nameCounter++); } @Override() public Map<String, ReportsGenerator> getReportGenerators() { return reportGeneratorsProvider; } /** * throws an exception if the given specification name is not existing. * @throws NoSuchNameException when name not existing. * @param specName the name of the specification to verify. */ protected void throwNoSuchNameExceptionIfNoSuchSpec(String specName) throws NoSuchNameException { if (!reportGeneratorsProvider.containsKey(specName)) { throw new NoSuchNameException("No ECSpec with such name defined: " + specName); } } @Autowired public void setAleSettings(ALESettings aleSettings) { this.aleSettings = aleSettings; } public void setReportGeneratorsProvider(ReportsGeneratorsProvider reportGeneratorsProvider) { this.reportGeneratorsProvider = reportGeneratorsProvider; } /** * set of input generators which deliver the tag event inputs. */ public void setInputGenerators(InputGeneratorProvider inputGenerators) { this.inputGenerators = inputGenerators; } @Autowired public void setPersistenceRemoveAPI(RemoveConfig persistenceRemoveAPI) { this.persistenceRemoveAPI = persistenceRemoveAPI; } @Autowired public void setPersistenceWriteAPI(WriteConfig persistenceWriteAPI) { this.persistenceWriteAPI = persistenceWriteAPI; } }