| /******************************************************************************* |
| * Copyright (c) 2010-2011 Composent, Inc. and others. All rights reserved. This |
| * program and the accompanying materials are made available under the terms of |
| * the Eclipse Public License v1.0 which accompanies this distribution, and is |
| * available at http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Composent, Inc. - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.ecf.osgi.services.remoteserviceadmin; |
| |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.security.PrivilegedActionException; |
| import java.security.PrivilegedExceptionAction; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.Dictionary; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.TreeMap; |
| import java.util.UUID; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.ISafeRunnable; |
| import org.eclipse.core.runtime.SafeRunner; |
| import org.eclipse.ecf.core.ContainerConnectException; |
| import org.eclipse.ecf.core.ContainerCreateException; |
| import org.eclipse.ecf.core.ContainerTypeDescription; |
| import org.eclipse.ecf.core.IContainer; |
| import org.eclipse.ecf.core.identity.ID; |
| import org.eclipse.ecf.core.identity.StringID; |
| import org.eclipse.ecf.core.util.ECFException; |
| import org.eclipse.ecf.internal.osgi.services.remoteserviceadmin.Activator; |
| import org.eclipse.ecf.internal.osgi.services.remoteserviceadmin.DebugOptions; |
| import org.eclipse.ecf.internal.osgi.services.remoteserviceadmin.LogUtility; |
| import org.eclipse.ecf.internal.osgi.services.remoteserviceadmin.PropertiesUtil; |
| import org.eclipse.ecf.remoteservice.IExtendedRemoteServiceRegistration; |
| import org.eclipse.ecf.remoteservice.IOSGiRemoteServiceContainerAdapter; |
| import org.eclipse.ecf.remoteservice.IRSAConsumerContainerAdapter; |
| import org.eclipse.ecf.remoteservice.IRemoteService; |
| import org.eclipse.ecf.remoteservice.IRemoteServiceContainer; |
| import org.eclipse.ecf.remoteservice.IRemoteServiceContainerAdapter; |
| import org.eclipse.ecf.remoteservice.IRemoteServiceID; |
| import org.eclipse.ecf.remoteservice.IRemoteServiceListener; |
| import org.eclipse.ecf.remoteservice.IRemoteServiceReference; |
| import org.eclipse.ecf.remoteservice.IRemoteServiceRegistration; |
| import org.eclipse.ecf.remoteservice.events.IRemoteServiceEvent; |
| import org.eclipse.ecf.remoteservice.events.IRemoteServiceUnregisteredEvent; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.BundleException; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.FrameworkUtil; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceEvent; |
| import org.osgi.framework.ServiceException; |
| import org.osgi.framework.ServiceFactory; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.framework.ServiceRegistration; |
| import org.osgi.framework.Version; |
| import org.osgi.framework.hooks.service.EventListenerHook; |
| import org.osgi.framework.hooks.service.ListenerHook.ListenerInfo; |
| import org.osgi.framework.wiring.BundleCapability; |
| import org.osgi.framework.wiring.BundleRevision; |
| import org.osgi.framework.wiring.BundleWire; |
| import org.osgi.framework.wiring.BundleWiring; |
| import org.osgi.service.event.Event; |
| import org.osgi.service.event.EventAdmin; |
| import org.osgi.service.remoteserviceadmin.EndpointPermission; |
| import org.osgi.service.remoteserviceadmin.RemoteServiceAdminListener; |
| import org.osgi.util.tracker.ServiceTracker; |
| |
| /** |
| * ECF implementation of <a |
| * href="http://www.osgi.org/download/r4v42/r4.enterprise.pdf">OSGI 4.2 Remote |
| * Service Admin service</a>. This service can be used by topology managers to |
| * to export and/or import remote services with any <a |
| * href="http://wiki.eclipse.org/ECF_Connection_Creation_and_Management">ECF |
| * container</a> that implements the <a |
| * href="http://wiki.eclipse.org/ECF/API_Docs#Remote_Services_API">ECF remote |
| * service API</a>. |
| */ |
| public class RemoteServiceAdmin implements |
| org.osgi.service.remoteserviceadmin.RemoteServiceAdmin { |
| |
| public static final String SERVICE_PROP = "org.eclipse.ecf.rsa"; //$NON-NLS-1$ |
| |
| private static final boolean disableServiceVersionChecking = new Boolean( |
| System.getProperty( |
| "org.eclipse.ecf.osgi.services.remoteserviceadmin.disableServiceVersionChecking", //$NON-NLS-1$ |
| "false")).booleanValue(); //$NON-NLS-1$ |
| |
| private Bundle clientBundle; |
| |
| private boolean hostAutoCreateContainer = new Boolean( |
| System.getProperty( |
| "org.eclipse.ecf.osgi.services.remoteserviceadmin.hostAutoCreateContainer", //$NON-NLS-1$ |
| "true")).booleanValue(); //$NON-NLS-1$ |
| private String[] hostDefaultConfigTypes = new String[] { System |
| .getProperty( |
| "org.eclipse.ecf.osgi.services.remoteserviceadmin.hostDefaultConfigType", //$NON-NLS-1$ |
| "ecf.generic.server") }; //$NON-NLS-1$ |
| |
| private boolean consumerAutoCreateContainer = new Boolean( |
| System.getProperty( |
| "org.eclipse.ecf.osgi.services.remoteserviceadmin.consumerAutoCreateContainer", //$NON-NLS-1$ |
| "true")).booleanValue(); //$NON-NLS-1$ |
| |
| private Object eventAdminTrackerLock = new Object(); |
| private ServiceTracker eventAdminTracker; |
| |
| private Object remoteServiceAdminListenerTrackerLock = new Object(); |
| private ServiceTracker remoteServiceAdminListenerTracker; |
| |
| private HostContainerSelector defaultHostContainerSelector; |
| private ServiceRegistration defaultHostContainerSelectorRegistration; |
| |
| private ConsumerContainerSelector defaultConsumerContainerSelector; |
| private ServiceRegistration defaultConsumerContainerSelectorRegistration; |
| |
| private Collection<org.osgi.service.remoteserviceadmin.ExportRegistration> exportedRegistrations; |
| private Collection<org.osgi.service.remoteserviceadmin.ImportRegistration> importedRegistrations; |
| |
| private Collection<ExportRegistration> localExportedRegistrations = new ArrayList<ExportRegistration>(); |
| private Collection<ImportRegistration> localImportedRegistrations = new ArrayList<ImportRegistration>(); |
| |
| private ServiceRegistration eventListenerHookRegistration; |
| |
| /** |
| * @return List of exported registrations |
| * @since 4.2 |
| */ |
| public List<ExportRegistration> getExportedRegistrations() { |
| synchronized (exportedRegistrations) { |
| return new ArrayList(exportedRegistrations); |
| } |
| } |
| |
| /** |
| * @return List of imported registrations |
| * @since 4.2 |
| */ |
| public List<ImportRegistration> getImportedRegistrations() { |
| synchronized (importedRegistrations) { |
| return new ArrayList(importedRegistrations); |
| } |
| } |
| |
| public RemoteServiceAdmin(Bundle clientBundle) { |
| this( |
| clientBundle, |
| new ArrayList<org.osgi.service.remoteserviceadmin.ExportRegistration>(), |
| new ArrayList<org.osgi.service.remoteserviceadmin.ImportRegistration>()); |
| } |
| |
| /** |
| * @param clientBundle client bundle for RemoteServiceAdmin instance |
| * @param exportedRegistrations of exported registrations |
| * @param importedRegistrations of imported registrations |
| * @since 4.1 |
| */ |
| public RemoteServiceAdmin(Bundle clientBundle, Collection<org.osgi.service.remoteserviceadmin.ExportRegistration> exportedRegistrations, Collection<org.osgi.service.remoteserviceadmin.ImportRegistration> importedRegistrations) { |
| this.clientBundle = clientBundle; |
| Assert.isNotNull(this.clientBundle); |
| this.exportedRegistrations = exportedRegistrations; |
| this.importedRegistrations = importedRegistrations; |
| // Only setup defaults if it hasn't already been done by some other |
| // Remote Service Admin instance |
| Properties props = new Properties(); |
| props.put(org.osgi.framework.Constants.SERVICE_RANKING, new Integer( |
| Integer.MIN_VALUE)); |
| // host container selector |
| ServiceReference[] hostContainerSelectorRefs = null; |
| BundleContext rsaBundleContext = getRSABundleContext(); |
| try { |
| hostContainerSelectorRefs = rsaBundleContext.getServiceReferences( |
| IHostContainerSelector.class.getName(), null); |
| } catch (InvalidSyntaxException e) { |
| // will not happen |
| } |
| // register a default only if no others already exist |
| if (hostContainerSelectorRefs == null |
| || hostContainerSelectorRefs.length == 0) { |
| defaultHostContainerSelector = new HostContainerSelector( |
| hostDefaultConfigTypes, hostAutoCreateContainer); |
| defaultHostContainerSelectorRegistration = rsaBundleContext |
| .registerService(IHostContainerSelector.class.getName(), |
| defaultHostContainerSelector, (Dictionary) props); |
| } |
| // consumer container selector |
| ServiceReference[] consumerContainerSelectorRefs = null; |
| try { |
| consumerContainerSelectorRefs = rsaBundleContext |
| .getServiceReferences( |
| IConsumerContainerSelector.class.getName(), null); |
| } catch (InvalidSyntaxException e) { |
| // will not happen |
| } |
| // register a default only if no others already exist |
| if (consumerContainerSelectorRefs == null |
| || consumerContainerSelectorRefs.length == 0) { |
| defaultConsumerContainerSelector = new ConsumerContainerSelector( |
| consumerAutoCreateContainer); |
| defaultConsumerContainerSelectorRegistration = rsaBundleContext |
| .registerService( |
| IConsumerContainerSelector.class.getName(), |
| defaultConsumerContainerSelector, |
| (Dictionary) props); |
| } |
| |
| eventListenerHookRegistration = rsaBundleContext.registerService( |
| EventListenerHook.class.getName(), new RSAEventListenerHook(), |
| null); |
| } |
| |
| private void handleServiceUnregistering(ServiceReference serviceReference) { |
| List<ExportRegistration> ers = getExportedRegistrations(); |
| for (ExportRegistration exportedRegistration : ers) { |
| if (exportedRegistration.match(serviceReference)) { |
| trace("handleServiceUnregistering", "closing exportRegistration for serviceReference=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + serviceReference); |
| exportedRegistration.close(); |
| } |
| } |
| } |
| |
| class RSAEventListenerHook implements EventListenerHook { |
| public void event(ServiceEvent event, |
| Map<BundleContext, Collection<ListenerInfo>> listeners) { |
| switch (event.getType()) { |
| case ServiceEvent.UNREGISTERING: |
| handleServiceUnregistering(event.getServiceReference()); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| private boolean validExportedInterfaces(ServiceReference serviceReference, |
| String[] exportedInterfaces) { |
| if (exportedInterfaces == null || exportedInterfaces.length == 0) |
| return false; |
| List<String> objectClassList = Arrays |
| .asList((String[]) serviceReference |
| .getProperty(org.osgi.framework.Constants.OBJECTCLASS)); |
| for (int i = 0; i < exportedInterfaces.length; i++) |
| if (!objectClassList.contains(exportedInterfaces[i])) |
| return false; |
| return true; |
| } |
| |
| // RemoteServiceAdmin service interface impl methods |
| public Collection<org.osgi.service.remoteserviceadmin.ExportRegistration> exportService( |
| final ServiceReference<?> serviceReference, Map<String, ?> op) { |
| trace("exportService", "serviceReference=" + serviceReference //$NON-NLS-1$ //$NON-NLS-2$ |
| + ",properties=" + op); //$NON-NLS-1$ |
| |
| final Map<String, ?> overridingProperties = PropertiesUtil |
| .mergeProperties(serviceReference, |
| op == null ? Collections.EMPTY_MAP : op); |
| // get exported interfaces |
| final String[] exportedInterfaces = PropertiesUtil |
| .getExportedInterfaces(serviceReference, overridingProperties); |
| if (exportedInterfaces == null) |
| throw new IllegalArgumentException( |
| org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_EXPORTED_INTERFACES |
| + " not set"); //$NON-NLS-1$ |
| // verifyExportedInterfaces |
| if (!validExportedInterfaces(serviceReference, exportedInterfaces)) |
| return Collections.EMPTY_LIST; |
| // Get optional exported configs |
| String[] ecs = PropertiesUtil |
| .getStringArrayFromPropertyValue(overridingProperties |
| .get(org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_EXPORTED_CONFIGS)); |
| if (ecs == null) { |
| ecs = PropertiesUtil |
| .getStringArrayFromPropertyValue(serviceReference |
| .getProperty(org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_EXPORTED_CONFIGS)); |
| } |
| final String[] exportedConfigs = ecs; |
| // Get all intents (service.intents, service.exported.intents, |
| // service.exported.intents.extra) |
| final String[] serviceIntents = PropertiesUtil.getServiceIntents( |
| serviceReference, overridingProperties); |
| |
| // Create result registrations. This collection will be returned |
| Collection<ExportRegistration> resultRegistrations = new ArrayList<ExportRegistration>(); |
| |
| // check for previously exported registration for the serviceReference |
| synchronized (exportedRegistrations) { |
| ExportEndpoint exportEndpoint = findExistingExportEndpoint( |
| serviceReference, null); |
| // If found then create a second ExportRegistration from endpoint |
| if (exportEndpoint != null) { |
| trace("exportService", "serviceReference=" + serviceReference + " export endpoint already exists=" + exportEndpoint + ". Returning new ExportRegistration for existing endpoint"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| ExportRegistration reg = new ExportRegistration(exportEndpoint); |
| addExportRegistration(reg); |
| resultRegistrations.add(reg); |
| } |
| } |
| // If the serviceReference hasn't already been exported before (above) |
| if (resultRegistrations.size() == 0) { |
| // Get a host container selector |
| final IHostContainerSelector hostContainerSelector = getHostContainerSelector(); |
| // and use it to select ECF remote service containers that match given exported |
| // interfaces, configs, and intents |
| IRemoteServiceContainer[] rsContainers = null; |
| try { |
| rsContainers = AccessController |
| .doPrivileged(new PrivilegedExceptionAction() { |
| public Object run() throws SelectContainerException { |
| return hostContainerSelector |
| .selectHostContainers( |
| serviceReference, |
| (Map<String, Object>) overridingProperties, |
| exportedInterfaces, |
| exportedConfigs, serviceIntents); |
| } |
| }); |
| } catch (PrivilegedActionException e) { |
| Exception except = e.getException(); |
| // see discussion on osgi bug https://www.osgi.org/members/bugzilla/show_bug.cgi?id=2591 |
| String errorMessage = "Failed to select host container"; //$NON-NLS-1$ |
| if (except instanceof SelectContainerException) { |
| SelectContainerException sce = (SelectContainerException) except; |
| Throwable sceCause = sce.getCause(); |
| if (sceCause instanceof ContainerCreateException) { |
| // Some dummy props need to be set to allow the creation of a dummy export registration |
| Map<String,Object> props = new HashMap<String,Object>(overridingProperties); |
| props.put(org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_ID, "0"); //$NON-NLS-1$ |
| props.put(org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_IMPORTED_CONFIGS, "import.error.config"); //$NON-NLS-1$ |
| props.put(RemoteConstants.ENDPOINT_ID,"export.error.id"); //$NON-NLS-1$ |
| props.put(RemoteConstants.ENDPOINT_CONTAINER_ID_NAMESPACE, StringID.class.getName()); |
| ExportRegistration errorRegistration = new RemoteServiceAdmin.ExportRegistration(sceCause, |
| new EndpointDescription(serviceReference,props)); |
| addExportRegistration(errorRegistration); |
| resultRegistrations.add(errorRegistration); |
| } else |
| throw new IllegalArgumentException(errorMessage, except); |
| } else |
| throw new IllegalArgumentException(errorMessage, except); |
| } |
| // If no registration exist (no errorRegistration added above) |
| if (resultRegistrations.size() == 0) { |
| // If no containers found above, log warning and return |
| if (rsContainers == null || rsContainers.length == 0) { |
| String errorMessage = "No containers found for serviceReference=" //$NON-NLS-1$ |
| + serviceReference |
| + " properties=" + overridingProperties + ". Remote service NOT EXPORTED"; //$NON-NLS-1$//$NON-NLS-2$ |
| logWarning("exportService", errorMessage); //$NON-NLS-1$ |
| return Collections.EMPTY_LIST; |
| } |
| // actually do the export |
| synchronized (exportedRegistrations) { |
| // For all selected containers |
| for (int i = 0; i < rsContainers.length; i++) { |
| Map endpointDescriptionProperties = createExportEndpointDescriptionProperties( |
| serviceReference, |
| (Map<String, Object>) overridingProperties, |
| exportedInterfaces, serviceIntents, |
| rsContainers[i]); |
| // otherwise, actually export the service to create |
| // a new ExportEndpoint and use it to create a new |
| // ExportRegistration |
| EndpointDescription endpointDescription = new EndpointDescription(endpointDescriptionProperties); |
| |
| checkEndpointPermission(endpointDescription, |
| EndpointPermission.EXPORT); |
| |
| ExportRegistration exportRegistration = null; |
| |
| try { |
| // Actually do the export and return export |
| // registration |
| exportRegistration = exportService( |
| serviceReference, overridingProperties, |
| exportedInterfaces, rsContainers[i], |
| endpointDescriptionProperties); |
| } catch (Exception e) { |
| exportRegistration = new ExportRegistration(e, |
| endpointDescription); |
| } |
| |
| addExportRegistration(exportRegistration); |
| // We add it to the results in either success or error case |
| resultRegistrations.add(exportRegistration); |
| } |
| } |
| } |
| } |
| |
| // publish all activeExportRegistrations |
| for (ExportRegistration exportReg : resultRegistrations) |
| publishExportEvent(exportReg); |
| |
| trace("exportService","exported registrations="+resultRegistrations); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| // and return |
| return new ArrayList<org.osgi.service.remoteserviceadmin.ExportRegistration>( |
| resultRegistrations); |
| } |
| |
| public org.osgi.service.remoteserviceadmin.ImportRegistration importService( |
| org.osgi.service.remoteserviceadmin.EndpointDescription endpointDescription) { |
| |
| trace("importService", "endpointDescription=" + endpointDescription); //$NON-NLS-1$ //$NON-NLS-2$ |
| // First, make sure that the client bundle has the IMPORT endpoint |
| // permission |
| checkEndpointPermission(endpointDescription, EndpointPermission.IMPORT); |
| final EndpointDescription ed = (endpointDescription instanceof EndpointDescription) ? (EndpointDescription) endpointDescription |
| : new EndpointDescription(endpointDescription.getProperties()); |
| // Now get IConsumerContainerSelector, to select the ECF container |
| // for the given endpointDescription |
| final IConsumerContainerSelector consumerContainerSelector = getConsumerContainerSelector(); |
| // If there is none, then we can go no further |
| if (consumerContainerSelector == null) { |
| String errorMessage = "No consumerContainerSelector available"; //$NON-NLS-1$ |
| logError("importService",errorMessage,new SelectContainerException(errorMessage,null,null)); //$NON-NLS-1$ |
| // As specified in section 122.5.2, return null |
| return null; |
| } |
| // Select the rsContainer to handle the endpoint description |
| IRemoteServiceContainer rsContainer = null; |
| ImportRegistration importRegistration = null; |
| try { |
| rsContainer = AccessController |
| .doPrivileged(new PrivilegedExceptionAction<IRemoteServiceContainer>() { |
| public IRemoteServiceContainer run() |
| throws SelectContainerException { |
| return consumerContainerSelector |
| .selectConsumerContainer(ed); |
| } |
| }); |
| } catch (PrivilegedActionException e) { |
| logError("importService","Unexpected exception in selectConsumerContainer",e.getException()); //$NON-NLS-1$ //$NON-NLS-2$ |
| importRegistration = new ImportRegistration(ed, e.getException()); |
| } catch (Exception e) { |
| logError("importService","Unexpected exception in selectConsumerContainer",e); //$NON-NLS-1$ //$NON-NLS-2$ |
| importRegistration = new ImportRegistration(ed, e); |
| } |
| // If none found, log an error and return null |
| if (rsContainer == null && importRegistration == null) { |
| String errorMessage = "No remote service container selected for endpoint=" //$NON-NLS-1$ |
| + endpointDescription |
| + ". Remote service NOT IMPORTED"; //$NON-NLS-1$ |
| logError("importService",errorMessage,new SelectContainerException(errorMessage,null,null)); //$NON-NLS-1$ |
| // As specified in section 122.5.2, return null |
| return null; |
| } |
| |
| // If one selected then import the service to create an import |
| // registration |
| synchronized (importedRegistrations) { |
| if (importRegistration == null) { |
| ImportEndpoint importEndpoint = findImportEndpoint(ed); |
| importRegistration = ((importEndpoint != null) ? new ImportRegistration(importEndpoint) |
| : importService(ed, rsContainer)); |
| } |
| addImportRegistration(importRegistration); |
| } |
| // publish import event |
| publishImportEvent(importRegistration); |
| trace("importService","importRegistration="+importRegistration); //$NON-NLS-1$ //$NON-NLS-2$ |
| // Finally, return the importRegistration. It may be null or not. |
| return importRegistration; |
| } |
| |
| public Collection<org.osgi.service.remoteserviceadmin.ExportReference> getExportedServices() { |
| Collection<org.osgi.service.remoteserviceadmin.ExportReference> results = new ArrayList<org.osgi.service.remoteserviceadmin.ExportReference>(); |
| synchronized (exportedRegistrations) { |
| // XXX The spec doesn't specify what is supposed to happen |
| // when the registrations is empty...but the TCK test method: RemoteServiceAdminSecure.testNoPermissions() |
| // assumes that a SecurityException is thrown when accessed without READ permission |
| if (exportedRegistrations.isEmpty()) |
| checkRSAReadAccess(); |
| for (org.osgi.service.remoteserviceadmin.ExportRegistration reg : exportedRegistrations) { |
| org.osgi.service.remoteserviceadmin.ExportReference eRef = reg |
| .getExportReference(); |
| if (eRef != null |
| && checkEndpointPermissionRead("getExportedServices", //$NON-NLS-1$ |
| eRef.getExportedEndpoint())) |
| results.add(eRef); |
| } |
| } |
| return results; |
| } |
| |
| private void checkRSAReadAccess() { |
| Map<String, Object> props = new HashMap(); |
| props.put( |
| org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_ID, |
| UUID.randomUUID().toString()); |
| props.put(org.osgi.framework.Constants.OBJECTCLASS, new String[] { UUID.randomUUID().toString() }); |
| props.put(org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_IMPORTED_CONFIGS, UUID.randomUUID().toString()); |
| checkEndpointPermission(new org.osgi.service.remoteserviceadmin.EndpointDescription( |
| props),org.osgi.service.remoteserviceadmin.EndpointPermission.READ); |
| } |
| |
| public Collection<org.osgi.service.remoteserviceadmin.ImportReference> getImportedEndpoints() { |
| Collection<org.osgi.service.remoteserviceadmin.ImportReference> results = new ArrayList<org.osgi.service.remoteserviceadmin.ImportReference>(); |
| synchronized (importedRegistrations) { |
| // XXX The spec doesn't specify what is supposed to happen |
| // when the registrations is empty...but the TCK test method: RemoteServiceAdminSecure.testNoPermissions() |
| // assumes that a SecurityException is thrown when accessed without READ permission |
| if (importedRegistrations.isEmpty()) |
| checkRSAReadAccess(); |
| for (org.osgi.service.remoteserviceadmin.ImportRegistration reg : importedRegistrations) { |
| org.osgi.service.remoteserviceadmin.ImportReference iRef = reg |
| .getImportReference(); |
| if (iRef != null |
| && checkEndpointPermissionRead("getImportedEndpoints", //$NON-NLS-1$ |
| iRef.getImportedEndpoint())) |
| results.add(iRef); |
| } |
| } |
| return results; |
| } |
| |
| // end RemoteServiceAdmin service interface impl methods |
| |
| private boolean checkEndpointPermissionRead( |
| String methodName, |
| org.osgi.service.remoteserviceadmin.EndpointDescription endpointDescription) { |
| try { |
| checkEndpointPermission(endpointDescription, |
| EndpointPermission.READ); |
| return true; |
| } catch (SecurityException e) { |
| logError(methodName, |
| "permission check failed for read access to endpointDescription=" //$NON-NLS-1$ |
| + endpointDescription, e); |
| return false; |
| } |
| } |
| |
| private BundleContext getClientBundleContext() { |
| return clientBundle.getBundleContext(); |
| } |
| |
| private BundleContext getRSABundleContext() { |
| return Activator.getContext(); |
| } |
| |
| private Bundle getRSABundle() { |
| BundleContext bc = Activator.getContext(); |
| if (bc == null) return null; |
| return bc.getBundle(); |
| } |
| |
| private void addImportRegistration(ImportRegistration importRegistration) { |
| synchronized (importedRegistrations) { |
| importedRegistrations.add(importRegistration); |
| localImportedRegistrations.add(importRegistration); |
| } |
| } |
| |
| private void addExportRegistration(ExportRegistration exportRegistration) { |
| synchronized (exportedRegistrations) { |
| exportedRegistrations.add(exportRegistration); |
| localExportedRegistrations.add(exportRegistration); |
| } |
| } |
| |
| private boolean removeExportRegistration( |
| ExportRegistration exportRegistration) { |
| synchronized (exportedRegistrations) { |
| localExportedRegistrations.remove(exportRegistration); |
| return exportedRegistrations.remove(exportRegistration); |
| } |
| } |
| |
| private boolean removeImportRegistration( |
| ImportRegistration importRegistration) { |
| synchronized (importedRegistrations) { |
| localExportedRegistrations.remove(importRegistration); |
| return importedRegistrations.remove(importRegistration); |
| } |
| } |
| |
| private void checkEndpointPermission( |
| org.osgi.service.remoteserviceadmin.EndpointDescription endpointDescription, |
| String permissionType) throws SecurityException { |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm == null) |
| return; |
| sm.checkPermission(new EndpointPermission(endpointDescription, |
| Activator.getDefault().getFrameworkUUID(), permissionType)); |
| } |
| |
| class ExportEndpoint { |
| |
| private ServiceReference serviceReference; |
| private EndpointDescription endpointDescription; |
| |
| private IRemoteServiceRegistration rsRegistration; |
| private Set<ExportRegistration> activeExportRegistrations = new HashSet<ExportRegistration>(); |
| |
| private Map<String,Object> originalProperties; |
| |
| public String toString() { |
| StringBuffer buf = new StringBuffer("ExportEndpoint["); //$NON-NLS-1$ |
| buf.append("serviceReference=").append(serviceReference).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buf.append("rsRegistration=").append(rsRegistration).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| return buf.toString(); |
| } |
| |
| ExportEndpoint(ServiceReference serviceReference, |
| EndpointDescription endpointDescription, |
| IRemoteServiceRegistration reg, Map<String,Object> originalProperties) { |
| Assert.isNotNull(serviceReference); |
| this.serviceReference = serviceReference; |
| Assert.isNotNull(endpointDescription); |
| this.endpointDescription = endpointDescription; |
| Assert.isNotNull(reg); |
| this.rsRegistration = reg; |
| Assert.isNotNull(originalProperties); |
| this.originalProperties = originalProperties; |
| } |
| |
| synchronized ID getContainerID() { |
| return endpointDescription.getContainerID(); |
| } |
| |
| synchronized ServiceReference getServiceReference() { |
| return serviceReference; |
| } |
| |
| synchronized EndpointDescription getEndpointDescription() { |
| return endpointDescription; |
| } |
| |
| synchronized IRemoteServiceRegistration getRemoteServiceRegistration() { |
| return rsRegistration; |
| } |
| |
| synchronized boolean addExportRegistration( |
| ExportRegistration exportRegistration) { |
| return this.activeExportRegistrations.add(exportRegistration); |
| } |
| |
| synchronized boolean close(ExportRegistration exportRegistration) { |
| boolean removed = this.activeExportRegistrations |
| .remove(exportRegistration); |
| if (removed && activeExportRegistrations.size() == 0) { |
| if (rsRegistration != null) { |
| rsRegistration.unregister(); |
| rsRegistration = null; |
| } |
| serviceReference = null; |
| endpointDescription = null; |
| originalProperties = null; |
| } |
| return removed; |
| } |
| |
| synchronized EndpointDescription update(Map properties) { |
| // As per ExportRegistraiton.update javadocs, query the |
| // serviceReference for current properties |
| Map<String, Object> serviceReferenceProperties = PropertiesUtil |
| .copyProperties(serviceReference, new HashMap()); |
| // As per ExportRegistration.update javadocs, if properties argument |
| // is null, |
| // use the original ED properties |
| // Get copy of original remote service properties |
| Map<String, Object> rsProperties = PropertiesUtil.copyProperties( |
| this.originalProperties, new HashMap<String, Object>()); |
| Map<String, Object> updateProperties = (properties == null) ? rsProperties |
| : PropertiesUtil.copyProperties(properties, rsProperties); |
| Map<String, Object> updatedEDProperties = PropertiesUtil |
| .mergeProperties(updateProperties, |
| serviceReferenceProperties); |
| // update timestamp |
| updatedEDProperties.put(RemoteConstants.ENDPOINT_TIMESTAMP, |
| System.currentTimeMillis()); |
| // Create new endpoint description, and this will be our updated |
| // EndpointDescription |
| this.endpointDescription = new EndpointDescription( |
| updatedEDProperties); |
| return this.endpointDescription; |
| } |
| } |
| |
| /** |
| * @since 4.2 |
| */ |
| public class ExportRegistration implements |
| org.osgi.service.remoteserviceadmin.ExportRegistration { |
| |
| private ExportReference exportReference; |
| |
| private boolean closed = false; |
| |
| public String toString() { |
| StringBuffer buf = new StringBuffer("ExportRegistration["); //$NON-NLS-1$ |
| buf.append("exportReference=").append(exportReference).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buf.append("closed=").append(closed).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| return buf.toString(); |
| } |
| |
| ExportRegistration(ExportEndpoint exportEndpoint) { |
| Assert.isNotNull(exportEndpoint); |
| exportEndpoint.addExportRegistration(this); |
| this.exportReference = new ExportReference(exportEndpoint); |
| } |
| |
| ExportRegistration(Throwable exception, |
| EndpointDescription errorEndpointDescription) { |
| Assert.isNotNull(exception); |
| this.exportReference = new ExportReference(exception, |
| errorEndpointDescription); |
| } |
| |
| public ID getContainerID() { |
| return (closed)?null:exportReference.getContainerID(); |
| } |
| |
| ServiceReference getServiceReference() { |
| return (closed)?null:exportReference.getExportedService(); |
| } |
| |
| public long getRemoteServiceId() { |
| return (closed) ? 0 : exportReference.getRemoteServiceId(); |
| } |
| |
| public org.osgi.service.remoteserviceadmin.ExportReference getExportReference() { |
| Throwable t = getException(); |
| if (t != null) |
| return null; |
| return (closed)?null:exportReference; |
| } |
| |
| boolean match(ServiceReference serviceReference) { |
| return match(serviceReference, null); |
| } |
| |
| boolean match(ServiceReference serviceReference, ID containerID) { |
| ServiceReference ourServiceReference = getServiceReference(); |
| if (ourServiceReference == null) |
| return false; |
| boolean serviceReferenceCompare = ourServiceReference |
| .equals(serviceReference); |
| // If the second parameter is null, then we compare only on service |
| // references |
| if (containerID == null) |
| return serviceReferenceCompare; |
| ID ourContainerID = getContainerID(); |
| if (ourContainerID == null) |
| return false; |
| return serviceReferenceCompare |
| && ourContainerID.equals(containerID); |
| } |
| |
| synchronized ExportEndpoint getExportEndpoint( |
| ServiceReference serviceReference, ID containerID) { |
| return (closed?null:(match(serviceReference, containerID) ? exportReference |
| .getExportEndpoint() : null)); |
| } |
| |
| IRemoteServiceRegistration getRemoteServiceRegistration() { |
| return (closed)?null:exportReference.getRemoteServiceRegistration(); |
| } |
| |
| EndpointDescription getEndpointDescription() { |
| return (closed)?null:exportReference.getEndpointDescription(); |
| } |
| |
| public void close() { |
| boolean publish = false; |
| ID containerID = null; |
| Throwable exception = null; |
| EndpointDescription endpointDescription = null; |
| ExportReference exRef = null; |
| synchronized (this) { |
| // Only do this once |
| if (!closed) { |
| containerID = getContainerID(); |
| exception = getException(); |
| endpointDescription = getEndpointDescription(); |
| exRef = this.exportReference; |
| publish = exportReference.close(this); |
| this.exportReference = null; |
| closed = true; |
| } |
| } |
| removeExportRegistration(this); |
| Bundle rsaBundle = getRSABundle(); |
| // Only publish events |
| if (publish && rsaBundle != null && exRef != null) |
| publishEvent(new RemoteServiceAdminEvent(containerID, |
| RemoteServiceAdminEvent.EXPORT_UNREGISTRATION, |
| rsaBundle, exRef, exception, |
| endpointDescription), endpointDescription); |
| } |
| |
| public Throwable getException() { |
| return (closed)?updateException:exportReference.getException(); |
| } |
| |
| private Throwable updateException; |
| |
| public org.osgi.service.remoteserviceadmin.EndpointDescription update( |
| Map<String, ?> properties) { |
| // If this registration has been closed then set updateException |
| // to IllegalStateException and return null |
| if (closed) { |
| updateException = new IllegalStateException("Update failed since ExportRegistration already closed"); //$NON-NLS-1$ |
| return null; |
| } |
| // Update exportReference. If exception is thrown, or update |
| // returns null then set updateException and return null; |
| EndpointDescription updatedED = null; |
| |
| Map<String, Object> props = PropertiesUtil.copySerializableProperties(properties, |
| new TreeMap<String, Object>()); |
| |
| try { |
| updatedED = exportReference.update(props); |
| } catch (RuntimeException e) { |
| updateException = e; |
| return null; |
| } |
| // If the exportReference returned null, then the underlying ExportEndpoint was null |
| if (updatedED == null) { |
| updateException = new IllegalStateException("Update failed because ExportEndpoint was null"); //$NON-NLS-1$ |
| return null; |
| } |
| // We've succeeded in the update to set updateException to null |
| // in case it was set by previous update |
| this.updateException = null; |
| Bundle rsaBundle = getRSABundle(); |
| // Notify with EXPORT_UPDATE |
| if (rsaBundle != null) |
| publishEvent(new RemoteServiceAdminEvent(getContainerID(), |
| RemoteServiceAdminEvent.EXPORT_UPDATE, |
| rsaBundle, this.exportReference, null, updatedED), updatedED); |
| return updatedED; |
| } |
| |
| } |
| |
| /** |
| * @since 4.2 |
| */ |
| public class ExportReference implements |
| org.osgi.service.remoteserviceadmin.ExportReference { |
| |
| private ExportEndpoint exportEndpoint; |
| |
| private Throwable exception; |
| private EndpointDescription errorEndpointDescription; |
| |
| public String toString() { |
| StringBuffer buf = new StringBuffer("ExportReference["); //$NON-NLS-1$ |
| buf.append("exportEndpoint="+exportEndpoint).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buf.append("exception=").append(exception).append(";").append("]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| return buf.toString(); |
| } |
| |
| ExportReference(ExportEndpoint exportEndpoint) { |
| Assert.isNotNull(exportEndpoint); |
| this.exportEndpoint = exportEndpoint; |
| } |
| |
| synchronized EndpointDescription update(Map<String, ?> properties) { |
| if (exportEndpoint == null) return null; |
| return exportEndpoint.update(properties); |
| } |
| |
| ExportReference(Throwable exception, |
| EndpointDescription errorEndpointDescription) { |
| Assert.isNotNull(exception); |
| this.exception = exception; |
| Assert.isNotNull(exception); |
| this.errorEndpointDescription = errorEndpointDescription; |
| } |
| |
| synchronized Throwable getException() { |
| return exception; |
| } |
| |
| synchronized boolean close(ExportRegistration exportRegistration) { |
| if (exportEndpoint == null) |
| return false; |
| boolean result = exportEndpoint.close(exportRegistration); |
| exportEndpoint = null; |
| return result; |
| } |
| |
| synchronized ExportEndpoint getExportEndpoint() { |
| return exportEndpoint; |
| } |
| |
| synchronized IRemoteServiceRegistration getRemoteServiceRegistration() { |
| return (exportEndpoint == null) ? null : exportEndpoint |
| .getRemoteServiceRegistration(); |
| } |
| |
| public synchronized ID getContainerID() { |
| return (exportEndpoint == null) ? null : exportEndpoint |
| .getContainerID(); |
| } |
| |
| public synchronized long getRemoteServiceId() { |
| IRemoteServiceRegistration r = getRemoteServiceRegistration(); |
| return (r == null)?0:r.getID().getContainerRelativeID(); |
| } |
| |
| public synchronized ServiceReference getExportedService() { |
| return (exportEndpoint == null) ? null : exportEndpoint |
| .getServiceReference(); |
| } |
| |
| public synchronized org.osgi.service.remoteserviceadmin.EndpointDescription getExportedEndpoint() { |
| return (exportEndpoint == null) ? null : exportEndpoint |
| .getEndpointDescription(); |
| } |
| |
| synchronized EndpointDescription getEndpointDescription() { |
| return (exportEndpoint == null) ? errorEndpointDescription |
| : exportEndpoint.getEndpointDescription(); |
| } |
| |
| } |
| |
| class ImportEndpoint { |
| |
| private IRemoteServiceContainer rsContainer; |
| private IRemoteService rs; |
| private IRemoteServiceListener rsListener; |
| private EndpointDescription endpointDescription; |
| private IRemoteServiceReference rsReference; |
| private ServiceRegistration proxyRegistration; |
| private Set<ImportRegistration> activeImportRegistrations = new HashSet<ImportRegistration>(); |
| |
| public String toString() { |
| StringBuffer buf = new StringBuffer("ImportEndpoint["); //$NON-NLS-1$ |
| buf.append("proxyRegistration=").append(proxyRegistration); //$NON-NLS-1$ |
| buf.append("rsReference=").append(rsReference).append(";").append("]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| return buf.toString(); |
| } |
| |
| ImportEndpoint(IRemoteServiceContainer rsContainer, |
| IRemoteServiceReference rsReference, |
| IRemoteService rs, |
| ServiceRegistration proxyRegistration, |
| EndpointDescription endpointDescription) { |
| this.rsContainer = rsContainer; |
| this.rsReference = rsReference; |
| this.endpointDescription = endpointDescription; |
| this.rs = rs; |
| this.proxyRegistration = proxyRegistration; |
| this.rsListener = new RemoteServiceListener(); |
| // Add the remoteservice listener to the container adapter, so that |
| // the rsListener notified asynchronously if our underlying remote |
| // service reference is unregistered locally due to disconnect or remote |
| // ejection |
| this.rsContainer.getContainerAdapter().addRemoteServiceListener(this.rsListener); |
| } |
| |
| synchronized EndpointDescription getEndpointDescription() { |
| return endpointDescription; |
| } |
| |
| synchronized ServiceRegistration getProxyRegistration() { |
| return proxyRegistration; |
| } |
| |
| synchronized ID getContainerID() { |
| return (rsReference == null) ? null : rsReference.getContainerID(); |
| } |
| |
| synchronized boolean addImportRegistration( |
| ImportRegistration importRegistration) { |
| return this.activeImportRegistrations.add(importRegistration); |
| } |
| |
| synchronized boolean close(ImportRegistration importRegistration) { |
| boolean removed = this.activeImportRegistrations |
| .remove(importRegistration); |
| if (removed && activeImportRegistrations.size() == 0) { |
| if (proxyRegistration != null) { |
| try { |
| proxyRegistration.unregister(); |
| } catch (Throwable t) { |
| // do nothing |
| } |
| proxyRegistration = null; |
| } |
| IRemoteServiceContainerAdapter rsContainerAdapter = rsContainer.getContainerAdapter(); |
| if (rsContainerAdapter != null) { |
| if (rsReference != null) { |
| rsContainerAdapter.ungetRemoteService(rsReference); |
| rsReference = null; |
| } |
| if (rsListener != null) { |
| rsContainerAdapter |
| .removeRemoteServiceListener(rsListener); |
| rsListener = null; |
| } |
| } |
| rs = null; |
| endpointDescription = null; |
| rsContainer = null; |
| } |
| return removed; |
| } |
| |
| synchronized boolean match(IRemoteServiceID remoteServiceID) { |
| if (remoteServiceID == null || rsReference == null) |
| return false; |
| return rsReference.getID().equals(remoteServiceID); |
| } |
| |
| synchronized boolean match(EndpointDescription ed) { |
| if (activeImportRegistrations.size() == 0) |
| return false; |
| return this.endpointDescription.isSameService(ed); |
| } |
| |
| synchronized void update( |
| org.osgi.service.remoteserviceadmin.EndpointDescription endpoint) { |
| if (proxyRegistration == null) |
| return; |
| // Get or create ECF endpoint description |
| EndpointDescription updatedEndpoint = (endpoint instanceof EndpointDescription) ? ((EndpointDescription) endpoint) |
| : new EndpointDescription(endpoint.getProperties()); |
| // Create new proxy properties from updatedEndpoint and rsReference and rs |
| Map newProxyProperties = createProxyProperties(rsContainer.getContainer().getID(), updatedEndpoint, |
| rsReference, rs); |
| // set the endpoint description with the proxy properties |
| updatedEndpoint.setPropertiesOverrides(newProxyProperties); |
| // set this endpointDescription to updatedEndpoint |
| this.endpointDescription = updatedEndpoint; |
| // Set proxyRegistration properties |
| this.proxyRegistration.setProperties(PropertiesUtil |
| .createDictionaryFromMap(newProxyProperties)); |
| } |
| } |
| |
| /** |
| * @since 4.2 |
| */ |
| public class ImportRegistration implements |
| org.osgi.service.remoteserviceadmin.ImportRegistration { |
| |
| private ImportReference importReference; |
| |
| private boolean closed = false; |
| |
| public String toString() { |
| StringBuffer buf = new StringBuffer("ImportRegistration["); //$NON-NLS-1$ |
| buf.append("importReference=").append(importReference).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buf.append("closed=").append(closed).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| return buf.toString(); |
| } |
| |
| ImportRegistration(ImportEndpoint importEndpoint) { |
| Assert.isNotNull(importEndpoint); |
| importEndpoint.addImportRegistration(this); |
| this.importReference = new ImportReference(importEndpoint); |
| } |
| |
| ImportRegistration(EndpointDescription errorEndpointDescription, |
| Throwable exception) { |
| this.importReference = new ImportReference( |
| errorEndpointDescription, exception); |
| } |
| |
| public ID getContainerID() { |
| return (closed)?null:importReference.getContainerID(); |
| } |
| |
| public long getRemoteServiceId() { |
| return (closed)?0:importReference.getRemoteServiceId(); |
| } |
| |
| EndpointDescription getEndpointDescription() { |
| return (closed)?null:importReference.getEndpointDescription(); |
| } |
| |
| boolean match(IRemoteServiceID remoteServiceID) { |
| return (closed)?null:importReference.match(remoteServiceID); |
| } |
| |
| boolean match(EndpointDescription ed) { |
| return (getImportEndpoint(ed) != null); |
| } |
| |
| ImportEndpoint getImportEndpoint(EndpointDescription ed) { |
| return (closed)?null:importReference.match(ed); |
| } |
| |
| public org.osgi.service.remoteserviceadmin.ImportReference getImportReference() { |
| Throwable t = getException(); |
| if (t != null) |
| return null; |
| return (closed)?null:importReference; |
| } |
| |
| public void close() { |
| boolean publish = false; |
| ID containerID = null; |
| Throwable exception = null; |
| EndpointDescription endpointDescription = null; |
| ImportReference imRef = null; |
| synchronized (this) { |
| // only do this once |
| if (!closed) { |
| containerID = getContainerID(); |
| exception = getException(); |
| endpointDescription = getEndpointDescription(); |
| imRef = this.importReference; |
| publish = importReference.close(this); |
| this.importReference = null; |
| closed = true; |
| } |
| } |
| removeImportRegistration(this); |
| Bundle rsaBundle = getRSABundle(); |
| if (publish && rsaBundle != null && imRef != null) |
| publishEvent(new RemoteServiceAdminEvent(containerID, |
| RemoteServiceAdminEvent.IMPORT_UNREGISTRATION, |
| rsaBundle, imRef, exception, |
| endpointDescription), endpointDescription); |
| |
| } |
| |
| public Throwable getException() { |
| return (closed)?updateException:importReference.getException(); |
| } |
| |
| private Throwable updateException; |
| |
| public boolean update( |
| org.osgi.service.remoteserviceadmin.EndpointDescription endpoint) { |
| // If this registration has been closed then set updateException |
| // to IllegalStateException and return null |
| if (closed) { |
| updateException = new IllegalStateException( |
| "Update failed since ImportRegistration already closed"); //$NON-NLS-1$ |
| return false; |
| } |
| try { |
| importReference.update(endpoint); |
| } catch (Exception e) { |
| updateException = e; |
| return false; |
| } |
| Bundle rsaBundle = getRSABundle(); |
| EndpointDescription ed = getEndpointDescription(); |
| if (rsaBundle != null) |
| publishEvent(new RemoteServiceAdminEvent(getContainerID(), |
| RemoteServiceAdminEvent.IMPORT_UPDATE, rsaBundle, |
| this.importReference, null, ed), ed); |
| return true; |
| } |
| |
| } |
| |
| /** |
| * @since 4.2 |
| */ |
| public class ImportReference implements |
| org.osgi.service.remoteserviceadmin.ImportReference { |
| |
| private ImportEndpoint importEndpoint; |
| |
| private Throwable exception; |
| private EndpointDescription errorEndpointDescription; |
| |
| public String toString() { |
| StringBuffer buf = new StringBuffer("ImportReference["); //$NON-NLS-1$ |
| buf.append("importEndpoint=").append(importEndpoint).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buf.append("exception=").append(exception).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| return buf.toString(); |
| } |
| |
| ImportReference(ImportEndpoint importEndpoint) { |
| Assert.isNotNull(importEndpoint); |
| this.importEndpoint = importEndpoint; |
| } |
| |
| synchronized void update( |
| org.osgi.service.remoteserviceadmin.EndpointDescription endpoint) { |
| if (importEndpoint != null) importEndpoint.update(endpoint); |
| } |
| |
| ImportReference(EndpointDescription endpointDescription, |
| Throwable exception) { |
| Assert.isNotNull(exception); |
| this.exception = exception; |
| Assert.isNotNull(endpointDescription); |
| this.errorEndpointDescription = endpointDescription; |
| } |
| |
| synchronized Throwable getException() { |
| return exception; |
| } |
| |
| synchronized boolean match(IRemoteServiceID remoteServiceID) { |
| return (importEndpoint == null) ? false : importEndpoint |
| .match(remoteServiceID); |
| } |
| |
| synchronized ImportEndpoint match(EndpointDescription ed) { |
| if (importEndpoint != null && importEndpoint.match(ed)) |
| return importEndpoint; |
| return null; |
| } |
| |
| synchronized EndpointDescription getEndpointDescription() { |
| return (importEndpoint == null) ? errorEndpointDescription |
| : importEndpoint.getEndpointDescription(); |
| } |
| |
| public synchronized ID getContainerID() { |
| return (importEndpoint == null) ? null : importEndpoint |
| .getContainerID(); |
| } |
| |
| public synchronized long getRemoteServiceId() { |
| EndpointDescription ed = getEndpointDescription(); |
| return (ed == null)?0:ed.getRemoteServiceId(); |
| } |
| |
| public synchronized ServiceReference getImportedService() { |
| return (importEndpoint == null) ? null : importEndpoint |
| .getProxyRegistration().getReference(); |
| } |
| |
| public synchronized org.osgi.service.remoteserviceadmin.EndpointDescription getImportedEndpoint() { |
| return (importEndpoint == null) ? null : importEndpoint |
| .getEndpointDescription(); |
| } |
| |
| synchronized boolean close(ImportRegistration importRegistration) { |
| if (importEndpoint == null) |
| return false; |
| boolean result = importEndpoint.close(importRegistration); |
| importEndpoint = null; |
| return result; |
| } |
| |
| } |
| |
| private void publishEvent(final RemoteServiceAdminEvent event, |
| EndpointDescription endpointDescription) { |
| // send event synchronously to RemoteServiceAdminListeners |
| EndpointPermission perm = new EndpointPermission(endpointDescription, |
| Activator.getDefault().getFrameworkUUID(), |
| EndpointPermission.READ); |
| // notify synchronously all appropriate listeners (those with READ |
| // permission) |
| final RemoteServiceAdminListener[] listeners = getListeners(perm); |
| if (listeners != null) |
| for (int i = 0; i < listeners.length; i++) { |
| final RemoteServiceAdminListener listener = listeners[i]; |
| SafeRunner.run(new ISafeRunnable() { |
| public void handleException(Throwable exception) { |
| logError("publishEvent", "Exeption in RemoteServiceAdminListener.remoteAdminEvent for listener="+listener, exception); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| public void run() throws Exception { |
| listener.remoteAdminEvent(event); |
| } |
| }); |
| } |
| // Now also post the event asynchronously to EventAdmin |
| postEvent(event, endpointDescription); |
| } |
| |
| private void postEvent(RemoteServiceAdminEvent event, |
| EndpointDescription endpointDescription) { |
| int eventType = event.getType(); |
| String eventTypeName = null; |
| String registrationTypeName = null; |
| switch (eventType) { |
| case (RemoteServiceAdminEvent.EXPORT_REGISTRATION): |
| eventTypeName = "EXPORT_REGISTRATION"; //$NON-NLS-1$ |
| registrationTypeName = "export.registration";//$NON-NLS-1$ |
| break; |
| case (RemoteServiceAdminEvent.EXPORT_ERROR): |
| eventTypeName = "EXPORT_ERROR"; //$NON-NLS-1$ |
| registrationTypeName = "export.registration";//$NON-NLS-1$ |
| break; |
| case (RemoteServiceAdminEvent.EXPORT_UNREGISTRATION): |
| eventTypeName = "EXPORT_UNREGISTRATION"; //$NON-NLS-1$ |
| registrationTypeName = "export.registration";//$NON-NLS-1$ |
| break; |
| case (RemoteServiceAdminEvent.EXPORT_WARNING): |
| eventTypeName = "EXPORT_WARNING"; //$NON-NLS-1$ |
| registrationTypeName = "export.registration";//$NON-NLS-1$ |
| break; |
| case (RemoteServiceAdminEvent.EXPORT_UPDATE): |
| eventTypeName = "EXPORT_UPDATE"; //$NON-NLS-1$ |
| registrationTypeName = "export.registration"; //$NON-NLS-1$ |
| break; |
| case (RemoteServiceAdminEvent.IMPORT_REGISTRATION): |
| eventTypeName = "IMPORT_REGISTRATION"; //$NON-NLS-1$ |
| registrationTypeName = "import.registration";//$NON-NLS-1$ |
| break; |
| case (RemoteServiceAdminEvent.IMPORT_ERROR): |
| eventTypeName = "IMPORT_ERROR"; //$NON-NLS-1$ |
| registrationTypeName = "import.registration";//$NON-NLS-1$ |
| break; |
| case (RemoteServiceAdminEvent.IMPORT_UNREGISTRATION): |
| eventTypeName = "IMPORT_UNREGISTRATION"; //$NON-NLS-1$ |
| registrationTypeName = "import.registration";//$NON-NLS-1$ |
| break; |
| case (RemoteServiceAdminEvent.IMPORT_WARNING): |
| eventTypeName = "IMPORT_WARNING"; //$NON-NLS-1$ |
| registrationTypeName = "import.registration";//$NON-NLS-1$ |
| break; |
| case (RemoteServiceAdminEvent.IMPORT_UPDATE): |
| eventTypeName = "IMPORT_UPDATE"; //$NON-NLS-1$ |
| registrationTypeName = "import.registration"; //$NON-NLS-1$ |
| break; |
| } |
| if (eventTypeName == null) { |
| logError("postEvent", "Event type=" + eventType //$NON-NLS-1$ //$NON-NLS-2$ |
| + " not understood for event=" + event + ". Not posting"); //$NON-NLS-1$ //$NON-NLS-2$ |
| return; |
| } |
| final String topic = "org/osgi/service/remoteserviceadmin/" + eventTypeName; //$NON-NLS-1$ |
| Bundle rsaBundle = getRSABundle(); |
| if (rsaBundle == null) { |
| logError( |
| "postEvent", "RSA Bundle is null. Not posting remote service admin event=" + event); //$NON-NLS-1$ //$NON-NLS-2$ |
| return; |
| } |
| final Dictionary eventProperties = new Properties(); |
| eventProperties.put("bundle", rsaBundle); //$NON-NLS-1$ |
| eventProperties.put("bundle.id", //$NON-NLS-1$ |
| new Long(rsaBundle.getBundleId())); |
| eventProperties.put("bundle.symbolicname", //$NON-NLS-1$ |
| rsaBundle.getSymbolicName()); |
| eventProperties.put("bundle.version", rsaBundle.getVersion()); //$NON-NLS-1$ |
| List<String> result = new ArrayList<String>(); |
| Map signers1 = clientBundle.getSignerCertificates(Bundle.SIGNERS_ALL); |
| for (Iterator i = signers1.keySet().iterator(); i.hasNext();) |
| result.add(i.next().toString()); |
| String[] signers = (String[]) result.toArray(new String[result.size()]); |
| if (signers != null && signers.length > 0) |
| eventProperties.put("bundle.signer", signers); //$NON-NLS-1$ |
| Throwable t = event.getException(); |
| if (t != null) { |
| eventProperties.put("cause", t); //$NON-NLS-1$ |
| // Additions for RSA 1.1 section 122.7.1 |
| eventProperties.put("exception", t); //$NON-NLS-1$ |
| eventProperties.put("exception.class", t.getClass().getName()); //$NON-NLS-1$ |
| String exceptionMessage = t.getMessage(); |
| if (exceptionMessage != null) |
| eventProperties.put("exception.message", exceptionMessage); //$NON-NLS-1$ |
| } |
| |
| long serviceId = endpointDescription.getServiceId(); |
| if (serviceId != 0) |
| eventProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_SERVICE_ID, |
| new Long(serviceId)); |
| String frameworkUUID = endpointDescription.getFrameworkUUID(); |
| if (frameworkUUID != null) |
| eventProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_FRAMEWORK_UUID, |
| frameworkUUID); |
| String endpointId = endpointDescription.getId(); |
| if (endpointId != null) |
| eventProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_ID, |
| endpointId); |
| List<String> interfaces = endpointDescription.getInterfaces(); |
| if (interfaces != null && interfaces.size() > 0) |
| eventProperties.put(org.osgi.framework.Constants.OBJECTCLASS, |
| interfaces.toArray(new String[interfaces.size()])); |
| List<String> importedConfigs = endpointDescription |
| .getConfigurationTypes(); |
| if (importedConfigs != null && importedConfigs.size() > 0) |
| eventProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_IMPORTED_CONFIGS, |
| importedConfigs.toArray(new String[importedConfigs |
| .size()])); |
| eventProperties.put("timestamp", new Long(new Date().getTime())); //$NON-NLS-1$ |
| eventProperties.put("event", event); //$NON-NLS-1$ |
| if (registrationTypeName != null) |
| eventProperties.put(registrationTypeName, endpointDescription); |
| |
| final EventAdmin eventAdmin = AccessController |
| .doPrivileged(new PrivilegedAction<EventAdmin>() { |
| public EventAdmin run() { |
| synchronized (eventAdminTrackerLock) { |
| eventAdminTracker = new ServiceTracker( |
| getRSABundleContext(), EventAdmin.class |
| .getName(), null); |
| eventAdminTracker.open(); |
| } |
| return (EventAdmin) eventAdminTracker.getService(); |
| } |
| }); |
| if (eventAdmin == null) { |
| logError("postEvent", //$NON-NLS-1$ |
| "No EventAdmin service available to send eventTopic=" //$NON-NLS-1$ |
| + topic + " eventProperties=" + eventProperties); //$NON-NLS-1$ |
| return; |
| } |
| // post via event admin |
| AccessController.doPrivileged(new PrivilegedAction<Object>() { |
| public Object run() { |
| eventAdmin.postEvent(new Event(topic, eventProperties)); |
| return null; |
| } |
| }); |
| } |
| |
| private void publishExportEvent(ExportRegistration exportRegistration) { |
| Throwable exception = exportRegistration.getException(); |
| org.osgi.service.remoteserviceadmin.ExportReference exportReference = (exception == null) ? exportRegistration |
| .getExportReference() : null; |
| EndpointDescription endpointDescription = exportRegistration |
| .getEndpointDescription(); |
| RemoteServiceAdminEvent rsaEvent = new RemoteServiceAdminEvent( |
| exportRegistration.getContainerID(), |
| (exception == null) ? RemoteServiceAdminEvent.EXPORT_REGISTRATION |
| : RemoteServiceAdminEvent.EXPORT_ERROR, getRSABundle(), |
| exportReference, exception, endpointDescription); |
| publishEvent(rsaEvent, endpointDescription); |
| } |
| |
| private void publishImportEvent(ImportRegistration importRegistration) { |
| Throwable exception = importRegistration.getException(); |
| org.osgi.service.remoteserviceadmin.ImportReference importReference = (exception == null) ? importRegistration |
| .getImportReference() : null; |
| EndpointDescription endpointDescription = importRegistration |
| .getEndpointDescription(); |
| RemoteServiceAdminEvent rsaEvent = new RemoteServiceAdminEvent( |
| importRegistration.getContainerID(), |
| (exception == null) ? RemoteServiceAdminEvent.IMPORT_REGISTRATION |
| : RemoteServiceAdminEvent.IMPORT_ERROR, getRSABundle(), |
| importReference, exception, endpointDescription); |
| publishEvent(rsaEvent, endpointDescription); |
| } |
| |
| private RemoteServiceAdminListener[] getListeners(EndpointPermission perm) { |
| AccessController.doPrivileged(new PrivilegedAction<Object>() { |
| public Object run() { |
| synchronized (remoteServiceAdminListenerTrackerLock) { |
| if (remoteServiceAdminListenerTracker == null) { |
| remoteServiceAdminListenerTracker = new ServiceTracker( |
| getRSABundleContext(), |
| RemoteServiceAdminListener.class.getName(), |
| null); |
| remoteServiceAdminListenerTracker.open(); |
| } |
| return null; |
| } |
| } |
| }); |
| ServiceReference[] unfilteredRefs = remoteServiceAdminListenerTracker |
| .getServiceReferences(); |
| if (unfilteredRefs == null) |
| return null; |
| // Filter by Bundle.hasPermission |
| List<ServiceReference> filteredRefs = new ArrayList<ServiceReference>(); |
| for (ServiceReference ref : unfilteredRefs) |
| if (perm == null || ref.getBundle().hasPermission(perm)) |
| filteredRefs.add(ref); |
| List<RemoteServiceAdminListener> results = new ArrayList<RemoteServiceAdminListener>(); |
| for (final ServiceReference ref : filteredRefs) { |
| RemoteServiceAdminListener l = AccessController |
| .doPrivileged(new PrivilegedAction<RemoteServiceAdminListener>() { |
| public RemoteServiceAdminListener run() { |
| return (RemoteServiceAdminListener) remoteServiceAdminListenerTracker |
| .getService(ref); |
| } |
| }); |
| if (l != null) |
| results.add(l); |
| } |
| return results.toArray(new RemoteServiceAdminListener[results.size()]); |
| } |
| |
| private ExportEndpoint findExistingExportEndpoint( |
| ServiceReference serviceReference, ID containerID) { |
| for (org.osgi.service.remoteserviceadmin.ExportRegistration eReg : exportedRegistrations) { |
| if (eReg instanceof ExportRegistration) { |
| |
| ExportEndpoint exportEndpoint = ((ExportRegistration) eReg) |
| .getExportEndpoint(serviceReference, containerID); |
| if (exportEndpoint != null) |
| return exportEndpoint; |
| } |
| } |
| return null; |
| } |
| |
| private Object consumerContainerSelectorTrackerLock = new Object(); |
| private ServiceTracker consumerContainerSelectorTracker; |
| |
| private Object hostContainerSelectorTrackerLock = new Object(); |
| private ServiceTracker hostContainerSelectorTracker; |
| |
| protected IHostContainerSelector getHostContainerSelector() { |
| return AccessController |
| .doPrivileged(new PrivilegedAction<IHostContainerSelector>() { |
| public IHostContainerSelector run() { |
| synchronized (hostContainerSelectorTrackerLock) { |
| if (hostContainerSelectorTracker == null) { |
| hostContainerSelectorTracker = new ServiceTracker( |
| getRSABundleContext(), |
| IHostContainerSelector.class.getName(), |
| null); |
| hostContainerSelectorTracker.open(); |
| } |
| } |
| return (IHostContainerSelector) hostContainerSelectorTracker |
| .getService(); |
| } |
| }); |
| } |
| |
| protected IConsumerContainerSelector getConsumerContainerSelector() { |
| return AccessController |
| .doPrivileged(new PrivilegedAction<IConsumerContainerSelector>() { |
| public IConsumerContainerSelector run() { |
| synchronized (consumerContainerSelectorTrackerLock) { |
| if (consumerContainerSelectorTracker == null) { |
| consumerContainerSelectorTracker = new ServiceTracker( |
| getRSABundleContext(), |
| IConsumerContainerSelector.class |
| .getName(), null); |
| consumerContainerSelectorTracker.open(); |
| } |
| } |
| return (IConsumerContainerSelector) consumerContainerSelectorTracker |
| .getService(); |
| } |
| }); |
| } |
| |
| private ContainerTypeDescription getContainerTypeDescription(ID containerID) { |
| return Activator.getDefault().getContainerManager() |
| .getContainerTypeDescription(containerID); |
| } |
| |
| private boolean isClient(IContainer container) { |
| ContainerTypeDescription ctd = getContainerTypeDescription(container.getID()); |
| if (ctd == null) |
| return false; |
| else |
| return !ctd.isServer(); |
| } |
| |
| private Version getPackageVersion(final ServiceReference serviceReference, |
| String serviceInterface, String packageName) { |
| Object service = AccessController |
| .doPrivileged(new PrivilegedAction<Object>() { |
| public Object run() { |
| return getRSABundleContext().getService( |
| serviceReference); |
| } |
| }); |
| if (service == null) |
| return null; |
| List<Class> interfaces = new ArrayList<Class>(); |
| Class<?> serviceClass = service.getClass(); |
| while (!serviceClass.equals(Object.class)) { |
| interfaces.addAll(Arrays.asList(serviceClass.getInterfaces())); |
| serviceClass = serviceClass.getSuperclass(); |
| } |
| Class[] interfaceClasses = interfaces.toArray(new Class[interfaces.size()]); |
| |
| if (interfaceClasses == null) |
| return null; |
| Class interfaceClass = null; |
| for (int i = 0; i < interfaceClasses.length; i++) |
| if (interfaceClasses[i].getName().equals(serviceInterface)) |
| interfaceClass = interfaceClasses[i]; |
| if (interfaceClass == null) |
| return null; |
| Bundle providingBundle = FrameworkUtil.getBundle(interfaceClass); |
| if (providingBundle == null) |
| return null; |
| return getVersionForPackage(providingBundle, packageName); |
| } |
| |
| private Map<String, Object> createExportEndpointDescriptionProperties( |
| ServiceReference serviceReference, |
| Map<String, Object> overridingProperties, |
| String[] exportedInterfaces, String[] serviceIntents, |
| IRemoteServiceContainer rsContainer) { |
| IContainer container = rsContainer.getContainer(); |
| ID containerID = container.getID(); |
| |
| Map<String, Object> endpointDescriptionProperties = new TreeMap<String, Object>( |
| String.CASE_INSENSITIVE_ORDER); |
| |
| // OSGi properties |
| // OBJECTCLASS set to exportedInterfaces |
| endpointDescriptionProperties.put( |
| org.osgi.framework.Constants.OBJECTCLASS, exportedInterfaces); |
| |
| // Service interface versions |
| for (int i = 0; i < exportedInterfaces.length; i++) { |
| String packageName = getPackageName(exportedInterfaces[i]); |
| String packageVersionKey = org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_PACKAGE_VERSION_ |
| + packageName; |
| // If it's pre-set...by registration or by overridingProperties, |
| // then use that value |
| String packageVersion = (String) PropertiesUtil.getPropertyValue( |
| serviceReference, overridingProperties, packageVersionKey); |
| if (packageVersion == null) { |
| Version version = getPackageVersion(serviceReference, |
| exportedInterfaces[i], packageName); |
| if (version != null && !version.equals(Version.emptyVersion)) |
| packageVersion = version.toString(); |
| } |
| // Only set the package version if we have a non-null value |
| if (packageVersion != null) |
| endpointDescriptionProperties.put(packageVersionKey, |
| packageVersion); |
| } |
| |
| // ENDPOINT_ID |
| String endpointId = (String) PropertiesUtil |
| .getPropertyValue( |
| serviceReference, |
| overridingProperties, |
| org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_ID); |
| if (endpointId == null) |
| endpointId = UUID.randomUUID().toString(); |
| endpointDescriptionProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_ID, |
| endpointId); |
| |
| // ECF ENDPOINT ID |
| String ecfEndpointId = (String) PropertiesUtil.getPropertyValue( |
| serviceReference, overridingProperties, |
| RemoteConstants.ENDPOINT_ID); |
| if (ecfEndpointId == null) |
| ecfEndpointId = containerID.getName(); |
| endpointDescriptionProperties.put(RemoteConstants.ENDPOINT_ID, |
| ecfEndpointId); |
| |
| // ENDPOINT_SERVICE_ID |
| // This is always set to the value from serviceReference as per 122.5.1 |
| Long serviceId = (Long) serviceReference |
| .getProperty(org.osgi.framework.Constants.SERVICE_ID); |
| endpointDescriptionProperties.put( |
| org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_SERVICE_ID, serviceId); |
| |
| // ENDPOINT_FRAMEWORK_ID |
| String frameworkId = (String) PropertiesUtil |
| .getPropertyValue( |
| serviceReference, |
| overridingProperties, |
| org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_FRAMEWORK_UUID); |
| if (frameworkId == null) |
| frameworkId = Activator.getDefault().getFrameworkUUID(); |
| endpointDescriptionProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_FRAMEWORK_UUID, |
| frameworkId); |
| |
| // REMOTE_CONFIGS_SUPPORTED |
| String[] remoteConfigsSupported = getSupportedConfigs(container.getID()); |
| if (remoteConfigsSupported == null) |
| remoteConfigsSupported = new String[0]; |
| endpointDescriptionProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.REMOTE_CONFIGS_SUPPORTED, |
| remoteConfigsSupported); |
| // SERVICE_IMPORTED_CONFIGS...set to constant value for all ECF |
| // providers |
| // supported (which is computed |
| // for the exporting ECF container |
| endpointDescriptionProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_IMPORTED_CONFIGS, |
| remoteConfigsSupported); |
| |
| // SERVICE_INTENTS |
| Object intents = PropertiesUtil |
| .getPropertyValue( |
| null, |
| overridingProperties, |
| org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_INTENTS); |
| if (intents == null) |
| intents = serviceIntents; |
| if (intents != null) |
| endpointDescriptionProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_INTENTS, |
| intents); |
| |
| // REMOTE_INTENTS_SUPPORTED |
| String[] remoteIntentsSupported = getSupportedIntents(container.getID()); |
| if (remoteIntentsSupported != null) |
| endpointDescriptionProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.REMOTE_INTENTS_SUPPORTED, |
| remoteIntentsSupported); |
| |
| // ECF properties |
| // ID namespace |
| String idNamespace = containerID.getNamespace().getName(); |
| endpointDescriptionProperties.put( |
| RemoteConstants.ENDPOINT_CONTAINER_ID_NAMESPACE, idNamespace); |
| |
| // timestamp |
| endpointDescriptionProperties.put(RemoteConstants.ENDPOINT_TIMESTAMP, System.currentTimeMillis()); |
| |
| // ENDPOINT_CONNECTTARGET_ID |
| String connectTarget = (String) PropertiesUtil.getPropertyValue( |
| serviceReference, overridingProperties, |
| RemoteConstants.ENDPOINT_CONNECTTARGET_ID); |
| if (connectTarget == null && isClient(container)) { |
| ID connectedID = container.getConnectedID(); |
| if (connectedID != null && !connectedID.equals(containerID)) |
| connectTarget = connectedID.getName(); |
| } |
| if (connectTarget != null) |
| endpointDescriptionProperties.put( |
| RemoteConstants.ENDPOINT_CONNECTTARGET_ID, connectTarget); |
| |
| // ENDPOINT_IDFILTER_IDS |
| String[] idFilter = (String[]) PropertiesUtil.getPropertyValue( |
| serviceReference, overridingProperties, |
| RemoteConstants.ENDPOINT_IDFILTER_IDS); |
| if (idFilter != null && idFilter.length > 0) |
| endpointDescriptionProperties.put( |
| RemoteConstants.ENDPOINT_IDFILTER_IDS, idFilter); |
| |
| // ENDPOINT_REMOTESERVICE_FILTER |
| String rsFilter = (String) PropertiesUtil.getPropertyValue( |
| serviceReference, overridingProperties, |
| RemoteConstants.ENDPOINT_REMOTESERVICE_FILTER); |
| if (rsFilter != null) |
| endpointDescriptionProperties.put( |
| RemoteConstants.ENDPOINT_REMOTESERVICE_FILTER, rsFilter); |
| |
| // Finally, copy all non-reserved properties |
| return PropertiesUtil.copyNonReservedProperties(overridingProperties, endpointDescriptionProperties); |
| } |
| |
| private Map<String, Object> copyNonReservedProperties( |
| ServiceReference serviceReference, |
| Map<String, Object> overridingProperties, Map<String, Object> target) { |
| // copy all other properties...from service reference |
| PropertiesUtil.copyNonReservedProperties(serviceReference, target); |
| // And override with overridingProperties |
| PropertiesUtil.copyNonReservedProperties(overridingProperties, target); |
| return target; |
| } |
| |
| private String[] getSupportedConfigs(ID containerID) { |
| ContainerTypeDescription ctd = getContainerTypeDescription(containerID); |
| return (ctd == null) ? null : ctd.getSupportedConfigs(); |
| } |
| |
| private String[] getImportedConfigs(ID containerID, |
| String[] exporterSupportedConfigs) { |
| ContainerTypeDescription ctd = getContainerTypeDescription(containerID); |
| return (ctd == null) ? null : ctd |
| .getImportedConfigs(exporterSupportedConfigs); |
| } |
| |
| private String[] getSupportedIntents(ID containerID) { |
| ContainerTypeDescription ctd = getContainerTypeDescription(containerID); |
| return (ctd == null) ? null : ctd.getSupportedIntents(); |
| } |
| |
| private ID[] getIDFilter(EndpointDescription endpointDescription, |
| ID endpointID) { |
| ID[] idFilter = endpointDescription.getIDFilter(); |
| // If it is null, |
| return (idFilter == null) ? new ID[] { endpointID } : idFilter; |
| } |
| |
| private String getRemoteServiceFilter( |
| EndpointDescription endpointDescription) { |
| |
| long rsId = 0; |
| // if the ECF remote service id is present in properties, allow it to |
| // override |
| Long l = endpointDescription.getRemoteServiceId(); |
| if (l != null) |
| rsId = l.longValue(); |
| // if rsId is still zero, use the endpoint.service.id from |
| // endpoint description |
| if (rsId == 0) |
| rsId = endpointDescription.getServiceId(); |
| // If it's *still* zero, then just use the raw filter |
| if (rsId == 0) { |
| // It's not known...so we just return the 'raw' remote service |
| // filter |
| return endpointDescription.getRemoteServiceFilter(); |
| } else { |
| String edRsFilter = endpointDescription.getRemoteServiceFilter(); |
| // It's a real remote service id...so we return |
| StringBuffer result = new StringBuffer("(&(") //$NON-NLS-1$ |
| .append(org.eclipse.ecf.remoteservice.Constants.SERVICE_ID) |
| .append("=").append(rsId).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (edRsFilter != null) |
| result.append(edRsFilter); |
| result.append(")"); //$NON-NLS-1$ |
| return result.toString(); |
| } |
| } |
| |
| private ImportEndpoint createAndRegisterProxy( |
| final EndpointDescription endpointDescription, |
| final IRemoteServiceContainer rsContainer, |
| final IRemoteServiceReference selectedRsReference) throws Exception { |
| |
| final BundleContext proxyServiceFactoryContext = getProxyServiceFactoryContext(endpointDescription); |
| if (proxyServiceFactoryContext == null) |
| throw new NullPointerException( |
| "getProxyServiceFactoryContext returned null. Cannot register proxy service factory"); //$NON-NLS-1$ |
| |
| final IRemoteServiceContainerAdapter containerAdapter = rsContainer |
| .getContainerAdapter(); |
| ID rsContainerID = rsContainer.getContainer().getID(); |
| // First get IRemoteService for selectedRsReference |
| final IRemoteService rs = containerAdapter |
| .getRemoteService(selectedRsReference); |
| if (rs == null) |
| throw new NullPointerException( |
| "getRemoteService returned null for selectedRsReference=" //$NON-NLS-1$ |
| + selectedRsReference + ",rsContainerID=" //$NON-NLS-1$ |
| + rsContainerID); |
| |
| final Map proxyProperties = createProxyProperties(rsContainerID, endpointDescription, |
| selectedRsReference, rs); |
| |
| // sync sref props with endpoint props |
| endpointDescription.setPropertiesOverrides(proxyProperties); |
| |
| final List<String> originalTypes = endpointDescription.getInterfaces(); |
| final List<String> asyncServiceTypes = endpointDescription.getAsyncInterfaces(); |
| |
| final List<String> serviceTypes = new ArrayList<String>(originalTypes); |
| |
| if (asyncServiceTypes != null) |
| for(String ast: asyncServiceTypes) |
| if (ast != null && !serviceTypes.contains(ast)) serviceTypes.add(ast); |
| |
| ServiceRegistration proxyRegistration = AccessController |
| .doPrivileged(new PrivilegedAction<ServiceRegistration>() { |
| public ServiceRegistration run() { |
| return proxyServiceFactoryContext.registerService( |
| (String[]) serviceTypes |
| .toArray(new String[serviceTypes.size()]), |
| createProxyServiceFactory(endpointDescription,containerAdapter,selectedRsReference, |
| rs), |
| (Dictionary) PropertiesUtil |
| .createDictionaryFromMap(proxyProperties)); |
| } |
| }); |
| |
| return new ImportEndpoint(rsContainer, selectedRsReference, rs, proxyRegistration, endpointDescription); |
| } |
| |
| private BundleContext getProxyServiceFactoryContext( |
| EndpointDescription endpointDescription) throws Exception { |
| Activator a = Activator.getDefault(); |
| if (a == null) |
| throw new NullPointerException( |
| "ECF RemoteServiceAdmin Activator cannot be null."); //$NON-NLS-1$ |
| if (a.isOldEquinox()) { |
| // In this case, we get the Bundle that exposes the first service |
| // interface class |
| BundleContext rsaContext = Activator.getContext(); |
| if (rsaContext == null) |
| throw new NullPointerException( |
| "RSA BundleContext cannot be null"); //$NON-NLS-1$ |
| List<String> interfaces = endpointDescription.getInterfaces(); |
| Collection<Class> serviceInterfaceClasses = loadServiceInterfacesViaBundle( |
| rsaContext.getBundle(), |
| interfaces.toArray(new String[interfaces.size()])); |
| if (serviceInterfaceClasses.size() == 0) |
| throw new NullPointerException( |
| "No interface classes loadable for endpointDescription=" //$NON-NLS-1$ |
| + endpointDescription); |
| // Get the bundle responsible for the first service interface class |
| Class serviceInterfaceClass = serviceInterfaceClasses.iterator() |
| .next(); |
| Bundle bundle = FrameworkUtil.getBundle(serviceInterfaceClass); |
| if (bundle == null) |
| throw new BundleException("Bundle for service interface class=" //$NON-NLS-1$ |
| + serviceInterfaceClass.getName() + " cannot be found"); //$NON-NLS-1$ |
| int bundleState = bundle.getState(); |
| BundleContext bundleContext = bundle.getBundleContext(); |
| if (bundleContext == null) |
| throw new BundleException("Bundle=" + bundle.getSymbolicName() //$NON-NLS-1$ |
| + " in wrong state (" + bundleState //$NON-NLS-1$ |
| + ") for using BundleContext proxy service factory"); //$NON-NLS-1$ |
| return bundleContext; |
| } |
| return a.getProxyServiceFactoryBundleContext(endpointDescription); |
| } |
| |
| private ServiceFactory createProxyServiceFactory( |
| EndpointDescription endpointDescription, |
| IRemoteServiceContainerAdapter containerAdapter, IRemoteServiceReference selectedRsReference, IRemoteService remoteService) { |
| return new ProxyServiceFactory( |
| endpointDescription.getInterfaceVersions(), containerAdapter, selectedRsReference, remoteService); |
| } |
| |
| private Collection<Class> loadServiceInterfacesViaBundle(Bundle bundle, |
| String[] interfaces) { |
| List<Class> result = new ArrayList<Class>(); |
| for (int i = 0; i < interfaces.length; i++) { |
| try { |
| result.add(bundle.loadClass(interfaces[i])); |
| } catch (ClassNotFoundException e) { |
| logError("loadInterfacesViaBundle", "interface=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + interfaces[i] + " cannot be loaded by clientBundle=" //$NON-NLS-1$ |
| + bundle.getSymbolicName(), e); |
| continue; |
| } catch (IllegalStateException e) { |
| logError( |
| "loadInterfacesViaBundle", //$NON-NLS-1$ |
| "interface=" //$NON-NLS-1$ |
| + interfaces[i] |
| + " cannot be loaded since clientBundle is in illegal state", //$NON-NLS-1$ |
| e); |
| continue; |
| } |
| } |
| return result; |
| } |
| |
| class ProxyServiceFactory implements ServiceFactory { |
| private final IRemoteServiceContainerAdapter containerAdapter; |
| private final IRemoteServiceReference rsReference; |
| private IRemoteService remoteService; |
| private Map<String, Version> interfaceVersions; |
| private long remoteProxyCount = 0L; |
| |
| public ProxyServiceFactory(Map<String, Version> interfaceVersions, |
| IRemoteServiceContainerAdapter containerAdapter, IRemoteServiceReference rsReference, IRemoteService remoteService) { |
| this.containerAdapter = containerAdapter; |
| this.rsReference = rsReference; |
| this.interfaceVersions = interfaceVersions; |
| this.remoteService = remoteService; |
| } |
| |
| public Object getService(Bundle bundle, ServiceRegistration registration) { |
| Object proxy = createProxy(bundle, registration.getReference(), |
| remoteService, interfaceVersions); |
| if (proxy != null) remoteProxyCount++; |
| return proxy; |
| } |
| |
| public void ungetService(Bundle bundle, |
| ServiceRegistration registration, Object service) { |
| if (remoteProxyCount == 1L) |
| containerAdapter.ungetRemoteService(rsReference); |
| remoteProxyCount--; |
| ungetProxyClassLoader(bundle); |
| } |
| } |
| |
| private Object createProxy(Bundle requestingBundle, |
| ServiceReference serviceReference, IRemoteService remoteService, |
| Map<String, Version> interfaceVersions) { |
| // Get symbolicName once for possible use below |
| String bundleSymbolicName = requestingBundle.getSymbolicName(); |
| // Get String[] via OBJECTCLASS constant property |
| String[] serviceClassnames = (String[]) serviceReference |
| .getProperty(org.osgi.framework.Constants.OBJECTCLASS); |
| // Load as many of the serviceInterface classes as possible |
| Collection<Class> serviceInterfaceClasses = loadServiceInterfacesViaBundle( |
| requestingBundle, serviceClassnames); |
| // There has to be at least one serviceInterface that the clientBundle |
| // can |
| // load...otherwise the service can't be accessed |
| if (serviceInterfaceClasses.size() < 1) |
| throw new RuntimeException( |
| "ProxyServiceFactory cannot load any serviceInterfaces=" //$NON-NLS-1$ |
| + serviceInterfaceClasses |
| + " for serviceReference=" + serviceReference //$NON-NLS-1$ |
| + " via clientBundle=" + bundleSymbolicName); //$NON-NLS-1$ |
| |
| // Now verify that the classes are of valid versions |
| if (!verifyServiceInterfaceVersionsForProxy(requestingBundle, |
| serviceInterfaceClasses, interfaceVersions)) |
| return null; |
| |
| // Now create/get class loader for proxy. This will typically |
| // be an instance of ProxyClassLoader |
| ClassLoader cl = getProxyClassLoader(requestingBundle); |
| try { |
| return remoteService.getProxy(cl, (Class[]) serviceInterfaceClasses |
| .toArray(new Class[serviceInterfaceClasses.size()])); |
| } catch (ECFException e) { |
| throw new ServiceException( |
| "ProxyServiceFactory cannot create proxy for clientBundle=" //$NON-NLS-1$ |
| + bundleSymbolicName + " from serviceReference=" //$NON-NLS-1$ |
| + serviceReference, e); |
| } |
| |
| } |
| |
| private Map<Bundle, ProxyClassLoader> proxyClassLoaders = new HashMap<Bundle, ProxyClassLoader>(); |
| |
| private ClassLoader getProxyClassLoader(Bundle bundle) { |
| ProxyClassLoader proxyClassLoaderForBundle = null; |
| synchronized (proxyClassLoaders) { |
| proxyClassLoaderForBundle = proxyClassLoaders.get(bundle); |
| if (proxyClassLoaderForBundle == null) { |
| proxyClassLoaderForBundle = new ProxyClassLoader(bundle); |
| proxyClassLoaders.put(bundle, proxyClassLoaderForBundle); |
| } else |
| proxyClassLoaderForBundle.addServiceUseCount(); |
| } |
| return proxyClassLoaderForBundle; |
| } |
| |
| private void ungetProxyClassLoader(Bundle bundle) { |
| synchronized (proxyClassLoaders) { |
| ProxyClassLoader proxyClassLoaderForBundle = proxyClassLoaders |
| .get(bundle); |
| if (proxyClassLoaderForBundle != null) { |
| int useCount = proxyClassLoaderForBundle.getServiceUseCount(); |
| if (useCount == 0) |
| proxyClassLoaders.remove(bundle); |
| else |
| proxyClassLoaderForBundle.removeServiceUseCount(); |
| } |
| } |
| } |
| |
| protected class ProxyClassLoader extends ClassLoader { |
| private Bundle loadingBundle; |
| private int serviceUseCount = 0; |
| |
| public ProxyClassLoader(Bundle loadingBundle) { |
| this.loadingBundle = loadingBundle; |
| } |
| |
| public Class loadClass(String name) throws ClassNotFoundException { |
| return loadingBundle.loadClass(name); |
| } |
| |
| public int getServiceUseCount() { |
| return serviceUseCount; |
| } |
| |
| public void addServiceUseCount() { |
| serviceUseCount++; |
| } |
| |
| public void removeServiceUseCount() { |
| serviceUseCount--; |
| } |
| } |
| |
| private String getPackageName(String className) { |
| int lastDotIndex = className.lastIndexOf("."); //$NON-NLS-1$ |
| if (lastDotIndex == -1) |
| return ""; //$NON-NLS-1$ |
| return className.substring(0, lastDotIndex); |
| } |
| |
| private boolean comparePackageVersions(String packageName, |
| Version remoteVersion, Version localVersion) |
| throws RuntimeException { |
| // If no remote version info, then set it to empty |
| if (remoteVersion == null) |
| remoteVersion = Version.emptyVersion; |
| if (localVersion == null) |
| localVersion = Version.emptyVersion; |
| // We do strict comparison of remote with local |
| int compareResult = localVersion.compareTo(remoteVersion); |
| // Now check compare result, and throw exception to fail compare |
| return (compareResult != 0); |
| } |
| |
| private boolean verifyServiceInterfaceVersionsForProxy(Bundle bundle, |
| Collection<Class> classes, Map<String, Version> interfaceVersions) { |
| // For all service interface classes |
| boolean result = true; |
| // For enhancement https://bugs.eclipse.org/bugs/show_bug.cgi?id=472106 |
| if (disableServiceVersionChecking) { |
| logWarning("verifyServiceInterfaceVersionsForProxy", //$NON-NLS-1$ |
| "Service version checking disabled via service property"); //$NON-NLS-1$ |
| return result; |
| } |
| for (Class clazz : classes) { |
| String className = clazz.getName(); |
| String packageName = getPackageName(className); |
| // Now get remoteVersion, localVersion and do compare via package |
| // version comparator service |
| Version remoteVersion = interfaceVersions.get(className); |
| Version localVersion = getPackageVersionViaRequestingBundle( |
| packageName, bundle, remoteVersion); |
| LogUtility.trace("comparePackageVersions", //$NON-NLS-1$ |
| DebugOptions.PACKAGE_VERSION_COMPARATOR, this.getClass(), |
| "bundle=" + bundle.getSymbolicName() + ",class=" + clazz + ",packageName=" + packageName //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ |
| + ",remoteVersion=" //$NON-NLS-1$ |
| + remoteVersion + ",localVersion=" + localVersion); //$NON-NLS-1$ |
| if (comparePackageVersions(packageName, remoteVersion, localVersion)) { |
| logError("verifyServiceInterfaceVersionsForProxy", //$NON-NLS-1$ |
| "Failed version check for proxy creation. clientBundle=" //$NON-NLS-1$ |
| + clientBundle + " interfaceType=" + className //$NON-NLS-1$ |
| + " remoteVersion=" + remoteVersion //$NON-NLS-1$ |
| + " localVersion=" + localVersion); //$NON-NLS-1$ |
| result = false; |
| } |
| } |
| return result; |
| } |
| |
| private Version getVersionForMatchingCapability(String packageName, |
| BundleCapability capability) { |
| // If it's a package namespace (Import-Package) |
| Map<String, Object> attributes = capability.getAttributes(); |
| // Then we get the package attribute |
| String p = (String) attributes.get(BundleRevision.PACKAGE_NAMESPACE); |
| // And compare it to the package name |
| if (p != null && packageName.equals(p)) |
| return (Version) attributes.get(Constants.VERSION_ATTRIBUTE); |
| return null; |
| } |
| |
| private Version getPackageVersionForMatchingWire(String packageName, |
| List<BundleWire> bundleWires, String namespace) { |
| Version result = null; |
| for (BundleWire wire : bundleWires) { |
| if (namespace.equals(BundleRevision.PACKAGE_NAMESPACE)) |
| result = getVersionForMatchingCapability(packageName, |
| wire.getCapability()); |
| else if (namespace.equals(BundleRevision.BUNDLE_NAMESPACE)) |
| // If it's a bundle namespace (Require-Bundle), then we get the |
| // version for package |
| // of the providing bundle |
| result = getVersionForPackage(wire.getProvider().getBundle(), |
| packageName); |
| |
| if (result != null) |
| return result; |
| |
| } |
| return result; |
| } |
| |
| private Version getVersionForPackage(final Bundle providingBundle, |
| String packageName) { |
| Version result = null; |
| BundleRevision providingBundleRevision = AccessController |
| .doPrivileged(new PrivilegedAction<BundleRevision>() { |
| public BundleRevision run() { |
| return providingBundle.adapt(BundleRevision.class); |
| } |
| }); |
| if (providingBundleRevision == null) |
| return null; |
| List<BundleCapability> providerCapabilities = providingBundleRevision |
| .getDeclaredCapabilities(BundleRevision.PACKAGE_NAMESPACE); |
| for (BundleCapability c : providerCapabilities) { |
| result = getVersionForMatchingCapability(packageName, c); |
| if (result != null) |
| return result; |
| } |
| return result; |
| } |
| |
| private Version getPackageVersionViaRequestingBundle(String packageName, |
| final Bundle requestingBundle, Version remoteVersion) { |
| Version result = null; |
| // First check the requesting bundle for the desired export package |
| // capability |
| BundleRevision requestingBundleRevision = AccessController |
| .doPrivileged(new PrivilegedAction<BundleRevision>() { |
| public BundleRevision run() { |
| return requestingBundle.adapt(BundleRevision.class); |
| } |
| }); |
| if (requestingBundleRevision != null) { |
| List<BundleCapability> requestingBundleCapabilities = requestingBundleRevision |
| .getDeclaredCapabilities(BundleRevision.PACKAGE_NAMESPACE); |
| for (BundleCapability requestingBundleCapability : requestingBundleCapabilities) { |
| Version candidate = getVersionForMatchingCapability( |
| packageName, requestingBundleCapability); |
| // If found, set our result |
| if (candidate != null) { |
| if (remoteVersion != null |
| && candidate.equals(remoteVersion)) |
| return candidate; |
| result = candidate; |
| } |
| } |
| } |
| // If not found in requestingBundle export package, then |
| // look in exported package that are wired to the requesting bundle |
| if (result == null) { |
| // look for wired exported packages |
| BundleWiring requestingBundleWiring = requestingBundle |
| .adapt(BundleWiring.class); |
| if (requestingBundleWiring != null) { |
| result = getPackageVersionForMatchingWire( |
| packageName, |
| requestingBundleWiring |
| .getRequiredWires(BundleRevision.PACKAGE_NAMESPACE), |
| BundleRevision.PACKAGE_NAMESPACE); |
| // If not found in wired exported packages, then look |
| // in wired require bundles |
| if (result == null) |
| result = getPackageVersionForMatchingWire( |
| packageName, |
| requestingBundleWiring |
| .getRequiredWires(BundleRevision.BUNDLE_NAMESPACE), |
| BundleRevision.BUNDLE_NAMESPACE); |
| } |
| } |
| return result; |
| } |
| |
| private IRemoteServiceReference selectRemoteServiceReference( |
| Collection<IRemoteServiceReference> rsRefs, ID targetID, |
| ID[] idFilter, Collection<String> interfaces, String rsFilter, |
| IRemoteServiceContainer rsContainer) { |
| if (rsRefs.size() == 0) |
| return null; |
| if (rsRefs.size() > 1) { |
| logWarning("selectRemoteServiceReference", "rsRefs=" + rsRefs //$NON-NLS-1$ //$NON-NLS-2$ |
| + ",targetID=" + targetID + ",idFilter=" + idFilter //$NON-NLS-1$ //$NON-NLS-2$ |
| + ",interfaces=" + interfaces + ",rsFilter=" + rsFilter //$NON-NLS-1$ //$NON-NLS-2$ |
| + ",rsContainer=" + rsContainer.getContainer().getID() //$NON-NLS-1$ |
| + " has " + rsRefs.size() //$NON-NLS-1$ |
| + " values. Selecting the first element"); //$NON-NLS-1$ |
| } |
| return rsRefs.iterator().next(); |
| } |
| |
| private Map createProxyProperties(ID importContainerID, EndpointDescription endpointDescription, |
| IRemoteServiceReference rsReference, IRemoteService remoteService) { |
| |
| Map resultProperties = new TreeMap<String, Object>( |
| String.CASE_INSENSITIVE_ORDER); |
| PropertiesUtil.copyNonReservedProperties(rsReference, resultProperties); |
| PropertiesUtil.copyNonReservedProperties( |
| endpointDescription.getProperties(), resultProperties); |
| // remove OBJECTCLASS |
| resultProperties |
| .remove(org.eclipse.ecf.remoteservice.Constants.OBJECTCLASS); |
| // remove remote service id |
| resultProperties |
| .remove(org.eclipse.ecf.remoteservice.Constants.SERVICE_ID); |
| // Set intents if there are intents |
| Object intentsValue = PropertiesUtil |
| .convertToStringPlusValue(endpointDescription.getIntents()); |
| if (intentsValue != null) |
| resultProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_INTENTS, |
| intentsValue); |
| |
| // Set service.imported to IRemoteService unless |
| // SERVICE_IMPORTED_VALUETYPE is |
| // set |
| String serviceImportedType = (String) endpointDescription |
| .getProperties() |
| .get(org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteConstants.SERVICE_IMPORTED_VALUETYPE); |
| if (serviceImportedType == null |
| || serviceImportedType.equals(IRemoteService.class.getName())) |
| resultProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_IMPORTED, |
| remoteService); |
| else |
| resultProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_IMPORTED, |
| new Boolean(true)); |
| |
| String[] exporterSupportedConfigs = PropertiesUtil.getStringArrayFromPropertyValue(endpointDescription.getProperties().get(org.osgi.service.remoteserviceadmin.RemoteConstants.REMOTE_CONFIGS_SUPPORTED)); |
| |
| String[] importedConfigs = getImportedConfigs(importContainerID, exporterSupportedConfigs); |
| // Set service.imported.configs |
| resultProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_IMPORTED_CONFIGS, |
| importedConfigs); |
| |
| // Set endpoint.id |
| String endpointId = endpointDescription.getId(); |
| resultProperties |
| .put(org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_ID, |
| endpointId); |
| |
| return resultProperties; |
| } |
| |
| private ExportRegistration exportService( |
| final ServiceReference serviceReference, |
| Map<String, ?> overridingProperties, String[] exportedInterfaces, |
| IRemoteServiceContainer rsContainer, |
| Map<String, Object> endpointDescriptionProperties) throws Exception { |
| |
| // Create remote service properties |
| Map remoteServiceProperties = copyNonReservedProperties( |
| serviceReference, (Map<String, Object>) overridingProperties, |
| new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER)); |
| |
| IRemoteServiceContainerAdapter containerAdapter = rsContainer |
| .getContainerAdapter(); |
| |
| // create serializable dictionary from remote service properties |
| Dictionary rsp = PropertiesUtil.createSerializableDictionaryFromMap(remoteServiceProperties); |
| |
| // Register remote service via ECF container adapter to create |
| // remote service registration |
| IRemoteServiceRegistration remoteRegistration = null; |
| if (containerAdapter instanceof IOSGiRemoteServiceContainerAdapter) { |
| IOSGiRemoteServiceContainerAdapter osgiContainerAdapter = (IOSGiRemoteServiceContainerAdapter) containerAdapter; |
| remoteRegistration = osgiContainerAdapter.registerRemoteService( |
| exportedInterfaces, serviceReference, rsp); |
| } else { |
| Object service = AccessController |
| .doPrivileged(new PrivilegedAction<Object>() { |
| public Object run() { |
| return getClientBundleContext().getService( |
| serviceReference); |
| } |
| }); |
| remoteRegistration = containerAdapter.registerRemoteService( |
| exportedInterfaces, service, rsp); |
| } |
| |
| endpointDescriptionProperties.put( |
| org.eclipse.ecf.remoteservice.Constants.SERVICE_ID, |
| remoteRegistration.getID().getContainerRelativeID()); |
| |
| if (remoteRegistration instanceof IExtendedRemoteServiceRegistration) { |
| IExtendedRemoteServiceRegistration iersr = (IExtendedRemoteServiceRegistration) remoteRegistration; |
| Map<String, Object> extraProperties = iersr.getExtraProperties(); |
| if (extraProperties != null) |
| endpointDescriptionProperties = PropertiesUtil.mergeProperties(endpointDescriptionProperties, extraProperties); |
| } |
| |
| // Copy only serializable properties |
| endpointDescriptionProperties = PropertiesUtil.copySerializableProperties(endpointDescriptionProperties, |
| new TreeMap<String, Object>()); |
| |
| // Create ExportEndpoint/ExportRegistration |
| return new ExportRegistration(new ExportEndpoint(serviceReference, |
| new EndpointDescription(endpointDescriptionProperties), remoteRegistration,endpointDescriptionProperties)); |
| } |
| |
| private ImportRegistration importService( |
| final EndpointDescription endpointDescription, |
| IRemoteServiceContainer rsContainer) { |
| // Get interfaces from endpoint description |
| Collection<String> interfaces = endpointDescription.getInterfaces(); |
| Assert.isNotNull(interfaces); |
| Assert.isTrue(interfaces.size() > 0); |
| // Get ECF endpoint ID...if this throws IDCreateException (because the |
| // local system does not have |
| // namespace for creating ID, or no namespace is present in |
| // endpointDescription or endpoint id, |
| // then it will be caught by the caller |
| ID endpointContainerID = endpointDescription.getContainerID(); |
| Assert.isNotNull(endpointContainerID); |
| // Get connect target ID. May be null |
| ID tID = endpointDescription.getConnectTargetID(); |
| if (tID == null) |
| tID = endpointContainerID; |
| final ID targetID = tID; |
| // Get idFilter...also may be null |
| final ID[] idFilter = getIDFilter(endpointDescription, |
| targetID); |
| // Get remote service filter |
| final String rsFilter = getRemoteServiceFilter(endpointDescription); |
| // IRemoteServiceReferences from query |
| Collection<IRemoteServiceReference> rsRefs = new ArrayList<IRemoteServiceReference>(); |
| // Get IRemoteServiceContainerAdapter |
| final IRemoteServiceContainerAdapter containerAdapter = rsContainer |
| .getContainerAdapter(); |
| // rsContainerID |
| ID rsContainerID = rsContainer.getContainer().getID(); |
| try { |
| final IRSAConsumerContainerAdapter cca = (IRSAConsumerContainerAdapter) containerAdapter.getAdapter(IRSAConsumerContainerAdapter.class); |
| // Get first interface name for service reference |
| // lookup |
| final String intf = interfaces.iterator().next(); |
| // Get/lookup remote service references |
| IRemoteServiceReference[] refs = AccessController |
| .doPrivileged(new PrivilegedExceptionAction<IRemoteServiceReference[]>() { |
| public IRemoteServiceReference[] run() |
| throws ContainerConnectException, |
| InvalidSyntaxException { |
| // If the RSAConsumerContainerAdapter is present, use it |
| if (cca != null) |
| // Call importEndpoint if the IRSAConsumerContainerAdapter is present |
| return cca.importEndpoint(endpointDescription.getProperties()); |
| // Otherwise use the 'old' container adapter |
| else return containerAdapter.getRemoteServiceReferences( |
| targetID, idFilter, intf, rsFilter); |
| } |
| }); |
| if (refs == null) { |
| logWarning("doImportService", //$NON-NLS-1$ |
| "getRemoteServiceReferences return null for targetID=" //$NON-NLS-1$ |
| + targetID + ",idFilter=" + idFilter //$NON-NLS-1$ |
| + ",intf=" + intf + ",rsFilter=" + rsFilter //$NON-NLS-1$ //$NON-NLS-2$ |
| + " on rsContainerID=" + rsContainerID); //$NON-NLS-1$ |
| } else |
| for (int i = 0; i < refs.length; i++) |
| rsRefs.add(refs[i]); |
| // If there are several refs resulting (should not be) |
| // we select the one to use |
| IRemoteServiceReference selectedRsReference = selectRemoteServiceReference( |
| rsRefs, targetID, idFilter, interfaces, rsFilter, |
| rsContainer); |
| // If none found, we obviously can't continue |
| if (selectedRsReference == null) |
| throw new RemoteReferenceNotFoundException(targetID, idFilter, |
| interfaces, rsFilter); |
| |
| return new ImportRegistration(createAndRegisterProxy( |
| endpointDescription, rsContainer, selectedRsReference)); |
| } catch (PrivilegedActionException e) { |
| logError( |
| "importService", "selectRemoteServiceReference returned null for rsRefs=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + rsRefs + ",targetID=" + targetID //$NON-NLS-1$ |
| + ",idFilter=" + idFilter + ",interfaces=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + interfaces + ",rsFilter=" + rsFilter //$NON-NLS-1$ |
| + ",rsContainerID=" + rsContainerID, e.getException()); //$NON-NLS-1$ |
| return new ImportRegistration(endpointDescription, e.getException()); |
| } catch (Exception e) { |
| logError( |
| "importService", "selectRemoteServiceReference returned null for rsRefs=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + rsRefs + ",targetID=" + targetID //$NON-NLS-1$ |
| + ",idFilter=" + idFilter + ",interfaces=" //$NON-NLS-1$ //$NON-NLS-2$ |
| + interfaces + ",rsFilter=" + rsFilter //$NON-NLS-1$ |
| + ",rsContainerID=" + rsContainerID, e); //$NON-NLS-1$ |
| return new ImportRegistration(endpointDescription, e); |
| } |
| } |
| |
| public void close() { |
| trace("close", "closing importedRegistrations=" + importedRegistrations //$NON-NLS-1$ //$NON-NLS-2$ |
| + " exportedRegistrations=" + exportedRegistrations); //$NON-NLS-1$ |
| // close any imported and exported registrations |
| List<org.osgi.service.remoteserviceadmin.ImportRegistration> toClose = null; |
| synchronized (importedRegistrations) { |
| toClose = new ArrayList<org.osgi.service.remoteserviceadmin.ImportRegistration>(localImportedRegistrations); |
| } |
| for (org.osgi.service.remoteserviceadmin.ImportRegistration reg : toClose) |
| reg.close(); |
| |
| List<org.osgi.service.remoteserviceadmin.ExportRegistration> toClose1 = null; |
| synchronized (localExportedRegistrations) { |
| toClose1 = new ArrayList<org.osgi.service.remoteserviceadmin.ExportRegistration>(localExportedRegistrations); |
| } |
| for (org.osgi.service.remoteserviceadmin.ExportRegistration reg1 : toClose1) |
| reg1.close(); |
| |
| this.localExportedRegistrations.clear(); |
| this.localImportedRegistrations.clear(); |
| |
| synchronized (remoteServiceAdminListenerTrackerLock) { |
| if (remoteServiceAdminListenerTracker != null) { |
| remoteServiceAdminListenerTracker.close(); |
| remoteServiceAdminListenerTracker = null; |
| } |
| } |
| synchronized (eventAdminTrackerLock) { |
| if (eventAdminTracker != null) { |
| eventAdminTracker.close(); |
| eventAdminTracker = null; |
| } |
| } |
| synchronized (proxyClassLoaders) { |
| proxyClassLoaders.clear(); |
| } |
| synchronized (consumerContainerSelectorTrackerLock) { |
| if (consumerContainerSelectorTracker != null) { |
| consumerContainerSelectorTracker.close(); |
| consumerContainerSelectorTracker = null; |
| } |
| } |
| if (defaultConsumerContainerSelector != null) { |
| defaultConsumerContainerSelector.close(); |
| defaultConsumerContainerSelector = null; |
| } |
| synchronized (hostContainerSelectorTrackerLock) { |
| if (hostContainerSelectorTracker != null) { |
| hostContainerSelectorTracker.close(); |
| hostContainerSelectorTracker = null; |
| } |
| } |
| if (defaultHostContainerSelector != null) { |
| defaultHostContainerSelector.close(); |
| defaultHostContainerSelector = null; |
| } |
| if (defaultHostContainerSelectorRegistration != null) { |
| defaultHostContainerSelectorRegistration.unregister(); |
| defaultHostContainerSelectorRegistration = null; |
| } |
| if (defaultHostContainerSelector != null) { |
| defaultHostContainerSelector.close(); |
| defaultHostContainerSelector = null; |
| } |
| if (defaultConsumerContainerSelectorRegistration != null) { |
| defaultConsumerContainerSelectorRegistration.unregister(); |
| defaultConsumerContainerSelectorRegistration = null; |
| } |
| if (defaultConsumerContainerSelector != null) { |
| defaultConsumerContainerSelector.close(); |
| defaultConsumerContainerSelector = null; |
| } |
| if (eventListenerHookRegistration != null) { |
| eventListenerHookRegistration.unregister(); |
| eventListenerHookRegistration = null; |
| } |
| } |
| |
| private ImportEndpoint findImportEndpoint(EndpointDescription ed) { |
| for (org.osgi.service.remoteserviceadmin.ImportRegistration reg : importedRegistrations) { |
| if (reg instanceof ImportRegistration) { |
| ImportEndpoint endpoint = ((ImportRegistration) reg) |
| .getImportEndpoint(ed); |
| if (endpoint != null) |
| return endpoint; |
| } |
| } |
| return null; |
| } |
| |
| private void unimportService(IRemoteServiceID remoteServiceID) { |
| List<ImportRegistration> removedRegistrations = new ArrayList<ImportRegistration>(); |
| synchronized (importedRegistrations) { |
| for (Iterator<org.osgi.service.remoteserviceadmin.ImportRegistration> i = importedRegistrations |
| .iterator(); i.hasNext();) { |
| org.osgi.service.remoteserviceadmin.ImportRegistration iReg = i |
| .next(); |
| if (iReg instanceof ImportRegistration) { |
| ImportRegistration importRegistration = (ImportRegistration) iReg; |
| if (importRegistration.match(remoteServiceID)) |
| removedRegistrations.add(importRegistration); |
| } |
| } |
| } |
| // Now close all of them |
| for (ImportRegistration removedReg : removedRegistrations) { |
| trace("unimportService", "closing importRegistration=" + removedReg); //$NON-NLS-1$ //$NON-NLS-2$ |
| removedReg.close(); |
| } |
| } |
| |
| class RemoteServiceListener implements IRemoteServiceListener { |
| public void handleServiceEvent(IRemoteServiceEvent event) { |
| if (event instanceof IRemoteServiceUnregisteredEvent) |
| unimportService(event.getReference().getID()); |
| } |
| } |
| |
| private void trace(String methodName, String message) { |
| LogUtility.trace(methodName, DebugOptions.REMOTE_SERVICE_ADMIN, |
| this.getClass(), message); |
| } |
| |
| private void logWarning(String methodName, String message) { |
| LogUtility.logWarning(methodName, DebugOptions.REMOTE_SERVICE_ADMIN, |
| this.getClass(), message); |
| } |
| |
| private void logError(String methodName, String message, Throwable t) { |
| LogUtility.logError(methodName, DebugOptions.REMOTE_SERVICE_ADMIN, |
| this.getClass(), message, t); |
| } |
| |
| private void logError(String methodName, String message) { |
| logError(methodName, message, (Throwable) null); |
| } |
| |
| public class RemoteServiceAdminEvent extends |
| org.osgi.service.remoteserviceadmin.RemoteServiceAdminEvent { |
| |
| private ID containerID; |
| private EndpointDescription endpointDescription; |
| |
| public RemoteServiceAdminEvent( |
| ID containerID, |
| int type, |
| Bundle source, |
| org.osgi.service.remoteserviceadmin.ExportReference exportReference, |
| Throwable exception, EndpointDescription endpointDescription) { |
| super(type, source, exportReference, exception); |
| this.containerID = containerID; |
| this.endpointDescription = endpointDescription; |
| } |
| |
| public RemoteServiceAdminEvent( |
| ID containerID, |
| int type, |
| Bundle source, |
| org.osgi.service.remoteserviceadmin.ImportReference importReference, |
| Throwable exception, EndpointDescription endpointDescription) { |
| super(type, source, importReference, exception); |
| this.containerID = containerID; |
| this.endpointDescription = endpointDescription; |
| } |
| |
| /** |
| * @return EndpointDescription for this remote service admin event |
| * @since 3.0 |
| */ |
| public EndpointDescription getEndpointDescription() { |
| return endpointDescription; |
| } |
| |
| public ID getContainerID() { |
| return containerID; |
| } |
| |
| public String toString() { |
| return "RemoteServiceAdminEvent[containerID=" + containerID //$NON-NLS-1$ |
| + ", getType()=" + getType() + ", getSource()=" + getSource() //$NON-NLS-1$ //$NON-NLS-2$ |
| + ", getException()=" + getException() //$NON-NLS-1$ |
| + ", getImportReference()=" + getImportReference() //$NON-NLS-1$ |
| + ", getExportReference()=" + getExportReference() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| } |
| |
| } |