| /* |
| * 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 WARRANTIESOR 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.jmx.core.whiteboard; |
| |
| import java.util.Hashtable; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentMap; |
| import java.util.concurrent.atomic.AtomicReference; |
| |
| import org.apache.aries.jmx.Logger; |
| import org.apache.aries.jmx.framework.BundleState; |
| import org.apache.aries.jmx.framework.Framework; |
| import org.apache.aries.jmx.framework.PackageState; |
| import org.apache.aries.jmx.framework.ServiceState; |
| import org.apache.aries.jmx.util.ObjectNameUtils; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleActivator; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.Filter; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceFactory; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.framework.ServiceRegistration; |
| import org.osgi.jmx.framework.BundleStateMBean; |
| import org.osgi.jmx.framework.FrameworkMBean; |
| import org.osgi.jmx.framework.PackageStateMBean; |
| import org.osgi.jmx.framework.ServiceStateMBean; |
| import org.osgi.jmx.service.cm.ConfigurationAdminMBean; |
| import org.osgi.jmx.service.permissionadmin.PermissionAdminMBean; |
| import org.osgi.jmx.service.provisioning.ProvisioningServiceMBean; |
| import org.osgi.jmx.service.useradmin.UserAdminMBean; |
| import org.osgi.service.cm.ConfigurationAdmin; |
| import org.osgi.service.packageadmin.PackageAdmin; |
| import org.osgi.service.permissionadmin.PermissionAdmin; |
| import org.osgi.service.provisioning.ProvisioningService; |
| import org.osgi.service.startlevel.StartLevel; |
| import org.osgi.service.useradmin.UserAdmin; |
| import org.osgi.util.tracker.ServiceTracker; |
| import org.osgi.util.tracker.ServiceTrackerCustomizer; |
| |
| public class Activator implements BundleActivator, ServiceTrackerCustomizer |
| { |
| private ServiceTracker tracker; |
| private BundleContext ctx; |
| private ConcurrentMap<Long, ServiceRegistration> _provisioningMBeans = new ConcurrentHashMap<Long, ServiceRegistration>(); |
| private ConcurrentMap<Long, ServiceRegistration> _userAdminMBeans = new ConcurrentHashMap<Long, ServiceRegistration>(); |
| private ConcurrentMap<Long, ServiceRegistration> _configAdminMBeans = new ConcurrentHashMap<Long, ServiceRegistration>(); |
| |
| private AtomicReference<ServiceRegistration> _serviceStateMbean = new AtomicReference<ServiceRegistration>(); |
| private AtomicReference<ServiceRegistration> _permissionAdminMbean = new AtomicReference<ServiceRegistration>(); |
| private AtomicReference<ServiceRegistration> _packageStateMbean = new AtomicReference<ServiceRegistration>(); |
| private AtomicReference<ServiceRegistration> _bundleState = new AtomicReference<ServiceRegistration>(); |
| private AtomicReference<ServiceRegistration> _framework = new AtomicReference<ServiceRegistration>(); |
| |
| private AtomicReference<ServiceReference> _startLevel = new AtomicReference<ServiceReference>(); |
| private AtomicReference<ServiceReference> _packageAdmin = new AtomicReference<ServiceReference>(); |
| |
| private static final String PACKAGE_ADMIN = "org.osgi.service.packageadmin.PackageAdmin"; |
| private static final String START_LEVEL = "org.osgi.service.startlevel.StartLevel"; |
| private static final String PERMISSION_ADMIN = "org.osgi.service.permissionadmin.PermissionAdmin"; |
| private static final String CONFIG_ADMIN = "org.osgi.service.cm.ConfigurationAdmin"; |
| private static final String USER_ADMIN = "org.osgi.service.useradmin.UserAdmin"; |
| private static final String PROVISIONING_SERVICE = "org.osgi.service.provisioning.ProvisioningService"; |
| |
| private Logger logger; |
| |
| private class MBeanServiceProxy<T> implements ServiceFactory |
| { |
| private Factory<T> objectFactory; |
| private AtomicReference<T> result = new AtomicReference<T>(); |
| |
| private MBeanServiceProxy(Factory<T> factory) { |
| objectFactory = factory; |
| } |
| |
| public Object getService(Bundle bundle, ServiceRegistration registration) |
| { |
| if (result.get() == null) { |
| result.compareAndSet(null, objectFactory.create()); |
| } |
| return result.get(); |
| } |
| |
| public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) |
| { |
| } |
| } |
| |
| private interface Factory<T> |
| { |
| public abstract T create(); |
| } |
| |
| private abstract class BaseFactory<T> implements Factory<T> |
| { |
| public abstract T create(PackageAdmin pa, StartLevel sl); |
| public final T create() |
| { |
| StartLevel sl = null; |
| PackageAdmin pa = null; |
| |
| ServiceReference slRef = _startLevel.get(); |
| if (slRef != null) { |
| sl = (StartLevel) ctx.getService(slRef); |
| } |
| ServiceReference paRef = _packageAdmin.get(); |
| |
| if (paRef != null) { |
| pa = (PackageAdmin) ctx.getService(paRef); |
| } |
| |
| if (pa == null) { |
| ctx.ungetService(slRef); |
| } |
| |
| if (sl != null && pa != null) { |
| return create(pa, sl); |
| } else { |
| return null; |
| } |
| } |
| } |
| |
| public void start(BundleContext context) throws Exception |
| { |
| ctx = context; |
| logger = new Logger(ctx); |
| |
| Filter filter = getFilter(context, PACKAGE_ADMIN, START_LEVEL, |
| PERMISSION_ADMIN, CONFIG_ADMIN, USER_ADMIN, |
| PROVISIONING_SERVICE); |
| |
| tracker = new ServiceTracker(context, filter, this); |
| tracker.open(); |
| |
| registerMBean(ServiceStateMBean.class.getName(), new Factory<ServiceStateMBean>() { |
| public ServiceStateMBean create() |
| { |
| return new ServiceState(ctx, logger); |
| } |
| }, ServiceStateMBean.OBJECTNAME, _serviceStateMbean ); |
| } |
| |
| private Filter getFilter(BundleContext ctx, String ... services) throws InvalidSyntaxException |
| { |
| StringBuilder builder = new StringBuilder("(|"); |
| |
| for (String type : services) { |
| builder.append('('); |
| builder.append(Constants.OBJECTCLASS); |
| builder.append('='); |
| builder.append(type); |
| builder.append(')'); |
| } |
| |
| builder.append(')'); |
| return ctx.createFilter(builder.toString()); |
| } |
| |
| public void stop(BundleContext context) throws Exception |
| { |
| tracker.close(); |
| } |
| |
| public Object addingService(ServiceReference reference) |
| { |
| Object tracked = null; |
| |
| String[] types = (String[]) reference.getProperty(Constants.OBJECTCLASS); |
| |
| for (String t : types) { |
| if (PACKAGE_ADMIN.equals(t)) { |
| foundPackageAdmin(reference); |
| tracked = reference; |
| } else if (START_LEVEL.equals(t)) { |
| foundStartLevel(reference); |
| tracked = reference; |
| } else if (PERMISSION_ADMIN.equals(t)) { |
| foundPermissionAdmin(reference); |
| tracked = reference; |
| } else if (CONFIG_ADMIN.equals(t)) { |
| foundConfigAdmin(reference); |
| tracked = reference; |
| } else if (USER_ADMIN.equals(t)) { |
| foundUserAdmin(reference); |
| tracked = reference; |
| } else if (PROVISIONING_SERVICE.equals(t)) { |
| foundProvisioningService(reference); |
| tracked = reference; |
| } |
| } |
| |
| return tracked; |
| } |
| |
| private <T> void registerMBean(String type, Factory<T> factory, String objectName, AtomicReference<ServiceRegistration> result) |
| { |
| synchronized (result) { |
| ServiceRegistration reg = registerAnMbean(type, factory, objectName); |
| |
| if (!!!result.compareAndSet(null, reg)) { |
| reg.unregister(); |
| } |
| } |
| } |
| |
| private <T> void registerMBean(String type, Factory<T> factory, String objectName, ConcurrentMap<Long, ServiceRegistration> mbeans, |
| ServiceReference referencedServices, String underlyingType) |
| { |
| try { |
| Class.forName(underlyingType); |
| if (referencedServices.isAssignableTo(ctx.getBundle(), underlyingType)) { |
| ServiceRegistration reg = registerAnMbean(type, factory, objectName); |
| |
| Long id = (Long) reg.getReference().getProperty(Constants.SERVICE_ID); |
| mbeans.put(id, reg); |
| } |
| } catch (ClassNotFoundException e) { |
| } |
| } |
| |
| private <T> ServiceRegistration registerAnMbean(String type, Factory<T> factory, String objectName) |
| { |
| Hashtable<String, Object> properties = new Hashtable<String, Object>(); |
| properties.put("jmx.objectname", ObjectNameUtils.createFullObjectName(ctx, objectName)); |
| |
| Object service = new MBeanServiceProxy<T>(factory); |
| |
| ServiceRegistration reg = ctx.registerService(type, service, properties); |
| return reg; |
| } |
| |
| private void foundPermissionAdmin(final ServiceReference reference) |
| { |
| registerMBean(PermissionAdminMBean.class.getName(), new Factory<PermissionAdminMBean>() { |
| public PermissionAdminMBean create() |
| { |
| PermissionAdmin service = (PermissionAdmin) ctx.getService(reference); |
| |
| if (service == null) return null; |
| else return new org.apache.aries.jmx.permissionadmin.PermissionAdmin(service); |
| } |
| }, PermissionAdminMBean.OBJECTNAME, _permissionAdminMbean); |
| } |
| |
| private void foundProvisioningService(final ServiceReference reference) |
| { |
| registerMBean(ProvisioningServiceMBean.class.getName(), new Factory<ProvisioningServiceMBean>() { |
| public ProvisioningServiceMBean create() |
| { |
| ProvisioningService service = (ProvisioningService) ctx.getService(reference); |
| |
| if (service == null) return null; |
| else return new org.apache.aries.jmx.provisioning.ProvisioningService(service); |
| } |
| }, ProvisioningServiceMBean.OBJECTNAME, _provisioningMBeans, reference, PROVISIONING_SERVICE); |
| } |
| |
| private void foundUserAdmin(final ServiceReference reference) |
| { |
| try { |
| Class.forName(USER_ADMIN); |
| if (reference.isAssignableTo(ctx.getBundle(), USER_ADMIN)) { |
| registerMBean(UserAdminMBean.class.getName(), new Factory<UserAdminMBean>() { |
| public UserAdminMBean create() |
| { |
| UserAdmin service = (UserAdmin) ctx.getService(reference); |
| |
| if (service == null) return null; |
| else return new org.apache.aries.jmx.useradmin.UserAdmin(service); |
| } |
| }, UserAdminMBean.OBJECTNAME, _userAdminMBeans, reference, USER_ADMIN); |
| } |
| } catch (ClassNotFoundException e) { |
| } |
| } |
| |
| private void foundConfigAdmin(final ServiceReference reference) |
| { |
| registerMBean(ConfigurationAdminMBean.class.getName(), new Factory<ConfigurationAdminMBean>() { |
| public ConfigurationAdminMBean create() |
| { |
| ConfigurationAdmin service = (ConfigurationAdmin) ctx.getService(reference); |
| |
| if (service == null) return null; |
| else return new org.apache.aries.jmx.cm.ConfigurationAdmin(service); |
| } |
| }, ConfigurationAdminMBean.OBJECTNAME, _configAdminMBeans, reference, CONFIG_ADMIN); |
| } |
| |
| private void foundStartLevel(final ServiceReference reference) |
| { |
| if (_startLevel.compareAndSet(null, reference)) { |
| registerBundleStateAndFrameworkIfPossible(); |
| } |
| } |
| |
| private void foundPackageAdmin(final ServiceReference reference) |
| { |
| registerMBean(PackageStateMBean.class.getName(), new Factory<PackageStateMBean>() { |
| public PackageStateMBean create() |
| { |
| PackageAdmin service = (PackageAdmin) ctx.getService(reference); |
| |
| if (service == null) return null; |
| else return new PackageState(ctx, service); |
| } |
| }, PackageStateMBean.OBJECTNAME, _packageStateMbean); |
| |
| if (_packageAdmin.compareAndSet(null, reference)) { |
| registerBundleStateAndFrameworkIfPossible(); |
| } |
| } |
| |
| // This method is synchronized to ensure that notification of StartLevel and PackageAdmin |
| // on different threads at the same time doesn't cause problems. It only affects these services |
| // so it shouldn't be too expensive. |
| private synchronized void registerBundleStateAndFrameworkIfPossible() |
| { |
| if (_bundleState.get() == null && _startLevel.get() != null && _packageAdmin.get() != null) { |
| registerMBean(BundleStateMBean.class.getName(), new BaseFactory<BundleStateMBean>() { |
| @Override |
| public BundleStateMBean create(PackageAdmin pa, StartLevel sl) |
| { |
| return new BundleState(ctx, pa, sl, logger); |
| } |
| }, BundleStateMBean.OBJECTNAME, _bundleState); |
| } |
| if (_framework.get() == null && _startLevel.get() != null && _packageAdmin.get() != null) { |
| registerMBean(FrameworkMBean.class.getName(), new BaseFactory<FrameworkMBean>() { |
| @Override |
| public FrameworkMBean create(PackageAdmin pa, StartLevel sl) |
| { |
| return new Framework(ctx, sl, pa); |
| } |
| }, FrameworkMBean.OBJECTNAME, _framework); |
| } |
| } |
| |
| public void modifiedService(ServiceReference reference, Object service) |
| { |
| } |
| |
| public void removedService(ServiceReference reference, Object service) |
| { |
| String[] types = (String[]) reference.getProperty(Constants.OBJECTCLASS); |
| |
| for (String t : types) { |
| if (PACKAGE_ADMIN.equals(t)) { |
| lostPackageAdmin(reference); |
| } else if (START_LEVEL.equals(t)) { |
| lostStartLevel(reference); |
| } else if (PERMISSION_ADMIN.equals(t)) { |
| lostPermissionAdmin(reference); |
| } else if (CONFIG_ADMIN.equals(t)) { |
| lostConfigAdmin(reference); |
| } else if (USER_ADMIN.equals(t)) { |
| lostUserAdmin(reference); |
| } else if (PROVISIONING_SERVICE.equals(t)) { |
| lostProvisioningService(reference); |
| } |
| } |
| |
| } |
| |
| private void lostProvisioningService(ServiceReference reference) |
| { |
| unregister(reference, _provisioningMBeans); |
| } |
| |
| private void lostUserAdmin(ServiceReference reference) |
| { |
| unregister(reference, _userAdminMBeans); |
| } |
| |
| private void lostConfigAdmin(ServiceReference reference) |
| { |
| unregister(reference, _configAdminMBeans); |
| } |
| |
| private void unregister(ServiceReference reference, ConcurrentMap<Long, ServiceRegistration> mbeans) |
| { |
| Long id = (Long) reference.getProperty(Constants.SERVICE_ID); |
| ServiceRegistration reg = mbeans.remove(id); |
| if (reg != null) reg.unregister(); |
| } |
| |
| private void lostPermissionAdmin(ServiceReference reference) |
| { |
| safeUnregister(_permissionAdminMbean); |
| } |
| |
| private void lostStartLevel(ServiceReference reference) |
| { |
| if (_startLevel.compareAndSet(reference, null)) { |
| safeUnregister(_bundleState); |
| safeUnregister(_framework); |
| } |
| } |
| |
| private void lostPackageAdmin(ServiceReference reference) |
| { |
| if (_packageAdmin.compareAndSet(reference, null)) { |
| safeUnregister(_bundleState); |
| safeUnregister(_framework); |
| |
| safeUnregister(_packageStateMbean); |
| } |
| } |
| |
| private void safeUnregister(AtomicReference<ServiceRegistration> atomicRegistration) |
| { |
| ServiceRegistration reg = atomicRegistration.getAndSet(null); |
| if (reg != null) reg.unregister(); |
| } |
| } |