You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by at...@apache.org on 2009/12/03 10:01:15 UTC

svn commit: r886712 - in /incubator/aries/trunk/jmx/jmx-core/src: main/java/org/apache/aries/jmx/codec/ main/java/org/apache/aries/jmx/framework/ test/java/org/apache/aries/jmx/codec/ test/java/org/apache/aries/jmx/framework/

Author: atk
Date: Thu Dec  3 09:01:14 2009
New Revision: 886712

URL: http://svn.apache.org/viewvc?rev=886712&view=rev
Log:
ARIES-35 Implement ServiceStateMBean

Added:
    incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceData.java   (with props)
    incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceEventData.java   (with props)
    incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceState.java   (with props)
    incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandler.java   (with props)
    incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceDataTest.java   (with props)
    incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceEventDataTest.java   (with props)
    incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandlerTest.java   (with props)
    incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateTest.java   (with props)

Added: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceData.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceData.java?rev=886712&view=auto
==============================================================================
--- incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceData.java (added)
+++ incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceData.java Thu Dec  3 09:01:14 2009
@@ -0,0 +1,172 @@
+/**
+ *  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.codec;
+
+import static org.apache.aries.jmx.util.FrameworkUtils.getBundleIds;
+import static org.apache.aries.jmx.util.TypeUtils.toLong;
+import static org.apache.aries.jmx.util.TypeUtils.toPrimitive;
+import static org.osgi.jmx.JmxConstants.PROPERTIES_TYPE;
+import static org.osgi.jmx.framework.ServiceStateMBean.BUNDLE_IDENTIFIER;
+import static org.osgi.jmx.framework.ServiceStateMBean.IDENTIFIER;
+import static org.osgi.jmx.framework.ServiceStateMBean.OBJECT_CLASS;
+import static org.osgi.jmx.framework.ServiceStateMBean.PROPERTIES;
+import static org.osgi.jmx.framework.ServiceStateMBean.SERVICE_TYPE;
+import static org.osgi.jmx.framework.ServiceStateMBean.USING_BUNDLES;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.jmx.framework.ServiceStateMBean;
+
+/**
+ * <p>
+ * <tt>ServiceData</tt> represents Service Type @see {@link ServiceStateMBean#SERVICE_TYPE}. It is a codec for the
+ * <code>CompositeData</code> representing an OSGi <code>ServiceReference</code>.
+ * </p>
+ * 
+ * @version $Rev$ $Date$
+ */
+public class ServiceData {
+
+    /**
+     * @see ServiceStateMBean#IDENTIFIER_ITEM
+     */
+    private long serviceId;
+    
+    /**
+     * @see ServiceStateMBean#BUNDLE_IDENTIFIER_ITEM
+     */
+    private long bundleId;
+    
+    /**
+     * @see ServiceStateMBean#OBJECT_CLASS_ITEM
+     */
+    private String[] serviceInterfaces;
+    
+    /**
+     * @see ServiceStateMBean#PROPERTIES_ITEM
+     */
+    private List<PropertyData<? extends Object>> properties = new ArrayList<PropertyData<? extends Object>>();
+    
+    /**
+     * @see ServiceStateMBean#USING_BUNDLES_ITEM
+     */
+    private long[] usingBundles;
+
+    private ServiceData() {
+        super();
+    }
+
+    public ServiceData(ServiceReference serviceReference) throws IllegalArgumentException {
+        if (serviceReference == null) {
+            throw new IllegalArgumentException("Argument serviceReference cannot be null");
+        }
+        this.serviceId = (Long) serviceReference.getProperty(Constants.SERVICE_ID);
+        this.bundleId = serviceReference.getBundle().getBundleId();
+        this.serviceInterfaces = (String[]) serviceReference.getProperty(Constants.OBJECTCLASS);
+        this.usingBundles = getBundleIds(serviceReference.getUsingBundles());
+        for (String propertyKey: serviceReference.getPropertyKeys()) {
+            this.properties.add(PropertyData.newInstance(propertyKey, serviceReference.getProperty(propertyKey)));
+        }
+    }
+
+    /**
+     * Returns CompositeData representing a ServiceReference typed by {@link ServiceStateMBean#SERVICE_TYPE}.
+     * @return
+     */
+    public CompositeData toCompositeData() {
+        CompositeData result = null;
+        Map<String, Object> items = new HashMap<String, Object>();
+        items.put(IDENTIFIER, this.serviceId);
+        items.put(BUNDLE_IDENTIFIER, this.bundleId);
+        items.put(OBJECT_CLASS, this.serviceInterfaces);
+        TabularData propertiesTable = new TabularDataSupport(PROPERTIES_TYPE);
+        for (PropertyData<? extends Object> propertyData : this.properties) {
+            propertiesTable.put(propertyData.toCompositeData());
+        }
+        items.put(PROPERTIES, propertiesTable);
+        items.put(USING_BUNDLES, toLong(this.usingBundles));
+        try {
+            result = new CompositeDataSupport(SERVICE_TYPE, items);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Failed to create CompositeData for ServiceReference with "
+                    + Constants.SERVICE_ID + " [" + this.serviceId + "]", e);
+        }
+        return result;
+    }
+
+    /**
+     * Constructs a <code>ServiceData</code> object from the given <code>CompositeData</code>
+     * 
+     * @param compositeData
+     * @return
+     * @throws IlleglArugmentException
+     *             if compositeData is null or not of type {@link ServiceStateMBean#SERVICE_TYPE}.
+     */
+    @SuppressWarnings("unchecked")
+    public static ServiceData from(CompositeData compositeData) {
+        if (compositeData == null) {
+            throw new IllegalArgumentException("Argument compositeData cannot be null");
+        }
+        if (!compositeData.getCompositeType().equals(SERVICE_TYPE)) {
+            throw new IllegalArgumentException("Invalid CompositeType [" + compositeData.getCompositeType() + "]");
+        }
+        ServiceData serviceData = new ServiceData();
+        serviceData.serviceId = (Long) compositeData.get(IDENTIFIER);
+        serviceData.bundleId = (Long) compositeData.get(BUNDLE_IDENTIFIER);
+        serviceData.serviceInterfaces = (String[]) compositeData.get(OBJECT_CLASS);
+        serviceData.usingBundles = toPrimitive((Long[]) compositeData.get(USING_BUNDLES));
+        TabularData propertiesTable = (TabularData) compositeData.get(PROPERTIES);
+        Collection<CompositeData> propertyData = (Collection<CompositeData>) propertiesTable.values();
+        for (CompositeData propertyRow: propertyData) {
+            serviceData.properties.add(PropertyData.from(propertyRow));
+        }
+        return serviceData;
+    }
+
+    public long getServiceId() {
+        return serviceId;
+    }
+
+    public long getBundleId() {
+        return bundleId;
+    }
+
+    public String[] getServiceInterfaces() {
+        return serviceInterfaces;
+    }
+
+    public List<PropertyData<? extends Object>> getProperties() {
+        return properties;
+    }
+
+    public long[] getUsingBundles() {
+        return usingBundles;
+    }
+
+}

Propchange: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceData.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceData.java
------------------------------------------------------------------------------
    svn:keywords = Revision Date

Added: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceEventData.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceEventData.java?rev=886712&view=auto
==============================================================================
--- incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceEventData.java (added)
+++ incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceEventData.java Thu Dec  3 09:01:14 2009
@@ -0,0 +1,164 @@
+/**
+ *  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.codec;
+
+import static org.osgi.jmx.framework.ServiceStateMBean.BUNDLE_IDENTIFIER;
+import static org.osgi.jmx.framework.ServiceStateMBean.BUNDLE_LOCATION;
+import static org.osgi.jmx.framework.ServiceStateMBean.BUNDLE_SYMBOLIC_NAME;
+import static org.osgi.jmx.framework.ServiceStateMBean.EVENT;
+import static org.osgi.jmx.framework.ServiceStateMBean.IDENTIFIER;
+import static org.osgi.jmx.framework.ServiceStateMBean.OBJECT_CLASS;
+import static org.osgi.jmx.framework.ServiceStateMBean.SERVICE_EVENT_TYPE;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.OpenDataException;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.jmx.framework.ServiceStateMBean;
+
+/**
+ <p>
+ * <tt>ServiceEventData</tt> represents ServiceEvent Type @see {@link ServiceStateMBean#SERVICE_EVENT_TYPE}.
+ * It is a codec for the <code>CompositeData</code> representing an OSGi ServiceEvent.
+ * </p>
+ *
+ * @version $Rev$ $Date$
+ */
+public class ServiceEventData {
+
+    /**
+     * @see ServiceStateMBean#IDENTIFIER_ITEM
+     */
+    private long serviceId;
+    
+    /**
+     * @see ServiceStateMBean#OBJECT_CLASS_ITEM
+     */
+    private String[] serviceInterfaces;
+    
+    /**
+     * @see ServiceStateMBean#BUNDLE_IDENTIFIER_ITEM
+     */
+    private long bundleId;
+    
+    /**
+     * @see ServiceStateMBean#BUNDLE_LOCATION_ITEM
+     */
+    private String bundleLocation;
+    
+    /**
+     * @see ServiceStateMBean#BUNDLE_SYMBOLIC_NAME_ITEM
+     */
+    private String bundleSymbolicName;
+    
+    /**
+     * @see ServiceStateMBean#EVENT_ITEM
+     */
+    private int eventType;
+    
+    
+    private ServiceEventData(){
+        super();
+    }
+    
+    public ServiceEventData(ServiceEvent serviceEvent) {
+        ServiceReference serviceReference = serviceEvent.getServiceReference();
+        this.serviceId = (Long) serviceReference.getProperty(Constants.SERVICE_ID);
+        this.serviceInterfaces = (String[]) serviceReference.getProperty(Constants.OBJECTCLASS);
+        Bundle bundle = serviceReference.getBundle();
+        this.bundleId = bundle.getBundleId();
+        this.bundleLocation = bundle.getLocation();
+        this.bundleSymbolicName = bundle.getSymbolicName();
+        this.eventType = serviceEvent.getType();
+    }
+    
+    /**
+     * Returns CompositeData representing a ServiceEvent typed by {@link ServiceStateMBean#SERVICE_EVENT_TYPE}.
+     * @return
+     */
+    public CompositeData toCompositeData() {
+        CompositeData result = null;
+        Map<String, Object> items = new HashMap<String, Object>();
+        items.put(IDENTIFIER, this.serviceId);
+        items.put(OBJECT_CLASS, this.serviceInterfaces);
+        items.put(BUNDLE_IDENTIFIER, this.bundleId);
+        items.put(BUNDLE_LOCATION, this.bundleLocation);
+        items.put(BUNDLE_SYMBOLIC_NAME, this.bundleSymbolicName);
+        items.put(EVENT, this.eventType);
+        try {
+            result = new CompositeDataSupport(SERVICE_EVENT_TYPE, items);
+        } catch (OpenDataException e) {
+            throw new IllegalStateException("Failed to create CompositeData for ServiceEvent for Service [" + this.serviceId + "]", e);
+        }
+        return result;
+    }
+    
+    /**
+     * Returns a <code>ServiceEventData</code> representation of the given compositeData
+     * @param compositeData
+     * @return
+     * @throws IllegalArgumentException if the compositeData is null or incorrect type
+     */
+    public static ServiceEventData from(CompositeData compositeData) throws IllegalArgumentException {
+        ServiceEventData serviceEventData = new ServiceEventData();
+        if ( compositeData == null ) {
+            throw new IllegalArgumentException("Argument compositeData cannot be null");
+        }
+        if (!compositeData.getCompositeType().equals(SERVICE_EVENT_TYPE)) {
+            throw new IllegalArgumentException("Invalid CompositeType [" + compositeData.getCompositeType() + "]");
+        }
+        serviceEventData.serviceId = (Long) compositeData.get(IDENTIFIER);
+        serviceEventData.serviceInterfaces = (String[]) compositeData.get(OBJECT_CLASS);
+        serviceEventData.bundleId = (Long) compositeData.get(BUNDLE_IDENTIFIER);
+        serviceEventData.bundleLocation = (String) compositeData.get(BUNDLE_LOCATION);
+        serviceEventData.bundleSymbolicName = (String) compositeData.get(BUNDLE_SYMBOLIC_NAME);
+        serviceEventData.eventType = (Integer) compositeData.get(EVENT);
+        return serviceEventData;
+    }
+    
+    public long getServiceId() {
+        return serviceId;
+    }
+    
+    public String[] getServiceInterfaces() {
+        return serviceInterfaces;
+    }
+    
+    public long getBundleId() {
+        return bundleId;
+    }
+    
+    public String getBundleLocation() {
+        return bundleLocation;
+    }
+    
+    public String getBundleSymbolicName() {
+        return bundleSymbolicName;
+    }
+    
+    public int getEventType() {
+        return eventType;
+    }
+    
+}

Propchange: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceEventData.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/codec/ServiceEventData.java
------------------------------------------------------------------------------
    svn:keywords = Revision Date

Added: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceState.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceState.java?rev=886712&view=auto
==============================================================================
--- incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceState.java (added)
+++ incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceState.java Thu Dec  3 09:01:14 2009
@@ -0,0 +1,211 @@
+/**
+ *  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.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$ $Date$
+ */
+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) {
+            bundleContext.removeServiceListener(serviceListener);
+            eventDispatcher.shutdown();
+        }
+    }
+
+    /**
+     * @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 (Exception e) {
+                            logger.log(LogService.LOG_WARNING,
+                                    "Exception occured on JMX Notification dispatch for event [" + serviceevent + "]",
+                                    e);
+                        }
+                    }
+                };
+            }
+        } finally {
+            lock.unlock();
+        }
+        return name;
+    }
+
+    /*
+     * Returns the ExecutorService used to dispatch Notifications
+     */
+    public ExecutorService getEventDispatcher() {
+        return eventDispatcher;
+    }
+
+}

Propchange: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceState.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceState.java
------------------------------------------------------------------------------
    svn:keywords = Revision Date

Added: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandler.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandler.java?rev=886712&view=auto
==============================================================================
--- incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandler.java (added)
+++ incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandler.java Thu Dec  3 09:01:14 2009
@@ -0,0 +1,88 @@
+/**
+ *  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.osgi.jmx.framework.ServiceStateMBean.OBJECTNAME;
+
+import javax.management.NotCompliantMBeanException;
+import javax.management.StandardMBean;
+
+import org.apache.aries.jmx.Logger;
+import org.apache.aries.jmx.MBeanHandler;
+import org.osgi.framework.BundleContext;
+import org.osgi.jmx.framework.ServiceStateMBean;
+import org.osgi.service.log.LogService;
+
+/**
+ * <p>
+ * Implementation of <code>MBeanHandler</code> which manages the <code>ServiceState</code>
+ * MBean implementation
+ * @see MBeanHandler
+ * </p> 
+ *
+ * @version $Rev$ $Date$
+ */
+public class ServiceStateMBeanHandler implements MBeanHandler {
+
+    private String name;
+    private StandardMBean mbean;
+    private BundleContext bundleContext;
+    private Logger logger;
+    
+    
+    public ServiceStateMBeanHandler(BundleContext bundleContext, Logger logger) {
+        this.bundleContext = bundleContext;
+        this.logger = logger;
+        this.name = OBJECTNAME;
+    }
+
+    /**
+     * @see org.apache.aries.jmx.MBeanHandler#open()
+     */
+    public void open() {
+        ServiceStateMBean serviceStateMBean = new ServiceState(bundleContext, logger);
+        try {
+            mbean = new RegistrableStandardEmitterMBean(serviceStateMBean, ServiceStateMBean.class);
+        } catch (NotCompliantMBeanException e) {
+            logger.log(LogService.LOG_ERROR, "Failed to instantiate MBean for " + ServiceStateMBean.class.getName(), e);
+        }
+    }
+    
+    /**
+     * @see org.apache.aries.jmx.MBeanHandler#getMbean()
+     */
+    public StandardMBean getMbean() {
+        return mbean;
+    }
+
+    /**
+     * @see org.apache.aries.jmx.MBeanHandler#getName()
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @see org.apache.aries.jmx.MBeanHandler#close()
+     */
+    public void close() {
+       // No action
+    }
+    
+    
+
+}

Propchange: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/aries/trunk/jmx/jmx-core/src/main/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandler.java
------------------------------------------------------------------------------
    svn:keywords = Revision Date

Added: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceDataTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceDataTest.java?rev=886712&view=auto
==============================================================================
--- incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceDataTest.java (added)
+++ incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceDataTest.java Thu Dec  3 09:01:14 2009
@@ -0,0 +1,167 @@
+/**
+ *  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.codec;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.osgi.jmx.JmxConstants.BOOLEAN;
+import static org.osgi.jmx.JmxConstants.KEY;
+import static org.osgi.jmx.JmxConstants.LONG;
+import static org.osgi.jmx.JmxConstants.PROPERTIES_TYPE;
+import static org.osgi.jmx.JmxConstants.P_BOOLEAN;
+import static org.osgi.jmx.JmxConstants.STRING;
+import static org.osgi.jmx.JmxConstants.TYPE;
+import static org.osgi.jmx.JmxConstants.VALUE;
+import static org.osgi.jmx.framework.BundleStateMBean.IDENTIFIER;
+import static org.osgi.jmx.framework.ServiceStateMBean.BUNDLE_IDENTIFIER;
+import static org.osgi.jmx.framework.ServiceStateMBean.OBJECT_CLASS;
+import static org.osgi.jmx.framework.ServiceStateMBean.PROPERTIES;
+import static org.osgi.jmx.framework.ServiceStateMBean.SERVICE_TYPE;
+import static org.osgi.jmx.framework.ServiceStateMBean.USING_BUNDLES;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * 
+ *
+ * @version $Rev$ $Date$
+ */
+public class ServiceDataTest {
+
+   
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testToCompositeData() throws Exception {
+
+        ServiceReference reference = mock(ServiceReference.class);
+        Bundle bundle = mock(Bundle.class);
+        String[] interfaces = new String[] { "org.apache.aries.jmx.Test", "org.apache.aries.jmx.Mock" };
+       
+        Bundle b1 = mock(Bundle.class);
+        when(b1.getBundleId()).thenReturn(new Long(6));
+        Bundle b2 = mock(Bundle.class);
+        when(b2.getBundleId()).thenReturn(new Long(9));
+        
+     
+        when(reference.getProperty(Constants.SERVICE_ID)).thenReturn(new Long(98));
+        when(reference.getBundle()).thenReturn(bundle);
+        when(bundle.getBundleId()).thenReturn(new Long(34));
+        when(reference.getProperty(Constants.OBJECTCLASS)).thenReturn(interfaces);
+        when(reference.getUsingBundles()).thenReturn(new Bundle[] { b1, b2 });
+        when(reference.getPropertyKeys()).thenReturn( new String[] {"x.vendor", "x.domain", "x.index", "x.optimized" } );
+        when(reference.getProperty("x.vendor")).thenReturn("aries");
+        when(reference.getProperty("x.domain")).thenReturn("test");
+        when(reference.getProperty("x.index")).thenReturn(new Long(67));
+        when(reference.getProperty("x.optimized")).thenReturn(true);
+        
+        
+        ServiceData serviceData = new ServiceData(reference);
+        
+        CompositeData compositeData = serviceData.toCompositeData();
+        assertEquals(new Long(98), compositeData.get(IDENTIFIER));
+        assertEquals(new Long(34), compositeData.get(BUNDLE_IDENTIFIER));
+        assertArrayEquals( new Long[] {new Long(6), new Long(9)}, (Long[]) compositeData.get(USING_BUNDLES));
+        assertArrayEquals(interfaces, (String[]) compositeData.get(OBJECT_CLASS));
+        TabularData propertiesTable = (TabularData) compositeData.get(PROPERTIES);
+        Collection<CompositeData> propertyData = (Collection<CompositeData>) propertiesTable.values();
+        assertEquals(4, propertyData.size());
+        for (CompositeData propertyRow: propertyData) {
+            String key = (String) propertyRow.get(KEY);
+            if (key.equals("x.vendor")) {
+                assertEquals("aries", propertyRow.get(VALUE));
+                assertEquals(STRING, propertyRow.get(TYPE));
+            } else if (key.equals("x.domain")) {
+                assertEquals("test", propertyRow.get(VALUE));
+                assertEquals(STRING, propertyRow.get(TYPE));
+            } else if (key.equals("x.index")) {
+                assertEquals("67", propertyRow.get(VALUE));
+                assertEquals(LONG, propertyRow.get(TYPE));
+            } else if (key.equals("x.optimized")) {
+                assertEquals("true", propertyRow.get(VALUE));
+                assertEquals(BOOLEAN, propertyRow.get(TYPE));
+            } else {
+                fail("unknown key parsed from properties");
+            }
+        }
+    }
+
+   
+    @Test
+    public void testFromCompositeData() throws Exception {
+        
+        Map<String, Object> items = new HashMap<String, Object>();
+        items.put(IDENTIFIER, new Long(99));
+        items.put(BUNDLE_IDENTIFIER, new Long(5));
+        items.put(USING_BUNDLES, new Long[] { new Long(10), new Long(11) });
+        items.put(OBJECT_CLASS, new String[] { "org.apache.aries.jmx.Test", "org.apache.aries.jmx.Mock" });
+        TabularData propertyTable = new TabularDataSupport(PROPERTIES_TYPE);
+        propertyTable.put(PropertyData.newInstance("a", true).toCompositeData());
+        propertyTable.put(PropertyData.newInstance("b", "value").toCompositeData());
+        propertyTable.put(PropertyData.newInstance("c", new int[] {1, 2}).toCompositeData());
+        propertyTable.put(PropertyData.newInstance("d", new Long[] {new Long(3), new Long(4)}).toCompositeData());
+        items.put(PROPERTIES, propertyTable);
+        CompositeData compositeData = new CompositeDataSupport(SERVICE_TYPE, items);
+        
+        ServiceData data = ServiceData.from(compositeData);
+        assertEquals(99, data.getServiceId());
+        assertEquals(5, data.getBundleId());
+        assertArrayEquals(new long[] {10, 11}, data.getUsingBundles());
+        assertArrayEquals(new String[] { "org.apache.aries.jmx.Test", "org.apache.aries.jmx.Mock" }, data.getServiceInterfaces());
+        
+        List<PropertyData<? extends Object>> properties = data.getProperties();
+        assertEquals(4, properties.size());
+        
+        for (PropertyData<? extends Object> property: properties) {
+            if (property.getKey().equals("a")) {
+                assertTrue((Boolean) property.getValue());
+                assertEquals(P_BOOLEAN, property.getEncodedType());
+            } else if (property.getKey().equals("b")) {
+                assertEquals("value", property.getValue());
+                assertEquals(STRING, property.getEncodedType());
+            } else if (property.getKey().equals("c")) {
+                assertArrayEquals(new int[] { 1, 2 }, (int[]) property.getValue());
+                assertEquals("Array of int", property.getEncodedType());
+                assertEquals("1,2", property.getEncodedValue());
+            } else if (property.getKey().equals("d")) {
+                assertArrayEquals(new Long[] {new Long(3), new Long(4) }, (Long[]) property.getValue());
+                assertEquals("Array of Long", property.getEncodedType());
+                assertEquals("3,4", property.getEncodedValue());
+            } else {
+                fail("unknown key parsed from properties");
+            }
+        }
+        
+    }
+
+}

Propchange: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceDataTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceDataTest.java
------------------------------------------------------------------------------
    svn:keywords = Revision Date

Added: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceEventDataTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceEventDataTest.java?rev=886712&view=auto
==============================================================================
--- incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceEventDataTest.java (added)
+++ incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceEventDataTest.java Thu Dec  3 09:01:14 2009
@@ -0,0 +1,102 @@
+/**
+ *  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.codec;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.osgi.jmx.framework.ServiceStateMBean.BUNDLE_IDENTIFIER;
+import static org.osgi.jmx.framework.ServiceStateMBean.BUNDLE_LOCATION;
+import static org.osgi.jmx.framework.ServiceStateMBean.BUNDLE_SYMBOLIC_NAME;
+import static org.osgi.jmx.framework.ServiceStateMBean.EVENT;
+import static org.osgi.jmx.framework.ServiceStateMBean.IDENTIFIER;
+import static org.osgi.jmx.framework.ServiceStateMBean.OBJECT_CLASS;
+import static org.osgi.jmx.framework.ServiceStateMBean.SERVICE_EVENT_TYPE;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+/**
+ * 
+ *
+ * @version $Rev$ $Date$
+ */
+public class ServiceEventDataTest {
+
+    
+    @Test
+    public void testToCompositeData() throws Exception {
+
+        ServiceEvent event = mock(ServiceEvent.class);
+        ServiceReference reference = mock(ServiceReference.class);
+        Bundle bundle = mock(Bundle.class);
+        
+        when(event.getType()).thenReturn(ServiceEvent.REGISTERED);
+        when(event.getServiceReference()).thenReturn(reference);
+        when(reference.getProperty(Constants.SERVICE_ID)).thenReturn(new Long(44));
+        when(reference.getProperty(Constants.OBJECTCLASS)).thenReturn(new String[] {"org.apache.aries.jmx.Mock"});
+        when(reference.getBundle()).thenReturn(bundle);
+        when(bundle.getBundleId()).thenReturn(new Long(1));
+        when(bundle.getLocation()).thenReturn("string");
+        when(bundle.getSymbolicName()).thenReturn("org.apache.aries.jmx.core");
+        
+        ServiceEventData eventData = new ServiceEventData(event);
+        CompositeData data = eventData.toCompositeData();
+        
+        assertEquals(new Long(44), data.get(IDENTIFIER));
+        assertEquals(new Long(1), data.get(BUNDLE_IDENTIFIER));
+        assertEquals("string", data.get(BUNDLE_LOCATION));
+        assertEquals("org.apache.aries.jmx.core", data.get(BUNDLE_SYMBOLIC_NAME));
+        assertArrayEquals(new String[] {"org.apache.aries.jmx.Mock" }, (String[]) data.get(OBJECT_CLASS));
+        assertEquals(ServiceEvent.REGISTERED, data.get(EVENT));
+        
+    }
+
+    
+    @Test
+    public void testFrom() throws Exception {
+        
+        Map<String, Object> items = new HashMap<String, Object>();
+        items.put(IDENTIFIER, new Long(7));
+        items.put(BUNDLE_IDENTIFIER, new Long(67));
+        items.put(BUNDLE_LOCATION, "string");
+        items.put(BUNDLE_SYMBOLIC_NAME, "test");
+        items.put(OBJECT_CLASS, new String[] {"org.apache.aries.jmx.Mock" });
+        items.put(EVENT, ServiceEvent.MODIFIED);
+
+        CompositeData compositeData = new CompositeDataSupport(SERVICE_EVENT_TYPE, items);
+        ServiceEventData event = ServiceEventData.from(compositeData);
+        
+        assertEquals(7, event.getServiceId());
+        assertEquals(67, event.getBundleId());
+        assertArrayEquals(new String[] {"org.apache.aries.jmx.Mock" }, event.getServiceInterfaces());
+        assertEquals("test", event.getBundleSymbolicName());
+        assertEquals("string", event.getBundleLocation());
+        assertEquals(ServiceEvent.MODIFIED, event.getEventType());
+        
+    }
+
+}

Propchange: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceEventDataTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/codec/ServiceEventDataTest.java
------------------------------------------------------------------------------
    svn:keywords = Revision Date

Added: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandlerTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandlerTest.java?rev=886712&view=auto
==============================================================================
--- incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandlerTest.java (added)
+++ incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandlerTest.java Thu Dec  3 09:01:14 2009
@@ -0,0 +1,47 @@
+/**
+ *  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.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import org.apache.aries.jmx.Logger;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+/**
+ * 
+ *
+ * @version $Rev$ $Date$
+ */
+public class ServiceStateMBeanHandlerTest {
+
+   
+    @Test
+    public void testOpen() throws Exception {
+        
+        BundleContext context = mock(BundleContext.class);
+        Logger logger = mock(Logger.class);
+        
+        ServiceStateMBeanHandler handler = new ServiceStateMBeanHandler(context, logger);
+        handler.open();
+        
+        assertNotNull(handler.getMbean());
+        
+    }
+
+}

Propchange: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandlerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateMBeanHandlerTest.java
------------------------------------------------------------------------------
    svn:keywords = Revision Date

Added: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateTest.java?rev=886712&view=auto
==============================================================================
--- incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateTest.java (added)
+++ incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateTest.java Thu Dec  3 09:01:14 2009
@@ -0,0 +1,202 @@
+/**
+ *  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.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.osgi.jmx.framework.ServiceStateMBean.BUNDLE_IDENTIFIER;
+import static org.osgi.jmx.framework.ServiceStateMBean.BUNDLE_LOCATION;
+import static org.osgi.jmx.framework.ServiceStateMBean.BUNDLE_SYMBOLIC_NAME;
+import static org.osgi.jmx.framework.ServiceStateMBean.EVENT;
+import static org.osgi.jmx.framework.ServiceStateMBean.IDENTIFIER;
+import static org.osgi.jmx.framework.ServiceStateMBean.OBJECTNAME;
+import static org.osgi.jmx.framework.ServiceStateMBean.OBJECT_CLASS;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.MBeanServer;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+
+import org.apache.aries.jmx.Logger;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.osgi.framework.AllServiceListener;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * 
+ *
+ * @version $Rev$ $Date$
+ */
+public class ServiceStateTest {
+
+    
+    @Test
+    public void testNotificationsForServiceEvents() throws Exception {
+        
+        BundleContext context = mock(BundleContext.class);
+        Logger logger = mock(Logger.class);
+        
+        ServiceState serviceState = new ServiceState(context, logger);
+        
+        ServiceReference reference = mock(ServiceReference.class);
+        Bundle b1 = mock(Bundle.class);
+        
+        when(b1.getBundleId()).thenReturn(new Long(9));
+        when(b1.getSymbolicName()).thenReturn("bundle");
+        when(b1.getLocation()).thenReturn("file:/location");
+        when(reference.getBundle()).thenReturn(b1);
+        when(reference.getProperty(Constants.SERVICE_ID)).thenReturn(new Long(44));
+        when(reference.getProperty(Constants.OBJECTCLASS)).thenReturn(new String[] {"org.apache.aries.jmx.Mock"});
+        
+        ServiceEvent registeredEvent = mock(ServiceEvent.class);
+        when(registeredEvent.getServiceReference()).thenReturn(reference);
+        when(registeredEvent.getType()).thenReturn(ServiceEvent.REGISTERED);
+       
+        ServiceEvent modifiedEvent = mock(ServiceEvent.class);
+        when(modifiedEvent.getServiceReference()).thenReturn(reference);
+        when(modifiedEvent.getType()).thenReturn(ServiceEvent.MODIFIED);
+        
+        MBeanServer server = mock(MBeanServer.class);
+        
+        //setup for notification
+        ObjectName objectName = new ObjectName(OBJECTNAME);
+        serviceState.preRegister(server, objectName);
+        serviceState.postRegister(true);
+        
+        //holder for Notifications captured
+        final List<Notification> received = new LinkedList<Notification>();
+        
+        //add NotificationListener to receive the events
+        serviceState.addNotificationListener(new NotificationListener() {
+            public void handleNotification(Notification notification, Object handback) {
+               received.add(notification);
+            }
+        }, null, null);
+        
+        // capture the ServiceListener registered with BundleContext to issue ServiceEvents
+        ArgumentCaptor<AllServiceListener> argument = ArgumentCaptor.forClass(AllServiceListener.class);        
+        verify(context).addServiceListener(argument.capture());
+        
+        //send events
+        AllServiceListener serviceListener = argument.getValue();
+        serviceListener.serviceChanged(registeredEvent);
+        serviceListener.serviceChanged(modifiedEvent);
+        
+        //shutdown dispatcher via unregister callback 
+        serviceState.postDeregister();
+        //check the ServiceListener is cleaned up
+        verify(context).removeServiceListener(serviceListener);
+        
+        ExecutorService dispatcher = serviceState.getEventDispatcher();
+        assertTrue(dispatcher.isShutdown());
+        dispatcher.awaitTermination(2, TimeUnit.SECONDS);
+        assertTrue(dispatcher.isTerminated());
+        
+        assertEquals(2, received.size());
+        Notification registered = received.get(0);
+        assertEquals(1, registered.getSequenceNumber());
+        CompositeData data = (CompositeData) registered.getUserData();
+        assertEquals(new Long(44), data.get(IDENTIFIER));
+        assertEquals(new Long(9), data.get(BUNDLE_IDENTIFIER));
+        assertEquals("file:/location", data.get(BUNDLE_LOCATION));
+        assertEquals("bundle", data.get(BUNDLE_SYMBOLIC_NAME));
+        assertArrayEquals(new String[] {"org.apache.aries.jmx.Mock" }, (String[]) data.get(OBJECT_CLASS));
+        assertEquals(ServiceEvent.REGISTERED, data.get(EVENT));
+        
+        Notification modified = received.get(1);
+        assertEquals(2, modified.getSequenceNumber());
+        data = (CompositeData) modified.getUserData();
+        assertEquals(new Long(44), data.get(IDENTIFIER));
+        assertEquals(new Long(9), data.get(BUNDLE_IDENTIFIER));
+        assertEquals("file:/location", data.get(BUNDLE_LOCATION));
+        assertEquals("bundle", data.get(BUNDLE_SYMBOLIC_NAME));
+        assertArrayEquals(new String[] {"org.apache.aries.jmx.Mock" }, (String[]) data.get(OBJECT_CLASS));
+        assertEquals(ServiceEvent.MODIFIED, data.get(EVENT));
+        
+    }
+    
+    @Test
+    public void testLifeCycleOfNotificationSupport() throws Exception {
+        
+        BundleContext context = mock(BundleContext.class);
+        Logger logger = mock(Logger.class);
+        
+        ServiceState serviceState = new ServiceState(context, logger);
+        
+        MBeanServer server1 = mock(MBeanServer.class);
+        MBeanServer server2 = mock(MBeanServer.class);
+
+        ObjectName objectName = new ObjectName(OBJECTNAME);
+        serviceState.preRegister(server1, objectName);
+        serviceState.postRegister(true);
+        
+        // capture the ServiceListener registered with BundleContext to issue ServiceEvents
+        ArgumentCaptor<AllServiceListener> argument = ArgumentCaptor.forClass(AllServiceListener.class);        
+        verify(context).addServiceListener(argument.capture());
+        
+        AllServiceListener serviceListener = argument.getValue();
+        assertNotNull(serviceListener);
+        
+        ExecutorService dispatcher = serviceState.getEventDispatcher();
+        
+        //do registration with another server
+        serviceState.preRegister(server2, objectName);
+        serviceState.postRegister(true);
+        
+        // check no more actions on BundleContext
+        argument = ArgumentCaptor.forClass(AllServiceListener.class);              
+        verify(context, atMost(1)).addServiceListener(argument.capture());
+        assertEquals(1, argument.getAllValues().size());
+        
+        //do one unregister
+        serviceState.postDeregister();
+        
+        //verify bundleListener not invoked
+        verify(context, never()).removeServiceListener(serviceListener);
+        assertFalse(dispatcher.isShutdown());
+        
+        //do second unregister and check cleanup
+        serviceState.postDeregister();
+        verify(context).removeServiceListener(serviceListener);
+        assertTrue(dispatcher.isShutdown());
+        dispatcher.awaitTermination(2, TimeUnit.SECONDS);
+        assertTrue(dispatcher.isTerminated());
+        
+      
+        
+    }
+
+}

Propchange: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/aries/trunk/jmx/jmx-core/src/test/java/org/apache/aries/jmx/framework/ServiceStateTest.java
------------------------------------------------------------------------------
    svn:keywords = Revision Date