/**
* Copyright (c) 2011, SOCIETIES Consortium (WATERFORD INSTITUTE OF TECHNOLOGY (TSSG), HERIOT-WATT UNIVERSITY (HWU), SOLUTA.NET
* (SN), GERMAN AEROSPACE CENTRE (Deutsches Zentrum fuer Luft- und Raumfahrt e.V.) (DLR), Zavod za varnostne tehnologije
* informacijske družbe in elektronsko poslovanje (SETCCE), INSTITUTE OF COMMUNICATION AND COMPUTER SYSTEMS (ICCS), LAKE
* COMMUNICATIONS (LAKE), INTEL PERFORMANCE LEARNING SOLUTIONS LTD (INTEL), PORTUGAL TELECOM INOVAÇÃO, SA (PTIN), IBM Corp.,
* INSTITUT TELECOM (ITSUD), AMITEC DIACHYTI EFYIA PLIROFORIKI KAI EPIKINONIES ETERIA PERIORISMENIS EFTHINIS (AMITEC), TELECOM
* ITALIA S.p.a.(TI), TRIALOG (TRIALOG), Stiftelsen SINTEF (SINTEF), NEC EUROPE LTD (NEC))
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.societies.platform.servicelifecycle.servicecontrol;
import java.io.File;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.societies.api.activity.IActivity;
import org.societies.api.activity.IActivityFeedCallback;
import org.societies.api.cis.management.ICis;
import org.societies.api.cis.management.ICisManager;
import org.societies.api.cis.management.ICisOwned;
import org.societies.api.comm.xmpp.interfaces.ICommManager;
import org.societies.api.identity.IIdentity;
import org.societies.api.identity.INetworkNode;
import org.societies.api.identity.RequestorService;
import org.societies.api.internal.css.devicemgmt.IDeviceManager;
import org.societies.api.internal.css.devicemgmt.model.DeviceCommonInfo;
import org.societies.api.internal.security.policynegotiator.INegotiation;
import org.societies.api.internal.servicelifecycle.serviceRegistry.IServiceRegistry;
import org.societies.api.osgi.event.CSSEvent;
import org.societies.api.osgi.event.EMSException;
import org.societies.api.osgi.event.EventListener;
import org.societies.api.osgi.event.EventTypes;
import org.societies.api.osgi.event.IEventMgr;
import org.societies.api.osgi.event.InternalEvent;
import org.societies.api.schema.cis.community.Community;
import org.societies.api.schema.servicelifecycle.model.Service;
import org.societies.api.schema.servicelifecycle.model.ServiceImplementation;
import org.societies.api.schema.servicelifecycle.model.ServiceInstance;
import org.societies.api.schema.servicelifecycle.model.ServiceResourceIdentifier;
import org.societies.api.schema.servicelifecycle.model.ServiceStatus;
import org.societies.api.schema.servicelifecycle.model.ServiceType;
import org.societies.api.schema.servicelifecycle.servicecontrol.ServiceControlResult;
import org.societies.api.schema.servicelifecycle.servicecontrol.ResultMessage;
import org.societies.api.services.ServiceMgmtEventType;
import org.societies.api.internal.servicelifecycle.IServiceControl;
import org.societies.api.internal.servicelifecycle.IServiceControlRemote;
import org.societies.api.internal.servicelifecycle.ServiceControlException;
import org.societies.api.internal.servicelifecycle.ServiceMgmtInternalEvent;
import org.societies.api.internal.servicelifecycle.ServiceModelUtils;
import org.societies.api.internal.useragent.feedback.IUserFeedback;
import org.societies.platform.servicelifecycle.servicecontrol.ServiceNegotiationCallback.ServiceNegotiationResult;
import org.springframework.osgi.context.BundleContextAware;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
/**
* Implementation of Service Control
*
* @author <a href="mailto:sanchocsa@gmail.com">Sancho Rêgo</a> (PTIN)
*
*/
public class ServiceControl implements IServiceControl, BundleContextAware {
private BundleContext bundleContext;
static final Logger logger = LoggerFactory.getLogger(ServiceControl.class);
private IServiceRegistry serviceReg;
private ICommManager commMngr;
private IServiceControlRemote serviceControlRemote;
private INegotiation policyNegotiation;
private ICisManager cisManager;
private IDeviceManager deviceMngr;
private IUserFeedback userFeedback;
private IEventMgr eventMgr;
private String serviceDir;
protected static boolean restart;
private static HashMap<Long,BlockingQueue<Service>> installServiceMap = new HashMap<Long,BlockingQueue<Service>>();
private static HashMap<Long,BlockingQueue<Service>> uninstallServiceMap = new HashMap<Long,BlockingQueue<Service>>();
private final long TIMEOUT = 60;
private SocietiesEventListener eventListener;
private INetworkNode thisNode;
private IIdentity myId;
private static ExecutorService executor;
public String getServiceDir() {
return serviceDir;
}
public void setServiceDir(String serviceDir) {
this.serviceDir = serviceDir;
}
public IEventMgr getEventMgr(){
return eventMgr;
}
public void setEventMgr(IEventMgr eventMgr){
this.eventMgr=eventMgr;
}
public IDeviceManager getDeviceMngr(){
return deviceMngr;
}
public void setDeviceMngr(IDeviceManager deviceMngr){
this.deviceMngr = deviceMngr;
}
public ICisManager getCisManager(){
return cisManager;
}
public void setCisManager(ICisManager cisManager){
this.cisManager = cisManager;
}
public IServiceRegistry getServiceReg() {
return serviceReg;
}
public void setServiceReg(IServiceRegistry serviceReg) {
this.serviceReg = serviceReg;
}
public void setCommMngr(ICommManager commMngr) {
this.commMngr = commMngr;
}
public ICommManager getCommMngr() {
return commMngr;
}
public void setPolicyNegotiation(INegotiation policyNegotiation){
this.policyNegotiation = policyNegotiation;
}
public INegotiation getPolicyNegotiation(){
return policyNegotiation;
}
public void setServiceControlRemote(IServiceControlRemote serviceControlRemote){
this.serviceControlRemote = serviceControlRemote;
}
public IServiceControlRemote getServiceControlRemote(){
return serviceControlRemote;
}
public IUserFeedback getUserFeedback(){
return userFeedback;
}
public void setUserFeedback(IUserFeedback userFeedback){
this.userFeedback = userFeedback;
}
@Override
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public ServiceControl(){
executor = Executors.newCachedThreadPool();
}
public void InitService() {
//REGISTER OUR ServiceManager WITH THE XMPP Communication Manager
try {
if(logger.isDebugEnabled())
logger.debug("Now creating the listener for events!");
this.eventListener = new SocietiesEventListener(this);
thisNode = getCommMngr().getIdManager().getThisNetworkNode();
myId = getCommMngr().getIdManager().fromJid(thisNode.getJid());
} catch (Exception e) {
logger.error("Exception registering for CIS events");
e.printStackTrace();
}
}
public void killService(){
// UnregisterStuff
try{
this.eventListener.unregister();
this.eventListener = null;
} catch(Exception e){
logger.error("Exception removing Bean! :" + e.getMessage());
e.printStackTrace();
}
}
@Async
@Override
public Future<ServiceControlResult> startService(ServiceResourceIdentifier serviceId)
throws ServiceControlException {
if(logger.isDebugEnabled()) logger.debug("Service Management: startService method");
ServiceControlResult returnResult = new ServiceControlResult();
returnResult.setServiceId(serviceId);
try{
// Our first task is to determine whether the service we're searching for is local or remote
String nodeJid = ServiceModelUtils.getJidFromServiceIdentifier(serviceId);
INetworkNode myNode = getCommMngr().getIdManager().getThisNetworkNode();
String localNodeJid = myNode.getJid();
if(logger.isDebugEnabled())
logger.debug("The JID of the node where the Service is: " + nodeJid + " and the local JID: " + localNodeJid);
if(!nodeJid.equals(localNodeJid)){
if(logger.isDebugEnabled())
logger.debug("We're dealing with a different node! Need to do a remote call!");
IIdentity node = getCommMngr().getIdManager().fromJid(nodeJid);
// Does this node belong to our CSS?
if(!node.equals((IIdentity) myNode)){
if(logger.isDebugEnabled()) logger.debug("This is not our CSS!");
}
ServiceControlRemoteClient callback = new ServiceControlRemoteClient();
getServiceControlRemote().startService(serviceId, node, callback);
if(logger.isDebugEnabled())
logger.debug("Remote call complete, now we need to wait for the result...");
ServiceControlResult result = callback.getResult();
if(result == null){
if(logger.isDebugEnabled())
logger.debug("Error with communication to remote client");
returnResult.setMessage(ResultMessage.COMMUNICATION_ERROR);
return new AsyncResult<ServiceControlResult>(returnResult);
} else{
if(logger.isDebugEnabled())
logger.debug("Result of operation was: " + result.getMessage());
return new AsyncResult<ServiceControlResult>(result);
}
}
//Local node
if(logger.isDebugEnabled())
logger.debug("We're dealing with our current, local node...");
// Our first task is to obtain the Service object from the identifier, for this we got to the registry
if(logger.isDebugEnabled()) logger.debug("Obtaining Service from SOCIETIES Registry");
Service service = getServiceReg().retrieveService(serviceId);
// Check to see if we actually got a service
if(service == null){
if(logger.isDebugEnabled()) logger.debug("Service represented by " + serviceId + " does not exist in SOCIETIES Registry");
returnResult.setMessage(ResultMessage.SERVICE_NOT_FOUND);
return new AsyncResult<ServiceControlResult>(returnResult);
}
//Next, we need to determine if we should continue
if(service.getServiceType().equals(ServiceType.DEVICE)){
if(logger.isDebugEnabled()) logger.debug("It's a device, so shouldn't proceed.");
returnResult.setMessage(ResultMessage.SERVICE_TYPE_NOT_SUPPORTED);
return new AsyncResult<ServiceControlResult>(returnResult);
}
// Next step, we obtain the bundle that corresponds to this service
Bundle serviceBundle = getBundleFromService(service);
// And we check if it isn't null!
if(serviceBundle == null){
if(logger.isDebugEnabled()) logger.debug("Service Bundle obtained from " + service.getServiceName() + " couldn't be found");
returnResult.setMessage(ResultMessage.BUNDLE_NOT_FOUND);
return new AsyncResult<ServiceControlResult>(returnResult);
}
if(serviceBundle.getState() == Bundle.ACTIVE){
if(logger.isDebugEnabled())
logger.debug("Service is already started, no need to act!");
returnResult.setMessage(ResultMessage.SUCCESS);
return new AsyncResult<ServiceControlResult>(returnResult);
}
//Before we start the bundle we prepare the entry on the hashmap
BlockingQueue<Service> idList = new ArrayBlockingQueue<Service>(1);
Long bundleId = new Long(serviceBundle.getBundleId());
synchronized(this){
installServiceMap.put(bundleId, idList);
}
// Now we need to start the bundle
if(logger.isDebugEnabled())
logger.debug("Attempting to start the bundle: " + serviceBundle.getSymbolicName());
serviceBundle.start();
if(logger.isDebugEnabled())
logger.debug("Bundle " + serviceBundle.getSymbolicName() + " is now in state " + ServiceModelUtils.getBundleStateName(serviceBundle.getState()));
if(serviceBundle.getState() == Bundle.ACTIVE ){
service = idList.take();
logger.info("Service " + service.getServiceName() + " has been started.");
returnResult.setMessage(ResultMessage.SUCCESS);
synchronized(this){
installServiceMap.remove(bundleId);
}
}
else{
logger.info("Service " + service.getServiceName() + " has NOT been started successfully.");
returnResult.setMessage(ResultMessage.OSGI_PROBLEM);
}
return new AsyncResult<ServiceControlResult>(returnResult);
} catch(Exception ex){
logger.error("Exception occured while starting Service: " + ex.getMessage());
throw new ServiceControlException("Exception occured while starting Service.", ex);
}
}
@Async
@Override
public Future<ServiceControlResult> stopService(ServiceResourceIdentifier serviceId)
throws ServiceControlException {
if(logger.isDebugEnabled()) logger.debug("Service Management: stopService method");
ServiceControlResult returnResult = new ServiceControlResult();
returnResult.setServiceId(serviceId);
try{
// Our first task is to determine whether the service we're searching for is local or remote
String nodeJid = ServiceModelUtils.getJidFromServiceIdentifier(serviceId);
String localNodeJid = getCommMngr().getIdManager().getThisNetworkNode().getJid();
if(logger.isDebugEnabled())
logger.debug("The JID of the node where the Service is: " + nodeJid + " and the local JID: " + localNodeJid);
if(!nodeJid.equals(localNodeJid)){
if(logger.isDebugEnabled())
logger.debug("We're dealing with a different node! Need to do a remote call!");
IIdentity node = getCommMngr().getIdManager().fromJid(nodeJid);
ServiceControlRemoteClient callback = new ServiceControlRemoteClient();
getServiceControlRemote().stopService(serviceId, node, callback);
if(logger.isDebugEnabled())
logger.debug("Remote call complete, now we need to wait for the result...");
ServiceControlResult result = callback.getResult();
if(result == null){
if(logger.isDebugEnabled())
logger.debug("Error with communication to remote client");
returnResult.setMessage(ResultMessage.COMMUNICATION_ERROR);
return new AsyncResult<ServiceControlResult>(returnResult);
} else{
if(logger.isDebugEnabled())
logger.debug("Result of operation was: " + result.getMessage());
return new AsyncResult<ServiceControlResult>(result);
}
}
//Local node
if(logger.isDebugEnabled())
logger.debug("We're dealing with our current, local node...");
// Our first task is to obtain the Service object from the identifier, for this we got to the registry
if(logger.isDebugEnabled()) logger.debug("Obtaining Service from SOCIETIES Registry");
Service service = getServiceReg().retrieveService(serviceId);
// Check to see if we actually got a service
if(service == null){
if(logger.isDebugEnabled()) logger.debug("Service represented by " + serviceId + " does not exist in SOCIETIES Registry");
returnResult.setMessage(ResultMessage.SERVICE_NOT_FOUND);
return new AsyncResult<ServiceControlResult>(returnResult); }
//Next, we need to determine if we should continue
if(service.getServiceType().equals(ServiceType.DEVICE)){
if(logger.isDebugEnabled()) logger.debug("It's a device, so shouldn't proceed.");
returnResult.setMessage(ResultMessage.SERVICE_TYPE_NOT_SUPPORTED);
return new AsyncResult<ServiceControlResult>(returnResult);
}
// Next step, we obtain the bundle that corresponds to this service
Bundle serviceBundle = getBundleFromService(service);
// And we check if it isn't null!
if(serviceBundle == null){
if(logger.isDebugEnabled()) logger.debug("Service Bundle obtained from " + service.getServiceName() + " couldn't be found");
returnResult.setMessage(ResultMessage.BUNDLE_NOT_FOUND);
return new AsyncResult<ServiceControlResult>(returnResult);
}
if(serviceBundle.getState() != Bundle.ACTIVE){
if(logger.isDebugEnabled())
logger.debug("Service is not ACTIVE, so no need to stop it.");
returnResult.setMessage(ResultMessage.SUCCESS);
return new AsyncResult<ServiceControlResult>(returnResult);
}
// Now we need to stop the bundle
if(logger.isDebugEnabled())
logger.debug("Attempting to stop the bundle: " + serviceBundle.getSymbolicName());
//Before we start the bundle we prepare the entry on the hashmap
BlockingQueue<Service> idList = new ArrayBlockingQueue<Service>(1);
Long bundleId = new Long(serviceBundle.getBundleId());
synchronized(this){
installServiceMap.put(bundleId, idList);
}
serviceBundle.stop();
if(logger.isDebugEnabled())
logger.debug("Bundle " + serviceBundle.getSymbolicName() + " is now in state " + ServiceModelUtils.getBundleStateName(serviceBundle.getState()));
if(serviceBundle.getState() == Bundle.RESOLVED ){
logger.info("Service " + service.getServiceName() + " has been stopped.");
returnResult.setMessage(ResultMessage.SUCCESS);
Service serviceStopped = idList.take();
synchronized(this){
installServiceMap.remove(bundleId);
}
return new AsyncResult<ServiceControlResult>(returnResult);
}
else{
logger.info("Service " + service.getServiceName() + " has NOT been stopped successfully.");
returnResult.setMessage(ResultMessage.OSGI_PROBLEM);
return new AsyncResult<ServiceControlResult>(returnResult);
}
} catch(Exception ex){
logger.error("Exception occured while stopping Service: " + ex.getMessage());
throw new ServiceControlException("Exception occured while stopping Service.", ex);
}
}
@Async
@Override
public Future<ServiceControlResult> installService(Service serviceToInstall)
throws ServiceControlException {
ServiceControlResult returnResult = new ServiceControlResult();
returnResult.setServiceId(serviceToInstall.getServiceIdentifier());
try{
if(logger.isDebugEnabled())
logger.debug("Service Management: installService method, trying to install a remote service!");
if(serviceToInstall.getServiceType().equals(ServiceType.DEVICE)){
if(logger.isDebugEnabled())
logger.debug("This is a device, calling Device Manager");
IIdentity deviceNodeId = getCommMngr().getIdManager().fromFullJid(serviceToInstall.getServiceInstance().getFullJid());
DeviceCommonInfo deviceCommonInfo = new DeviceCommonInfo();
deviceCommonInfo.setDeviceDescription(serviceToInstall.getServiceDescription());
deviceCommonInfo.setDeviceID(serviceToInstall.getServiceIdentifier().getServiceInstanceIdentifier());
deviceCommonInfo.setDeviceLocation(serviceToInstall.getServiceLocation());
deviceCommonInfo.setDeviceName(serviceToInstall.getServiceName());
deviceCommonInfo.setDeviceType(serviceToInstall.getServiceCategory());
deviceCommonInfo.setDevicePhysicalAddress(null);
deviceCommonInfo.setDeviceFamilyIdentity(null);
deviceCommonInfo.setDeviceProvider(serviceToInstall.getServiceInstance().getServiceImpl().getServiceProvider());
deviceCommonInfo.setDeviceConnectionType(null);
if(serviceToInstall.getContextSource().equals("isContextSource"))
deviceCommonInfo.setContextSource(true);
else
deviceCommonInfo.setContextSource(false);
logger.debug("About to install!");
String deviceId = getDeviceMngr().fireNewSharedDevice(deviceCommonInfo, deviceNodeId);
if(deviceId == null){
if(logger.isDebugEnabled())
logger.debug("Problem installing device!");
returnResult.setMessage(ResultMessage.OSGI_PROBLEM);
sendUserNotification("Device '"+serviceToInstall.getServiceName()+"' not installed: " + returnResult.getMessage());
sendEvent(ServiceMgmtEventType.PROBLEM_OCURRED,serviceToInstall,null);
return new AsyncResult<ServiceControlResult>(returnResult);
} else{
if(logger.isDebugEnabled())
logger.debug("Device installed with id: " + deviceId);
returnResult.setServiceId(ServiceModelUtils.generateServiceResourceIdentifierForDevice(serviceToInstall, deviceId));
returnResult.setMessage(ResultMessage.SUCCESS);
sendUserNotification("Service '"+serviceToInstall.getServiceName()+"' installed!");
return new AsyncResult<ServiceControlResult>(returnResult);
}
}
// First up, we need to do the negotiation check
if(logger.isDebugEnabled())
logger.debug("Trying to do policy negotiation!");
IIdentity providerNode = getCommMngr().getIdManager().fromJid(serviceToInstall.getServiceInstance().getFullJid());
INetworkNode myNode = getCommMngr().getIdManager().getThisNetworkNode();
if(logger.isDebugEnabled())
logger.debug("Got the provider IIdentity, now creating the Requestor");
RequestorService provider = new RequestorService(providerNode, serviceToInstall.getServiceIdentifier());
ServiceNegotiationCallback negotiationCallback = new ServiceNegotiationCallback();
getPolicyNegotiation().startNegotiation(provider, negotiationCallback);
ServiceNegotiationResult negotiationResult = negotiationCallback.getResult();
if(negotiationResult == null){
if(logger.isDebugEnabled()) logger.debug("Problem doing negotiation!");
returnResult.setMessage(ResultMessage.NEGOTIATION_ERROR);
sendUserNotification("Service '"+serviceToInstall.getServiceName()+"' not installed: " + returnResult.getMessage());
sendEvent(ServiceMgmtEventType.PROBLEM_OCURRED,serviceToInstall,null);
return new AsyncResult<ServiceControlResult>(returnResult);
}
if(!negotiationResult.getSuccess()){
if(logger.isDebugEnabled())
logger.debug("Negotiation was not successful!");
returnResult.setMessage(ResultMessage.NEGOTIATION_FAILED);
sendUserNotification("Service '"+serviceToInstall.getServiceName()+"' not installed: " + returnResult.getMessage());
sendEvent(ServiceMgmtEventType.PROBLEM_OCURRED,serviceToInstall,null);
return new AsyncResult<ServiceControlResult>(returnResult);
}
if(logger.isDebugEnabled())
logger.debug("Negotiation was successful! URI returned is: " + negotiationResult.getServiceUri());
//sendUserNotification("Service '"+serviceToInstall.getServiceName()+"' : negotiation success!");
// Now install the client!
if(serviceToInstall.getServiceType().equals(ServiceType.THIRD_PARTY_WEB)){
if(logger.isDebugEnabled()) logger.debug("This is a web-type service, no client to install!");
//serviceToInstall.setServiceEndpoint(negotiationResult.getServiceUri().toString());
ServiceInstance si = serviceToInstall.getServiceInstance();
si.setParentIdentifier(serviceToInstall.getServiceIdentifier());
si.setParentJid(serviceToInstall.getServiceInstance().getFullJid());
si.setFullJid(myNode.getJid());
si.setCssJid(myNode.getBareJid());
serviceToInstall.setServiceInstance(si);
List<Service> addServices = new ArrayList<Service>();
addServices.add(serviceToInstall);
getServiceReg().registerServiceList(addServices);
logger.info("Installed web-type third-party service.");
returnResult.setMessage(ResultMessage.SUCCESS);
sendUserNotification("Service '"+serviceToInstall.getServiceName()+"' installed!");
sendEvent(ServiceMgmtEventType.NEW_SERVICE,serviceToInstall,null);
sendEvent(ServiceMgmtEventType.SERVICE_STARTED,serviceToInstall,null);
} else{
// CLIENT BASED SERVICE
if(logger.isDebugEnabled()) logger.debug("This is a client-based service, we need to install it");
Future<ServiceControlResult> asyncResult = null;
URL bundleLocation = null;
List<URI> urlList = negotiationResult.getServiceUri();
if(!urlList.isEmpty()){
logger.debug("More than one service client detected, finding the the virgo one!");
for(URI uri: urlList){
logger.debug("Service Client URI: {}", uri);
if(uri.toString().contains(".war") || uri.toString().contains(".jar")){
bundleLocation = uri.toURL();
}
}
}
else
{
if(logger.isDebugEnabled())
logger.debug("No client url returned from negotiation!");
returnResult.setMessage(ResultMessage.NEGOTIATION_ERROR);
sendEvent(ServiceMgmtEventType.PROBLEM_OCURRED,serviceToInstall,null);
sendUserNotification("Service '"+serviceToInstall.getServiceName()+"' not installed: No file to install returned!");
return new AsyncResult<ServiceControlResult>(returnResult);
}
if(logger.isDebugEnabled())
logger.debug("Now trying to download the jar...");
URI jarLocation = ServiceDownloader.downloadClientJar(bundleLocation, serviceToInstall,myNode.getIdentifier(),getServiceDir());
if(jarLocation == null){
if(logger.isDebugEnabled())
logger.debug("Problem with downloading jar, no file available!");
returnResult.setMessage(ResultMessage.COMMUNICATION_ERROR);
sendUserNotification("Service '"+serviceToInstall.getServiceName()+"' not installed: Failure to download jar!");
sendEvent(ServiceMgmtEventType.PROBLEM_OCURRED,serviceToInstall,null);
return new AsyncResult<ServiceControlResult>(returnResult);
}
ServiceControlResult result = installService(jarLocation.toURL()).get();
if(result == null){
if(logger.isDebugEnabled())
logger.debug("Error with installation! ");
returnResult.setMessage(ResultMessage.COMMUNICATION_ERROR);
logger.warn("Couldn't install the service, deleting the file then!");
ServiceDownloader.deleteFile(jarLocation);
sendUserNotification("Service '"+serviceToInstall.getServiceName()+"' not installed: " + returnResult.getMessage());
sendEvent(ServiceMgmtEventType.PROBLEM_OCURRED,serviceToInstall,null);
return new AsyncResult<ServiceControlResult>(returnResult);
}
if(result.getMessage() == ResultMessage.SUCCESS){
// We get the service from the registry
Service newService = getServiceReg().retrieveService(result.getServiceId());
ServiceInstance newServiceInstance = newService.getServiceInstance();
newServiceInstance.setParentJid(serviceToInstall.getServiceInstance().getFullJid());
newServiceInstance.setParentIdentifier(serviceToInstall.getServiceIdentifier());
ServiceImplementation newServImpl = newServiceInstance.getServiceImpl();
//newServImpl.setServiceClient(jarLocation.toString());
newServiceInstance.setServiceImpl(newServImpl);
newService.setServiceInstance(newServiceInstance);
boolean test = getServiceReg().updateRegisteredService(newService);
//
logger.info("Installed shared third-party service client! : " + test);
returnResult.setServiceId(result.getServiceId());
returnResult.setMessage(result.getMessage());
sendUserNotification("Service '"+serviceToInstall.getServiceName()+"' installed!");
sendEvent(ServiceMgmtEventType.NEW_SERVICE,newService,null);
sendEvent(ServiceMgmtEventType.SERVICE_STARTED,newService,null);
} else{
if(logger.isDebugEnabled())
logger.debug("Installation of client was not successful");
returnResult.setMessage(result.getMessage());
logger.warn("Couldn't install the service, deleting the file then!");
ServiceDownloader.deleteFile(jarLocation);
sendUserNotification("Service '"+serviceToInstall.getServiceName()+"' not installed: " + result.getMessage());
sendEvent(ServiceMgmtEventType.PROBLEM_OCURRED,serviceToInstall,null);
}
}
return new AsyncResult<ServiceControlResult>(returnResult);
} catch (Exception ex) {
sendUserNotification("Service '"+serviceToInstall.getServiceName()+"' : Problems!");
sendEvent(ServiceMgmtEventType.PROBLEM_OCURRED,serviceToInstall,null);
logger.error("Exception while attempting to install a bundle: " + ex.getMessage());
ex.printStackTrace();
throw new ServiceControlException("Exception while attempting to install a bundle.", ex);
}
}
@Async
@Override
public Future<ServiceControlResult> installService(URL bundleLocation) {
if(logger.isDebugEnabled()) logger.debug("Service Management: installService method, local node");
ServiceControlResult returnResult = new ServiceControlResult();
returnResult.setServiceId(null);
Bundle newBundle = null;
try {
logger.info("Installing service bundle from location: {} ", bundleLocation);
try{
newBundle = bundleContext.installBundle(bundleLocation.toString());
} catch(BundleException ex){
logger.error("Exception installing the bundle itself! {}", ex.getMessage());
ex.printStackTrace();
returnResult.setMessage(ResultMessage.OSGI_PROBLEM);
return new AsyncResult<ServiceControlResult>(returnResult);
}
if(logger.isDebugEnabled()){
logger.debug("Service bundle {} has been installed with id: {}",newBundle.getSymbolicName(),newBundle.getBundleId());
logger.debug("Service bundle {} is in state: {}",newBundle.getSymbolicName(),ServiceModelUtils.getBundleStateName(newBundle.getState()));
logger.debug("Service bundle {} is in location: {}",newBundle.getSymbolicName(),newBundle.getLocation());
}
//Before we start the bundle we prepare the entry on the hashmap
BlockingQueue<Service> idList = new ArrayBlockingQueue<Service>(1);
Long bundleId = new Long(newBundle.getBundleId());
synchronized(this){
installServiceMap.put(bundleId, idList);
}
//Now we need to start the bundle so that its services are registered with the OSGI Registry, and then SOCIETIES Registry
if(logger.isDebugEnabled())
logger.debug("Attempting to start bundle: " + newBundle.getSymbolicName() );
try{
newBundle.start();
} catch(BundleException ex){
logger.error("Exception while trying to start bundle: {}",ex.getMessage());
ex.printStackTrace();
}
if(newBundle.getState() == Bundle.ACTIVE ){
logger.info("Bundle " + newBundle.getSymbolicName() + " has been installed and activated.");
// Now we need to search the service registry for the list of services and find the correct one!
if(logger.isDebugEnabled()) logger.debug("Now searching for the service installed by the new bundle");
//TODO Something to assure the other function is called first...
Service service = idList.poll(TIMEOUT,TimeUnit.SECONDS);
if(service != null){
if(logger.isDebugEnabled()) logger.debug("Found service: " + service.getServiceName() + " so install was success!");
returnResult.setServiceId(service.getServiceIdentifier());
returnResult.setMessage(ResultMessage.SUCCESS);
} else{
if(logger.isDebugEnabled()) logger.debug("Couldn't find the service!");
returnResult.setMessage(ResultMessage.SERVICE_NOT_FOUND);
newBundle.stop();
newBundle.uninstall();
}
synchronized(this){
installServiceMap.remove(bundleId);
}
}
else{
logger.info("Bundle " + newBundle.getSymbolicName() + " has been installed, but not activated.");
returnResult.setMessage(ResultMessage.OSGI_PROBLEM);
newBundle.uninstall();
}
} catch (Exception ex) {
logger.error("Exception while attempting to install a bundle: " + ex.getMessage());
returnResult.setMessage(ResultMessage.OSGI_PROBLEM);
}
return new AsyncResult<ServiceControlResult>(returnResult);
}
@Async
@Override
public Future<ServiceControlResult> installService(InputStream inputStream, String fileName)
throws ServiceControlException {
if(logger.isDebugEnabled())
logger.debug("Installing service from a received input stream!");
ServiceControlResult returnResult = new ServiceControlResult();
returnResult.setServiceId(null);
URI jarLocation = ServiceDownloader.downloadServerJar(inputStream, fileName,myId.getIdentifier(),getServiceDir());
if(jarLocation == null){
if(logger.isDebugEnabled())
logger.debug("Problem with downloading jar, no file available!");
returnResult.setMessage(ResultMessage.COMMUNICATION_ERROR);
sendUserNotification("Service not installed: Failure to download jar: "+fileName);
return new AsyncResult<ServiceControlResult>(returnResult);
}
try {
Future<ServiceControlResult> asyncResult = installService(jarLocation.toURL());
ServiceControlResult result = asyncResult.get();
if(!result.getMessage().equals(ResultMessage.SUCCESS)){
logger.warn("Couldn't install the service, deleting the file then!");
ServiceDownloader.deleteFile(jarLocation);
}
return new AsyncResult<ServiceControlResult>(result);
} catch (Exception e) {
logger.error("Exception while installing bundle! {}", e.getMessage());
logger.warn("Couldn't install the service, deleting the file then!");
ServiceDownloader.deleteFile(jarLocation);
e.printStackTrace();
throw new ServiceControlException("Exception while attempting to install a bundle.", e);
}
}
@Async
@Override
public Future<ServiceControlResult> installService(URL bundleLocation, IIdentity node)
throws ServiceControlException {
if(logger.isDebugEnabled()) logger.debug("Service Management: installService method, on a given node, Identity input");
ServiceControlResult returnResult = new ServiceControlResult();
returnResult.setServiceId(null);
try {
// First we verify if we are installing in our own CSS
// Our first task is to verify if we're installing in the right node..
String localNodeJid = getCommMngr().getIdManager().getThisNetworkNode().getJid();
String nodeJid = localNodeJid;
if(node != null)
nodeJid = node.getJid();
if(logger.isDebugEnabled())
logger.debug("The JID of the node where the Service is: " + nodeJid + " and the local JID: " + localNodeJid);
if(!nodeJid.equals(localNodeJid)){
if(logger.isDebugEnabled())
logger.debug("We're dealing with a different node! Need to do a remote call!");
ServiceControlRemoteClient callback = new ServiceControlRemoteClient();
getServiceControlRemote().installService(bundleLocation, node, callback);
if(logger.isDebugEnabled())
logger.debug("Remote call complete, now we need to wait for the result...");
ServiceControlResult result = callback.getResult();
if(result == null){
if(logger.isDebugEnabled())
logger.debug("Error with communication to remote client");
returnResult.setMessage(ResultMessage.COMMUNICATION_ERROR);
return new AsyncResult<ServiceControlResult>(returnResult);
} else{
if(logger.isDebugEnabled())
logger.debug("Result of operation was: " + result.getMessage());
return new AsyncResult<ServiceControlResult>(result);
}
} else
{
if(logger.isDebugEnabled())
logger.debug("It's the local node, installing...");
URI jarLocation = ServiceDownloader.downloadServerJar(bundleLocation,myId.getIdentifier(),getServiceDir());
if(jarLocation == null){
if(logger.isDebugEnabled())
logger.debug("Problem with downloading jar, no file available!");
returnResult.setMessage(ResultMessage.COMMUNICATION_ERROR);
sendUserNotification("Service not installed: Failure to download jar!");
return new AsyncResult<ServiceControlResult>(returnResult);
}
Future<ServiceControlResult> asyncResult = installService(jarLocation.toURL());
ServiceControlResult result = asyncResult.get();
return new AsyncResult<ServiceControlResult>(result);
}
} catch (Exception ex) {
logger.error("Exception while attempting to install a bundle: " + ex.getMessage());
throw new ServiceControlException("Exception while attempting to install a bundle.", ex);
}
}
@Async
@Override
public Future<ServiceControlResult> installService(URL bundleLocation, String nodeJid)
throws ServiceControlException {
if(logger.isDebugEnabled()) logger.debug("Service Management: installService method, on given node, String input");
try {
// We convert to a node, then call the other method...
IIdentity node = null;
if(nodeJid != null && !nodeJid.isEmpty())
node = getCommMngr().getIdManager().fromJid(nodeJid);
Future<ServiceControlResult> asyncResult = null;
asyncResult = installService(bundleLocation,node);
ServiceControlResult result = asyncResult.get();
return new AsyncResult<ServiceControlResult>(result);
} catch (Exception ex) {
logger.error("Exception while attempting to install a bundle: " + ex.getMessage());
throw new ServiceControlException("Exception while attempting to install a bundle.", ex);
}
}
@Async
@Override
public Future<ServiceControlResult> uninstallService(ServiceResourceIdentifier serviceId)
throws ServiceControlException {
if(logger.isDebugEnabled()) logger.debug("Service Management: uninstallService method");
ServiceControlResult returnResult = new ServiceControlResult();
returnResult.setServiceId(serviceId);
try{
// Our first task is to obtain the Service object from the identifier, for this we got to the registry
if(logger.isDebugEnabled()) logger.debug("Obtaining Service from SOCIETIES Registry");
Service service = getServiceReg().retrieveService(serviceId);
String nodeJid = ServiceModelUtils.getJidFromServiceIdentifier(serviceId);
String localNodeJid = getCommMngr().getIdManager().getThisNetworkNode().getJid();
if(logger.isDebugEnabled())
logger.debug("The JID of the node where the Service is: " + nodeJid + " and the local JID: " + localNodeJid);
if(!nodeJid.equals(localNodeJid) && service == null){
if(logger.isDebugEnabled())
logger.debug("We're dealing with a different node! Need to do a remote call!");
IIdentity node = getCommMngr().getIdManager().fromJid(nodeJid);
ServiceControlRemoteClient callback = new ServiceControlRemoteClient();
getServiceControlRemote().uninstallService(serviceId, node, callback);
if(logger.isDebugEnabled())
logger.debug("Remote call complete, now we need to wait for the result...");
ServiceControlResult result = callback.getResult();
if(result == null){
if(logger.isDebugEnabled())
logger.debug("Error with communication to remote client");
returnResult.setMessage(ResultMessage.COMMUNICATION_ERROR);
return new AsyncResult<ServiceControlResult>(returnResult);
} else{
if(logger.isDebugEnabled())
logger.debug("Result of operation was: " + result.getMessage());
return new AsyncResult<ServiceControlResult>(result);
}
}
//Local node
if(logger.isDebugEnabled())
logger.debug("We're dealing with our current, local node...");
// Check to see if we actually got a service
if(service == null){
if(logger.isDebugEnabled()) logger.debug("Service represented by " + serviceId + " does not exist in SOCIETIES Registry");
returnResult.setMessage(ResultMessage.SERVICE_NOT_FOUND);
return new AsyncResult<ServiceControlResult>(returnResult);
}
if(service.getServiceType().equals(ServiceType.DEVICE) && !nodeJid.equals(localNodeJid)){
if(logger.isDebugEnabled()) logger.debug("It's a remote device...");
getDeviceMngr().fireDisconnectedSharedDevice(service.getServiceIdentifier().getServiceInstanceIdentifier());
returnResult.setMessage(ResultMessage.SUCCESS);
return new AsyncResult<ServiceControlResult>(returnResult);
}
//Next, we need to determine if we should continue
if(service.getServiceType().equals(ServiceType.DEVICE) || service.getServiceType().equals(ServiceType.THIRD_PARTY_ANDROID)){
if(logger.isDebugEnabled()) logger.debug("It's a device, so shouldn't proceed.");
returnResult.setMessage(ResultMessage.SERVICE_TYPE_NOT_SUPPORTED);
return new AsyncResult<ServiceControlResult>(returnResult);
}
//Next, we need to determine if we should continue
if(service.getServiceType().equals(ServiceType.THIRD_PARTY_WEB) && !nodeJid.equals(localNodeJid)){
if(logger.isDebugEnabled())
logger.debug("It's a web-app, we need to remove it");
List<Service> servicesToRemove = new ArrayList<Service>();
servicesToRemove.add(service);
if(logger.isDebugEnabled()) logger.debug("Removing service: " + service.getServiceName() + " from SOCIETIES Registry");
getServiceReg().unregisterServiceList(servicesToRemove);
logger.info("Service " + service.getServiceName() + " has been uninstalled");
returnResult.setMessage(ResultMessage.SUCCESS);
if(service.getServiceStatus().equals(ServiceStatus.STARTED))
sendEvent(ServiceMgmtEventType.SERVICE_STOPPED,service,null);
sendEvent(ServiceMgmtEventType.SERVICE_REMOVED,service,null);
return new AsyncResult<ServiceControlResult>(returnResult);
}
// Next step, we obtain the bundle that corresponds to this service
Bundle serviceBundle = getBundleFromService(service);
// And we check if it isn't null!
if(serviceBundle == null){
if(logger.isDebugEnabled()) logger.debug("Service Bundle obtained from " + service.getServiceName() + " couldn't be found");
returnResult.setMessage(ResultMessage.BUNDLE_NOT_FOUND);
return new AsyncResult<ServiceControlResult>(returnResult);
}
logger.info("Uninstalling service " + service.getServiceName());
//Before we uninstall the bundle we prepare the entry on the hashmap
BlockingQueue<Service> idList = new ArrayBlockingQueue<Service>(1);
Long bundleId = new Long(serviceBundle.getBundleId());
synchronized(this){
uninstallServiceMap.put(bundleId, idList);
}
if(logger.isDebugEnabled()) logger.debug("Attempting to uninstall bundle: " + serviceBundle.getSymbolicName());
serviceBundle.uninstall();
if(serviceBundle.getState() == Bundle.UNINSTALLED){
if(logger.isDebugEnabled()) logger.debug("Bundle: " + serviceBundle.getSymbolicName() + " has been uninstalled.");
returnResult.setMessage(ResultMessage.SUCCESS);
Service serviceUninstalled = idList.take();
synchronized(this){
uninstallServiceMap.remove(bundleId);
}
if(logger.isDebugEnabled())
logger.debug("Now we need to delete the file: " + service.getServiceLocation());
String serviceLocation = service.getServiceLocation();
int index = serviceLocation.indexOf('@');
String newServiceLocation = serviceLocation.substring(index+1);
ServiceDownloader.deleteFile(new URI(newServiceLocation));
return new AsyncResult<ServiceControlResult>(returnResult);
} else{
logger.info("Service " + service.getServiceName() + " has NOT been uninstalled");
returnResult.setMessage(ResultMessage.OSGI_PROBLEM);
return new AsyncResult<ServiceControlResult>(returnResult);
}
} catch(Exception ex){
logger.error("Exception while uninstalling service: " + ex.getMessage());
ex.printStackTrace();
throw new ServiceControlException("Exception uninstalling service bundle.", ex);
}
}
/**
* This method is used to obtain the Bundle that corresponds to a given a Service
*
* @param The Service object whose bundle we wish to find
* @return The Bundle that exposes this service
*/
private Bundle getBundleFromService(Service service) {
if(logger.isDebugEnabled()) logger.debug("Obtaining Bundle that corresponds to a service...");
// Now we get the bundle
Bundle result = bundleContext.getBundle(service.getServiceLocation());
if(logger.isDebugEnabled())
logger.debug("Bundle is " + result.getSymbolicName() + " with id: " + result.getBundleId() + " and state: " + ServiceModelUtils.getBundleStateName(result.getState()));
// Finally, we return
return result;
}
protected static boolean installingBundle(long bundleId){
if(logger.isDebugEnabled()) logger.debug("installingBundle Called for bundleId: " + bundleId );
return installServiceMap.containsKey(new Long(bundleId));
}
protected static boolean uninstallingBundle(long bundleId){
if(logger.isDebugEnabled()) logger.debug("uninstallingBundle Called for bundleId: " + bundleId );
return uninstallServiceMap.containsKey(new Long(bundleId));
}
protected static void serviceInstalled(long bundleIdentifier, Service newService){
Long bundleId = new Long(bundleIdentifier);
if(logger.isDebugEnabled()) logger.debug("serviceInstalled Called for bundleId: " + bundleId );
BlockingQueue<Service> queue = installServiceMap.get(bundleId);
queue.add(newService);
}
protected static void serviceUninstalled(long bundleIdentifier, Service newService){
Long bundleId = new Long(bundleIdentifier);
if(logger.isDebugEnabled()) logger.debug("serviceUninstalled Called for bundleId: " + bundleId );
BlockingQueue<Service> queue = uninstallServiceMap.get(bundleId);
queue.add(newService);
}
@Async
@Override
public Future<ServiceControlResult> shareService(Service service, String nodeJid)
throws ServiceControlException {
if(logger.isDebugEnabled()) logger.debug("Service Management: shareShared method, String input");
try {
// We convert to a node, then call the other method...
IIdentity node = null;
if(nodeJid != null && !nodeJid.isEmpty())
node = getCommMngr().getIdManager().fromJid(nodeJid);
Future<ServiceControlResult> asyncResult = null;
asyncResult = shareService(service,node);
ServiceControlResult result = asyncResult.get();
return new AsyncResult<ServiceControlResult>(result);
} catch (Exception ex) {
logger.error("Exception while attempting to share a service: " + ex.getMessage());
throw new ServiceControlException("Exception while attempting to share a service:", ex);
}
}
@Async
@Override
public Future<ServiceControlResult> shareService(Service service, IIdentity node) throws ServiceControlException {
if(logger.isDebugEnabled()) logger.debug("Service Management: shareShared method, node input");
ServiceControlResult returnResult = new ServiceControlResult();
returnResult.setServiceId(service.getServiceIdentifier());
try {
// First we check if the service is already in the repository
//TODO a check to see if the service is "ours"? And then only add it if it's not?
Service ourService = getServiceReg().retrieveService(service.getServiceIdentifier());
if(ourService==null){
if(logger.isDebugEnabled())
logger.debug("Service is not in the repository yet, adding it");
List<Service> servicesList = new ArrayList<Service>();
servicesList.add(service);
getServiceReg().registerServiceList(servicesList );
}
// Now that we've added it, we can share it!
switch (node.getType())
{
case CSS:
case CSS_RICH:
case CSS_LIGHT:
if(logger.isDebugEnabled()) logger.debug("For now, sharing to specific CSS is not supported");
break;
case CIS:
if(logger.isDebugEnabled()) logger.debug("Sharing with a CIS: " + node.getJid());
// First we need to check if we own the CIS. If so, then we can add it, if not then we need to tell the respective CIS
ICisOwned myCIS = getCisManager().getOwnedCis(node.getJid());
if(myCIS!= null) {
if(logger.isDebugEnabled())
logger.debug("We are dealing with a CIS that we own: " + myCIS.getName());
//Adding service to repository
if(logger.isDebugEnabled())
logger.debug("Adding service-cis association to repository");
getServiceReg().notifyServiceIsSharedInCIS(service.getServiceIdentifier(), node.getJid());
returnResult.setMessage(ResultMessage.SUCCESS);
if(logger.isDebugEnabled())
logger.debug("Updating ActivityFeed for " + myCIS.getCisId());
updateActivityFeed(node,"Shared",service);
sendEvent(ServiceMgmtEventType.SERVICE_SHARED,service,node);
sendUserNotification("Shared service '"+ service.getServiceName()+"' with CIS: " + myCIS.getName());
} else {
if(logger.isDebugEnabled())
logger.debug("We need to send the message to the remote CIS!");
ServiceControlRemoteClient callback = new ServiceControlRemoteClient();
getServiceControlRemote().shareService(service, node, callback);
if(logger.isDebugEnabled())
logger.debug("Remote call complete, now we need to wait for the result...");
ServiceControlResult result = callback.getResult();
if(result == null){
if(logger.isDebugEnabled())
logger.debug("Error with communication to remote client");
returnResult.setMessage(ResultMessage.COMMUNICATION_ERROR);
} else{
if(logger.isDebugEnabled())
logger.debug("Result of operation was: " + result.getMessage());
returnResult.setMessage(result.getMessage());
returnResult.setServiceId(result.getServiceId());
if(result.getMessage() == ResultMessage.SUCCESS && ServiceModelUtils.isServiceOurs(service,getCommMngr())){
// And we add it to the table
getServiceReg().notifyServiceIsSharedInCIS(service.getServiceIdentifier(), node.getJid());
ICis remoteCis = getCisManager().getCis(node.getJid());
if(logger.isDebugEnabled())
logger.debug("Updating ActivityFeed for " + remoteCis.getCisId());
updateActivityFeed(node,"Shared",service);
sendUserNotification("Shared service '"+ service.getServiceName()+"' with CIS: " + remoteCis.getName());
sendEvent(ServiceMgmtEventType.SERVICE_SHARED,service,node);
}
}
}
break;
default:
if(logger.isDebugEnabled()) logger.debug("Unknown kind of node!");
returnResult.setMessage(ResultMessage.UNKNOWN_NODE);
break;
}
} catch (Exception ex) {
logger.error("Exception while attempting to share a service: " + ex.getMessage());
throw new ServiceControlException("Exception while attempting to share a service:", ex);
}
return new AsyncResult<ServiceControlResult>(returnResult);
}
@Async
@Override
public Future<ServiceControlResult> unshareService(Service service, String nodeJid) throws ServiceControlException {
if(logger.isDebugEnabled()) logger.debug("Service Management: unshareShared method, String input");
try {
// We convert to a node, then call the other method...
IIdentity node = null;
if(nodeJid != null && !nodeJid.isEmpty())
node = getCommMngr().getIdManager().fromJid(nodeJid);
Future<ServiceControlResult> asyncResult = null;
asyncResult = unshareService(service,node);
ServiceControlResult result = asyncResult.get();
return new AsyncResult<ServiceControlResult>(result);
} catch (Exception ex) {
logger.error("Exception while attempting to unshare a service: " + ex.getMessage());
throw new ServiceControlException("Exception while attempting to unshare a service:", ex);
}
}
@Async
@Override
public Future<ServiceControlResult> unshareService(Service service, IIdentity node) throws ServiceControlException {
if(logger.isDebugEnabled()) logger.debug("Service Management: shareShared method, node input");
ServiceControlResult returnResult = new ServiceControlResult();
returnResult.setServiceId(service.getServiceIdentifier());
try {
// First we check if the service is already in the repository. If it's not, then there's something wrong!
//TODO a check to see if the service is "ours"? And then only add it if it's not?
Service ourService = getServiceReg().retrieveService(service.getServiceIdentifier());
if(ourService==null){
if(logger.isDebugEnabled())
logger.debug("Service is not in the repository yet, then how can we unshare it?");
returnResult.setMessage(ResultMessage.SERVICE_NOT_FOUND);
return new AsyncResult<ServiceControlResult>(returnResult);
}
// Now we unshare it!
switch (node.getType())
{
case CSS:
case CSS_RICH:
case CSS_LIGHT:
if(logger.isDebugEnabled()) logger.debug("For now, sharing to specific CSS is not supported");
break;
case CIS:
if(logger.isDebugEnabled()) logger.debug("Removing sharing with a CIS: " + node.getJid());
// First we need to check if we own the CIS. If so, then we can remove it, if not then we need to tell the respective CIS
ICisOwned myCIS = getCisManager().getOwnedCis(node.getJid());
if(myCIS!= null) {
if(logger.isDebugEnabled())
logger.debug("We are dealing with a CIS that we own: " + myCIS.getName());
//Removing service from repository
if(logger.isDebugEnabled())
logger.debug("Removing service from sharing");
getServiceReg().removeServiceSharingInCIS(service.getServiceIdentifier(), node.getJid());
List<String> sharedCis = getServiceReg().retrieveCISSharedService(service.getServiceIdentifier());
//Checking if the service is ours, if not then we remove it from the repository IF it's no longer shared
if(!ServiceModelUtils.isServiceOurs(service,getCommMngr()) && sharedCis.isEmpty()){
if(logger.isDebugEnabled())
logger.debug("Service isn't ours, removing it from the service repository!");
List<Service> servicesList = new ArrayList<Service>();
servicesList.add(service);
getServiceReg().unregisterServiceList(servicesList);
//And if it's a device...
if(service.getServiceType().equals(ServiceType.DEVICE)){
if(logger.isDebugEnabled())
logger.debug("Service is a device, alerting device management");
getDeviceMngr().fireDisconnectedSharedDevice(service.getServiceIdentifier().getServiceInstanceIdentifier());
}
} else{
updateActivityFeed(node,"Unshared",service);
sendEvent(ServiceMgmtEventType.SERVICE_UNSHARED,service,node);
sendUserNotification("No longer sharing "+ service.getServiceName() + " with " + myCIS.getName());
}
returnResult.setMessage(ResultMessage.SUCCESS);
} else {
if(logger.isDebugEnabled())
logger.debug("We need to send the message to the remote CIS!");
ServiceControlRemoteClient callback = new ServiceControlRemoteClient();
getServiceControlRemote().unshareService(service, node, callback);
if(logger.isDebugEnabled())
logger.debug("Remote call complete, now we need to wait for the result...");
ServiceControlResult result = callback.getResult();
if(result == null){
if(logger.isDebugEnabled())
logger.debug("Error with communication to remote client");
returnResult.setMessage(ResultMessage.COMMUNICATION_ERROR);
} else{
if(logger.isDebugEnabled())
logger.debug("Result of operation was: " + result.getMessage());
returnResult.setMessage(result.getMessage());
if(result.getMessage() == ResultMessage.SUCCESS){
// Don't think this makes sense or is needed... should you be able to remove a service that isn't yours from a remote CIS?!
if(!ServiceModelUtils.isServiceOurs(ourService, getCommMngr())){
if(logger.isDebugEnabled())
logger.debug("Service isn't ours, removing it from the service repository!");
List<Service> servicesList = new ArrayList<Service>();
servicesList.add(service);
getServiceReg().unregisterServiceList(servicesList);
} else{
getServiceReg().removeServiceSharingInCIS(ourService.getServiceIdentifier(), node.getJid());
updateActivityFeed(node,"Unshared",service);
sendEvent(ServiceMgmtEventType.SERVICE_UNSHARED,service,node);
sendUserNotification("No longer sharing "+ service.getServiceName() + " with " + getCisManager().getCis(node.getJid()).getName());
}
}
}
}
break;
default:
if(logger.isDebugEnabled()) logger.debug("Unknown kind of node!");
returnResult.setMessage(ResultMessage.UNKNOWN_NODE);
break;
}
} catch (Exception ex) {
logger.error("Exception while attempting to share a service: " + ex.getMessage());
throw new ServiceControlException("Exception while attempting to share a service:", ex);
}
return new AsyncResult<ServiceControlResult>(returnResult);
}
@Override
@Async
public Future<List<ICis>> getCisServiceIsSharedWith(ServiceResourceIdentifier serviceId){
if(logger.isDebugEnabled())
logger.debug("Getting all CIS the service is shared with...");
List<ICis> finalResult = new ArrayList<ICis>();
try{
String myLocalJid = getCommMngr().getIdManager().getThisNetworkNode().getJid();
String serviceJid = ServiceModelUtils.getJidFromServiceIdentifier(serviceId);
// Is it supposed to be local?
if(!myLocalJid.equals(serviceJid)){
//TODO
} else{
List<String> cisList = getServiceReg().retrieveCISSharedService(serviceId);
for(String cisId : cisList){
ICis myCis = getCisManager().getCis(cisId);
if(myCis != null){
finalResult.add(myCis);
}
}
}
} catch(Exception ex){
ex.printStackTrace();
logger.error("getService():: Exception getting Service: " + ex);
}
return new AsyncResult<List<ICis>>(finalResult);
}
private void sendEvent(ServiceMgmtEventType eventType, Service service,IIdentity node){
ServiceControlAsync servAsync = new ServiceControlAsync(eventType,service,node);
executor.execute(servAsync);
}
private void sendUserNotification(String message){
ServiceControlAsync servAsync = new ServiceControlAsync(message);
executor.execute(servAsync);
}
private void updateActivityFeed(IIdentity target, String verb, Service service){
ServiceControlAsync servAsync = new ServiceControlAsync(target,verb,service);
executor.execute(servAsync);
}
@Override
public void cleanAfterRestart(){
if(logger.isDebugEnabled())
logger.debug("Cleaning and Restarting. First we try to restore already installed servers!");
String fullJid = getCommMngr().getIdManager().getThisNetworkNode().getJid();
List<Service> deleteServices = new ArrayList<Service>();
logger.debug("The JID of this node is: {}",fullJid);
try{
List<Service> oldServices = getServiceReg().retrieveServicesInCSSNode(fullJid);
for(Service oldService : oldServices){
if(oldService.getServiceType().equals(ServiceType.DEVICE) || oldService.getServiceType().equals(ServiceType.THIRD_PARTY_ANDROID)){
if(logger.isDebugEnabled())
logger.debug("Service is a device or Android, so we don't reinstall...");
continue;
}
String serviceLocation = oldService.getServiceLocation();
if(logger.isDebugEnabled())
logger.debug("Checking if Bundle with location: " + serviceLocation + " exists in OSGI...");
Bundle thisBundle = this.bundleContext.getBundle(serviceLocation);
if(thisBundle == null || (thisBundle != null && !(thisBundle.getSymbolicName().equals(oldService.getServiceInstance().getServiceImpl().getServiceNameSpace())))){
if(logger.isDebugEnabled()){
logger.debug("Bundle doesn't exist, or isn't our service! We need to install!");
logger.debug("Attempting to reinstall service: " + oldService.getServiceName() + " from " + oldService.getServiceLocation());
//logger.debug("Parent is: " + ServiceModelUtils.serviceResourceIdentifierToString(oldService.getServiceInstance().getParentIdentifier()));
}
int index = serviceLocation.indexOf('@');
String newServiceLocation = serviceLocation.substring(index+1);
if(logger.isDebugEnabled())
logger.debug("ServiceLocation: " + serviceLocation);
URI bundleLocation = new URI(newServiceLocation);
File localBundle = new File(bundleLocation);
if(localBundle.isFile()){
Future<ServiceControlResult> asyncResult = installService(bundleLocation.toURL());
ServiceControlResult result = asyncResult.get();
if(result.getMessage() == ResultMessage.SUCCESS){
Service newService = getServiceReg().retrieveService(result.getServiceId());
if(newService.getServiceType().equals(ServiceType.THIRD_PARTY_CLIENT)){
// We get the service from the registry
ServiceInstance newServiceInstance = newService.getServiceInstance();
newServiceInstance.setParentJid(oldService.getServiceInstance().getParentJid());
newServiceInstance.setParentIdentifier(oldService.getServiceInstance().getParentIdentifier());
ServiceImplementation newServImpl = newServiceInstance.getServiceImpl();
newServiceInstance.setServiceImpl(newServImpl);
newService.setServiceInstance(newServiceInstance);
getServiceReg().updateRegisteredService(newService);
}
sendEvent(ServiceMgmtEventType.NEW_SERVICE,newService,null);
sendEvent(ServiceMgmtEventType.SERVICE_STARTED,newService,null);
if(logger.isDebugEnabled())
logger.debug("Installed service " + newService.getServiceName());
} else{
if(logger.isDebugEnabled()){
logger.debug("Installation of "+ ServiceModelUtils.serviceResourceIdentifierToString(oldService.getServiceIdentifier()) +" was not successful");
logger.debug("Deleting the service from database: " + oldService);
}
deleteServices.add(oldService);
}
} else{
if(logger.isDebugEnabled()){
logger.debug("Bundle for " + ServiceModelUtils.serviceResourceIdentifierToString(oldService.getServiceIdentifier()) + " can't be found at: " + bundleLocation);
logger.debug("Deleting the service from database: " + oldService);
}
deleteServices.add(oldService);
}
} else{
if(logger.isDebugEnabled()){
logger.debug("Bundle for " + ServiceModelUtils.serviceResourceIdentifierToString(oldService.getServiceIdentifier()) + " is installed!");
}
}
}
} catch(Exception ex){
logger.error("Error on cleanAfterRestart, not able to restart installed 3rd party service clients");
ex.printStackTrace();
}
if(logger.isDebugEnabled())
logger.debug("Cleaning services that are no longer installed");
try{
getServiceReg().unregisterServiceList(deleteServices);
} catch(Exception ex){
ex.printStackTrace();
logger.error("Exception while cleaning database: " + ex);
}
restart = false;
InternalEvent internalEvent = new InternalEvent(EventTypes.SERVICE_LIFECYCLE_EVENT, "SLM_START", "org/societies/servicelifecycle", "SLM_START");
try {
getEventMgr().publishInternalEvent(internalEvent);
} catch (EMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logger.error("Error sending event!");
}
}
private class ServiceControlAsync implements Runnable{
String message;
IIdentity target;
String verb;
Service service;
ServiceMgmtEventType eventType;
boolean activityUpdate;
boolean internalEvent;
public ServiceControlAsync(String message){
this.message = message;
activityUpdate = false;
internalEvent = false;
}
public ServiceControlAsync(IIdentity target, String verb, Service service){
this.target = target;
this.verb = verb;
this.service = service;
activityUpdate = true;
internalEvent = false;
}
public ServiceControlAsync(ServiceMgmtEventType eventType, Service service,IIdentity node){
internalEvent = true;
this.service = service;
this.target = node;
this.eventType = eventType;
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
if(internalEvent){
logger.debug("Sending event of type: {} for service {}", eventType,ServiceModelUtils.serviceResourceIdentifierToString(service.getServiceIdentifier()));
ServiceModelUtils.sendServiceMgmtEvent(eventType,service,target,ServiceModelUtils.getBundleFromService(service, bundleContext),getEventMgr());
} else{
if(activityUpdate)
this.updateActivityFeed(target,verb,service);
else
this.sendUserNotification(message);
}
}
private void sendUserNotification(String message){
if(logger.isDebugEnabled())
logger.debug("Sending notification: " + message);
getUserFeedback().showNotification(message);
}
private void updateActivityFeed(IIdentity target, String verb, Service service){
ICis remoteCis = getCisManager().getCis(target.getJid());
IActivity activity = remoteCis.getActivityFeed().getEmptyIActivity();
activity.setActor(getCommMngr().getIdManager().getThisNetworkNode().getJid());
activity.setObject(service.getServiceName());
activity.setTarget(target.getJid());
activity.setVerb(verb);
IActivityFeedCallback cisCallback = new ServiceActivityFeedbackCallback();
remoteCis.getActivityFeed().addActivity(activity, cisCallback );
if(logger.isDebugEnabled())
logger.debug("Updated ActivityFeed for " + remoteCis.getCisId());
}
}
}