/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.gecko.rsa.topology; import java.util.logging.Level; import java.util.logging.Logger; import org.gecko.rsa.api.ExportPolicy; import org.gecko.rsa.topology.exports.DefaultExportPolicy; import org.gecko.rsa.topology.exports.TopologyManagerExport; import org.gecko.rsa.topology.imports.TopologyManagerImport; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.remoteserviceadmin.RemoteConstants; import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; /** * * @author Mark Hoffmann * @since 30.08.2018 */ public class Activator implements BundleActivator { public static final String RSA_EXPORT_POLICY_FILTER = "rsa.export.policy.filter"; private static final Logger logger = Logger.getLogger(Activator.class.getName()); static final String DOSGI_SERVICE_FILTER = "(" + RemoteConstants.SERVICE_EXPORTED_INTERFACES + "=*)"; private TopologyManagerExport exportManager; private TopologyManagerImport importManager; private ServiceTracker rsaTracker; private ServiceTracker exportPolicyTracker; private volatile ServiceRegistration exportPolicyRegistration = null; private EndpointListenerManager endpointListenerManager; /* * (non-Javadoc) * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */ public void start(final BundleContext context) throws Exception { // Register default export poilicy as default exportPolicyRegistration = context.registerService(ExportPolicy.class, new DefaultExportPolicy(), DefaultExportPolicy.getExportPolicyProperties()); // now track all export policies Filter policyFilter = exportPolicyFilter(context); exportPolicyTracker = new ServiceTracker(context, policyFilter, null) { /* * (non-Javadoc) * @see org.osgi.util.tracker.ServiceTracker#addingService(org.osgi.framework.ServiceReference) */ @Override public ExportPolicy addingService(ServiceReference reference) { ExportPolicy policy = super.addingService(reference); // start the topology manager, with the first export policy if (exportManager == null) { doStart(context, policy); } return policy; } /* * (non-Javadoc) * @see org.osgi.util.tracker.ServiceTracker#removedService(org.osgi.framework.ServiceReference, java.lang.Object) */ @Override public void removedService(ServiceReference reference, ExportPolicy service) { // stop the topology manager when export policy was removed if (exportManager != null) { doStop(context); } super.removedService(reference, service); } }; exportPolicyTracker.open(); } /* * (non-Javadoc) * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext bc) throws Exception { // first remove export policy registration if (exportPolicyRegistration != null) { exportPolicyRegistration.unregister(); } // after that stop the tracker exportPolicyTracker.close(); } /** * Start the topology manager. It is started when an export policy is registered * @param bundleContext the bundle context * @param policy the export policy */ public void doStart(final BundleContext bundleContext, ExportPolicy policy) { logger.fine("TopologyManager: start()"); exportManager = new TopologyManagerExport(policy); importManager = new TopologyManagerImport(bundleContext); // create and start the end-point manager endpointListenerManager = new EndpointListenerManager(bundleContext, importManager, exportManager); endpointListenerManager.start(); // create service tracker for RemoteServiceAadmin instances rsaTracker = new RSATracker(bundleContext, RemoteServiceAdmin.class, null); rsaTracker.open(); exportExistingServices(bundleContext); } /** * Stop topology manager * @param bundleContext the bundle context */ public void doStop(BundleContext bundleContext) { logger.fine("TopologyManager: stop()"); // stop end-point manager endpointListenerManager.stop(); rsaTracker.close(); } /** * Gets all service references with a remote-service filter. * @param context the bundle context */ public void exportExistingServices(BundleContext context) { try { // cast to String is necessary for compiling against OSGi core version >= 4.3 ServiceReference[] references = context.getServiceReferences((String)null, DOSGI_SERVICE_FILTER); if (references != null) { for (ServiceReference sref : references) { exportManager.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, sref)); } } } catch (InvalidSyntaxException e) { logger.log(Level.SEVERE, String.format("Error in filter %s. This should not happen!", DOSGI_SERVICE_FILTER)); } } /** * Creates a filter for the {@link ExportPolicy} * @param bundleContext the bundel context * @return the {@link Filter} instance * @throws InvalidSyntaxException */ private Filter exportPolicyFilter(BundleContext bundleContext) throws InvalidSyntaxException { String filter = bundleContext.getProperty(RSA_EXPORT_POLICY_FILTER); if (filter == null) { filter = "(name=default)"; } return FrameworkUtil.createFilter(String.format("(&(objectClass=%s)%s)", ExportPolicy.class.getName(), filter)); } /** * {@link ServiceTracker} that tracks {@link RemoteServiceAdmin} instances * @author Mark Hoffmann * @since 30.08.2018 */ private final class RSATracker extends ServiceTracker { private RSATracker(BundleContext context, Class clazz, ServiceTrackerCustomizer customizer) { super(context, clazz, customizer); } /* * (non-Javadoc) * @see org.osgi.util.tracker.ServiceTracker#addingService(org.osgi.framework.ServiceReference) */ @Override public RemoteServiceAdmin addingService(ServiceReference reference) { RemoteServiceAdmin rsa = super.addingService(reference); logger.fine(String.format("New RemoteServiceAdmin '%s' detected, trying to import and export services with it", rsa)); importManager.add(rsa); exportManager.add(rsa); return rsa; } /* * (non-Javadoc) * @see org.osgi.util.tracker.ServiceTracker#removedService(org.osgi.framework.ServiceReference, java.lang.Object) */ @Override public void removedService(ServiceReference reference, RemoteServiceAdmin rsa) { logger.fine(String.format("RemoteServiceAdmin '%s' removal detected, trying to un-import and un-export services with it", rsa)); exportManager.remove(rsa); importManager.remove(rsa); super.removedService(reference, rsa); } } }