blob: 1c1eeb3585768801b2dd561121dfaf89601f4d98 [file] [log] [blame]
/*
* 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();
}
}