Add support for introspection of a single service to ServiceStateMBean. Fix for bug 363458.
diff --git a/.gitignore b/.gitignore
index da92513..66772f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-*/target
\ No newline at end of file
+*/target
+*/bin
diff --git a/gemini.mgmt.releng/pom.xml b/gemini.mgmt.releng/pom.xml
index fbdf7a5..34e85f7 100644
--- a/gemini.mgmt.releng/pom.xml
+++ b/gemini.mgmt.releng/pom.xml
@@ -38,13 +38,13 @@
 				<configuration>
 					<resolver>p2</resolver>
 					<target>
-            <artifact>
-						  <groupId>org.eclipse.gemini.mgmt</groupId>
-              <artifactId>target-platform</artifactId>
-              <version>1.0.0-SNAPSHOT</version>
-              <classifier>gemini-management</classifier>
-            </artifact>
-          </target>
+						<artifact>
+							<groupId>org.eclipse.gemini.mgmt</groupId>
+							<artifactId>target-platform</artifactId>
+							<version>1.0.0-SNAPSHOT</version>
+							<classifier>gemini-management</classifier>
+						</artifact>
+					</target>
 				</configuration>
 			</plugin>
 		</plugins>
diff --git a/org.eclipse.gemini.mgmt/META-INF/MANIFEST.MF b/org.eclipse.gemini.mgmt/META-INF/MANIFEST.MF
index acc55d6..74af427 100644
--- a/org.eclipse.gemini.mgmt/META-INF/MANIFEST.MF
+++ b/org.eclipse.gemini.mgmt/META-INF/MANIFEST.MF
@@ -3,7 +3,6 @@
 Bundle-Name: Gemini Management
 Bundle-SymbolicName: org.eclipse.gemini.mgmt
 Bundle-Version: 1.0.0.qualifier
-Bundle-Vendor: Oracle
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Import-Package: org.osgi.framework;version="1.3.0",
  org.osgi.jmx,
@@ -22,4 +21,3 @@
  javax.management,
  javax.management.openmbean
 Bundle-Activator: org.eclipse.gemini.mgmt.Activator
-Bundle-ActivationPolicy: lazy
diff --git a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/Monitor.java b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/Monitor.java
index 01bbfaf..8da3874 100644
--- a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/Monitor.java
+++ b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/Monitor.java
@@ -23,27 +23,16 @@
 /** 

  * 

  */

-

 abstract public class Monitor extends NotificationBroadcasterSupport implements

 		MBeanRegistration {

 

 	public void postDeregister() {

 	}

 

-	/*

-	 * (non-Javadoc)

-	 * 

-	 * @see javax.management.MBeanRegistration#postRegister(java.lang.Boolean)

-	 */

 	public void postRegister(Boolean registrationDone) {

 		addListener();

 	}

 

-	/*

-	 * (non-Javadoc)

-	 * 

-	 * @see javax.management.MBeanRegistration#preDeregister()

-	 */

 	public void preDeregister() throws Exception {

 		removeListener();

 	}

diff --git a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/ServiceState.java b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/ServiceState.java
index e40e727..cf2c569 100644
--- a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/ServiceState.java
+++ b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/ServiceState.java
@@ -11,18 +11,28 @@
  *

  * Contributors:

  *     Hal Hildebrand - Initial JMX support 

+ *     Christopher Frost - Updates for RFC 169

  ******************************************************************************/

 

 package org.eclipse.gemini.mgmt.framework;

 

 import static org.osgi.framework.Constants.OBJECTCLASS;

+import static org.osgi.framework.Constants.SERVICE_ID;

 

 import java.io.IOException;

 import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.List;

 

 import javax.management.Notification;

+import javax.management.openmbean.CompositeData;

 import javax.management.openmbean.TabularData;

 

+import org.eclipse.gemini.mgmt.Monitor;

+import org.eclipse.gemini.mgmt.codec.OSGiProperties;

+import org.eclipse.gemini.mgmt.codec.Util;

+import org.eclipse.gemini.mgmt.framework.codec.OSGiService;

+import org.eclipse.gemini.mgmt.framework.codec.OSGiServiceEvent;

 import org.osgi.framework.AllServiceListener;

 import org.osgi.framework.Bundle;

 import org.osgi.framework.BundleContext;

@@ -32,53 +42,57 @@
 import org.osgi.framework.ServiceEvent;

 import org.osgi.framework.ServiceListener;

 import org.osgi.framework.ServiceReference;

-

 import org.osgi.jmx.framework.ServiceStateMBean;

 import org.osgi.util.tracker.ServiceTracker;

 

-import org.eclipse.gemini.mgmt.Monitor;

-import org.eclipse.gemini.mgmt.codec.OSGiProperties;

-import org.eclipse.gemini.mgmt.framework.codec.OSGiService;

-import org.eclipse.gemini.mgmt.framework.codec.OSGiServiceEvent;

-

 /** 

  * 

  */

 public class ServiceState extends Monitor implements ServiceStateMBean {

+

+	protected ServiceListener serviceListener;

+	

+	protected BundleContext bundleContext;

+	

+	/**

+	 * Constructor

+	 * 

+	 * @param bundleContext

+	 */

 	public ServiceState(BundleContext bc) {

-		this.bc = bc;

+		this.bundleContext = bc;

 	}

 

+	/**

+	 * {@inheritDoc}

+	 */

 	public long getBundleIdentifier(long serviceId) throws IOException {

 		return ref(serviceId).getBundle().getBundleId();

 	}

 

+	/**

+	 * {@inheritDoc}

+	 */

 	public TabularData getProperties(long serviceId) throws IOException {

 		return OSGiProperties.tableFrom(ref(serviceId));

 	}

 

-	/*

-	 * (non-Javadoc)

-	 * 

-	 * @see org.osgi.jmx.core.ServiceStateMBean#getBundle(long)

+	/**

+	 * {@inheritDoc}

 	 */

-

 	public String[] getObjectClass(long serviceId) throws IOException {

 		return (String[]) ref(serviceId).getProperty(OBJECTCLASS);

 	}

 

-	/*

-	 * (non-Javadoc)

-	 * 

-	 * @see org.osgi.jmx.core.ServiceStateMBean#listServices()

+	/**

+	 * {@inheritDoc}

 	 */

-

 	public TabularData listServices() {

 		ArrayList<OSGiService> services = new ArrayList<OSGiService>();

-		for (Bundle bundle : bc.getBundles()) {

-			ServiceReference[] refs = bundle.getRegisteredServices();

+		for (Bundle bundle : bundleContext.getBundles()) {

+			ServiceReference<?>[] refs = bundle.getRegisteredServices();

 			if (refs != null) {

-				for (ServiceReference ref : refs) {

+				for (ServiceReference<?> ref : refs) {

 					services.add(new OSGiService(ref));

 				}

 			}

@@ -86,12 +100,9 @@
 		return OSGiService.tableFrom(services);

 	}

 

-	/*

-	 * (non-Javadoc)

-	 * 

-	 * @see org.osgi.jmx.core.ServiceStateMBean#getServiceInterfaces(long)

+	/**

+	 * {@inheritDoc}

 	 */

-

 	public long[] getUsingBundles(long serviceId) throws IOException {

 		Bundle[] bundles = ref(serviceId).getUsingBundles();

 		long[] ids = new long[bundles.length];

@@ -101,28 +112,137 @@
 		return ids;

 	}

 

-	/*

-	 * (non-Javadoc)

-	 * 

-	 * @see org.osgi.jmx.core.ServiceStateMBean#getServices()

+	/**

+	 * {@inheritDoc}

 	 */

+	public CompositeData getService(long serviceId) throws IOException {

+		for (Bundle bundle : bundleContext.getBundles()) {

+			ServiceReference<?>[] refs = bundle.getRegisteredServices();

+			if (refs != null) {

+				for (ServiceReference<?> ref : refs) {

+					if(serviceId == (Long) ref.getProperty(Constants.SERVICE_ID)){

+						return new OSGiService(ref).asCompositeData();

+					}

+				}

+			}

+		}

+		return null;

+	}

 

-	/*

-	 * (non-Javadoc)

-	 * 

-	 * @see org.osgi.jmx.Monitor#addListener()

+	/**

+	 * {@inheritDoc}

+	 * @param <T>

+	 */

+	public CompositeData getProperty(long serviceId, String key) throws IOException {

+		for (Bundle bundle : bundleContext.getBundles()) {

+			ServiceReference<?>[] refs = bundle.getRegisteredServices();

+			if (refs != null) {

+				for (ServiceReference<?> ref : refs) {

+					if(serviceId == (Long) ref.getProperty(Constants.SERVICE_ID)){

+						return OSGiProperties.encode(key, ref.getProperty(key));

+					}

+				}

+			}

+		}

+		return null;

+	}

+

+	/**

+	 * {@inheritDoc}

+	 */

+	public TabularData listServices(String clazz, String filter) throws IOException {

+		ArrayList<OSGiService> services = new ArrayList<OSGiService>();

+		try {

+			ServiceReference<?>[] allServiceReferences = bundleContext.getAllServiceReferences(clazz, filter);

+			for (ServiceReference<?> ref : allServiceReferences) {

+				services.add(new OSGiService(ref));

+			}

+			return OSGiService.tableFrom(services);

+		} catch (InvalidSyntaxException e) {

+			throw new IOException(e);

+		}

+	}

+

+	/**

+	 * {@inheritDoc}

+	 */

+	public TabularData listServices(String clazz, String filter, String... serviceTypeItems) throws IOException {

+		ArrayList<OSGiService> services = new ArrayList<OSGiService>();

+		List<String> serviceTypeNames = Arrays.asList(serviceTypeItems);

+		try {

+			ServiceReference<?>[] allServiceReferences = bundleContext.getAllServiceReferences(clazz, filter);

+			for (ServiceReference<?> reference : allServiceReferences) {

+				Long identifier;

+				if(serviceTypeNames.contains(ServiceStateMBean.IDENTIFIER)){

+					identifier = (Long) reference.getProperty(SERVICE_ID);

+				} else {

+					identifier = null;

+				}

+				String[] interfaces;

+				if(serviceTypeNames.contains(ServiceStateMBean.OBJECT_CLASS)){

+					interfaces = (String[]) reference.getProperty(OBJECTCLASS);

+				} else {

+					interfaces = null;

+				}

+				Long bundle;

+				if(serviceTypeNames.contains(ServiceStateMBean.BUNDLE_IDENTIFIER)){

+					bundle = reference.getBundle().getBundleId();

+				} else {

+					bundle = null;

+				}

+				long[] usingBundles;

+				if(serviceTypeNames.contains(ServiceStateMBean.USING_BUNDLES)){

+					usingBundles = Util.bundleIds(reference.getUsingBundles());

+				} else {

+					usingBundles = null;

+				}

+				services.add(new OSGiService(identifier, interfaces, bundle, usingBundles));

+			}

+			return OSGiService.tableFrom(services);

+		} catch (InvalidSyntaxException e) {

+			throw new IOException(e);

+		}

+	}

+

+	/**

+	 * {@inheritDoc}

+	 */

+	public long[] getServiceIds() throws IOException {

+		ServiceReference<?>[] allServiceReferences;

+		try {

+			allServiceReferences = bundleContext.getAllServiceReferences(null, null);

+			long[] serviceIds = new long[allServiceReferences.length];

+			for (int i = 0; i < allServiceReferences.length; i++) {

+				serviceIds[i] = (Long) allServiceReferences[i].getProperty(Constants.SERVICE_ID);

+			}

+			return serviceIds;

+		} catch (InvalidSyntaxException e) {

+			//passing in null so should never happen

+			throw new IOException(e);

+		}

+	}

+	

+	//End methods for the MBean

+	

+

+	/**

+	 * {@inheritDoc}

 	 */

 	@Override

 	protected void addListener() {

-		serviceListener = getServiceListener();

-		bc.addServiceListener(serviceListener);

+		serviceListener = this.getServiceListener();

+		bundleContext.addServiceListener(serviceListener);

 	}

 

-	/*

-	 * (non-Javadoc)

-	 * 

-	 * @see org.osgi.jmx.core.ServiceStateMBean#getUsingBundles(long)

+	/**

+	 * {@inheritDoc}

 	 */

+	@Override

+	protected void removeListener() {

+		if (serviceListener != null) {

+			bundleContext.removeServiceListener(serviceListener);

+		}

+	}

 

 	protected ServiceListener getServiceListener() {

 		return new AllServiceListener() {

@@ -135,30 +255,17 @@
 			}

 		};

 	}

-

-	/*

-	 * (non-Javadoc)

-	 * 

-	 * @see org.osgi.jmx.Monitor#removeListener()

-	 */

-	@Override

-	protected void removeListener() {

-		if (serviceListener != null) {

-			bc.removeServiceListener(serviceListener);

-		}

-	}

-

-	protected ServiceReference ref(long serviceId) throws IOException {

+	

+	protected ServiceReference<?> ref(long serviceId) throws IOException {

 		Filter filter;

 		try {

-			filter = bc.createFilter("(" + Constants.SERVICE_ID + "="

-					+ serviceId + ")");

+			filter = bundleContext.createFilter("(" + Constants.SERVICE_ID + "=" + serviceId + ")");

 		} catch (InvalidSyntaxException e) {

 			throw new IOException("Invalid filter syntax: " + e);

 		}

-		ServiceTracker tracker = new ServiceTracker(bc, filter, null);

+		ServiceTracker<?, ?> tracker = new ServiceTracker<Object, Object>(bundleContext, filter, null);

 		tracker.open();

-		ServiceReference serviceReference = tracker.getServiceReference();

+		ServiceReference<?> serviceReference = tracker.getServiceReference();

 		if (serviceReference == null) {

 			throw new IOException("Service <" + serviceId + "> does not exist");

 		}

@@ -166,7 +273,4 @@
 		return serviceReference;

 	}

 

-	protected ServiceListener serviceListener;

-	protected BundleContext bc;

-

 }

diff --git a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/codec/OSGiService.java b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/codec/OSGiService.java
index e608794..dcb4a57 100644
--- a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/codec/OSGiService.java
+++ b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/codec/OSGiService.java
@@ -20,8 +20,8 @@
 import static org.eclipse.gemini.mgmt.codec.Util.LongArrayFrom;

 import static org.eclipse.gemini.mgmt.codec.Util.longArrayFrom;

 

-import java.util.ArrayList;

 import java.util.HashMap;

+import java.util.List;

 import java.util.Map;

 

 import javax.management.openmbean.CompositeData;

@@ -70,13 +70,11 @@
 	 * @param data

 	 *            - the <link>CompositeData</link> encoding the OSGiService

 	 */

-	@SuppressWarnings("boxing")

 	public OSGiService(CompositeData data) {

-		this((Long) data.get(ServiceStateMBean.IDENTIFIER), (String[]) data

-				.get(ServiceStateMBean.OBJECT_CLASS), (Long) data

-				.get(ServiceStateMBean.BUNDLE_IDENTIFIER),

-				longArrayFrom((Long[]) data

-						.get(ServiceStateMBean.USING_BUNDLES)));

+		this((Long) data.get(ServiceStateMBean.IDENTIFIER), 

+				(String[]) data.get(ServiceStateMBean.OBJECT_CLASS), 

+				(Long) data.get(ServiceStateMBean.BUNDLE_IDENTIFIER),

+				longArrayFrom((Long[]) data.get(ServiceStateMBean.USING_BUNDLES)));

 	}

 

 	/**

@@ -88,8 +86,7 @@
 	 * @param bundle

 	 * @param usingBundles

 	 */

-	public OSGiService(long identifier, String[] interfaces, long bundle,

-			long[] usingBundles) {

+	public OSGiService(long identifier, String[] interfaces, long bundle, long[] usingBundles) {

 		this.identifier = identifier;

 		this.interfaces = interfaces;

 		this.bundle = bundle;

@@ -104,9 +101,10 @@
 	 *            - the reference of the service

 	 */

 	@SuppressWarnings("boxing")

-	public OSGiService(ServiceReference reference) {

-		this((Long) reference.getProperty(SERVICE_ID), (String[]) reference

-				.getProperty(OBJECTCLASS), reference.getBundle().getBundleId(),

+	public OSGiService(ServiceReference<?> reference) {

+		this((Long) reference.getProperty(SERVICE_ID), 

+				(String[]) reference.getProperty(OBJECTCLASS), 

+				reference.getBundle().getBundleId(),

 				Util.bundleIds(reference.getUsingBundles()));

 	}

 

@@ -118,9 +116,8 @@
 	 * 

 	 * @return the TabularData representing the list of OSGiServices

 	 */

-	public static TabularData tableFrom(ArrayList<OSGiService> services) {

-		TabularDataSupport table = new TabularDataSupport(

-				ServiceStateMBean.SERVICES_TYPE);

+	public static TabularData tableFrom(List<OSGiService> services) {

+		TabularDataSupport table = new TabularDataSupport(ServiceStateMBean.SERVICES_TYPE);

 		for (OSGiService service : services) {

 			table.put(service.asCompositeData());

 		}

@@ -132,7 +129,6 @@
 	 * 

 	 * @return the CompositeData encoding of the receiver.

 	 */

-	@SuppressWarnings("boxing")

 	public CompositeData asCompositeData() {

 		Map<String, Object> items = new HashMap<String, Object>();

 		items.put(ServiceStateMBean.IDENTIFIER, identifier);

@@ -141,8 +137,7 @@
 		items.put(ServiceStateMBean.USING_BUNDLES, LongArrayFrom(usingBundles));

 

 		try {

-			return new CompositeDataSupport(ServiceStateMBean.SERVICE_TYPE,

-					items);

+			return new CompositeDataSupport(ServiceStateMBean.SERVICE_TYPE, items);

 		} catch (OpenDataException e) {

 			throw new IllegalStateException("Cannot form service open data", e);

 		}