/******************************************************************************* * Copyright (c) 2014 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.internal.osgi.services.distribution; import java.util.HashMap; import java.util.Map; import org.eclipse.ecf.osgi.services.remoteserviceadmin.AbstractTopologyManager; import org.eclipse.ecf.osgi.services.remoteserviceadmin.EndpointDescription; import org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteConstants; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.remoteserviceadmin.EndpointEvent; import org.osgi.service.remoteserviceadmin.EndpointEventListener; import org.osgi.service.remoteserviceadmin.EndpointListener; public class OSGiTopologyManagerImpl extends AbstractTopologyManager implements EndpointListener, EndpointEventListener { private static final boolean exportRegisteredSvcs = new Boolean( System.getProperty( "org.eclipse.ecf.osgi.services.osgitopologymanager.exportRegisteredSvcs", "true")).booleanValue(); //$NON-NLS-1$ //$NON-NLS-2$ private static final String exportRegisteredSvcsFilter = System .getProperty( "org.eclipse.ecf.osgi.services.osgitopologymanager.exportRegisteredSvcsFilter", "(service.exported.interfaces=*)"); //$NON-NLS-1$ //$NON-NLS-2$ private static final String exportRegisteredSvcsClassname = System .getProperty("org.eclipse.ecf.osgi.services.osgitopologymanager.exportRegisteredSvcsClassname"); //$NON-NLS-1$ private String ecfLocalEndpointListenerScope; private String ecfNonLocalEndpointListenerScope; private String osgiLocalEndpointListenerScope; private String osgiNonLocalEndpointListenerScope; private static final String ONLY_ECF_SCOPE = "(" + RemoteConstants.ENDPOINT_CONTAINER_ID_NAMESPACE + "=*)"; //$NON-NLS-1$ //$NON-NLS-2$ private static final String NO_ECF_SCOPE = "(!(" //$NON-NLS-1$ + RemoteConstants.ENDPOINT_CONTAINER_ID_NAMESPACE + "=*))"; //$NON-NLS-1$ OSGiTopologyManagerImpl(BundleContext context) { super(context); String frameworkUUID = getFrameworkUUID(); StringBuffer ecfLocalScope = new StringBuffer(""); //$NON-NLS-1$ ecfLocalScope .append("(&(").append(org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_FRAMEWORK_UUID).append("=").append(frameworkUUID).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ ecfLocalScope.append(ONLY_ECF_SCOPE); ecfLocalScope.append(")"); //$NON-NLS-1$ ecfLocalEndpointListenerScope = ecfLocalScope.toString(); StringBuffer ecfNonLocalScope = new StringBuffer(""); //$NON-NLS-1$ ecfNonLocalScope .append("(&(!(").append(org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_FRAMEWORK_UUID).append("=").append(frameworkUUID).append("))"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ ecfNonLocalScope.append(ONLY_ECF_SCOPE); ecfNonLocalScope.append(")"); //$NON-NLS-1$ ecfNonLocalEndpointListenerScope = ecfNonLocalScope.toString(); StringBuffer localScope = new StringBuffer(""); //$NON-NLS-1$ localScope .append("(&(").append(org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_FRAMEWORK_UUID).append("=").append(frameworkUUID).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ localScope.append(NO_ECF_SCOPE); localScope.append(")"); //$NON-NLS-1$ osgiLocalEndpointListenerScope = localScope.toString(); StringBuffer nonlocalScope = new StringBuffer(""); //$NON-NLS-1$ nonlocalScope .append("(&(!(").append(org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_FRAMEWORK_UUID).append("=").append(frameworkUUID).append("))"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ nonlocalScope.append(NO_ECF_SCOPE); nonlocalScope.append(")"); //$NON-NLS-1$ osgiNonLocalEndpointListenerScope = nonlocalScope.toString(); } String[] getScope() { return new String[] { ecfLocalEndpointListenerScope, ecfNonLocalEndpointListenerScope, osgiLocalEndpointListenerScope, osgiNonLocalEndpointListenerScope }; } protected String getFrameworkUUID() { return super.getFrameworkUUID(); } void exportRegisteredServices(String exportRegisteredSvcsClassname, String exportRegisteredSvcsFilter) { try { final ServiceReference[] existingServiceRefs = getContext() .getAllServiceReferences(exportRegisteredSvcsClassname, exportRegisteredSvcsFilter); // Now export as if the service was registering right now...i.e. // perform // export if (existingServiceRefs != null && existingServiceRefs.length > 0) { // After having collected all pre-registered services (with // marker prop) we are going to asynchronously remote them. // Registering potentially is a long-running operation (due to // discovery I/O...) and thus should no be carried out in the // OSGi FW thread. (https://bugs.eclipse.org/405027) new Thread(new Runnable() { public void run() { for (int i = 0; i < existingServiceRefs.length; i++) { // This method will check the service properties for // remote service props. If previously registered as // a // remote service, it will export the remote // service if not it will simply return/skip handleServiceRegistering(existingServiceRefs[i]); } } }, "BasicTopologyManagerPreRegSrvExporter").start(); //$NON-NLS-1$ } } catch (InvalidSyntaxException e) { logError( "exportRegisteredServices", //$NON-NLS-1$ "Could not retrieve existing service references for exportRegisteredSvcsClassname=" //$NON-NLS-1$ + exportRegisteredSvcsClassname + " and exportRegisteredSvcsFilter=" //$NON-NLS-1$ + exportRegisteredSvcsFilter, e); } } // EndpointListener impl /* * (non-Javadoc) * * @see * org.osgi.service.remoteserviceadmin.EndpointListener#endpointAdded(org * .osgi.service.remoteserviceadmin.EndpointDescription, java.lang.String) * * * From the R5 spec page 329 section 122.6.2: * * Notify the Endpoint Listener of a new Endpoint Description. The second * parameter is the filter that matched the Endpoint Description. * Registering the same Endpoint multiple times counts as a single * registration. */ public void endpointAdded( org.osgi.service.remoteserviceadmin.EndpointDescription endpoint, String matchedFilter) { handleEndpointAdded(endpoint, matchedFilter); } protected void handleEndpointAdded( org.osgi.service.remoteserviceadmin.EndpointDescription endpoint, String matchedFilter) { if (matchedFilter.equals(osgiLocalEndpointListenerScope)) { advertiseEndpointDescription(endpoint); } else if (matchedFilter.equals(osgiNonLocalEndpointListenerScope)) { EndpointDescription ed = convertEndpointDescriptionFromOSGiToECF(endpoint); if (ed != null) { handleECFEndpointAdded(ed); } } else if (matchedFilter.equals(ecfNonLocalEndpointListenerScope)) { handleECFEndpointAdded((EndpointDescription) endpoint); } else if (matchedFilter.equals(ecfLocalEndpointListenerScope)) { advertiseEndpointDescription(endpoint); } } private EndpointDescription convertEndpointDescriptionFromOSGiToECF( org.osgi.service.remoteserviceadmin.EndpointDescription ed) { Map<String, Object> newProps = new HashMap<String, Object>(); newProps.putAll(ed.getProperties()); String ecfNS = (String) newProps .remove(RemoteConstants.OSGI_CONTAINER_ID_NS); if (ecfNS == null) return null; newProps.put(RemoteConstants.ENDPOINT_CONTAINER_ID_NAMESPACE, ecfNS); return new EndpointDescription(newProps); } /* * (non-Javadoc) * * @see * org.osgi.service.remoteserviceadmin.EndpointListener#endpointRemoved( * org.osgi.service.remoteserviceadmin.EndpointDescription, * java.lang.String) */ public void endpointRemoved( org.osgi.service.remoteserviceadmin.EndpointDescription endpoint, String matchedFilter) { handleEndpointRemoved(endpoint, matchedFilter); } protected void handleEndpointRemoved( org.osgi.service.remoteserviceadmin.EndpointDescription endpoint, String matchedFilter) { if (matchedFilter.equals(osgiLocalEndpointListenerScope)) { unadvertiseEndpointDescription(endpoint); } else if (matchedFilter.equals(osgiNonLocalEndpointListenerScope)) { EndpointDescription ed = convertEndpointDescriptionFromOSGiToECF(endpoint); if (ed != null) handleECFEndpointRemoved(ed); } else if (matchedFilter.equals(ecfNonLocalEndpointListenerScope)) { handleECFEndpointRemoved((EndpointDescription) endpoint); } else if (matchedFilter.equals(ecfLocalEndpointListenerScope)) { unadvertiseEndpointDescription(endpoint); } } /** * Implementation of * org.osgi.service.remoteserviceadmin.EndpointEventListener for rfc 203/RSA * 1.1 * * @see EndpointEventListener#endpointChanged(EndpointEvent, String) */ public void endpointChanged(EndpointEvent event, String matchedFilter) { int eventType = event.getType(); org.osgi.service.remoteserviceadmin.EndpointDescription ed = event .getEndpoint(); switch (eventType) { case EndpointEvent.ADDED: handleEndpointAdded(ed, matchedFilter); break; case EndpointEvent.REMOVED: handleEndpointRemoved(ed, matchedFilter); break; case EndpointEvent.MODIFIED: handleEndpointModified(ed, matchedFilter); break; case EndpointEvent.MODIFIED_ENDMATCH: handleEndpointModifiedEndmatch(ed, matchedFilter); break; } } protected void handleEndpointModifiedEndmatch( org.osgi.service.remoteserviceadmin.EndpointDescription endpoint, String matchedFilter) { // By default do nothing for end match. subclasses may decide // to change this behavior } private static Long getOSGiEndpointModifiedValue( Map<String, Object> properties) { Object modifiedValue = properties .get(RemoteConstants.OSGI_ENDPOINT_MODIFIED); if (modifiedValue != null && modifiedValue instanceof String) return Long.valueOf((String) modifiedValue); return null; } protected void handleEndpointModified( org.osgi.service.remoteserviceadmin.EndpointDescription endpoint, String matchedFilter) { if (matchedFilter.equals(osgiLocalEndpointListenerScope)) { Map<String, Object> edProperties = endpoint.getProperties(); Long modified = getOSGiEndpointModifiedValue(edProperties); Map<String, Object> newEdProperties = new HashMap<String, Object>(); newEdProperties.putAll(endpoint.getProperties()); if (modified != null) { newEdProperties.remove(RemoteConstants.OSGI_ENDPOINT_MODIFIED); handleNonECFEndpointModified( this, new org.osgi.service.remoteserviceadmin.EndpointDescription( newEdProperties)); } else { newEdProperties.put(RemoteConstants.OSGI_ENDPOINT_MODIFIED, String.valueOf(System.currentTimeMillis())); advertiseModifyEndpointDescription(new org.osgi.service.remoteserviceadmin.EndpointDescription( newEdProperties)); } } else if (matchedFilter.equals(osgiNonLocalEndpointListenerScope)) { handleNonECFEndpointModified(this, endpoint); } } public void activate() { if (exportRegisteredSvcs) exportRegisteredServices(exportRegisteredSvcsClassname, exportRegisteredSvcsFilter); } }