/*
* Dog - Core
*
* Copyright (c) 2009-2013 Emiliano Castellina and Luigi De Russis
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package it.polito.elite.dog.core.devicefactory;
import it.polito.elite.dog.core.devicefactory.api.DeviceFactory;
import it.polito.elite.dog.core.housemodel.api.HouseModel;
import it.polito.elite.dog.core.library.model.AbstractDevice;
import it.polito.elite.dog.core.library.model.DeviceCostants;
import it.polito.elite.dog.core.library.model.DeviceDescriptor;
import it.polito.elite.dog.core.library.model.devicemodel.DogControllable;
import it.polito.elite.dog.core.library.util.LogHelper;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicReference;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.device.Device;
import org.osgi.service.log.LogService;
/**
* This class listens for the HouseModel and creates (Dog)Device instances at
* runtime
*
* @author Emiliano Castellina (original implementation)
* @author <a href="mailto:luigi.derussis@polito.it">Luigi De Russis</a>
* (successive modifications)
* @see <a href="http://elite.polito.it">http://elite.polito.it</a>
*
*/
public class DeviceFactoryImpl implements DeviceFactory
{
// class prefix for loading DogDevices at runtime
private final String classPrefix = DogControllable.class.getPackage().getName();
// logger
private LogHelper logger;
// Bundle context
private BundleContext context;
// Reference to the registration of the DeviceFactory
private ServiceRegistration<?> srDeviceFactory;
// reference to the HouseModel
private AtomicReference<HouseModel> houseModel = null;
/**
* Class constructor.
*/
public DeviceFactoryImpl()
{
this.houseModel = new AtomicReference<HouseModel>();
}
/**
* Activate this component (after its bind)
*
* @param bundleContext
* the bundle context
*/
public void activate(BundleContext bundleContext)
{
// init
this.context = bundleContext;
this.logger = new LogHelper(context);
// if the HouseModel service bind was ok, get and parse the house
// configuration...
HouseModel activeModel = houseModel.get();
if (activeModel != null)
{
Vector<DeviceDescriptor> devicesProp = activeModel.getConfiguration();
this.parseConfigurationMessage(devicesProp);
}
}
/**
* Deactivate this component (before its unbind)
*/
public void deactivate()
{
// unregister the EventAdmin service
this.unRegister();
// set everything to null
this.logger = null;
this.context = null;
this.srDeviceFactory = null;
}
/**
* Unregister all the services...
*/
public void unRegister()
{
if (this.srDeviceFactory != null)
{
this.srDeviceFactory.unregister();
}
}
/**
* Bind the HouseModel to this component
*
* @param houseModel
* the HouseModel service to add
*/
public void addedHouseModel(HouseModel houseModel)
{
this.houseModel.set(houseModel);
}
/**
* Unbind the HouseModel to this component
*
* @param houseModel
* the HouseModel service to remove
*/
public void removedHouseModel(HouseModel houseModel)
{
this.houseModel.compareAndSet(houseModel, null);
}
/**
* Parse a configuration message and create the DogDevice instances
*
* @param devicesProp
* the properties of the devices to create
*/
private synchronized void parseConfigurationMessage(Vector<DeviceDescriptor> devicesProp)
{
// for each device in the configuration
for (DeviceDescriptor devProp : devicesProp)
{
try
{
// instantiate the device
this.createDeviceFromDeviceDescriptor(devProp);
}
catch (Exception e)
{
// log the error
this.logger.log(LogService.LOG_ERROR, devProp.getDeviceURI() + " gives the exception: ", e);
}
}
}
/**
* Create a device class from a device descriptor
*
* @param devDescriptor
* the device descriptor needed to create a new device
* @throws ClassNotFoundException
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws IllegalArgumentException
*/
private void createDeviceFromDeviceDescriptor(DeviceDescriptor devDescriptor) throws ClassNotFoundException,
SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException,
IllegalAccessException, InvocationTargetException
{
// get the class corresponding to the desired DogDevice category
Class<?> cls = DeviceFactoryImpl.class.getClassLoader().loadClass(
this.classPrefix + ".Dog" + devDescriptor.getDeviceCategory());
// create the desired DogDevice instance
Class<?> partypes[] = new Class[2];
partypes[0] = BundleContext.class;
partypes[1] = DeviceDescriptor.class;
Constructor<?> ct = cls.getConstructor(partypes);
Object arglist[] = new Object[2];
arglist[0] = this.context;
arglist[1] = devDescriptor;
ct.newInstance(arglist);
// log success
this.logger.log(LogService.LOG_INFO, "Created device " + devDescriptor.getDeviceURI() + " with properties: " + devDescriptor.toString());
}
@Override
public void addNewDevice(DeviceDescriptor descriptor)
{
// get the device URI
String deviceUri = descriptor.getDeviceURI();
// log
this.logger.log(LogService.LOG_INFO, "Adding " + deviceUri + "...");
// check if the device already exists...
String deviceFilter = String.format("(%s=%s)", DeviceCostants.DEVICEURI, deviceUri);
try
{
ServiceReference<?> references[] = this.context.getServiceReferences(Device.class.getName(), deviceFilter);
if (references == null)
{
// the device does not exists, so we can create it
this.createDeviceFromDeviceDescriptor(descriptor);
// update the model
houseModel.get().addToConfiguration(descriptor);
}
else
{
// the device already exist... log a warning
this.logger.log(LogService.LOG_WARNING, "Device " + deviceUri
+ " already exist. Skipping its creation...");
}
}
catch (Exception e)
{
// error in the device creation
this.logger.log(LogService.LOG_ERROR, "Exception while creating " + descriptor, e);
}
}
@Override
public void removeDevice(String deviceURI)
{
// log
this.logger.log(LogService.LOG_INFO, "Removing " + deviceURI + "...");
// get the device from the framework
String deviceFilter = String.format("(%s=%s)", DeviceCostants.DEVICEURI, deviceURI);
try
{
ServiceReference<?> references[] = this.context.getServiceReferences(Device.class.getName(), deviceFilter);
if (references != null)
{
AbstractDevice device = (AbstractDevice) this.context.getService(references[0]);
// effectively remove the device
device.removeDevice();
// update the model
this.houseModel.get().removeFromConfiguration(deviceURI);
// log success
this.logger.log(LogService.LOG_INFO, deviceURI + " has been successfully removed!");
// log a warning if more than a device exists with
// the same URI (it should be impossible by construction, in any
// way...)
if (references.length > 1)
{
this.logger.log(LogService.LOG_WARNING, "Found more than one device with the URI:" + deviceURI
+ ". Only the first has been removed.");
}
}
else
{
// no device found
this.logger.log(LogService.LOG_WARNING, deviceURI + " not found. Skipping removing procedure...");
}
}
catch (Exception e)
{
// error in removing the device
this.logger.log(LogService.LOG_ERROR, "Exception while removing " + deviceURI, e);
}
}
@Override
public void updateDevice(DeviceDescriptor descriptor)
{
// update the HouseModel
this.houseModel.get().updateConfiguration(descriptor);
// get the device URI
String deviceUri = descriptor.getDeviceURI();
// log
this.logger.log(LogService.LOG_INFO, "Updating " + deviceUri + "...");
// get the device from the framework...
String deviceFilter = String.format("(%s=%s)", DeviceCostants.DEVICEURI, deviceUri);
try
{
ServiceReference<?> references[] = this.context.getServiceReferences(Device.class.getName(), deviceFilter);
if (references != null && references.length == 1)
{
AbstractDevice device = (AbstractDevice) this.context.getService(references[0]);
// update the device in the framework
device.setDeviceProperties(descriptor);
}
}
catch (Exception e)
{
// error in updating the device
this.logger.log(LogService.LOG_ERROR, "Exception while updating " + descriptor, e);
}
}
}