365711 Custom interface now makes it clear which methods are in addition to the 4.1 spec
diff --git a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/codec/OSGiProperties.java b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/codec/OSGiProperties.java
index 3dbfec7..8cf2774 100644
--- a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/codec/OSGiProperties.java
+++ b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/codec/OSGiProperties.java
@@ -85,7 +85,7 @@
  * <p>

  * The

  */

-public class OSGiProperties {

+public final class OSGiProperties {

 

 	/**

 	 * The key of the entry

@@ -384,7 +384,7 @@
 	 * @param type

 	 * @return the composite data representation of the key/value pair

 	 */

-	protected static CompositeData propertyData(String key, String value, String type) {

+	private static CompositeData propertyData(String key, String value, String type) {

 		Object[] itemValues = new Object[PROPERTIES.length];

 		itemValues[0] = key;

 		itemValues[1] = value;

diff --git a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/codec/Util.java b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/codec/Util.java
index 1561096..77f0373 100644
--- a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/codec/Util.java
+++ b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/codec/Util.java
@@ -39,7 +39,7 @@
  * Static utilities

  * 

  */

-public class Util {

+public final class Util {

 	

 	/**

 	 * 

diff --git a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/CustomServiceStateMBean.java b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/CustomServiceStateMBean.java
index ba2f446..936c5be 100644
--- a/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/CustomServiceStateMBean.java
+++ b/org.eclipse.gemini.mgmt/src/org/eclipse/gemini/mgmt/framework/CustomServiceStateMBean.java
@@ -14,12 +14,60 @@
  ******************************************************************************/
 package org.eclipse.gemini.mgmt.framework;
 
+import java.io.IOException;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
 import org.osgi.jmx.framework.ServiceStateMBean;
 
 /**
- * @author cgfrost
  *
  */
 public interface CustomServiceStateMBean extends ServiceStateMBean {
 
+
+	/**
+	 * 
+	 * @param serviceId
+	 * @return
+	 * @throws IOException
+	 */
+	public CompositeData getService(long serviceId) throws IOException;
+
+	/**
+	 * 
+	 * @param serviceId
+	 * @param key
+	 * @return
+	 * @throws IOException
+	 */
+	public CompositeData getProperty(long serviceId, String key) throws IOException;
+
+	/**
+	 * 
+	 * @param clazz
+	 * @param filter
+	 * @return
+	 * @throws IOException
+	 */
+	public TabularData listServices(String clazz, String filter) throws IOException;
+
+	/**
+	 * 
+	 * @param clazz
+	 * @param filter
+	 * @param serviceTypeItems
+	 * @return
+	 * @throws IOException
+	 */
+	public TabularData listServices(String clazz, String filter, String... serviceTypeItems) throws IOException;
+
+	/**
+	 * 
+	 * @return array of the bundle IDs of the bundles using this service
+	 * @throws IOException
+	 */
+	public long[] getServiceIds() throws IOException;
+	
 }
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 4560e13..834f7f1 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
@@ -17,12 +17,9 @@
 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;

@@ -48,11 +45,11 @@
 /** 

  * 

  */

-public class ServiceState extends Monitor implements CustomServiceStateMBean {

+public final class ServiceState extends Monitor implements CustomServiceStateMBean {

 

-	protected ServiceListener serviceListener;

+	private ServiceListener serviceListener;

 	

-	protected BundleContext bundleContext;

+	private BundleContext bundleContext;

 	

 	/**

 	 * Constructor

@@ -126,7 +123,6 @@
 

 	/**

 	 * {@inheritDoc}

-	 * @param <T>

 	 */

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

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

@@ -146,11 +142,11 @@
 	 * {@inheritDoc}

 	 */

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

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

 		try {

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

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

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

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

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

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

 			}

 			return OSGiService.tableFrom(services);

 		} catch (InvalidSyntaxException e) {

@@ -162,38 +158,14 @@
 	 * {@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 {

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

 			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.getBundlesUsingBundles(reference);

-				} else {

-					usingBundles = null;

-				}

 				services.add(new OSGiService(reference));

 			}

-			return OSGiService.tableFrom(services);

+			TabularData table = OSGiService.tableFrom(services, serviceTypeItems);

+			return table;

 		} catch (InvalidSyntaxException e) {

 			throw new IOException(e);

 		}

@@ -212,7 +184,6 @@
 			}

 			return serviceIds;

 		} catch (InvalidSyntaxException e) {

-			//passing in null so should never happen

 			throw new IOException(e);

 		}

 	}

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 7d739c0..3adbf6d 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
@@ -19,18 +19,23 @@
 import static org.osgi.framework.Constants.SERVICE_ID;

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

 

+import java.io.IOException;

+import java.util.ArrayList;

+import java.util.Arrays;

 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.CompositeType;

 import javax.management.openmbean.OpenDataException;

 import javax.management.openmbean.TabularData;

 import javax.management.openmbean.TabularDataSupport;

 

 import org.osgi.framework.ServiceReference;

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

+import org.osgi.jmx.Item;

 import org.osgi.jmx.framework.ServiceStateMBean;

 

 /**

@@ -61,7 +66,7 @@
  * </tr>

  * </table>

  */

-public class OSGiService {

+public final class OSGiService {

 

 	private long bundle;

 	private long identifier;

@@ -98,6 +103,41 @@
 		}

 		return table;

 	}

+	

+	/**

+	 * Answer the TabularData representing the list of OSGiService state

+	 * 

+	 * @param bundles

+	 *            - the list of bundles to represent

+	 * @param mask 

+	 * 

+	 * @return the Tabular data which represents the list of bundles

+	 * @throws IOException 

+	 */

+	public static TabularData tableFrom(ArrayList<OSGiService> services, String... serviceTypeItems) throws IOException {

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

+		TabularDataSupport table = new TabularDataSupport(Item.tabularType("SERVICES", "The table of all services", OSGiService.computeServiceType(serviceTypes), ServiceStateMBean.IDENTIFIER));

+		for (OSGiService service : services) {

+			table.put(service.asCompositeData(serviceTypes));

+		}

+		return table;

+	}

+	

+	private static CompositeType computeServiceType(List<String> serviceTypes) {

+		List<Item> serviceTypeItems = new ArrayList<Item>();

+		serviceTypeItems.add(ServiceStateMBean.IDENTIFIER_ITEM);

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

+			serviceTypeItems.add(ServiceStateMBean.OBJECT_CLASS_ITEM);

+		}

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

+			serviceTypeItems.add(ServiceStateMBean.BUNDLE_IDENTIFIER_ITEM);

+		}

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

+			serviceTypeItems.add(ServiceStateMBean.USING_BUNDLES_ITEM);

+		}

+		CompositeType currentCompositeType = Item.compositeType("SERVICE", "This type encapsulates an OSGi service", serviceTypeItems.toArray(new Item[]{}));

+		return currentCompositeType;

+	}

 

 	/**

 	 * Answer the receiver encoded as CompositeData

@@ -119,6 +159,32 @@
 	}

 

 	/**

+	 * Answer the receiver encoded as CompositeData

+	 * 

+	 * @return the CompositeData encoding of the receiver.

+	 */

+	private CompositeData asCompositeData(List<String> serviceTypes) {

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

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

+			items.put(ServiceStateMBean.IDENTIFIER, identifier);

+		}

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

+			items.put(ServiceStateMBean.OBJECT_CLASS, interfaces);

+		}

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

+			items.put(ServiceStateMBean.BUNDLE_IDENTIFIER, bundle);

+		}

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

+			items.put(ServiceStateMBean.USING_BUNDLES, LongArrayFrom(usingBundles));

+		}

+		try {

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

+		} catch (OpenDataException e) {

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

+		}

+	}

+

+	/**

 	 * @return the identifier of the bundle the service belongs to

 	 */

 	public long getBundle() {