/** * * Copyright (c) 2009-2016 Freedomotic team http://freedomotic.com * * This file is part of Freedomotic * * This Program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2, or (at your option) any later version. * * This Program 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * Freedomotic; see the file COPYING. If not, see * <http://www.gnu.org/licenses/>. */ package com.freedomotic.api; import com.freedomotic.bus.BusConsumer; import com.freedomotic.bus.BusMessagesListener; import com.freedomotic.bus.BusService; import com.freedomotic.exceptions.UnableToExecuteException; import com.freedomotic.reactions.Command; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.ObjectMessage; /** * TODO: THIS CLASS IT'S NOT FINISHED IT NEEDS TO IMPLEMENT THE REPLY FEATURE * Convenience root class for all bus message consumers * * @author Enrico Nicoletti */ public abstract class AbstractConsumer implements BusConsumer { private static final Logger LOG = LoggerFactory.getLogger(AbstractConsumer.class.getName()); private final BusMessagesListener listener; private final BusService busService; private boolean automaticReply; /** * * @param c the command received * @throws IOException * @throws UnableToExecuteException */ protected abstract void onCommand(Command c) throws IOException, UnableToExecuteException; /** * * @param event */ protected abstract void onEvent(EventTemplate event); protected abstract String getMessagingChannel(); public AbstractConsumer(BusService busService) { this.busService = busService; listener = new BusMessagesListener(this, busService); listener.consumeCommandFrom(getMessagingChannel()); setAutomaticReply(true); } @Override public void onMessage(ObjectMessage message) { Object jmsObject; try { jmsObject = message.getObject(); if (jmsObject instanceof Command) { final Command command = (Command) jmsObject; LOG.info("\"{}\" receives command \"{}\" with parameters '{''{'{}'}''}'", new Object[]{ this.getClass().getCanonicalName(), command.getName(), command.getProperties()}); ActuatorPerforms task = new ActuatorPerforms(command, message.getJMSReplyTo(), message.getJMSCorrelationID()); task.start(); } else { if (jmsObject instanceof EventTemplate) { final EventTemplate event = (EventTemplate) jmsObject; onEvent(event); } else { throw new RuntimeException("Unrecognized type in JMS message, is neither a Command or an Event"); } } } catch (JMSException ex) { LOG.error("Error while receiving a JMS message", ex); } } public boolean isAutomaticReply() { return automaticReply; } public void setAutomaticReply(boolean automaticReply) { this.automaticReply = automaticReply; } public BusService getBusService() { return busService; } //public void reply(Command command) { // sends back the command // final String defaultCorrelationID = "-1"; // getBusService().reply(command, lastDestination, defaultCorrelationID); //} private class ActuatorPerforms extends Thread { private final Command command; private final Destination reply; private final String correlationID; ActuatorPerforms(Command c, Destination reply, String correlationID) { this.command = c; this.reply = reply; this.correlationID = correlationID; this.setName("command-executor"); } @Override public void run() { try { // a command is supposed executed if the plugin doesn't say the contrary command.setExecuted(true); onCommand(command); } catch (IOException ex) { LOG.error(ex.getLocalizedMessage()); command.setExecuted(false); } catch (UnableToExecuteException ex) { command.setExecuted(false); LOG.info("\"{}\" failed to execute command \"{}\": {}", new Object[]{getName(), command.getName(), ex.getMessage()}); } // automatic-reply-to-command is used when the plugin executes the command in a // separate thread. In this cases the onCommand() returns immediately (as execution is forked in a thread) // and sometimes this is not the intended behavior. Take a look at the Delayer plugin configuration // it has to call reply(...) explicitely if ((isAutomaticReply()) && (command.getReplyTimeout() > 0)) { getBusService().reply(command, reply, correlationID); //sends back the command marked as executed or not } } } }