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