| /* |
| * Licensed 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.apache.aries.subsystem.core.internal; |
| |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Dictionary; |
| import java.util.HashSet; |
| import java.util.Hashtable; |
| |
| import org.apache.aries.subsystem.ContentHandler; |
| import org.apache.aries.subsystem.core.content.ConfigAdminContentHandler; |
| import org.apache.aries.util.filesystem.IDirectoryFinder; |
| import org.eclipse.equinox.region.RegionDigraph; |
| 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.ServiceReference; |
| import org.osgi.framework.ServiceRegistration; |
| import org.osgi.framework.hooks.bundle.EventHook; |
| import org.osgi.framework.hooks.resolver.ResolverHookFactory; |
| import org.osgi.service.coordinator.Coordinator; |
| import org.osgi.service.resolver.Resolver; |
| import org.osgi.util.tracker.ServiceTracker; |
| import org.osgi.util.tracker.ServiceTrackerCustomizer; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * The bundle activator for the this bundle. When the bundle is starting, this |
| * activator will create and register the SubsystemAdmin service. |
| */ |
| public class Activator implements BundleActivator, ServiceTrackerCustomizer<Object, Object> { |
| private static final Logger logger = LoggerFactory.getLogger(Activator.class); |
| public static final String MODELLED_RESOURCE_MANAGER = "org.apache.aries.application.modelling.ModelledResourceManager"; |
| |
| public static final String LOG_ENTRY = "Method entry: {}, args {}"; |
| public static final String LOG_EXIT = "Method exit: {}, returning {}"; |
| |
| private static Activator instance; |
| |
| public static synchronized Activator getInstance() { |
| logger.debug(LOG_ENTRY, "getInstance"); |
| checkInstance(); |
| logger.debug(LOG_EXIT, "getInstance", instance); |
| return instance; |
| } |
| |
| private static synchronized void checkInstance() { |
| logger.debug(LOG_ENTRY, "checkInstance"); |
| if (instance == null) |
| throw new IllegalStateException("The activator has not been initialized or has been shutdown"); |
| logger.debug(LOG_EXIT, "checkInstance"); |
| } |
| |
| // @GuardedBy("this") |
| private BundleEventHook bundleEventHook; |
| private volatile BundleContext bundleContext; |
| private volatile ConfigAdminContentHandler configAdminHandler; |
| private volatile Coordinator coordinator; |
| private volatile Object modelledResourceManager; |
| private volatile ServiceModeller serviceModeller; |
| private volatile SubsystemServiceRegistrar registrar; |
| private volatile RegionDigraph regionDigraph; |
| private volatile Resolver resolver; |
| private ServiceTracker<?,?> serviceTracker; |
| |
| private volatile Subsystems subsystems; |
| |
| private final Collection<ServiceRegistration<?>> registrations = new HashSet<ServiceRegistration<?>>(); |
| private final Collection<IDirectoryFinder> finders = Collections.synchronizedSet(new HashSet<IDirectoryFinder>()); |
| |
| public BundleContext getBundleContext() { |
| return bundleContext; |
| } |
| |
| public Coordinator getCoordinator() { |
| return coordinator; |
| } |
| |
| public ServiceModeller getServiceModeller() { |
| return serviceModeller; |
| } |
| |
| public RegionDigraph getRegionDigraph() { |
| return regionDigraph; |
| } |
| |
| public Collection<IDirectoryFinder> getIDirectoryFinders() { |
| return Collections.unmodifiableCollection(finders); |
| } |
| |
| public Resolver getResolver() { |
| return resolver; |
| } |
| |
| public Subsystems getSubsystems() { |
| return subsystems; |
| } |
| |
| public SubsystemServiceRegistrar getSubsystemServiceRegistrar() { |
| logger.debug(LOG_ENTRY, "getSubsystemServiceRegistrar"); |
| SubsystemServiceRegistrar result = registrar; |
| logger.debug(LOG_EXIT, "getSubsystemServiceRegistrar", result); |
| return result; |
| } |
| |
| public org.apache.aries.subsystem.core.repository.Repository getSystemRepository() { |
| return new SystemRepository(getSubsystems().getRootSubsystem()); |
| } |
| |
| @Override |
| public synchronized void start(BundleContext context) throws Exception { |
| logger.debug(LOG_ENTRY, "start", context); |
| bundleContext = context; |
| serviceTracker = new ServiceTracker<Object, Object>(bundleContext, generateServiceFilter(), this); |
| serviceTracker.open(); |
| logger.debug(LOG_EXIT, "start"); |
| } |
| |
| @Override |
| public synchronized void stop(BundleContext context) { |
| logger.debug(LOG_ENTRY, "stop", context); |
| serviceTracker.close(); |
| serviceTracker = null; |
| bundleContext = null; |
| logger.debug(LOG_EXIT, "stop"); |
| } |
| |
| private void activate() { |
| if (isActive() || !hasRequiredServices()) |
| return; |
| synchronized (Activator.class) { |
| instance = Activator.this; |
| } |
| subsystems = new Subsystems(); |
| registerBundleEventHook(); |
| registrations.add(bundleContext.registerService(ResolverHookFactory.class, new SubsystemResolverHookFactory(subsystems), null)); |
| Dictionary<String, Object> handlerProps = new Hashtable<String, Object>(); |
| handlerProps.put(ContentHandler.CONTENT_TYPE_PROPERTY, ConfigAdminContentHandler.CONTENT_TYPES); |
| configAdminHandler = new ConfigAdminContentHandler(bundleContext); |
| registrations.add(bundleContext.registerService(ContentHandler.class, configAdminHandler, handlerProps)); |
| registrar = new SubsystemServiceRegistrar(bundleContext); |
| BasicSubsystem root = subsystems.getRootSubsystem(); |
| bundleEventHook.activate(); |
| root.start(); |
| registerWovenClassListener(); |
| } |
| |
| private void deactivate() { |
| if (!isActive()) |
| return; |
| bundleEventHook.deactivate(); |
| new StopAction(subsystems.getRootSubsystem(), subsystems.getRootSubsystem(), true).run(); |
| for (ServiceRegistration<?> registration : registrations) { |
| try { |
| registration.unregister(); |
| } |
| catch (IllegalStateException e) { |
| logger.debug("Service had already been unregistered", e); |
| } |
| } |
| configAdminHandler.shutDown(); |
| bundleEventHook.processPendingEvents(); |
| synchronized (Activator.class) { |
| instance = null; |
| } |
| } |
| |
| private <T> T findAlternateServiceFor(Class<T> service) { |
| Object[] services = serviceTracker.getServices(); |
| if (services == null) |
| return null; |
| for (Object alternate : services) |
| if (service.isInstance(alternate)) |
| return service.cast(alternate); |
| return null; |
| } |
| |
| private Filter generateServiceFilter() throws InvalidSyntaxException { |
| return FrameworkUtil.createFilter(generateServiceFilterString()); |
| } |
| |
| private String generateServiceFilterString() { |
| return new StringBuilder("(|(") |
| .append(org.osgi.framework.Constants.OBJECTCLASS).append('=') |
| .append(Coordinator.class.getName()).append(")(") |
| .append(org.osgi.framework.Constants.OBJECTCLASS).append('=') |
| .append(RegionDigraph.class.getName()).append(")(") |
| .append(org.osgi.framework.Constants.OBJECTCLASS).append('=') |
| .append(Resolver.class.getName()).append(")(") |
| .append(org.osgi.framework.Constants.OBJECTCLASS).append('=') |
| .append("org.osgi.service.repository.Repository").append(")(") |
| .append(org.osgi.framework.Constants.OBJECTCLASS).append('=') |
| .append(MODELLED_RESOURCE_MANAGER).append(")(") |
| .append(org.osgi.framework.Constants.OBJECTCLASS).append('=') |
| .append(IDirectoryFinder.class.getName()).append("))").toString(); |
| } |
| |
| private boolean hasRequiredServices() { |
| return coordinator != null && |
| regionDigraph != null && |
| resolver != null; |
| } |
| |
| private boolean isActive() { |
| synchronized (Activator.class) { |
| return instance != null && getSubsystems() != null; |
| } |
| } |
| |
| private void registerBundleEventHook() { |
| Dictionary<String, Object> properties = new Hashtable<String, Object>(1); |
| properties.put(org.osgi.framework.Constants.SERVICE_RANKING, Integer.MAX_VALUE); |
| bundleEventHook = new BundleEventHook(); |
| registrations.add(bundleContext.registerService(EventHook.class, bundleEventHook, properties)); |
| } |
| |
| private void registerWovenClassListener() { |
| registrations.add( |
| bundleContext.registerService( |
| org.osgi.framework.hooks.weaving.WovenClassListener.class, |
| new WovenClassListener(bundleContext, subsystems), |
| null)); |
| } |
| |
| /* Begin ServiceTrackerCustomizer methods */ |
| |
| @Override |
| public synchronized Object addingService(ServiceReference<Object> reference) { |
| Object service = bundleContext.getService(reference); |
| // Use all of each type of the following services. |
| if (service instanceof IDirectoryFinder) |
| finders.add((IDirectoryFinder) service); |
| // Use only one of each type of the following services. |
| else if (service instanceof Coordinator && coordinator == null) |
| coordinator = (Coordinator) service; |
| else if (service instanceof RegionDigraph && regionDigraph == null) |
| regionDigraph = (RegionDigraph) service; |
| else if (service instanceof Resolver && resolver == null) |
| resolver = (Resolver) service; |
| else { |
| try { |
| Class clazz = getClass().getClassLoader().loadClass(MODELLED_RESOURCE_MANAGER); |
| if (clazz.isInstance(service) && serviceModeller == null) { |
| modelledResourceManager = service; |
| serviceModeller = new ApplicationServiceModeller(service); |
| } else { |
| service = null; |
| } |
| } catch (ClassNotFoundException e) { |
| service = null; |
| } catch (NoClassDefFoundError e) { |
| service = null; |
| } |
| } |
| // Activation is harmless if already active or all required services |
| // have not yet been found. |
| activate(); |
| // Filter guarantees we want to track all services received. |
| return service; |
| } |
| |
| @Override |
| public void modifiedService(ServiceReference<Object> reference, Object service) { |
| // Nothing |
| } |
| |
| @Override |
| public synchronized void removedService(ServiceReference<Object> reference, Object service) { |
| if (service instanceof Coordinator) { |
| if (service.equals(coordinator)) { |
| Coordinator coordinator = findAlternateServiceFor(Coordinator.class); |
| if (coordinator == null) |
| deactivate(); |
| this.coordinator = coordinator; |
| } |
| } |
| else if (service instanceof RegionDigraph) { |
| if (service.equals(regionDigraph)) { |
| RegionDigraph regionDigraph = findAlternateServiceFor(RegionDigraph.class); |
| if (regionDigraph == null) |
| deactivate(); |
| this.regionDigraph = regionDigraph; |
| } |
| } |
| else if (service instanceof Resolver) { |
| if (service.equals(resolver)) { |
| Resolver resolver = findAlternateServiceFor(Resolver.class); |
| if (resolver == null) |
| deactivate(); |
| this.resolver = resolver; |
| } |
| } |
| else if (service instanceof IDirectoryFinder) |
| finders.remove(service); |
| else { |
| if (service.equals(modelledResourceManager)) { |
| try { |
| Class clazz = getClass().getClassLoader().loadClass(MODELLED_RESOURCE_MANAGER); |
| Object manager = findAlternateServiceFor(clazz); |
| if (manager == null) { |
| modelledResourceManager = null; |
| serviceModeller = null; |
| } else { |
| modelledResourceManager = service; |
| serviceModeller = new ApplicationServiceModeller(service); |
| } |
| } catch (ClassNotFoundException e) { |
| // ignore |
| } catch (NoClassDefFoundError e) { |
| // ignore |
| } |
| } |
| } |
| } |
| |
| /* End ServiceTrackerCustomizer methods */ |
| } |