/** * 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.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Scanner; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleListener; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.societies.api.comm.xmpp.interfaces.ICommManager; import org.societies.api.css.devicemgmt.model.DeviceMgmtConstants; import org.societies.api.identity.IIdentity; import org.societies.api.identity.INetworkNode; import org.societies.api.identity.RequestorService; import org.societies.api.identity.util.RequestorUtils; import org.societies.api.internal.privacytrust.privacyprotection.IPrivacyPolicyManager; import org.societies.api.internal.security.policynegotiator.INegotiationProviderSLMCallback; import org.societies.api.internal.security.policynegotiator.INegotiationProviderServiceMgmt; import org.societies.api.internal.servicelifecycle.IServiceControl; 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.servicelifecycle.serviceRegistry.IServiceRegistry; import org.societies.api.internal.servicelifecycle.serviceRegistry.exception.ServiceNotFoundException; import org.societies.api.internal.servicelifecycle.serviceRegistry.exception.ServiceRegistrationException; import org.societies.api.internal.servicelifecycle.serviceRegistry.exception.ServiceRetrieveException; import org.societies.api.internal.servicelifecycle.serviceRegistry.exception.ServiceUpdateException; import org.societies.api.osgi.event.EMSException; 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.privacytrust.privacy.model.PrivacyException; import org.societies.api.schema.privacytrust.privacy.model.privacypolicy.RequestPolicy; import org.societies.api.schema.servicelifecycle.model.Service; import org.societies.api.schema.servicelifecycle.model.ServiceImplementation; import org.societies.api.schema.servicelifecycle.model.ServiceStatus; import org.societies.api.schema.servicelifecycle.model.ServiceInstance; import org.societies.api.schema.servicelifecycle.model.ServiceType; import org.societies.api.services.ServiceMgmtEventType; import org.springframework.osgi.context.BundleContextAware; import org.springframework.osgi.util.OsgiListenerUtils; /** * * This class implements the Service Registry Listener, that registers and unregisters services * * @author pkuppuud * @author mmanniox * @author <a href="mailto:sanchocsa@gmail.com">Sancho Rêgo</a> (PTIN) * */ public class OsgiRegistryListener implements BundleContextAware, ServiceListener, BundleListener { private BundleContext bctx; private static Logger log = LoggerFactory.getLogger(OsgiRegistryListener.class); private IServiceRegistry serviceReg; private ICommManager commMngr; private INegotiationProviderServiceMgmt negotiationProvider; private IServiceControl serviceControl; private IPrivacyPolicyManager privacyManager; private IEventMgr eventMgr; private String clientRepository; private String serviceDir; private IIdentity myId; private INetworkNode thisNode; public String getServiceDir() { return serviceDir; } public void setServiceDir(String serviceDir) { this.serviceDir = serviceDir; } public String getClientRepository() { return clientRepository; } public void setClientRepository(String clientRepository) { this.clientRepository = clientRepository; } public IEventMgr getEventMgr(){ return eventMgr; } public void setEventMgr(IEventMgr eventMgr){ this.eventMgr=eventMgr; } public IPrivacyPolicyManager getPrivacyManager(){ return privacyManager; } public void setPrivacyManager(IPrivacyPolicyManager privacyManager){ this.privacyManager = privacyManager; } public IServiceControl getServiceControl(){ return serviceControl; } public void setServiceControl(IServiceControl serviceControl){ this.serviceControl = serviceControl; } public INegotiationProviderServiceMgmt getNegotiationProvider(){ return negotiationProvider; } public void setNegotiationProvider(INegotiationProviderServiceMgmt negotiationProvider){ this.negotiationProvider = negotiationProvider; } public IServiceRegistry getServiceReg() { return serviceReg; } public void setServiceReg(IServiceRegistry serviceReg) { this.serviceReg = serviceReg; } public ICommManager getCommMngr() { return commMngr; } public void setCommMngr(ICommManager commMngr) { this.commMngr = commMngr; } public OsgiRegistryListener() { log.info("Service RegistryListener Bean Instantiated"); } public void registerListener() { Filter fltr = null; if(log.isDebugEnabled()) log.debug("Registering Listener!"); try{ thisNode = getCommMngr().getIdManager().getThisNetworkNode(); myId = getCommMngr().getIdManager().fromJid(thisNode.getJid()); } catch(Exception ex){ log.error("Exception getting current node!"); ex.printStackTrace(); } try { fltr = this.bctx.createFilter("(TargetPlatform=SOCIETIES)"); log.info("Service Filter Registered"); } catch (InvalidSyntaxException e) { log.error("Error creating Service Listener Filter"); e.printStackTrace(); } OsgiListenerUtils.addServiceListener(this.bctx, this, fltr); log.info("Bundle Listener Registered"); this.bctx.addBundleListener(this); getServiceControl().cleanAfterRestart(); } public void unRegisterListener() { log.info("Service Management unregistering service listener"); OsgiListenerUtils.removeServiceListener(this.bctx, this); log.info("Service Management unregistering bundle listener"); this.bctx.removeBundleListener(this); } @Override public void setBundleContext(BundleContext ctx) { this.bctx = ctx; } @Override public void serviceChanged(ServiceEvent event) { log.debug("ServiceEvent from OSGI received for a SOCIETIES service!"); Bundle serviceBundle = event.getServiceReference().getBundle(); Service serviceReference = (Service) event.getServiceReference().getProperty("ServiceMetaModel"); if(serviceReference == null){ log.debug("Bean {} is not a valid SOCIETIES service, so we can ignore the event!", event.getServiceReference().getProperty("org.springframework.osgi.bean.name")); return; } boolean isDevice = serviceReference.getServiceType().equals(ServiceType.DEVICE); log.debug("SOCIETIES service {} is a {}",serviceReference.getServiceName(),serviceReference.getServiceType()); // Now we actually get the service! Service service = null; Service existService = null; if(isDevice){ service = getServiceFromOSGIService(event.getServiceReference()); try{ if(service != null) existService = getServiceReg().retrieveService(service.getServiceIdentifier()); } catch(Exception ex){ log.error("Exception while trying to start/register device! {}",ex.getMessage()); ex.printStackTrace(); return; } } else{ existService = getServiceFromBundle(serviceBundle); if(existService == null && event.getType() == ServiceEvent.REGISTERED){ log.debug("{} might be a new service, we need the information from the metamodel.",serviceReference.getServiceName()); service = getServiceFromOSGIService(event.getServiceReference()); } else service = existService; } if(service == null){ log.warn("Couldn't get information from service!"); return; } switch (event.getType()) { case ServiceEvent.MODIFIED: if(log.isDebugEnabled()) log.debug("Service Modification: we do nothing!"); break; case ServiceEvent.REGISTERED: log.debug("We must check if the service that was registered for {} is new or just starting.",serviceReference.getServiceName()); if(existService == null) installService(service,serviceBundle); else startService(service,serviceBundle); break; case ServiceEvent.UNREGISTERING: if(isDevice){ sendEvent(ServiceMgmtEventType.SERVICE_STOPPED,service,serviceBundle); removeService(service,serviceBundle); } else{ stopService(service,serviceBundle); } break; default: log.warn("Unknown ServiceEvent Type!"); } } @Override public void bundleChanged(BundleEvent event) { if(event.getType() != BundleEvent.UNINSTALLED){ return; } Bundle bundle = event.getBundle(); log.debug("Bundle {} has been uninstalled, we must check if it corresponds to a SOCIETIES service.",bundle.getSymbolicName()); Service bundleService = getServiceFromBundle(bundle); if(bundleService != null){ log.debug("Bundle {} corresponds to SOCIETIES service {}. Uninstalling!", bundle.getSymbolicName(),bundleService.getServiceName()); removeService(bundleService,bundle); } /* if(bundleService == null){ if(event.getType() == BundleEvent.STARTED){ log.debug("Bundle {} does not refer to an existing service... it could be a new service, we must check!",bundle.getSymbolicName()); executor.execute(new BundleStartAsyncHandler(bundle,5000)); } return; } // Now we do stuff differently depending on what the event type is... switch(event.getType()){ case BundleEvent.STARTED: startService(bundleService,bundle); break; case BundleEvent.STOPPED: stopService(bundleService,bundle); break; case BundleEvent.UNINSTALLED: removeService(bundleService,bundle); break; default: log.warn("Unknown bundle event type... this shouldn't get here!"); } */ } /** * @param newService * @param newBundle */ /** * @param serviceReference * @return */ private Service getServiceFromOSGIService(ServiceReference<?> serviceReference) { log.debug("Processing new Service Reference, in order to obtain a SOCIETIES service!"); Bundle serviceBundle = serviceReference.getBundle(); try{ if(log.isDebugEnabled()){ log.debug("Checking Service Reference's properties:"); for (String key : serviceReference.getPropertyKeys() ) { log.debug("{} : {}",key,serviceReference.getProperty(key)); } log.debug("Bundle Id: {} with Symbolic Name: {}", serviceBundle.getBundleId(), serviceBundle.getSymbolicName()); } Service service = (Service) serviceReference.getProperty("ServiceMetaModel"); if(service==null || (!(service instanceof Service) )){ if(log.isDebugEnabled()) log.debug("**Service MetadataModel object is null**"); return null; } INetworkNode myNode = commMngr.getIdManager().getThisNetworkNode(); //TODO DEAL WITH THIS service.setServiceEndpoint(myNode.getJid() + "/" + service.getServiceName().replaceAll(" ", "")); //TODO: Do this properly! ServiceInstance si = new ServiceInstance(); if(service.getServiceType().equals(ServiceType.DEVICE)){ String nodeId = (String) serviceReference.getProperty(DeviceMgmtConstants.DEVICE_NODE_ID); log.debug("This is device with nodeId: {} ", nodeId); try{ INetworkNode serviceNode = getCommMngr().getIdManager().fromFullJid(nodeId); si.setFullJid(serviceNode.getJid()); si.setCssJid(serviceNode.getBareJid()); si.setParentJid(serviceNode.getJid()); //This is later changed! si.setXMPPNode(serviceNode.getNodeIdentifier()); }catch(Exception ex){ ex.printStackTrace(); log.warn("Exception in IdManager, doing alternate solution!"); si.setFullJid(nodeId); si.setCssJid(nodeId); si.setParentJid(nodeId); //This is later changed! si.setXMPPNode(myNode.getNodeIdentifier()); } } else{ log.debug("This is a normal service, not a device!"); si.setFullJid(myNode.getJid()); si.setCssJid(myNode.getBareJid()); si.setParentJid(myNode.getJid()); //This is later changed! si.setXMPPNode(myNode.getNodeIdentifier()); service.setServiceLocation(serviceBundle.getLocation()); } ServiceImplementation servImpl = new ServiceImplementation(); servImpl.setServiceVersion((String) serviceReference.getProperty("Bundle-Version")); if(service.getServiceType().equals(ServiceType.DEVICE)) servImpl.setServiceNameSpace("device."+service.getServiceName()+"."+myNode.getBareJid()); else servImpl.setServiceNameSpace(serviceBundle.getSymbolicName()); servImpl.setServiceProvider((String) serviceReference.getProperty("ServiceProvider")); servImpl.setServiceClient((String) serviceReference.getProperty("ServiceClient")); si.setServiceImpl(servImpl); service.setServiceInstance(si); // By default, the status is started... service.setServiceStatus(ServiceStatus.STARTED); if(log.isDebugEnabled()){ log.debug("**Service MetadataModel Data Read**"); log.debug("Service Name: "+service.getServiceName()); log.debug("Service Description: "+service.getServiceDescription()); log.debug("Service type: "+service.getServiceType().toString()); log.debug("Service Location: "+service.getServiceLocation()); log.debug("Service Endpoint: "+service.getServiceEndpoint()); log.debug("Service PrivacyPolicy: "+service.getPrivacyPolicy()); log.debug("Service SecurityPolicy: "+service.getSecurityPolicy()); log.debug("Service SecurityPolicy: "+service.getContextSource()); log.debug("Service Provider: "+service.getServiceInstance().getServiceImpl().getServiceProvider()); log.debug("Service Namespace: "+service.getServiceInstance().getServiceImpl().getServiceNameSpace()); log.debug("Service ServiceClient: "+service.getServiceInstance().getServiceImpl().getServiceClient()); log.debug("Service Version: "+service.getServiceInstance().getServiceImpl().getServiceVersion()); log.debug("Service XMPPNode: "+service.getServiceInstance().getXMPPNode()); log.debug("Service FullJid: "+service.getServiceInstance().getFullJid()); log.debug("Service CssJid: "+service.getServiceInstance().getCssJid()); } if(!service.getServiceType().equals(ServiceType.DEVICE)){ service.setServiceIdentifier(ServiceModelUtils.generateServiceResourceIdentifier(service, serviceBundle)); } else{ String deviceId = (String) serviceReference.getProperty("DeviceId"); if(service.getServiceType().equals(ServiceType.DEVICE) && deviceId == null){ log.warn("Service Type is DEVICE but no device Id. Aborting"); return null; } service.setServiceIdentifier(ServiceModelUtils.generateServiceResourceIdentifierForDevice(service, deviceId)); } si.setParentIdentifier(service.getServiceIdentifier()); service.setServiceInstance(si); log.debug("Generated ServiceResourceIdentifier for new service: {}", ServiceModelUtils.serviceResourceIdentifierToString(service.getServiceIdentifier())); return service; } catch(Exception ex){ log.error("Exception occured while trying to process ServiceReference and turn it into a SOCIETIES event! {}",ex.getMessage()); ex.printStackTrace(); } return null; } /** * This method is used to obtain the Service that is exposed by given Bundle * * @param The Bundle that exposes this service * @return The Service object whose bundle we wish to find */ private Service getServiceFromBundle(Bundle bundle) { if(log.isDebugEnabled()) log.debug("Obtaining Service that corresponds to a bundle: " + bundle.getSymbolicName()); // Preparing the search filter Service filter = ServiceModelUtils.generateEmptyFilter(); filter.getServiceIdentifier().setServiceInstanceIdentifier(bundle.getSymbolicName()); filter.setServiceLocation(bundle.getLocation()); List<Service> listServices; try { listServices = getServiceReg().findServices(filter); } catch (ServiceRetrieveException e) { log.error("Exception while searching for services:" + e.getMessage()); e.printStackTrace(); return null; } if(listServices == null || listServices.isEmpty()){ if(log.isDebugEnabled()) log.debug("Couldn't find any services that fulfill the criteria"); return null; } Service result = null; for(Service service: listServices){ String bundleSymbolic = service.getServiceIdentifier().getServiceInstanceIdentifier(); if(bundleSymbolic.equals(bundle.getSymbolicName())){ result = service; break; } } if(log.isDebugEnabled() && result != null) log.debug("The service corresponding to bundle " + bundle.getSymbolicName() + " is "+ result.getServiceName() ); // Finally, we return return result; } private boolean updateSecurityPolicy(Service service, Bundle bundle){ try{ if(service.getServiceType() != ServiceType.THIRD_PARTY_SERVER){ log.debug("{} is does not need to process the security stuff!", service.getServiceName()); return true; } log.debug("Processing Security and Service Clients for {}",service.getServiceName()); String slaXml = null; List<URL> clientList = getServiceClients(service,bundle); log.debug("Obtained {} service clients for {}",clientList.size(),service.getServiceName()); INegotiationProviderSLMCallback callback = new ServiceNegotiationCallback(); if(clientList.isEmpty()){ log.debug("There are no clients to register, so we don't supply the fileServer!"); getNegotiationProvider().addService(service.getServiceIdentifier(), slaXml, null, clientList.toArray(new URL[0]), callback); } else{ log.debug("There are clients to register, so we supply the fileServer {}", clientRepository); getNegotiationProvider().addService(service.getServiceIdentifier(), slaXml, new URI(clientRepository), clientList.toArray(new URL[clientList.size()]), callback); } } catch(Exception ex){ log.error("Exception Registring in Security Provider: {}",ex.getMessage()); ex.printStackTrace(); return false; } return true; } private boolean updatePrivacyPolicy(Service service, Bundle bundle){ try{ if(service.getServiceType() != ServiceType.THIRD_PARTY_SERVER){ log.debug("{} is does not need to process the privacy policy!", service.getServiceName()); return true; } log.debug("Adding privacy policy for {} . Need to obtain it...",service.getServiceName()); //First we check if we have a privacy policy online String privacyPolicy = null; String privacyLocation = service.getPrivacyPolicy(); if(privacyLocation != null){ log.debug("Attempting to retrieve Privacy Policy from supplied URL: {}",privacyLocation); privacyPolicy = new Scanner( new URL(privacyLocation).openStream(), "UTF-8").useDelimiter("\\A").next(); } else{ log.debug("Privacy Policy URL not supplied, so we check inside the .jar/war, at: {} ", bundle.getLocation()); String privacyPath = bundle.getLocation(); int index = privacyPath.indexOf('@'); privacyLocation = privacyPath.substring(index+1); File bundleFile = new File(new URI(privacyLocation)); if(bundleFile.isDirectory()){ if(log.isDebugEnabled()) log.debug("OSGI expanded .jar, getting privacy-policy directly"); privacyLocation = privacyLocation + "/privacy-policy.xml"; privacyPolicy = new Scanner( new URL(privacyLocation).openStream(), "UTF-8").useDelimiter("\\A").next(); } else if(bundleFile.isFile()) { if(log.isDebugEnabled()) log.debug("OSGI didn't expand .jar/.war, getting privacy-policy from inside."); JarFile jarFile = new JarFile(bundleFile); privacyPolicy = new Scanner( jarFile.getInputStream(jarFile.getEntry("privacy-policy.xml")) ).useDelimiter("\\A").next(); } else{ if(log.isDebugEnabled()) log.debug("Couldn't get privacy-policy from jar!"); } } if(privacyPolicy == null){ log.debug("Failed to obtain the Privacy Policy for {}!",service.getServiceName()); return false; } IIdentity myNode = getCommMngr().getIdManager().getThisNetworkNode(); RequestPolicy policyResult = getPrivacyManager().updatePrivacyPolicy(privacyPolicy, RequestorUtils.create(myNode.getBareJid(), service.getServiceIdentifier())); if(policyResult == null){ log.debug("Error adding privacyPolicy for {} to Privacy Manager!",service.getServiceName()); return true; } else{ log.debug("Added privacyPolicy for {} to Privacy Manager!",service.getServiceName()); return true; } } catch(Exception ex){ log.error("Exception while trying to update Privacy Policy for {}!",service.getServiceName()); ex.printStackTrace(); return false; } } private void installService(Service service, Bundle serviceBundle) { log.debug("{} has been installed in OSGI.",ServiceModelUtils.serviceResourceIdentifierToString(service.getServiceIdentifier())); try{ if(!updateSecurityPolicy(service,serviceBundle) || !updatePrivacyPolicy(service,serviceBundle)){ log.warn("Adding security and privacy failed!"); return; } log.debug("Adding {} to the database!", service.getServiceName()); List<Service> serviceList = new ArrayList<Service>(); serviceList.add(service); this.getServiceReg().registerServiceList(serviceList); if(!service.getServiceType().equals(ServiceType.THIRD_PARTY_CLIENT)){ sendEvent(ServiceMgmtEventType.NEW_SERVICE,service,serviceBundle); sendEvent(ServiceMgmtEventType.SERVICE_STARTED,service,serviceBundle); } //The service is now registered, so we update the hashmap if(ServiceControl.installingBundle(serviceBundle.getBundleId())){ log.debug("ServiceControl is installing the bundle {}, so we need to tell it it's done", serviceBundle.getBundleId()); ServiceControl.serviceInstalled(serviceBundle.getBundleId(), service); } } catch(Exception ex){ log.error("Exception occurred while trying to install a service: {}", ex.getMessage()); ex.printStackTrace(); } } private void startService(Service service, Bundle serviceBundle){ log.debug("{} has been started in OSGI.",ServiceModelUtils.serviceResourceIdentifierToString(service.getServiceIdentifier())); try{ // First we check if the service was already started if(service.getServiceStatus()==ServiceStatus.STARTED){ log.debug("{} is already started in the database, so this is a SOCIETIES restart.",service.getServiceName()); if(ServiceModelUtils.isServiceOurs(service, getCommMngr()) && !service.getServiceType().equals(ServiceType.THIRD_PARTY_CLIENT) && !service.getServiceType().equals(ServiceType.DEVICE)){ log.debug("{}"); if(!updateSecurityPolicy(service,serviceBundle) || !updatePrivacyPolicy(service,serviceBundle)){ log.warn("Adding security and privacy failed!"); return; } sendEvent(ServiceMgmtEventType.NEW_SERVICE,service,serviceBundle); sendEvent(ServiceMgmtEventType.SERVICE_STARTED,service,serviceBundle); } else{ if(log.isDebugEnabled()) log.debug("It's a restart, but this service doesn't need security & privacy updates"); } } else{ log.debug("{} is stopped in the database, so this is a normal service start. We update the database.", service.getServiceName()); this.getServiceReg().changeStatusOfService(service.getServiceIdentifier(), ServiceStatus.STARTED); sendEvent(ServiceMgmtEventType.SERVICE_STARTED,service,serviceBundle); } //The service is now registered, so we update the hashmap if(ServiceControl.installingBundle(serviceBundle.getBundleId())){ log.debug("ServiceControl is installing the bundle {}, so we need to tell it it's done", serviceBundle.getBundleId()); ServiceControl.serviceInstalled(serviceBundle.getBundleId(), service); } } catch(Exception ex){ log.error("Exception occurred while trying to start a service: {}", ex.getMessage()); ex.printStackTrace(); } } private void stopService(Service service, Bundle serviceBundle){ log.debug("{} has been stopped in OSGI.",ServiceModelUtils.serviceResourceIdentifierToString(service.getServiceIdentifier())); try{ // Double check if it's not a device! if(!service.getServiceType().equals(ServiceType.DEVICE)){ log.debug("{} must be stopped in the database as well!", service.getServiceName()); this.getServiceReg().changeStatusOfService(service.getServiceIdentifier(), ServiceStatus.STOPPED); sendEvent(ServiceMgmtEventType.SERVICE_STOPPED,service,serviceBundle); //The service is now unregistered, so we update the hashmap if(ServiceControl.installingBundle(serviceBundle.getBundleId())){ log.debug("ServiceControl is stopping the bundle {}, so we need to tell it it's done", serviceBundle.getBundleId()); ServiceControl.serviceInstalled(serviceBundle.getBundleId(), service); } } else{ log.debug("{} is a Device, so we handle it a bit differently!"); sendEvent(ServiceMgmtEventType.SERVICE_STOPPED,service,serviceBundle); removeService(service,serviceBundle); } } catch(Exception ex){ log.error("Exception occurred while trying to stop a service: {}", ex.getMessage()); ex.printStackTrace(); } } private void removeService(Service service, Bundle serviceBundle){ log.debug("{} has been removed from OSGI.",ServiceModelUtils.serviceResourceIdentifierToString(service.getServiceIdentifier()));; List<Service> servicesToRemove = new ArrayList<Service>(); servicesToRemove.add(service); try { log.debug("Checking if service {} is shared with any CIS, and removing that association.", service.getServiceName()); List<String> cisSharedList = getServiceReg().retrieveCISSharedService(service.getServiceIdentifier()); if(!cisSharedList.isEmpty()){ for(String cisShared: cisSharedList){ log.debug("Removing {} sharing to CIS: {}", service.getServiceName(), cisShared); try { getServiceControl().unshareService(service, cisShared); } catch (ServiceControlException e) { log.error("Couldn't unshare {} from that CIS {}", service.getServiceName(), cisShared); e.printStackTrace(); } } } else{ log.debug("Service {} not shared with any CIS.", service.getServiceName()); } if(service.getServiceType().equals(ServiceType.THIRD_PARTY_SERVER)){ // We notify the Negotiation/Policy Provider log.debug("Removing the service {} from the Security Manager!", service.getServiceName()); getNegotiationProvider().removeService(service.getServiceIdentifier()); log.debug("Removing the service {} from Privacy Manager",service.getServiceName()); try{ getPrivacyManager().deletePrivacyPolicy(RequestorUtils.create(myId.getBareJid(), service.getServiceIdentifier())); } catch (PrivacyException e) { log.error("Exception while removing privacy policy: " + e.getMessage()); e.printStackTrace(); } if(service.getServiceInstance().getServiceImpl().getServiceClient() != null){ log.debug("{} has service clients we might need to clean!",service.getServiceName()); ServiceDownloader.cleanClients(serviceBundle.getSymbolicName(), myId.getIdentifier(), serviceDir); } } log.debug("Removing service {} from SOCIETIES Registry",service.getServiceName()); getServiceReg().unregisterServiceList(servicesToRemove); log.info("Service {} has been removed!",service.getServiceName()); sendEvent(ServiceMgmtEventType.SERVICE_REMOVED,service,serviceBundle); //The service is now registered, so we update the hashmap if(ServiceControl.uninstallingBundle(serviceBundle.getBundleId())){ if(log.isDebugEnabled()) log.debug("ServiceControl is uninstalling the bundle, so we need to tell it it's done"); ServiceControl.serviceUninstalled(serviceBundle.getBundleId(), service); } } catch(Exception ex){ log.error("Exception occurred while trying to uninstall a service: {}", ex.getMessage()); ex.printStackTrace(); } } private void sendEvent(ServiceMgmtEventType eventType, Service service, Bundle bundle){ log.debug("Sending event of type: {} for service {}", eventType,ServiceModelUtils.serviceResourceIdentifierToString(service.getServiceIdentifier())); ServiceModelUtils.sendServiceMgmtEvent(eventType, service, null, bundle, eventMgr); } private List<URL> getServiceClients(Service service, Bundle bundle){ log.debug("Trying to see if the service {} has serviceClients", service.getServiceName()); String serviceClient = service.getServiceInstance().getServiceImpl().getServiceClient(); Set<URL> clientList = new HashSet<URL>(); if(serviceClient != null){ log.debug("Supplied metadata says Service Client is: {}", serviceClient); String[] clients = serviceClient.split(" "); for(int k=0; k < clients.length; k++){ try { URL clientUrl = new URL(clients[k]); // We should verify if the URL is valid before passing it on... maybe later! clientList.add(clientUrl); } catch (MalformedURLException e) { log.error("Exception getting URL for metadata client!"); e.printStackTrace(); } } } else{ log.debug("Supplied metadata includes no clients"); } // Now we check inside the .jar or .war for clients! try{ String bundlePath = bundle.getLocation(); int index = bundlePath.indexOf('@'); bundlePath = bundlePath.substring(index+1); log.debug("Now we check for serviceClients inside: {}",bundlePath); File bundleFile = new File(new URI(bundlePath)); if(bundleFile.isDirectory()){ if(log.isDebugEnabled()) log.debug("OSGI expanded .jar, searching for clients directly..."); String clientDirPath = bundlePath + "/societies-client/"; File clientDir = new File(new URI(clientDirPath)); if(clientDir.exists() && clientDir.isDirectory()){ log.debug("Searching inside {}",clientDirPath); File[] clientFiles = clientDir.listFiles(); for(int i = 0; i < clientFiles.length ; i++){ String clientName = clientFiles[i].getName().toLowerCase(); if(clientFiles[i].isFile() && ( clientName.endsWith(".jar") || clientName.endsWith(".jar") || clientName.endsWith(".jar") )){ log.debug("Found a client: {}",clientName); clientList.add(clientFiles[i].toURI().toURL()); } } } } else { if(bundleFile.isFile()) { if(log.isDebugEnabled()) log.debug("OSGI didn't expand .jar, searching for clients inside..."); JarFile jarFile = new JarFile(bundleFile); Enumeration<JarEntry> jarEntries = jarFile.entries(); while(jarEntries.hasMoreElements()){ JarEntry jarEntry = jarEntries.nextElement(); String entryName = jarEntry.getName().toLowerCase(); if(entryName.contains("societies-client/") && !jarEntry.isDirectory() && (entryName.endsWith(".jar") || entryName.endsWith(".war") || entryName.endsWith(".apk"))){ String fileName = entryName.substring(entryName.lastIndexOf('/')+1); log.debug("Found a client inside jar: {} so trying to download!",fileName); URI storedClient = ServiceDownloader.storeClient(jarFile.getInputStream(jarEntry), fileName, bundle.getSymbolicName(), myId.getIdentifier(), getServiceDir()); if(storedClient == null){ log.debug("There was a problem storing this client locally, so we don't do anything..."); } else{ log.debug("Stored client {} at {}",fileName,storedClient.toString()); clientList.add(storedClient.toURL()); } } } } else{ if(log.isDebugEnabled()) log.debug("Couldn't get access service clients from inside bundle"); } } } catch(Exception ex){ log.error("Exception trying to get clients from inside jar: {}", ex.getMessage()); ex.printStackTrace(); } List<URL> result = new ArrayList<URL>(); if(!clientList.isEmpty()){ StringBuilder serviceClientList = new StringBuilder(); for(URL client : clientList){ result.add(client); serviceClientList.append(client.toString()).append(' '); } service.getServiceInstance().getServiceImpl().setServiceClient(serviceClientList.toString()); log.debug("Service Client List is now {}",service.getServiceInstance().getServiceImpl().getServiceClient()); } return result; } }