/**
*
* 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.core;
import com.freedomotic.app.Freedomotic;
import com.freedomotic.bus.BusConsumer;
import com.freedomotic.bus.BusMessagesListener;
import com.freedomotic.bus.BusService;
import com.freedomotic.events.ObjectHasChangedBehavior;
import com.freedomotic.model.ds.Config;
import com.freedomotic.behaviors.BehaviorLogic;
import com.freedomotic.exceptions.RepositoryException;
import com.freedomotic.things.EnvObjectLogic;
import com.freedomotic.things.ThingFactory;
import com.freedomotic.things.ThingRepository;
import com.google.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;
/**
*
* @author Enrico Nicoletti
*/
public class SynchManager implements BusConsumer {
private static final Logger LOG = LoggerFactory.getLogger(TopologyManager.class.getName());
public static final String LISTEN_CHANNEL = "app.event.sensor.object.behavior.change";
private BusMessagesListener listener;
private final BusService busService;
private final ThingRepository thingsRepository;
public static final String KEY_PROVENANCE = "provenance";
private final ThingFactory thingFactory;
@Inject
SynchManager(BusService busService, ThingRepository thingsRepository, ThingFactory thingFactory) {
this.busService = busService;
this.thingsRepository = thingsRepository;
this.thingFactory = thingFactory;
listener = new BusMessagesListener(this, this.busService);
// It register the GLOBAL event channel, this mean it is using
// standard JMS Topics not the activemq Virtual Topics
listener.subscribeCrossInstanceEvents(LISTEN_CHANNEL);
}
@Override
public void onMessage(ObjectMessage message) {
try {
// Skip if the message comes from the same freedomotic instance
// We don't want to notify changes to ourself
if (!message.getStringProperty(KEY_PROVENANCE).equals(Freedomotic.INSTANCE_ID)) {
Object jmsObject = message.getObject();
if (jmsObject instanceof ObjectHasChangedBehavior) {
synchronizeLocalThing((ObjectHasChangedBehavior) jmsObject);
} else if (jmsObject instanceof SynchThingRequest) {
SynchThingRequest synchThingRequest = (SynchThingRequest) jmsObject;
EnvObjectLogic thing = null;
try {
thing = thingFactory.create(synchThingRequest.getThing());
} catch (RepositoryException ex) {
LOG.error(ex.getMessage());
}
// A new thing was created in another instance
if (synchThingRequest.getProperty(SynchAction.KEY_SYNCH_ACTION)
.equalsIgnoreCase(SynchAction.CREATED.name())) {
thingsRepository.create(thing);
}
// A thing was deleted in another instance
if (synchThingRequest.getProperty(SynchAction.KEY_SYNCH_ACTION)
.equalsIgnoreCase(SynchAction.DELETED.name())) {
thingsRepository.delete(thing);
}
}
}
} catch (JMSException ex) {
LOG.error(ex.getMessage());
}
}
private void synchronizeLocalThing(ObjectHasChangedBehavior event) {
// Synchronize changed behaviors
EnvObjectLogic obj = thingsRepository.findOne(event.getProperty("object.uuid"));
for (BehaviorLogic b : obj.getBehaviors()) {
String value = event.getProperty("object.behavior." + b.getName());
if (value != null && !value.isEmpty()) {
Config conf = new Config();
conf.setProperty("value", value);
LOG.info("Synch thing \"{}\" behavior \"{}\" to \"{}\" notified by \"{}\"",
new Object[]{obj.getPojo().getName(), b.getName(), value});
obj.getBehavior(b.getName()).filterParams(conf, false);
}
}
// Synchronize the thing location (if possible)
// Must be done after synchornizing behaviors, because it changes the current thing representation pointer
try {
int locationX = Integer.parseInt(event.getProperty("object.location.x"));
int locationY = Integer.parseInt(event.getProperty("object.location.y"));
LOG.info("Synch thing \"{}\" location to {},{}",
new Object[]{obj.getPojo().getName(), locationX, locationY});
obj.synchLocation(locationX, locationY);
} catch (NumberFormatException numberFormatException) {
LOG.warn("Synch thing location is not possible because notified location it's not a valid number");
}
}
}