Package org.apache.aries.jmx.framework

Source Code of org.apache.aries.jmx.framework.ServiceState

/**
*  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.apache.aries.jmx.framework;

import static org.apache.aries.jmx.util.FrameworkUtils.getBundleIds;
import static org.apache.aries.jmx.util.FrameworkUtils.resolveService;
import static org.osgi.jmx.JmxConstants.PROPERTIES_TYPE;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import javax.management.MBeanNotificationInfo;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
import javax.management.ObjectName;
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;

import org.apache.aries.jmx.Logger;
import org.apache.aries.jmx.codec.PropertyData;
import org.apache.aries.jmx.codec.ServiceData;
import org.apache.aries.jmx.codec.ServiceEventData;
import org.osgi.framework.AllServiceListener;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceReference;
import org.osgi.jmx.framework.ServiceStateMBean;
import org.osgi.service.log.LogService;

/**
* Implementation of <code>ServiceStateMBean</code> which emits JMX <code>Notification</code> for framework
* <code>ServiceEvent</code> events
*
* @version $Rev: 898958 $ $Date: 2010-01-13 23:00:58 +0100 (Wed, 13 Jan 2010) $
*/
public class ServiceState extends NotificationBroadcasterSupport implements ServiceStateMBean, MBeanRegistration {

    protected Logger logger;
    private BundleContext bundleContext;

    protected ExecutorService eventDispatcher;
    protected AllServiceListener serviceListener;
    private AtomicInteger notificationSequenceNumber = new AtomicInteger(1);
    private AtomicInteger registrations = new AtomicInteger(0);
    private Lock lock = new ReentrantLock();
    // notification type description
    public static String SERVICE_EVENT = "org.osgi.service.event";

    public ServiceState(BundleContext bundleContext, Logger logger) {
        if (bundleContext == null) {
            throw new IllegalArgumentException("Argument bundleContext cannot be null");
        }
        this.bundleContext = bundleContext;
        this.logger = logger;
    }

    /**
     * @see org.osgi.jmx.framework.ServiceStateMBean#getBundleIdentifier(long)
     */
    public long getBundleIdentifier(long serviceId) throws IOException, IllegalArgumentException {
        ServiceReference reference = resolveService(bundleContext, serviceId);
        return reference.getBundle().getBundleId();
    }

    /**
     * @see org.osgi.jmx.framework.ServiceStateMBean#getObjectClass(long)
     */
    public String[] getObjectClass(long serviceId) throws IOException {
        ServiceReference reference = resolveService(bundleContext, serviceId);
        return (String[]) reference.getProperty(Constants.OBJECTCLASS);
    }

    /**
     * @see org.osgi.jmx.framework.ServiceStateMBean#getProperties(long)
     */
    public TabularData getProperties(long serviceId) throws IOException {
        ServiceReference reference = resolveService(bundleContext, serviceId);
        TabularData propertiesTable = new TabularDataSupport(PROPERTIES_TYPE);
        for (String propertyKey : reference.getPropertyKeys()) {
            propertiesTable.put(PropertyData.newInstance(propertyKey, reference.getProperty(propertyKey))
                    .toCompositeData());
        }
        return propertiesTable;
    }

    /**
     * @see org.osgi.jmx.framework.ServiceStateMBean#getUsingBundles(long)
     */
    public long[] getUsingBundles(long serviceId) throws IOException {
        ServiceReference reference = resolveService(bundleContext, serviceId);
        Bundle[] usingBundles = reference.getUsingBundles();
        return getBundleIds(usingBundles);
    }

    /**
     * @see org.osgi.jmx.framework.ServiceStateMBean#listServices()
     */
    public TabularData listServices() throws IOException {
        TabularData servicesTable = new TabularDataSupport(SERVICES_TYPE);
        ServiceReference[] allServiceReferences = null;
        try {
            allServiceReferences = bundleContext.getAllServiceReferences(null, null);
        } catch (InvalidSyntaxException e) {
            throw new IllegalStateException("Failed to retrieve all service references", e);
        }
        if (allServiceReferences != null) {
            for (ServiceReference reference : allServiceReferences) {
                servicesTable.put(new ServiceData(reference).toCompositeData());
            }
        }
        return servicesTable;
    }

    /**
     * @see javax.management.NotificationBroadcasterSupport#getNotificationInfo()
     */
    public MBeanNotificationInfo[] getNotificationInfo() {
        String[] types = new String[] { SERVICE_EVENT };
        String name = Notification.class.getName();
        String description = "A ServiceEvent issued from the Framework describing a service lifecycle change";
        MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description);
        return new MBeanNotificationInfo[] { info };
    }

    /**
     * @see javax.management.MBeanRegistration#postDeregister()
     */
    public void postDeregister() {
        if (registrations.decrementAndGet() < 1) {
            shutDownDispatcher();
        }
    }

    /**
     * @see javax.management.MBeanRegistration#postRegister(java.lang.Boolean)
     */
    public void postRegister(Boolean registrationDone) {
        if (registrationDone && registrations.incrementAndGet() == 1) {
            eventDispatcher = Executors.newSingleThreadExecutor();
            bundleContext.addServiceListener(serviceListener);
        }
    }

    public void preDeregister() throws Exception {
        // No action
    }

    /**
     * @see javax.management.MBeanRegistration#preRegister(javax.management.MBeanServer, javax.management.ObjectName)
     */
    public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
        lock.lock();
        try {
            if (serviceListener == null) {
                serviceListener = new AllServiceListener() {
                    public void serviceChanged(ServiceEvent serviceevent) {
                        final Notification notification = new Notification(EVENT, OBJECTNAME,
                                notificationSequenceNumber.getAndIncrement());
                        try {
                            notification.setUserData(new ServiceEventData(serviceevent).toCompositeData());
                            eventDispatcher.submit(new Runnable() {
                                public void run() {
                                    sendNotification(notification);
                                }
                            });
                        } catch (RejectedExecutionException re) {
                            logger.log(LogService.LOG_WARNING, "Task rejected for JMX Notification dispatch of event ["
                                    + serviceevent + "] - Dispatcher may have been shutdown");
                        } catch (Exception e) {
                            logger.log(LogService.LOG_WARNING,
                                    "Exception occured on JMX Notification dispatch for event [" + serviceevent + "]",
                                    e);
                        }
                    }
                };
            }
        } finally {
            lock.unlock();
        }
        return name;
    }

    /*
     * Shuts down the notification dispatcher
     * [ARIES-259] MBeans not getting unregistered reliably
     */
    protected void shutDownDispatcher() {
        if (serviceListener != null) {
            try {
               bundleContext.removeServiceListener(serviceListener);
            }
            catch (Exception e) {
               // ignore
            }
        }
        if (eventDispatcher != null) { 
            eventDispatcher.shutdown();
        }
    }

    /*
     * Returns the ExecutorService used to dispatch Notifications
     */
    protected ExecutorService getEventDispatcher() {
        return eventDispatcher;
    }

}
TOP

Related Classes of org.apache.aries.jmx.framework.ServiceState

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.