You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2012/01/04 14:22:42 UTC

svn commit: r1227144 [11/18] - in /karaf/eik/trunk: ./ features/ features/info.evanchik.eclipse.karaf.feature/ features/info.evanchik.eclipse.karaf.jmx.feature/ features/info.evanchik.eclipse.karaf.update/ features/info.evanchik.eclipse.karaf.update/fe...

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafMBeanProvider.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafMBeanProvider.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafMBeanProvider.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafMBeanProvider.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,165 @@
+/**
+ * Copyright (c) 2009 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.internal;
+
+import info.evanchik.eclipse.karaf.workbench.KarafWorkbenchActivator;
+import info.evanchik.eclipse.karaf.workbench.MBeanProvider;
+import info.evanchik.eclipse.karaf.workbench.jmx.JMXServiceDescriptor;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+
+import org.eclipse.core.runtime.PlatformObject;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class KarafMBeanProvider extends PlatformObject implements MBeanProvider, NotificationListener {
+
+    private final JMXConnector connector;
+
+    private final ExecutorService connectionHandler;
+
+    private final JMXServiceDescriptor jmxServiceDescriptor;
+
+    private final MBeanServerConnection mbeanServer;
+
+    private Object memento;
+
+    private ServiceRegistration mbeanProviderService;
+
+    /**
+     * Constructs an {@link MBeanProvider} that opens a connection to a
+     * {@link MBeanServerConnection}
+     *
+     * @param jmxServiceDescriptor
+     *            the {@link JMXServiceDescriptor} which was used to make the
+     *            connection to the JMX end point
+     * @param connector
+     *            the {@link JMXConnector} that represents the JMX connection
+     * @throws IOException
+     *             if the connection to the MBean Server cannot be made
+     */
+    public KarafMBeanProvider(final JMXServiceDescriptor jmxServiceDescriptor, final JMXConnector connector) throws IOException {
+        this.connector = connector;
+        this.jmxServiceDescriptor = jmxServiceDescriptor;
+        this.mbeanServer = connector.getMBeanServerConnection();
+
+        this.connectionHandler = Executors.newSingleThreadExecutor();
+
+        this.connector.addConnectionNotificationListener(this, null, null);
+    }
+
+    @Override
+    public void close() {
+
+        // JMXConnector.close() is a potentially long running operation.
+        final Runnable r = new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    connector.removeConnectionNotificationListener(KarafMBeanProvider.this);
+                    connector.close();
+                } catch (final IOException e) {
+                    // Do nothing
+                    // KarafWorkbenchActivator.getLogger().info("Unable to close connection to JMX MBeanServer", e);
+                } catch (final ListenerNotFoundException e) {
+                    // Nothing to do since this is impossible
+                }
+            }
+        };
+
+        connectionHandler.submit(r);
+
+        if (isOpen()) {
+            unregisterServices();
+        }
+    }
+
+    @Override
+    public JMXServiceDescriptor getJMXServiceDescriptor() {
+        return jmxServiceDescriptor;
+    }
+
+    @Override
+    public <T> T getMBean(final ObjectName objectName, final Class<T> interfaceClass) {
+        return MBeanServerInvocationHandler.newProxyInstance(
+                mbeanServer,
+                objectName,
+                interfaceClass,
+                false);
+    }
+
+    @Override
+    public MBeanServerConnection getMBeanServerConnection() {
+        return mbeanServer;
+    }
+
+    @Override
+    public void handleNotification(final Notification notification, final Object handback) {
+    }
+
+    /**
+     * Determines if this provider is open by examining if a memento has been
+     * set.
+     *
+     * @return true if the memento has been set, false otherwise
+     */
+    @Override
+    public boolean isOpen() {
+        return memento != null;
+    }
+
+    @Override
+    public void open(final Object memento) {
+        if (memento == null) {
+            throw new NullPointerException("Cannot specify a null memento");
+        }
+
+        if (isOpen()) {
+            // Log something at Trace level?
+            return;
+        }
+
+        this.memento = memento;
+
+        registerServices();
+    }
+
+    private void registerServices() {
+        final BundleContext bundleContext =
+            KarafWorkbenchActivator.getDefault().getBundle().getBundleContext();
+
+        final Dictionary<String, Object> dictionary = new Hashtable<String, Object>();
+        dictionary.put(MBeanProvider.KARAF_WORKBENCH_SERVICES_ID, memento);
+
+        mbeanProviderService = bundleContext.registerService(MBeanProvider.class.getName(), this, dictionary);
+    }
+
+    private void unregisterServices() {
+        mbeanProviderService.unregister();
+        mbeanProviderService = null;
+    }
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafMBeanProviderWorkbenchService.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafMBeanProviderWorkbenchService.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafMBeanProviderWorkbenchService.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafMBeanProviderWorkbenchService.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,361 @@
+/**
+ * Copyright (c) 2010 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.internal;
+
+import info.evanchik.eclipse.karaf.core.KarafCorePluginUtils;
+import info.evanchik.eclipse.karaf.core.KarafWorkingPlatformModel;
+import info.evanchik.eclipse.karaf.core.equinox.BundleEntry;
+import info.evanchik.eclipse.karaf.ui.workbench.KarafWorkbenchService;
+import info.evanchik.eclipse.karaf.workbench.KarafWorkbenchActivator;
+import info.evanchik.eclipse.karaf.workbench.MBeanProvider;
+import info.evanchik.eclipse.karaf.workbench.WorkbenchServiceManager;
+import info.evanchik.eclipse.karaf.workbench.jmx.JMXServiceDescriptor;
+import info.evanchik.eclipse.karaf.workbench.jmx.LocalJMXServiceDescriptor;
+import info.evanchik.eclipse.karaf.workbench.provider.RuntimeDataProvider;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.remote.JMXServiceURL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IDebugEventSetListener;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchListener;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.jdt.launching.SocketUtil;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class KarafMBeanProviderWorkbenchService implements KarafWorkbenchService {
+
+    /**
+     *
+     * @author Stephen Evanchik (evanchsa@gmail.com)
+     *
+     */
+    private final class JMXServiceCleanupLaunchListener implements ILaunchListener {
+
+        @Override
+        public void launchAdded(final ILaunch launch) {
+        }
+
+        @Override
+        public void launchChanged(final ILaunch launch) {
+        }
+
+        @Override
+        public void launchRemoved(final ILaunch launch) {
+            try {
+                final String memento = launch.getLaunchConfiguration().getMemento();
+
+                final JMXServiceDescriptor jmxServiceDescriptor = mbeanProviderDataMap.get(memento).getJmxServiceDescriptor();
+
+                if (jmxServiceDescriptor == null) {
+                    return;
+                }
+
+                jmxServiceManager.remove(jmxServiceDescriptor);
+
+                mbeanProviderDataMap.remove(memento);
+            } catch (final CoreException e) {
+                // Log something
+            }
+        }
+    };
+
+    private static final class KarafMBeanProviderEntry {
+
+        private JMXServiceDescriptor jmxServiceDescriptor;
+
+        private MBeanProvider mbeanProvider;
+
+        private MBeanServerConnectionJob mbeanServerConnectionJob;
+
+        private RuntimeDataProvider runtimeDataProvider;
+
+        public JMXServiceDescriptor getJmxServiceDescriptor() {
+            return jmxServiceDescriptor;
+        }
+
+        public MBeanProvider getMbeanProvider() {
+            return mbeanProvider;
+        }
+
+        public MBeanServerConnectionJob getMBeanServerConnectionJob() {
+            return mbeanServerConnectionJob;
+        }
+
+        public RuntimeDataProvider getRuntimeDataProvider() {
+            return runtimeDataProvider;
+        }
+
+        public void setJmxServiceDescriptor(
+                final JMXServiceDescriptor jmxServiceDescriptor) {
+            this.jmxServiceDescriptor = jmxServiceDescriptor;
+        }
+
+        public void setMbeanConnectionJob(final MBeanServerConnectionJob mbeanServerConnectionJob) {
+            this.mbeanServerConnectionJob = mbeanServerConnectionJob;
+        }
+
+        public void setMbeanProvider(final MBeanProvider mbeanProvider) {
+            this.mbeanProvider = mbeanProvider;
+        }
+
+        public void setRuntimeDataProvider(final RuntimeDataProvider runtimeDataProvider) {
+            this.runtimeDataProvider = runtimeDataProvider;
+        }
+    };
+
+    public static final String JMX_JMXRMI_DOMAIN = "jmxrmi"; //$NON-NLS-1$
+
+    private WorkbenchServiceManager<JMXServiceDescriptor> jmxServiceManager;
+
+    private final Map<String, KarafMBeanProviderEntry> mbeanProviderDataMap =
+        Collections.synchronizedMap(new HashMap<String, KarafMBeanProviderEntry>());
+
+    private WorkbenchServiceManager<MBeanProvider> mbeanProviderManager;
+
+    private WorkbenchServiceManager<RuntimeDataProvider> runtimeDataProviderManager;
+
+    public KarafMBeanProviderWorkbenchService() {
+        DebugPlugin.getDefault().getLaunchManager().addLaunchListener(new JMXServiceCleanupLaunchListener());
+
+        jmxServiceManager = KarafWorkbenchActivator.getDefault().getJMXServiceManager();
+        mbeanProviderManager = KarafWorkbenchActivator.getDefault().getMBeanProviderManager();
+        runtimeDataProviderManager = KarafWorkbenchActivator.getDefault().getRuntimeDataProviderManager();
+    }
+
+    @Override
+    public List<BundleEntry> getAdditionalBundles(
+        final KarafWorkingPlatformModel platformModel,
+        final ILaunchConfiguration configuration)
+    {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Map<String, String> getAdditionalEquinoxConfiguration(
+        final KarafWorkingPlatformModel platformModel,
+        final ILaunchConfiguration configuration)
+    {
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Starts a background system job that will connect to the Karaf MBeanServer
+     *
+     * 1. Register a remote JMX port to bind the JMX server to
+     * 2. Establish an MBeanServerConnectionJob to connect to that port
+     * 3. When connected: Register OSGi C&C MBeanProvider in the service registry
+     * 4. When connected: Register the RuntimeDataProvider in the service registry
+     */
+    @Override
+    public List<String> getVMArguments(
+            final KarafWorkingPlatformModel platformModel,
+            final ILaunchConfiguration configuration) throws CoreException
+    {
+        final String memento = configuration.getMemento();
+        mbeanProviderDataMap.put(memento, new KarafMBeanProviderEntry());
+
+        final List<String> arguments = new ArrayList<String>();
+
+        /*
+         * Ensure the Remote JMX connector port is unique
+         */
+        final int jmxPort = SocketUtil.findFreePort();
+
+        if (jmxPort == -1) {
+            throw new CoreException(new Status(IStatus.ERROR, KarafWorkbenchActivator.PLUGIN_ID,
+                    "Could not find suitable TCP/IP port for JMX connection"));
+        }
+
+        arguments.add(
+                KarafCorePluginUtils.constructSystemProperty(
+                        "com.sun.management.jmxremote.authenticate", //$NON-NLS-1$
+                        "false")); //$NON-NLS-1$
+        arguments.add(
+                KarafCorePluginUtils.constructSystemProperty(
+                        "com.sun.management.jmxremote.ssl", //$NON-NLS-1$
+                        "false")); //$NON-NLS-1$
+        arguments.add(
+                KarafCorePluginUtils.constructSystemProperty(
+                        "com.sun.management.jmxremote.port", //$NON-NLS-1$
+                        new Integer(jmxPort).toString()));
+
+        final MBeanServerConnectionJob mbeanConnectionJob;
+        try {
+            final JMXServiceURL standardJmxConnection = new JMXServiceURL(
+                    "service:jmx:rmi:///jndi/rmi://localhost:" + jmxPort + "/jmxrmi"); //$NON-NLS-1$ $NON-NLS-2$
+
+            final JMXServiceDescriptor descriptor = new LocalJMXServiceDescriptor(
+                        configuration.getName(),
+                        platformModel,
+                        standardJmxConnection,
+                        null,
+                        null,
+                        JMX_JMXRMI_DOMAIN);
+
+            mbeanConnectionJob = new MBeanServerConnectionJob(configuration.getName(), descriptor);
+
+            mbeanProviderDataMap.get(memento).setMbeanConnectionJob(mbeanConnectionJob);
+            mbeanProviderDataMap.get(memento).setJmxServiceDescriptor(descriptor);
+
+            jmxServiceManager.add(descriptor);
+        } catch(final MalformedURLException e) {
+            KarafWorkbenchActivator.getLogger().error("Unable to connect to JMX endpoint on Karaf instance", e);
+
+            throw new CoreException(new Status(IStatus.ERROR, "", "")); //$NON-NLS-1$ $NON-NLS-2$
+        }
+
+        final IJobChangeListener listener = new JobChangeAdapter() {
+            @Override
+            public void done(final IJobChangeEvent event) {
+                final IStatus result = event.getResult();
+                if (result == null || !result.isOK()) {
+                    // TODO: Log something
+                    return;
+                }
+
+                if (!mbeanConnectionJob.isConnected()) {
+                    // TODO: Log something
+                    return;
+                }
+
+                final KarafMBeanProvider mbeanProvider;
+                try {
+                    final JMXServiceDescriptor jmxServiceDescriptor = mbeanProviderDataMap.get(memento).getJmxServiceDescriptor();
+                    mbeanProvider = new LocalKarafMBeanProvider(jmxServiceDescriptor, mbeanConnectionJob.getJmxClient(), platformModel);
+                    mbeanProvider.open(memento);
+
+                    mbeanProviderDataMap.get(memento).setMbeanProvider(mbeanProvider);
+                    mbeanProviderManager.add(mbeanProvider);
+                } catch (final IOException e) {
+                    KarafWorkbenchActivator.getLogger().error("Unable to create MBeanProvider from JMXConnector", e);
+
+                    return;
+                }
+
+                final KarafRuntimeDataProvider runtimeDataProvider = new KarafRuntimeDataProvider(configuration.getName(), mbeanProvider);
+                runtimeDataProvider.start();
+
+                mbeanProviderDataMap.get(memento).setRuntimeDataProvider(runtimeDataProvider);
+                runtimeDataProviderManager.add(runtimeDataProvider);
+            }
+        };
+
+        mbeanConnectionJob.addJobChangeListener(listener);
+        mbeanConnectionJob.schedule(MBeanServerConnectionJob.DEFAULT_INITIAL_SCHEDULE_DELAY);
+
+        return arguments;
+    }
+
+    @Override
+    public void initialize(final KarafWorkingPlatformModel platformModel,
+            final ILaunchConfigurationWorkingCopy configuration) {
+    }
+
+    @Override
+    public void launch(
+            final KarafWorkingPlatformModel platformModel,
+            final ILaunchConfiguration configuration,
+            final String mode,
+            final ILaunch launch,
+            final IProgressMonitor monitor) throws CoreException
+    {
+        final IDebugEventSetListener debugListener = getDebugEventListener(launch);
+        DebugPlugin.getDefault().addDebugEventListener(debugListener);
+    }
+
+    public void setJmxServiceManager(final WorkbenchServiceManager<JMXServiceDescriptor> jmxServiceManager) {
+        this.jmxServiceManager = jmxServiceManager;
+    }
+
+    public void setMbeanProviderManager(final WorkbenchServiceManager<MBeanProvider> mbeanProviderManager) {
+        this.mbeanProviderManager = mbeanProviderManager;
+    }
+
+    public void setRuntimeDataProviderManager(final WorkbenchServiceManager<RuntimeDataProvider> runtimeDataProviderManager) {
+        this.runtimeDataProviderManager = runtimeDataProviderManager;
+    }
+
+    /**
+     * Registers an event listener on the debug session that responds to
+     * {@link DebugEvent.TERMINATE} events. This will stop the MBBean connection
+     * job, the {@link RuntimeDataProvider} and the {@link MBeanProvider}<br>
+     * <br>
+     * This will also cleanup the services registered during this debug session.
+     *
+     * @param launch
+     *            the launch process
+     */
+    private IDebugEventSetListener getDebugEventListener(final ILaunch launch) throws CoreException {
+        final IProcess process = launch.getProcesses()[0];
+
+        final String memento =
+            launch.getLaunchConfiguration().getMemento();
+
+        return new IDebugEventSetListener() {
+            @Override
+            public void handleDebugEvents(final DebugEvent[] events) {
+                if (events == null) {
+                    return;
+                }
+
+                for (final DebugEvent event : events) {
+                    if (   process != null
+                        && process.equals(event.getSource())
+                        && event.getKind() == DebugEvent.TERMINATE)
+                    {
+                        final JMXServiceDescriptor descriptor = mbeanProviderDataMap.get(memento).getJmxServiceDescriptor();
+                        jmxServiceManager.remove(descriptor);
+
+                        final MBeanServerConnectionJob job = mbeanProviderDataMap.get(memento).getMBeanServerConnectionJob();
+                        if (job != null) {
+                            job.cancel();
+                        }
+
+                        final RuntimeDataProvider runtimeDataProvider = mbeanProviderDataMap.get(memento).getRuntimeDataProvider();
+                        runtimeDataProviderManager.remove(runtimeDataProvider);
+                        if (runtimeDataProvider != null) {
+                            runtimeDataProvider.stop();
+                        }
+
+                        final MBeanProvider mbeanProvider = mbeanProviderDataMap.get(memento).getMbeanProvider();
+                        mbeanProviderManager.remove(mbeanProvider);
+
+                        if (mbeanProvider != null) {
+                            mbeanProvider.close();
+                        }
+                    }
+                }
+            }
+        };
+    }
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafRuntimeDataProvider.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafRuntimeDataProvider.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafRuntimeDataProvider.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/KarafRuntimeDataProvider.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,304 @@
+/**
+ * Copyright (c) 2009 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.internal;
+
+import info.evanchik.eclipse.karaf.workbench.KarafWorkbenchActivator;
+import info.evanchik.eclipse.karaf.workbench.MBeanProvider;
+import info.evanchik.eclipse.karaf.workbench.provider.AbstractRuntimeDataProvider;
+import info.evanchik.eclipse.karaf.workbench.provider.BundleItem;
+import info.evanchik.eclipse.karaf.workbench.provider.RuntimeDataProvider;
+import info.evanchik.eclipse.karaf.workbench.provider.RuntimeDataProviderListener;
+import info.evanchik.eclipse.karaf.workbench.provider.ServiceItem;
+
+import java.io.IOException;
+import java.util.EnumSet;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+import org.apache.aries.jmx.codec.ServiceData;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.swt.graphics.Image;
+import org.osgi.jmx.framework.BundleStateMBean;
+import org.osgi.jmx.framework.ServiceStateMBean;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class KarafRuntimeDataProvider extends AbstractRuntimeDataProvider {
+
+    private static final ObjectName BUNDLE_STATE;
+
+    @SuppressWarnings("unused")
+    private static final ObjectName CM_SERVICE;
+
+    @SuppressWarnings("unused")
+    private static final ObjectName PACKAGE_STATE;
+
+    private static final ObjectName SERVICE_STATE;
+
+    /*
+     * If this throws an exception we're in trouble because it means that the
+     * constants are invalid
+     */
+    static {
+        try {
+            BUNDLE_STATE = new ObjectName("osgi.core:type=bundleState,version=1.5");
+            CM_SERVICE = new ObjectName("osgi.core:type=cm,version=1.3");
+            PACKAGE_STATE = new ObjectName("osgi.core:type=packageState,version=1.5");
+            SERVICE_STATE = new ObjectName("osgi.core:type=serviceState,version=1.5");
+        } catch (final Exception e) {
+            throw new IllegalStateException("The OSGi JMX implementation references an invalid ObjectName", e);
+        }
+    }
+
+    private final String name;
+
+    private final MBeanProvider mbeanProvider;
+
+    /**
+     * Updates the runtime data referenced by the {@link BundleStateMBean} and
+     * {@link ServiceStateMBean}
+     */
+    private final Job updateDataJob;
+
+    /**
+     * A {@link RuntimeDataProvider} implementation specific to Karaf instances
+     * being run/debugged in Eclipse.
+     *
+     * @param name
+     *            the human readable name of this provider
+     * @param provider
+     *            the {@link MBeanProvider} for the running Karaf instance
+     */
+    public KarafRuntimeDataProvider(final String name, final MBeanProvider provider) {
+        super();
+
+        this.name = name;
+        this.mbeanProvider = provider;
+
+        this.updateDataJob = new Job("Populating OSGi Runtime view data for: " + name) {
+
+            private volatile boolean cancel = false;
+
+            @Override
+            public IStatus run(IProgressMonitor monitor) {
+                if (monitor == null) {
+                    monitor = new NullProgressMonitor();
+                }
+
+                if (   !KarafRuntimeDataProvider.this.mbeanProvider.isOpen()
+                    && !cancel)
+                {
+                    this.schedule(25000);
+                }
+
+                monitor.beginTask("Populating view data set", IProgressMonitor.UNKNOWN);
+
+                IStatus status = loadBundleData(monitor);
+                if (!status.isOK()) {
+                    // Do something?
+                }
+
+                if (monitor.isCanceled()) {
+                    return Status.OK_STATUS;
+                }
+
+                status = loadServiceData(monitor);
+                if (!status.isOK()) {
+                    // Do something?
+                }
+
+                monitor.done();
+
+                if (monitor.isCanceled()) {
+                    return Status.OK_STATUS;
+                }
+
+                if (!cancel) {
+                    /*
+                     * Poll every 25 seconds because the MBeans are not notification
+                     * enabled
+                     */
+                    this.schedule(25000);
+                }
+
+                fireProviderChangeEvent(EnumSet.of(RuntimeDataProviderListener.EventType.CHANGE));
+
+                return Status.OK_STATUS;
+            }
+
+            @Override
+            protected void canceling() {
+                cancel = true;
+            }
+        };
+
+        this.updateDataJob.setSystem(true);
+        this.updateDataJob.setPriority(Job.LONG);
+    }
+
+    @Override
+    public Object getAdapter(@SuppressWarnings("rawtypes") final Class adapter) {
+        if (MBeanProvider.class.equals(adapter)) {
+            return mbeanProvider;
+        } else {
+            return super.getAdapter(adapter);
+        }
+    }
+
+    @Override
+    public Image getIcon() {
+        return KarafWorkbenchActivator.getDefault().getImageRegistry().get(KarafWorkbenchActivator.LOGO_16X16_IMG);
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Starts the {@link RuntimeDataProvider} which will collect the OSGi
+     * runtime information from the running Karaf instance.
+     */
+    @Override
+    public void start() {
+        fireStartEvent();
+
+        updateDataJob.schedule();
+    }
+
+    @Override
+    public void stop() {
+        updateDataJob.cancel();
+
+        synchronized (bundleSet) {
+            bundleSet.clear();
+            idToBundleMap.clear();
+        }
+
+        synchronized (serviceSet) {
+            serviceSet.clear();
+            idToServiceMap.clear();
+        }
+
+        fireStopEvent();
+    }
+
+    private IStatus loadBundleData(final IProgressMonitor monitor) {
+        monitor.subTask("OSGi Bundles");
+
+        if (monitor.isCanceled()) {
+            return Status.OK_STATUS;
+        }
+
+        if (!mbeanProvider.isOpen()) {
+            return new Status(IStatus.WARNING, KarafWorkbenchActivator.PLUGIN_ID, "Connection to MBean server has been closed");
+        }
+
+        try {
+            final TabularData rawBundleData = mbeanProvider.getMBean(BUNDLE_STATE, BundleStateMBean.class).listBundles();
+
+            synchronized (bundleSet) {
+                bundleSet.clear();
+                idToBundleMap.clear();
+            }
+
+            for (final Object o : rawBundleData.values()) {
+                final CompositeData composite = (CompositeData) o;
+                final BundleItem bundle = new BundleItem(composite);
+
+                synchronized (bundleSet) {
+                    bundleSet.add(bundle);
+                    idToBundleMap.put(bundle.getIdentifier(), bundle);
+                }
+
+                monitor.worked(1);
+
+                if (monitor.isCanceled()) {
+                    break;
+                }
+
+            }
+
+        } catch (final IOException e) {
+            return new Status(IStatus.ERROR, KarafWorkbenchActivator.PLUGIN_ID, "Unable to connect to MBeanServer", e);
+        } catch (final Exception e) {
+            KarafWorkbenchActivator.getLogger().warn("Unable to update OSGi Bundles", e);
+        }
+
+        return Status.OK_STATUS;
+    }
+
+    private IStatus loadServiceData(final IProgressMonitor monitor) {
+        monitor.subTask("OSGi Services");
+
+        if (monitor.isCanceled()) {
+            return Status.OK_STATUS;
+        }
+
+        if (!mbeanProvider.isOpen()) {
+            return new Status(IStatus.WARNING, KarafWorkbenchActivator.PLUGIN_ID, "Connection to MBean server has been closed");
+        }
+
+        try {
+            final TabularData rawServiceData = mbeanProvider.getMBean(SERVICE_STATE, ServiceStateMBean.class).listServices();
+
+            synchronized (serviceSet) {
+                serviceSet.clear();
+                idToServiceMap.clear();
+            }
+
+            for (final Object o : rawServiceData.values()) {
+                final CompositeData composite = (CompositeData) o;
+                final ServiceData service = ServiceData.from(composite);
+
+                /*
+                 * Get the service's properties from the JMX enabled runtime
+                 */
+                if (!mbeanProvider.isOpen()) {
+                    return new Status(IStatus.WARNING, KarafWorkbenchActivator.PLUGIN_ID, "Connection to MBean server has been closed");
+                }
+
+                final ServiceItem serviceWrapper = new MBeanServiceItem(composite, mbeanProvider, idToBundleMap);
+
+                synchronized (serviceSet) {
+                    serviceSet.add(serviceWrapper);
+                    idToServiceMap.put(service.getServiceId(), serviceWrapper);
+                }
+
+                monitor.worked(1);
+
+                if (monitor.isCanceled()) {
+                    break;
+                }
+
+            }
+        } catch (final IOException e) {
+        	if (monitor.isCanceled()) {
+        		return new Status(IStatus.CANCEL, KarafWorkbenchActivator.PLUGIN_ID, "Unable to connect to MBeanServer", e);
+        	} else {
+        		return new Status(IStatus.ERROR, KarafWorkbenchActivator.PLUGIN_ID, "Unable to connect to MBeanServer", e);
+        	}
+        } catch (final Exception e) {
+            KarafWorkbenchActivator.getLogger().warn("Unable to update OSGi Services", e);
+        }
+
+        return Status.OK_STATUS;
+    }
+
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/LocalKarafMBeanProvider.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/LocalKarafMBeanProvider.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/LocalKarafMBeanProvider.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/LocalKarafMBeanProvider.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2011 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.internal;
+
+import info.evanchik.eclipse.karaf.core.KarafPlatformModel;
+import info.evanchik.eclipse.karaf.workbench.jmx.JMXServiceDescriptor;
+
+import java.io.IOException;
+
+import javax.management.remote.JMXConnector;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class LocalKarafMBeanProvider extends KarafMBeanProvider {
+
+    private final KarafPlatformModel platformModel;
+
+    /**
+     * @param jmxServiceDescriptor
+     * @param connector
+     * @param platformModel
+     * @throws IOException
+     */
+    public LocalKarafMBeanProvider(final JMXServiceDescriptor jmxServiceDescriptor, final JMXConnector connector, final KarafPlatformModel platforModel) throws IOException {
+        super(jmxServiceDescriptor, connector);
+
+        this.platformModel = platforModel;
+    }
+
+    @Override
+    public Object getAdapter(final @SuppressWarnings("rawtypes") Class adapter) {
+        if (KarafPlatformModel.class.equals(adapter)) {
+            return platformModel;
+        } else {
+            return super.getAdapter(adapter);
+        }
+    }
+
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanProviderManager.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanProviderManager.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanProviderManager.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanProviderManager.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2011 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.internal;
+
+import info.evanchik.eclipse.karaf.workbench.MBeanProvider;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class MBeanProviderManager extends AbstractWorkbenchServiceManager<MBeanProvider> {
+
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanServerConnectionJob.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanServerConnectionJob.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanServerConnectionJob.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanServerConnectionJob.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,172 @@
+/**
+ * Copyright (c) 2009 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.internal;
+
+import info.evanchik.eclipse.karaf.workbench.KarafWorkbenchActivator;
+import info.evanchik.eclipse.karaf.workbench.jmx.JMXServiceDescriptor;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class MBeanServerConnectionJob extends Job {
+
+    /**
+     * Default maximum number of connection attempts
+     */
+    public static final int DEFAULT_MAX_RETRIES = 5;
+
+    /**
+     * Default number of milliseconds between rescheduling
+     */
+    public static final long DEFAULT_RESCHEDULE_DELAY = 5 * 1000;
+
+    /**
+     * Default number of milliseconds before attempting to connect to the JMX
+     * server
+     */
+    public static final long DEFAULT_INITIAL_SCHEDULE_DELAY = 3 * 1000;
+
+    /**
+     * The JMX connection descriptor
+     */
+    private final JMXServiceDescriptor connection;
+
+    /**
+     * The time between connection retries
+     */
+    private long rescheduleDelay = DEFAULT_RESCHEDULE_DELAY;
+
+    /**
+     * The JMX environment used for passing credentials to the JMX connection
+     */
+    private final Hashtable<String, String[]> environment = new Hashtable<String, String[]>();
+
+    /**
+     * Determines if this {@link Job} has been canceled
+     */
+    private volatile boolean cancel = false;
+
+    /**
+     * The JMX MBeanServer client
+     */
+    private JMXConnector jmxClient;
+
+    /**
+     * Constructs a {@link Job} that will connect to the JMX MBeanServer on a
+     * remote (or local) Karaf instance.
+     *
+     * @param name
+     *            the friendly name of this job as displayed to the user
+     * @param connection
+     *            the {@link JMXServiceDescriptor} that represents
+     *            the JMX MBeanServer this {@link Job} will connect to
+     */
+    public MBeanServerConnectionJob(final String name, final JMXServiceDescriptor connection) {
+        super(name);
+
+        this.connection = connection;
+
+        String[] credentials;
+        if (hasCredentials()) {
+            credentials = new String[] { connection.getUsername(), connection.getPassword() };
+            environment.put(JMXConnector.CREDENTIALS, credentials);
+        }
+    }
+
+    public JMXConnector getJmxClient() {
+        return jmxClient;
+    }
+
+    public JMXServiceDescriptor getMBeanServerConnectionDescriptor() {
+        return connection;
+    }
+
+    public final long getRescheduleDelay() {
+        return rescheduleDelay;
+    }
+
+    /**
+     * Determines if this job successfully connected to the MBeanServer
+     *
+     * @return true if connected to the MBeanServer, false otherwise
+     */
+    public final boolean isConnected() {
+        return jmxClient != null;
+    }
+
+    /**
+     * @param rescheduleDelay
+     *            the rescheduleDelay to set
+     */
+    public final void setRescheduleDelay(final long rescheduleDelay) {
+        this.rescheduleDelay = rescheduleDelay;
+    }
+
+    @Override
+    protected void canceling() {
+        cancel = true;
+    }
+
+    @Override
+    protected IStatus run(final IProgressMonitor monitor) {
+
+	    IStatus status;
+
+	    try {
+	        jmxClient = JMXConnectorFactory.connect(connection.getUrl(), environment);
+
+	        monitor.worked(5);
+
+	        status = new Status(
+	                IStatus.OK,
+	                KarafWorkbenchActivator.PLUGIN_ID,
+	                "Successfully connected to JMX MBeanServer for: " + getName());
+
+	    } catch (final IOException ex) {
+	        status = new Status(
+	        		IStatus.WARNING,
+	        		KarafWorkbenchActivator.PLUGIN_ID,
+	        		"Retrying connection for for: " + getName(), ex);
+
+		    if (!cancel) {
+		    	schedule(rescheduleDelay);
+		    }
+	    }
+
+	    return status;
+    }
+
+    /**
+     * Determines if the {@link JMXServiceDescriptor} has
+     * authentication information provided
+     *
+     * @return true if there is authentication information, false otherwise
+     */
+    private boolean hasCredentials() {
+        if (connection.getUsername() != null && connection.getUsername().length() > 0) {
+            return true;
+        }
+
+        return false;
+    }
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanServiceItem.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanServiceItem.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanServiceItem.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/MBeanServiceItem.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2010 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.internal;
+
+import info.evanchik.eclipse.karaf.workbench.MBeanProvider;
+import info.evanchik.eclipse.karaf.workbench.provider.BundleItem;
+import info.evanchik.eclipse.karaf.workbench.provider.ServiceItem;
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.management.openmbean.CompositeData;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class MBeanServiceItem extends ServiceItem {
+
+    private final Map<Long, BundleItem> bundleCache;
+
+    @SuppressWarnings("unused")
+    private final MBeanProvider mbeanProvider;
+
+    public MBeanServiceItem(final CompositeData compositeData, final MBeanProvider mbeanProvider, final Map<Long, BundleItem> bundleCache) {
+        super(compositeData);
+
+        this.mbeanProvider = mbeanProvider;
+        this.bundleCache = Collections.synchronizedMap(bundleCache);
+    }
+
+    @Override
+    public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
+        Object o;
+        if (adapter == null) {
+            o = null;
+        } else {
+            o = super.getAdapter(adapter);
+            if (o == null && adapter.equals(BundleItem.class)) {
+                if (bundleCache.containsKey(Long.valueOf(getBundleId()))) {
+                    o = bundleCache.get(Long.valueOf(getBundleId()));
+                } else {
+                    // TODO: Fetch this data from the remote source
+                    o = null;
+                }
+            }
+        }
+
+        return o;
+    }
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/RuntimeDataProviderManager.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/RuntimeDataProviderManager.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/RuntimeDataProviderManager.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/RuntimeDataProviderManager.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2011 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.internal;
+
+import info.evanchik.eclipse.karaf.workbench.provider.RuntimeDataProvider;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class RuntimeDataProviderManager extends AbstractWorkbenchServiceManager<RuntimeDataProvider> {
+
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/WorkbenchActionProvider.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/WorkbenchActionProvider.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/WorkbenchActionProvider.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/WorkbenchActionProvider.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2011 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.internal;
+
+import info.evanchik.eclipse.karaf.ui.IKarafProject;
+import info.evanchik.eclipse.karaf.workbench.KarafWorkbenchActivator;
+import info.evanchik.eclipse.karaf.workbench.ui.editor.KarafPlatformEditorInput;
+import info.evanchik.eclipse.karaf.workbench.ui.editor.KarafPlatformEditorPart;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.navigator.CommonActionProvider;
+import org.eclipse.ui.navigator.ICommonActionExtensionSite;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class WorkbenchActionProvider extends CommonActionProvider {
+
+    @Override
+    public void init(final ICommonActionExtensionSite aSite) {
+        super.init(aSite);
+
+        aSite.getStructuredViewer().addDoubleClickListener(new IDoubleClickListener() {
+
+            @Override
+            public void doubleClick(final DoubleClickEvent event) {
+                // TODO: This method is a mess: clean it up!
+                if (!(event.getSelection() instanceof IStructuredSelection)) {
+                    return;
+                }
+
+                final IStructuredSelection structuredSelection = (IStructuredSelection) event.getSelection();
+                if (structuredSelection.size() > 1) {
+                    return;
+                }
+
+                final Object element = structuredSelection.getFirstElement();
+                if (!(element instanceof IProject)) {
+                    return;
+                }
+
+                final IProject project = (IProject) element;
+                final IKarafProject karafProject = (IKarafProject) project.getAdapter(IKarafProject.class);
+                final IEditorInput editorInput = new KarafPlatformEditorInput(karafProject);
+
+                try {
+                    final IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+                    page.openEditor(editorInput, KarafPlatformEditorPart.ID);
+                } catch (final PartInitException e) {
+                    KarafWorkbenchActivator.getLogger().error("Unable to open editor for " + karafProject.getName(), e);
+                }
+            }
+        });
+    }
+
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/eclipse/EclipseRuntimeDataProvider.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/eclipse/EclipseRuntimeDataProvider.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/eclipse/EclipseRuntimeDataProvider.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/internal/eclipse/EclipseRuntimeDataProvider.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,254 @@
+/**
+ * Copyright (c) 2009 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.internal.eclipse;
+
+import info.evanchik.eclipse.karaf.workbench.KarafWorkbenchActivator;
+import info.evanchik.eclipse.karaf.workbench.provider.AbstractRuntimeDataProvider;
+import info.evanchik.eclipse.karaf.workbench.provider.BundleItem;
+import info.evanchik.eclipse.karaf.workbench.provider.RuntimeDataProvider;
+import info.evanchik.eclipse.karaf.workbench.provider.RuntimeDataProviderListener;
+import info.evanchik.eclipse.karaf.workbench.provider.ServiceItem;
+
+import java.util.EnumSet;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.osgi.framework.AllServiceListener;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.startlevel.StartLevel;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class EclipseRuntimeDataProvider extends AbstractRuntimeDataProvider implements RuntimeDataProvider {
+
+    private final BundleContext context;
+
+    private final BundleListener eclipseBundleListener;
+
+    private final AllServiceListener eclipseAllServiceListener;
+
+    private ServiceReference packageAdminReference;
+
+    private PackageAdmin packageAdmin;
+
+    private ServiceReference startLevelReference;
+
+    private StartLevel startLevel;
+
+    /**
+     *
+     * @author Stephen Evanchik (evanchsa@gmail.com)
+     *
+     */
+    private final class EclipseBundleListener implements BundleListener {
+
+        @Override
+        public void bundleChanged(BundleEvent event) {
+            final BundleItem wrappedBundle = new BundleItem(event.getBundle(), startLevel, packageAdmin);
+
+            EnumSet<RuntimeDataProviderListener.EventType> events = EnumSet.noneOf(RuntimeDataProviderListener.EventType.class);
+
+            switch (event.getType()) {
+            case BundleEvent.INSTALLED:
+                synchronized (bundleSet) {
+                    if (!bundleSet.contains(wrappedBundle)) {
+                        bundleSet.add(wrappedBundle);
+
+                        events = EnumSet.of(RuntimeDataProviderListener.EventType.ADD);
+                    }
+                }
+                break;
+            case BundleEvent.UNINSTALLED:
+                synchronized (bundleSet) {
+                    if (bundleSet.contains(wrappedBundle)) {
+                        bundleSet.remove(wrappedBundle);
+
+                        events = EnumSet.of(RuntimeDataProviderListener.EventType.REMOVE);
+                    }
+                }
+                break;
+            default:
+                events = EnumSet.of(RuntimeDataProviderListener.EventType.CHANGE);
+                break;
+            }
+
+            fireProviderChangeEvent(events);
+        }
+    };
+
+    /**
+     *
+     * @author Stephen Evanchik (evanchsa@gmail.com)
+     *
+     */
+    private final class EclipseAllServiceListener implements AllServiceListener {
+
+        @Override
+        public void serviceChanged(ServiceEvent event) {
+            final ServiceReference reference = event.getServiceReference();
+
+            final ServiceItem ri = new ServiceItem(reference);
+
+            EnumSet<RuntimeDataProviderListener.EventType> events = EnumSet.noneOf(RuntimeDataProviderListener.EventType.class);
+
+            switch (event.getType()) {
+            case ServiceEvent.REGISTERED:
+                synchronized (serviceSet) {
+                    if (serviceSet.contains(ri)) {
+                        serviceSet.add(ri);
+                        events = EnumSet.of(RuntimeDataProviderListener.EventType.ADD);
+                    }
+                }
+                break;
+            case ServiceEvent.UNREGISTERING:
+                synchronized (serviceSet) {
+                    if (serviceSet.contains(ri)) {
+                        serviceSet.remove(ri);
+                        events = EnumSet.of(RuntimeDataProviderListener.EventType.REMOVE);
+                    }
+                }
+                break;
+            case ServiceEvent.MODIFIED:
+            default:
+                events = EnumSet.of(RuntimeDataProviderListener.EventType.CHANGE);
+                break;
+            }
+
+            fireProviderChangeEvent(events);
+        }
+    };
+
+    public EclipseRuntimeDataProvider(BundleContext context) {
+        super();
+
+        this.context = context;
+
+        this.eclipseBundleListener = new EclipseBundleListener();
+        this.eclipseAllServiceListener = new EclipseAllServiceListener();
+
+        this.packageAdminReference = context.getServiceReference(PackageAdmin.class.getName());
+        this.packageAdmin = (PackageAdmin) context.getService(packageAdminReference);
+
+        this.startLevelReference = context.getServiceReference(StartLevel.class.getName());
+        this.startLevel = (StartLevel) context.getService(startLevelReference);
+    }
+
+    public String getName() {
+        return "Eclipse Workbench";
+    }
+
+    public void start() {
+        context.addBundleListener(eclipseBundleListener);
+        context.addServiceListener(eclipseAllServiceListener);
+
+        final Job initializeJob = new Job("Populating OSGi Runtime view data for: Eclipse Workbench") {
+            @Override
+            public IStatus run(IProgressMonitor monitor) {
+                if (monitor == null) {
+                    monitor = new NullProgressMonitor();
+                }
+
+                final Bundle[] bundles;
+                final ServiceReference[] services;
+
+                try {
+                    bundles = context.getBundles();
+                    services = context.getAllServiceReferences(null, null);
+                } catch (InvalidSyntaxException e) {
+                    // TODO: Log something?
+                    return new Status(IStatus.ERROR, KarafWorkbenchActivator.PLUGIN_ID,
+                            "Unable to  get service references for running Eclipse Workbench", e);
+                }
+
+                int servicesLength = 0;
+                if (services != null) {
+                    servicesLength = services.length;
+                }
+
+                monitor.worked(10);
+
+                monitor.beginTask("Populating view data set", bundles.length + servicesLength);
+
+                monitor.subTask("OSGi Bundles");
+
+                for (Bundle b : bundles) {
+                    /*
+                     * This bundle can't be added because it does not have a
+                     * context
+                     */
+                    if (b == null || b.getBundleContext() == null) {
+                        continue;
+                    }
+
+                    synchronized (bundleSet) {
+                        bundleSet.add(new BundleItem(b, startLevel, packageAdmin));
+                    }
+
+                    monitor.worked(1);
+                }
+
+                // If there are no services then this is null
+                if (services != null) {
+                    monitor.subTask("OSGi Services");
+
+                    for (ServiceReference r : services) {
+                        synchronized (serviceSet) {
+                            serviceSet.add(new ServiceItem(r));
+                        }
+
+                        monitor.worked(1);
+                    }
+                }
+
+                monitor.done();
+
+                return Status.OK_STATUS;
+            }
+        };
+
+        initializeJob.setPriority(Job.LONG);
+        initializeJob.schedule();
+
+        fireStartEvent();
+    }
+
+    public void stop() {
+        context.removeBundleListener(eclipseBundleListener);
+        context.removeServiceListener(eclipseAllServiceListener);
+
+        context.ungetService(startLevelReference);
+        startLevel = null;
+        startLevelReference = null;
+
+        context.ungetService(packageAdminReference);
+        packageAdmin = null;
+        packageAdminReference = null;
+
+        synchronized (bundleSet) {
+            bundleSet.clear();
+            serviceSet.clear();
+        }
+
+        fireStopEvent();
+    }
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/IJMXTransportListener.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/IJMXTransportListener.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/IJMXTransportListener.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/IJMXTransportListener.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2009 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.jmx;
+
+import info.evanchik.eclipse.karaf.workbench.WorkbenchServiceListener;
+
+import javax.management.remote.JMXConnectorProvider;
+
+/**
+ * A {@code IJMXTransportListener} is notified when a
+ * {@link JMXConnectorProvider} is added or removed from a
+ * {@link IJMXTransportRegistry}.
+ *
+ * @see IJMXTransportRegistry
+ *
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public interface IJMXTransportListener extends WorkbenchServiceListener<JMXConnectorProvider> {
+
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/IJMXTransportRegistry.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/IJMXTransportRegistry.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/IJMXTransportRegistry.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/IJMXTransportRegistry.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2009 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.jmx;
+
+import java.util.Set;
+
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorProvider;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public interface IJMXTransportRegistry {
+
+	/**
+	 * Adds a {@link IJMXTransportListener} to the list of listeners for this
+	 * registry. The listener will be notified whenever a
+	 * {@link JMXConnectorProvider} is added or removed from the registry.<br>
+	 * <br>
+	 * Adding the same listener multiple times has no effect.
+	 *
+	 * @param listener the {@code IJMXTransportListener} to add
+	 */
+	public void addJMXTransportListener(IJMXTransportListener listener);
+
+	/**
+	 * Returns a {@link Set} of names representing
+	 * {@link JMXConnectorProvider}s
+	 *
+	 * @return
+	 * 		a {@code Set} of names representing {@link JMXConnectorProvider}s
+	 */
+	public Set<String> getConnectorNames();
+
+	/**
+	 * Getter for a {@link JMXConnectorProvider} using its name as a retrieval
+	 * key
+	 *
+	 * @param name the name of the {@code JMXConnectorProvider}
+	 *
+	 * @return
+	 * 		the {@code JMXConnectorProvider} for the given name, or null if it
+	 * 		does not exist
+	 */
+	public JMXConnectorProvider getConnectorProvider(String name);
+
+	/**
+	 * Gets a {@link JMXConnector} for a {@link JMXServiceDescriptor} making use
+	 * of the {@code JMXConnectorProvider} registered with the transport
+	 * registry
+	 *
+	 * @param serviceDescriptor the {@code JMXServiceDescriptor} for which the
+	 * {@code JMXConnector} is requested
+	 *
+	 * @return
+	 * 		the {@code JMXConnector} used to connect to the service
+	 *		represented by the {@code JMXServiceDescriptor}
+	 */
+	public JMXConnector getJMXConnector(JMXServiceDescriptor serviceDescriptor);
+
+	/**
+	 * Removes the given {@link IJMXTransportListener} from the registry.<br>
+	 * <br>
+	 * If the {@code JMXConnectorProvider} is not registered with the registry,
+	 * this method has no effect.
+	 *
+	 * @param listener the {@code IJMXTransportListener} to remove
+	 */
+	public void removeJMXTransportListner(IJMXTransportListener listener);
+
+	// TODO: This should not be here
+	public void loadTransportExtensions();
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/JMXServiceDescriptor.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/JMXServiceDescriptor.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/JMXServiceDescriptor.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/JMXServiceDescriptor.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,206 @@
+/**
+ * Copyright (c) 2009 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.jmx;
+
+import java.io.Serializable;
+import java.net.MalformedURLException;
+
+import javax.management.remote.JMXServiceURL;
+
+import org.eclipse.core.runtime.PlatformObject;
+
+/**
+ * A {@code JMXServiceDescriptor} contains all of the elements necessary to
+ * describe a connection to a JMX endpoint:<br>
+ * <br>
+ * <ol>
+ * <li>A human readable name - Suitable for displaying via the UI</li>
+ * <li>A {@link JMXServiceURL} - Used to connect to the MBeanServer</li>
+ * <li>Credentials - A username and password credential pair</li>
+ * </ol>
+ * <br>
+ * These elements form the necessary descriptive information to use in the JMX
+ * Client UI.
+ *
+ * @see JMXServiceURL
+ *
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class JMXServiceDescriptor extends PlatformObject implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private final String name;
+
+    private final String username;
+
+    private final String password;
+
+    private final String domain;
+
+    /**
+     * The {@link JMXServiceURL} of the JMX server
+     */
+    private final JMXServiceURL jmxServiceUrl;
+
+    /**
+     * Constructor that creates a {@link JMXServiceURL} connection description
+     * using a preexisting {@code JMXServiceURL} instance.
+     *
+     * @param name
+     *            the name for this connection descriptor
+     * @param url
+     *            the {@code JMXServiceURL} to use
+     * @param username
+     *            the username or null if authentication is not necessary
+     * @param password
+     *            the password or null if authentication is not necessary
+     * @param domain
+     *            the JMX domain used in {@code url}
+     */
+    public JMXServiceDescriptor(
+    		final String name,
+    		final JMXServiceURL url,
+    		final String username,
+    		final String password,
+    		final String domain)
+	{
+        this.name = name;
+        this.username = username;
+        this.password = password;
+        this.domain = domain;
+
+        this.jmxServiceUrl = url;
+    }
+
+	/**
+	 * Constructor that creates a {@link JMXServiceURL} connection description
+	 * using a String URL as the primary means of connecting.
+	 *
+	 * @param name
+	 *            the name for this connection descriptor
+	 * @param url
+	 *            a URL to the MBeanServer, similar to {@code
+	 *            service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi}
+	 * @param username
+	 *            the username or null if authentication is not necessary
+	 * @param password
+	 *            the password or null if authentication is not necessary
+     * @param domain
+     *            the JMX domain to use
+	 * @throws MalformedURLException if the given string URL is not well formed
+	 */
+    public JMXServiceDescriptor(
+    		final String name,
+    		final String url,
+    		final String username,
+    		final String password,
+    		final String domain) throws MalformedURLException
+	{
+    	this(name, new JMXServiceURL(url), username, password, domain);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public JMXServiceURL getUrl() {
+        return jmxServiceUrl;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (domain == null ? 0 : domain.hashCode());
+        result = prime * result + (jmxServiceUrl == null ? 0 : jmxServiceUrl.hashCode());
+        result = prime * result + (name == null ? 0 : name.hashCode());
+        result = prime * result + (password == null ? 0 : password.hashCode());
+        result = prime * result + (username == null ? 0 : username.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        final JMXServiceDescriptor other = (JMXServiceDescriptor) obj;
+        if (domain == null) {
+            if (other.domain != null) {
+                return false;
+            }
+        } else if (!domain.equals(other.domain)) {
+            return false;
+        }
+
+        if (jmxServiceUrl == null) {
+            if (other.jmxServiceUrl != null) {
+                return false;
+            }
+        } else if (!jmxServiceUrl.equals(other.jmxServiceUrl)) {
+            return false;
+        }
+
+        if (name == null) {
+            if (other.name != null) {
+                return false;
+            }
+        } else if (!name.equals(other.name)) {
+            return false;
+        }
+
+        if (password == null) {
+            if (other.password != null) {
+                return false;
+            }
+        } else if (!password.equals(other.password)) {
+            return false;
+        }
+
+        if (username == null) {
+            if (other.username != null) {
+                return false;
+            }
+        } else if (!username.equals(other.username)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return name + "[" + username + "@" + jmxServiceUrl.toString() + "]";
+    }
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/LocalJMXServiceDescriptor.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/LocalJMXServiceDescriptor.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/LocalJMXServiceDescriptor.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/LocalJMXServiceDescriptor.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2011 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.jmx;
+
+import info.evanchik.eclipse.karaf.core.KarafPlatformModel;
+
+import java.net.MalformedURLException;
+
+import javax.management.remote.JMXServiceURL;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class LocalJMXServiceDescriptor extends JMXServiceDescriptor {
+
+    private static final long serialVersionUID = 1L;
+
+    private final KarafPlatformModel karafPlatformModel;
+
+    /**
+     * @param name
+     * @param karafPlatformModel
+     * @param url
+     * @param username
+     * @param password
+     * @param domain
+     */
+    public LocalJMXServiceDescriptor(
+            final String name,
+            final KarafPlatformModel karafPlatformModel,
+            final JMXServiceURL url,
+            final String username,
+            final String password,
+            final String domain)
+    {
+        super(name, url, username, password, domain);
+
+        this.karafPlatformModel = karafPlatformModel;
+    }
+
+    /**
+     * @param name
+     * @param karafPlatformModel
+     * @param url
+     * @param username
+     * @param password
+     * @param domain
+     * @throws MalformedURLException
+     */
+    public LocalJMXServiceDescriptor(
+            final String name,
+            final KarafPlatformModel karafPlatformModel,
+            final String url,
+            final String username,
+            final String password,
+            final String domain)
+        throws MalformedURLException
+    {
+        super(name, url, username, password, domain);
+
+        this.karafPlatformModel = karafPlatformModel;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!super.equals(obj)) {
+            return false;
+        }
+
+        if (!(obj instanceof LocalJMXServiceDescriptor)) {
+            return false;
+        }
+
+        final LocalJMXServiceDescriptor other = (LocalJMXServiceDescriptor) obj;
+        if (karafPlatformModel == null) {
+            if (other.karafPlatformModel != null) {
+                return false;
+            }
+        } else if (!karafPlatformModel.equals(other.karafPlatformModel)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public Object getAdapter(@SuppressWarnings("rawtypes") final Class adapter) {
+        if (KarafPlatformModel.class.equals(adapter)) {
+            return karafPlatformModel;
+        }
+
+        return super.getAdapter(adapter);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + (karafPlatformModel == null ? 0 : karafPlatformModel.hashCode());
+        return result;
+    }
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/JMXServiceManager.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/JMXServiceManager.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/JMXServiceManager.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/JMXServiceManager.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2009 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.jmx.internal;
+
+import info.evanchik.eclipse.karaf.workbench.internal.AbstractWorkbenchServiceManager;
+import info.evanchik.eclipse.karaf.workbench.jmx.JMXServiceDescriptor;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class JMXServiceManager extends AbstractWorkbenchServiceManager<JMXServiceDescriptor>{
+
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/JMXTransportRegistry.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/JMXTransportRegistry.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/JMXTransportRegistry.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/JMXTransportRegistry.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,228 @@
+/**
+ * Copyright (c) 2009 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.jmx.internal;
+
+import info.evanchik.eclipse.karaf.workbench.KarafWorkbenchActivator;
+import info.evanchik.eclipse.karaf.workbench.jmx.IJMXTransportListener;
+import info.evanchik.eclipse.karaf.workbench.jmx.IJMXTransportRegistry;
+import info.evanchik.eclipse.karaf.workbench.jmx.JMXServiceDescriptor;
+
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorProvider;
+import javax.management.remote.JMXServiceURL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.RegistryFactory;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class JMXTransportRegistry implements IJMXTransportRegistry {
+
+	private final Map<String, JMXConnectorProvider> transports;
+
+	protected final ListenerList jmxTransportListeners;
+
+	private static enum EventType {
+		ADDED,
+		REMOVED;
+	}
+
+	private class JMXTransportNotifier implements ISafeRunnable {
+
+		private EventType event;
+
+		private IJMXTransportListener listener;
+
+		private JMXConnectorProvider jmxConnectorProvider;
+
+		public JMXTransportNotifier() {
+			// Intentionally left blank
+		}
+
+		@Override
+        public void handleException(Throwable exception) {
+			final IStatus status =
+				new Status(
+						IStatus.ERROR,
+						KarafWorkbenchActivator.PLUGIN_ID,
+						120,
+						"An exception occurred during breakpoint change notification.", exception);  //$NON-NLS-1$
+			KarafWorkbenchActivator.getDefault().getLog().log(status);
+		}
+
+		@Override
+        public void run() throws Exception {
+			switch (event) {
+				case ADDED:
+					listener.serviceAdded(jmxConnectorProvider);
+					break;
+				case REMOVED:
+					listener.serviceRemoved(jmxConnectorProvider);
+					break;
+			}
+		}
+
+		/**
+		 * Notifies the listeners of the add/remove
+		 *
+		 * @param jmxConnectorProviders
+		 * 		the {@link JMXConnectorProvider}s that changed
+		 * @param event
+		 * 			the type of change
+		 */
+		public void notify(List<JMXConnectorProvider> jmxConnectorProviders, EventType e) {
+			this.event = e;
+
+			Object[] copiedListeners = jmxTransportListeners.getListeners();
+			for (int i= 0; i < copiedListeners.length; i++) {
+				listener = (IJMXTransportListener)copiedListeners[i];
+				for(JMXConnectorProvider connector : jmxConnectorProviders) {
+					jmxConnectorProvider = connector;
+                    SafeRunner.run(this);
+				}
+			}
+
+			listener = null;
+			jmxConnectorProvider = null;
+		}
+	}
+
+	public JMXTransportRegistry() {
+		transports = Collections.synchronizedMap(new HashMap<String, JMXConnectorProvider>());
+		jmxTransportListeners = new ListenerList();
+	}
+
+	@Override
+    public void addJMXTransportListener(IJMXTransportListener listener) {
+		jmxTransportListeners.add(listener);
+	}
+
+	@Override
+    public Set<String> getConnectorNames() {
+		return Collections.unmodifiableSet(transports.keySet());
+	}
+
+	@Override
+    public JMXConnectorProvider getConnectorProvider(String key) {
+		final JMXConnectorProvider connector = transports.get(key);
+
+		// TODO: Add logging
+
+		return connector;
+	}
+
+	@Override
+    public JMXConnector getJMXConnector(JMXServiceDescriptor serviceDescriptor) {
+		try {
+			final String transport = serviceDescriptor.getUrl().getProtocol();
+
+			final JMXConnectorProvider connectorProvider = getConnectorProvider(transport);
+
+			final JMXServiceURL url = getJMXServiceURL(
+									serviceDescriptor.getUrl().getHost(),
+									serviceDescriptor.getUrl().getPort(),
+									serviceDescriptor.getUrl().getProtocol(),
+									serviceDescriptor.getDomain());
+
+			Map<String, Object> environment = null;
+			if (serviceDescriptor.getUsername() != null) {
+				environment = new HashMap<String, Object>();
+				String[] credentials = new String[] {
+							serviceDescriptor.getUsername(),
+							serviceDescriptor.getPassword()
+				};
+				environment.put(JMXConnector.CREDENTIALS, credentials);
+			}
+
+			return connectorProvider.newJMXConnector(url, environment);
+		} catch (Exception e) {
+			KarafWorkbenchActivator.getLogger().error(e.getMessage(), e);
+			return null;
+		}
+	}
+
+	@Override
+    public void removeJMXTransportListner(IJMXTransportListener listener) {
+		jmxTransportListeners.remove(listener);
+	}
+
+	private JMXTransportNotifier getJMXTransportrNotifier() {
+		return new JMXTransportNotifier();
+	}
+
+	@Override
+    public void loadTransportExtensions() {
+		final IExtensionPoint point =
+			RegistryFactory.getRegistry().getExtensionPoint(
+					KarafWorkbenchActivator.PLUGIN_ID,
+					KarafWorkbenchActivator.JMX_CONNECTOR_PROVIDER_EXTENSION_ID);
+
+		final IExtension[] types = point.getExtensions();
+
+		for (int i = 0; i < types.length; i++) {
+			loadTransportConfigurationElements(types[i].getConfigurationElements());
+		}
+	}
+
+	private void loadTransportConfigurationElements(IConfigurationElement[] configElems) {
+		for (int j = 0; j < configElems.length; j++) {
+			final IConfigurationElement element = configElems[j];
+			final String elementName = element.getName();
+			String transport;
+			if (elementName.equals("transport") //$NON-NLS-1$
+					&& null != element.getAttribute("class") //$NON-NLS-1$
+					&& null != (transport = element.getAttribute("protocol"))) //$NON-NLS-1$
+			{
+				try {
+					Object obj = element.createExecutableExtension("class"); //$NON-NLS-1$
+					if (obj instanceof JMXConnectorProvider) {
+						transports.put(transport, (JMXConnectorProvider)obj);
+					}
+				} catch (CoreException e) {
+					KarafWorkbenchActivator.getLogger().error(e.getMessage(), e);
+				}
+			}
+		}
+
+		final List<JMXConnectorProvider> transportsAdded = new ArrayList<JMXConnectorProvider>();
+		transportsAdded.addAll(transports.values());
+
+		getJMXTransportrNotifier().notify(transportsAdded, EventType.ADDED);
+	}
+
+    private static JMXServiceURL getJMXServiceURL(
+            String host,
+            int port,
+            String protocol,
+            String domain)
+        throws MalformedURLException
+    {
+        return new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/" + domain);
+    }
+}

Added: karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/RMIConnectionProvider.java
URL: http://svn.apache.org/viewvc/karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/RMIConnectionProvider.java?rev=1227144&view=auto
==============================================================================
--- karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/RMIConnectionProvider.java (added)
+++ karaf/eik/trunk/plugins/info.evanchik.eclipse.karaf.workbench/src/main/java/info/evanchik/eclipse/karaf/workbench/jmx/internal/RMIConnectionProvider.java Wed Jan  4 13:22:10 2012
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2010 Stephen Evanchik
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *  Stephen Evanchik - initial implementation
+ */
+package info.evanchik.eclipse.karaf.workbench.jmx.internal;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorProvider;
+import javax.management.remote.JMXServiceURL;
+
+/**
+ * @author Stephen Evanchik (evanchsa@gmail.com)
+ *
+ */
+public class RMIConnectionProvider implements JMXConnectorProvider {
+
+    @Override
+    public JMXConnector newJMXConnector(JMXServiceURL serviceURL, Map<String, ?> environment)
+            throws IOException
+    {
+        return JMXConnectorFactory.newJMXConnector(serviceURL, environment);
+    }
+}