changeset 301:3f0129a44803

Merge
author Roman Kennke <rkennke@redhat.com>
date Mon, 14 May 2012 16:34:08 +0200
parents ac7d017c9fa7 (current diff) 357cba70fdc4 (diff)
children b365e9b369c1
files client/core/src/main/java/com/redhat/thermostat/client/MainWindowControllerImpl.java client/core/src/main/java/com/redhat/thermostat/client/SwingViewFactory.java client/core/src/main/java/com/redhat/thermostat/client/UiFacadeFactory.java client/core/src/main/java/com/redhat/thermostat/client/UiFacadeFactoryImpl.java client/core/src/main/java/com/redhat/thermostat/client/osgi/ThermostatActivator.java client/core/src/main/java/com/redhat/thermostat/client/osgi/VmInformationServiceTracker.java client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationPanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationView.java client/core/src/test/java/com/redhat/thermostat/client/ui/HostInformationPanelTest.java client/launcher/src/main/java/com/redhat/thermostat/client/osgi/Thermostat.java client/launcher/src/test/java/com/redhat/thermostat/client/osgi/ThermostatTest.java client/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java client/src/main/java/com/redhat/thermostat/client/ui/HostInformationPanel.java client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/Activator.java common/src/main/java/com/redhat/thermostat/osgi/OSGiRegistry.java distribution/pom.xml
diffstat 24 files changed, 919 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/main/java/com/redhat/thermostat/backend/system/EtcOsRelease.java	Mon May 14 15:03:00 2012 +0200
+++ b/agent/src/main/java/com/redhat/thermostat/backend/system/EtcOsRelease.java	Mon May 14 16:34:08 2012 +0200
@@ -80,11 +80,11 @@
         String version = DistributionInformation.UNKNOWN_VERSION;
         String line = null;
         while ((line = reader.readLine()) != null) {
-            if (line.startsWith("NAME=")) {
-                name = readShellVariable("NAME", line);
+            if (line.matches("^NAME *=.*")) {
+                name = readShellVariable(line);
             }
-            if (line.startsWith("VERSION=")) {
-                version = readShellVariable("VERSION", line);
+            if (line.matches("^VERSION *=.*")) {
+                version = readShellVariable(line);
             }
         }
         return new DistributionInformation(name, version);
@@ -94,11 +94,13 @@
      *
      * @return the value of the shell variable
      */
-    private String readShellVariable(String variableName, String line) {
+    private String readShellVariable(String line) {
         // TODO we should try to handle shell quotes better
-        String result = line.substring((variableName + "=").length());
+        String result = line.substring(line.indexOf("=")+1);
+        result = result.trim();
         if (result.startsWith("\"") && result.endsWith("\"")) {
             result = result.substring(1, result.length()-1);
+            result = result.trim();
         }
         return result;
     }
--- a/agent/src/test/java/com/redhat/thermostat/backend/system/EtcOsReleaseTest.java	Mon May 14 15:03:00 2012 +0200
+++ b/agent/src/test/java/com/redhat/thermostat/backend/system/EtcOsReleaseTest.java	Mon May 14 16:34:08 2012 +0200
@@ -44,6 +44,8 @@
 
 import org.junit.Test;
 
+import com.redhat.thermostat.test.Bug;
+
 public class EtcOsReleaseTest {
 
     @Test
@@ -61,4 +63,22 @@
         assertEquals("Version", info.getVersion());
     }
 
+    @Bug(id="981",
+        summary="DistributionInformationTest fails on OpenSUSE Linux 12.1",
+        url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=981")
+    @Test
+    public void testFormattedOutput() throws IOException {
+        String output =
+            "NAME=openSUSE\n" +
+            "VERSION = 12.1 (Asparagus)\n" +
+            "VERSION_ID=\"12.1\"\n" +
+            "PRETTY_NAME=\"openSUSE 12.1 (Asparagus) (x86_64)\"\n" +
+            "ID=opensuse";
+        BufferedReader reader = new BufferedReader(new StringReader(output));
+        DistributionInformation info = new EtcOsRelease().getFromOsRelease(reader);
+
+        assertEquals("openSUSE", info.getName());
+        assertEquals("12.1 (Asparagus)", info.getVersion());
+    }
+
 }
--- a/client/core/src/main/java/com/redhat/thermostat/client/MainWindowControllerImpl.java	Mon May 14 15:03:00 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/MainWindowControllerImpl.java	Mon May 14 16:34:08 2012 +0200
@@ -45,7 +45,7 @@
 import com.redhat.thermostat.client.ui.AgentConfigurationView;
 import com.redhat.thermostat.client.ui.ClientConfigurationController;
 import com.redhat.thermostat.client.ui.ClientConfigurationView;
-import com.redhat.thermostat.client.ui.HostPanel;
+import com.redhat.thermostat.client.ui.HostInformationController;
 import com.redhat.thermostat.client.ui.SummaryController;
 import com.redhat.thermostat.client.ui.VmInformationController;
 import com.redhat.thermostat.common.ActionEvent;
@@ -236,7 +236,8 @@
             view.setSubView(controller.getComponent());
         } else if (ref instanceof HostRef) {
             HostRef hostRef = (HostRef) ref;
-            view.setSubView(new HostPanel(facadeFactory.getHostPanel(hostRef)));
+            HostInformationController hostController = facadeFactory.getHostController(hostRef);
+            view.setSubView(hostController.getComponent());
         } else if (ref instanceof VmRef) {
             VmRef vmRef = (VmRef) ref;
             VmInformationController vmInformation =
--- a/client/core/src/main/java/com/redhat/thermostat/client/SwingViewFactory.java	Mon May 14 15:03:00 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/SwingViewFactory.java	Mon May 14 16:34:08 2012 +0200
@@ -48,6 +48,8 @@
 import com.redhat.thermostat.client.ui.EdtHelper;
 import com.redhat.thermostat.client.ui.HostCpuPanel;
 import com.redhat.thermostat.client.ui.HostCpuView;
+import com.redhat.thermostat.client.ui.HostInformationPanel;
+import com.redhat.thermostat.client.ui.HostInformationView;
 import com.redhat.thermostat.client.ui.HostMemoryPanel;
 import com.redhat.thermostat.client.ui.HostMemoryView;
 import com.redhat.thermostat.client.ui.HostOverviewPanel;
@@ -78,6 +80,7 @@
 
         setViewClass(SummaryView.class, SummaryPanel.class);
 
+        setViewClass(HostInformationView.class, HostInformationPanel.class);
         setViewClass(VmInformationView.class, VmInformationPanel.class);
 
         setViewClass(HostCpuView.class, HostCpuPanel.class);
--- a/client/core/src/main/java/com/redhat/thermostat/client/UiFacadeFactory.java	Mon May 14 15:03:00 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/UiFacadeFactory.java	Mon May 14 16:34:08 2012 +0200
@@ -39,6 +39,7 @@
 import java.util.Collection;
 
 import com.redhat.thermostat.client.osgi.service.VmInformationService;
+import com.redhat.thermostat.client.ui.HostInformationController;
 import com.redhat.thermostat.client.ui.SummaryController;
 import com.redhat.thermostat.client.ui.VmInformationController;
 import com.redhat.thermostat.common.dao.HostRef;
@@ -50,7 +51,7 @@
 
     public SummaryController getSummary();
 
-    public HostPanelFacade getHostPanel(HostRef ref);
+    public HostInformationController getHostController(HostRef ref);
 
     public VmInformationController getVmController(VmRef ref);
 
--- a/client/core/src/main/java/com/redhat/thermostat/client/UiFacadeFactoryImpl.java	Mon May 14 15:03:00 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/UiFacadeFactoryImpl.java	Mon May 14 16:34:08 2012 +0200
@@ -40,6 +40,7 @@
 import java.util.Collection;
 
 import com.redhat.thermostat.client.osgi.service.VmInformationService;
+import com.redhat.thermostat.client.ui.HostInformationController;
 import com.redhat.thermostat.client.ui.MainWindow;
 import com.redhat.thermostat.client.ui.SummaryController;
 import com.redhat.thermostat.client.ui.VmInformationController;
@@ -63,8 +64,8 @@
     }
 
     @Override
-    public HostPanelFacade getHostPanel(HostRef ref) {
-        return new HostPanelFacadeImpl(ref);
+    public HostInformationController getHostController(HostRef ref) {
+        return new HostInformationController(ref);
 
     }
 
--- a/client/core/src/main/java/com/redhat/thermostat/client/osgi/ThermostatActivator.java	Mon May 14 15:03:00 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/osgi/ThermostatActivator.java	Mon May 14 16:34:08 2012 +0200
@@ -43,6 +43,7 @@
 import com.redhat.thermostat.client.UiFacadeFactory;
 import com.redhat.thermostat.client.UiFacadeFactoryImpl;
 import com.redhat.thermostat.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.client.osgi.service.VmInformationService;
 
 public class ThermostatActivator implements BundleActivator {
 
@@ -50,16 +51,16 @@
 
     @Override
     public void start(final BundleContext context) throws Exception {
-        context.registerService(ApplicationService.class.getName(), new ApplicationServiceProvider(), null);
         UiFacadeFactory uiFacadeFactory = new UiFacadeFactoryImpl();
         vmInfoServiceTracker = new VmInformationServiceTracker(context, uiFacadeFactory);
-        context.addServiceListener(vmInfoServiceTracker);
+        vmInfoServiceTracker.open();
         
         Main.main(uiFacadeFactory, new String[0]);
+        context.registerService(ApplicationService.class.getName(), new ApplicationServiceProvider(), null);
     }
 
     @Override
     public void stop(BundleContext context) throws Exception {
-        context.removeServiceListener(vmInfoServiceTracker);
+        vmInfoServiceTracker.close(); //context.removeServiceListener(vmInfoServiceTracker);
     }
 }
--- a/client/core/src/main/java/com/redhat/thermostat/client/osgi/VmInformationServiceTracker.java	Mon May 14 15:03:00 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/osgi/VmInformationServiceTracker.java	Mon May 14 16:34:08 2012 +0200
@@ -38,27 +38,28 @@
 
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
 
 import com.redhat.thermostat.client.UiFacadeFactory;
 import com.redhat.thermostat.client.osgi.service.VmInformationService;
 
-class VmInformationServiceTracker implements ServiceListener {
+class VmInformationServiceTracker extends ServiceTracker {
 
     private UiFacadeFactory uiFacadeFactory;
 
     private BundleContext context;
 
     VmInformationServiceTracker(BundleContext context, UiFacadeFactory uiFacadeFactory) {
+        super(context, VmInformationService.class, null);
         this.context = context;
         this.uiFacadeFactory = uiFacadeFactory;
     }
 
     @Override
-    public void serviceChanged(ServiceEvent event) {
-        ServiceReference reference = event.getServiceReference();
+    public Object addingService(ServiceReference reference) {
         VmInformationService service = (VmInformationService) context.getService(reference);
         uiFacadeFactory.addVmInformationService(service);
+        return service;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java	Mon May 14 16:34:08 2012 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import static com.redhat.thermostat.client.locale.Translate.localize;
+
+import java.awt.Component;
+
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.dao.HostRef;
+
+public class HostInformationController {
+
+    private final HostOverviewController overviewController;
+    private final HostCpuController cpuController;
+    private final HostMemoryController memoryController;
+
+    private final HostInformationView view;
+
+    public HostInformationController(HostRef ref) {
+        overviewController = new HostOverviewController(ref);
+        cpuController = new HostCpuController(ref);
+        memoryController = new HostMemoryController(ref);
+
+        view = ApplicationContext.getInstance().getViewFactory().getView(HostInformationView.class);
+
+        view.addChildView(localize(LocaleResources.HOST_INFO_TAB_OVERVIEW), getOverviewController().getComponent());
+        view.addChildView(localize(LocaleResources.HOST_INFO_TAB_CPU), getCpuController().getComponent());
+        view.addChildView(localize(LocaleResources.HOST_INFO_TAB_MEMORY), getMemoryController().getComponent());
+
+    }
+
+    public HostOverviewController getOverviewController() {
+        return overviewController;
+    }
+
+    public HostCpuController getCpuController() {
+        return cpuController;
+    }
+
+    public HostMemoryController getMemoryController() {
+        return memoryController;
+    }
+
+    public Component getComponent() {
+        return view.getUiComponent();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationPanel.java	Mon May 14 16:34:08 2012 +0200
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.SwingUtilities;
+
+public class HostInformationPanel extends JPanel implements HostInformationView {
+
+    private static final long serialVersionUID = 4835316442841009133L;
+
+    private final JTabbedPane tabPane;
+
+    private int viewCount = 0;
+
+    public HostInformationPanel() {
+        setLayout(new BorderLayout());
+        tabPane = new JTabbedPane();
+        this.add(tabPane);
+    }
+
+    @Override
+    public void addChildView(final String title, final Component view) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                tabPane.insertTab(title, null, view, null, viewCount);
+                viewCount++;
+            }
+
+        });
+    }
+
+    @Override
+    public void removeChildView(final String title) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < viewCount; i++) {
+                    if (tabPane.getTitleAt(i).equals(title)) {
+                        tabPane.remove(i);
+                        return;
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return this;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationView.java	Mon May 14 16:34:08 2012 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import java.awt.Component;
+
+import com.redhat.thermostat.common.View;
+
+public interface HostInformationView extends View {
+
+    void addChildView(String title, Component view);
+
+    void removeChildView(String title);
+
+    Component getUiComponent();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/HostInformationPanelTest.java	Mon May 14 16:34:08 2012 +0200
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiQuery;
+import org.fest.swing.edt.GuiTask;
+import org.fest.swing.fixture.FrameFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class HostInformationPanelTest {
+
+    private HostInformationPanel panel;
+    private JFrame frame;
+    private FrameFixture window;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @Before
+    public void setUp() {
+        panel = GuiActionRunner.execute(new GuiQuery<HostInformationPanel>() {
+            @Override
+            protected HostInformationPanel executeInEDT() throws Throwable {
+                return new HostInformationPanel();
+            }
+        });
+
+        frame = GuiActionRunner.execute(new GuiQuery<JFrame>() {
+            @Override
+            protected JFrame executeInEDT() throws Throwable {
+                JFrame jFrame = new JFrame();
+                panel.setName("panel");
+                jFrame.add(panel);
+                return jFrame;
+            }
+        });
+
+        window = new FrameFixture(frame);
+        window.show();
+    }
+
+    @After
+    public void tearDown() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                frame.dispose();
+            }
+        });
+        window.cleanUp();
+    }
+
+    private JPanel createJPanel() {
+        return GuiActionRunner.execute(new GuiQuery<JPanel>() {
+            @Override
+            protected JPanel executeInEDT() throws Throwable {
+                return new JPanel();
+            }
+        });
+    }
+
+    @Test
+    public void testAddTwice() throws InvocationTargetException, InterruptedException {
+        JPanel mock1 = createJPanel();
+
+        panel.addChildView("foo1", mock1);
+
+        window.panel("panel").tabbedPane().requireTabTitles("foo1");
+
+        JPanel mock2 = createJPanel();
+        panel.addChildView("foo2", mock2);
+
+        window.panel("panel").tabbedPane().requireTabTitles("foo1", "foo2");
+    }
+
+    @Test
+    public void testAddRemove() throws InvocationTargetException, InterruptedException {
+        JPanel test1 = createJPanel();
+        JPanel test2 = createJPanel();
+
+        panel.addChildView("test1", test1);
+        panel.addChildView("test2", test2);
+
+        window.panel("panel").tabbedPane().requireTabTitles("test1", "test2");
+
+        panel.removeChildView("test1");
+
+        window.panel("panel").tabbedPane().requireTabTitles("test2");
+    }
+}
--- a/client/launcher/src/main/java/com/redhat/thermostat/client/osgi/Thermostat.java	Mon May 14 15:03:00 2012 +0200
+++ b/client/launcher/src/main/java/com/redhat/thermostat/client/osgi/Thermostat.java	Mon May 14 16:34:08 2012 +0200
@@ -37,19 +37,23 @@
 package com.redhat.thermostat.client.osgi;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.ServiceLoader;
 
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
 import org.osgi.framework.launch.Framework;
 import org.osgi.framework.launch.FrameworkFactory;
 
 import com.redhat.thermostat.common.config.ConfigUtils;
 import com.redhat.thermostat.common.config.InvalidConfigurationException;
+import com.redhat.thermostat.osgi.OSGiRegistry;
 
 public class Thermostat {
 
@@ -57,43 +61,41 @@
     private Thermostat() { /* nothing to do */ }
     
     private void setUp() throws InvalidConfigurationException {
-        
         String thermostatHome = ConfigUtils.getThermostatHome();
         thermostatBundleHome = new File(thermostatHome, "osgi");
-        // check if the file exist before creating a new one
-        if (!thermostatBundleHome.exists()) {
-            if (!thermostatBundleHome.mkdirs()) {
-                throw new InternalError("cannot create bundle directory");
-            }
-        }
     }
     
-    private Map<String, String> initPublicAPIforBundles() {
-        
-        // here we should register all the packages that should be exported
-        
-        Map<String, String> bundleConfigurations = new HashMap<String, String>();
-        return bundleConfigurations;
-    }
-    
-    private void installAndStartBundles(Framework framework,
-                                        String ... bundleLocations)
+    private List<Bundle> installBundles(Framework framework,
+                                        List<String>bundleLocations)
         throws Exception
     {
+        List<Bundle> bundles = new ArrayList<>();
         BundleContext bundleContext = framework.getBundleContext();
         for (String location : bundleLocations) {
-            Bundle addition = bundleContext.installBundle(location);
-            addition.start();
+            Bundle bundle = bundleContext.installBundle(location);
+            bundles.add(bundle);
+        }
+        return bundles;
+    }
+
+    private void startBundles(List<Bundle> bundles) throws BundleException {
+        for (Bundle bundle : bundles) {
+            bundle.start();
         }
     }
-    
+
     private void start(String[] args) throws Exception {
         setUp();
         
         ServiceLoader<FrameworkFactory> loader =
                 ServiceLoader.load(FrameworkFactory.class);
         
-        Map<String, String> bundleConfigurations = initPublicAPIforBundles();
+        Map<String, String> bundleConfigurations = new HashMap<String, String>();
+        
+        String publicPackages = OSGiRegistry.getOSGiPublicPackages();
+        publicPackages = publicPackages + ", com.redhat.thermostat.client.osgi.service, com.redhat.thermostat.common.dao";
+        bundleConfigurations.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, publicPackages);
+        
         bundleConfigurations.put(Constants.FRAMEWORK_STORAGE,
                                  thermostatBundleHome.getAbsolutePath());
         bundleConfigurations.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "com.mongodb," +
@@ -120,9 +122,11 @@
             // we just want the first found
             Framework framework = factories.next().newFramework(bundleConfigurations);
             framework.init();
+            
+            List<String> bundles = OSGiRegistry.getSystemBundles();
+            List<Bundle> bundleList = installBundles(framework, bundles);
             framework.start();
-            
-            installAndStartBundles(framework, args);
+            startBundles(bundleList);
             
         } else {
             throw new InternalError("Can't find factories for ServiceLoader!");
--- a/client/launcher/src/test/java/com/redhat/thermostat/client/osgi/ThermostatTest.java	Mon May 14 15:03:00 2012 +0200
+++ b/client/launcher/src/test/java/com/redhat/thermostat/client/osgi/ThermostatTest.java	Mon May 14 16:34:08 2012 +0200
@@ -43,6 +43,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -68,7 +69,19 @@
         tempDir = Files.createTempDirectory("test");
         tempDir.toFile().deleteOnExit();
         System.setProperty("THERMOSTAT_HOME", tempDir.toString());
-
+        
+        File tempEtc = new File(tempDir.toFile(), "etc");
+        tempEtc.mkdirs();
+        tempEtc.deleteOnExit();
+        
+        File tempProps = new File(tempEtc, "osgi-export.properties");
+        tempProps.createNewFile();
+        tempProps.deleteOnExit();
+        
+        File tempLibs = new File(tempDir.toFile(), "libs");
+        tempLibs.mkdirs();
+        tempLibs.deleteOnExit();
+        
 	mockContext = mock(BundleContext.class);
 
         mockFramework = mock(Framework.class);
@@ -78,14 +91,6 @@
     }
 
     @Test
-    public void testCreateOSGIDir() throws Exception {
-        Path osgiDir = tempDir.resolve("osgi");
-        assertFalse(osgiDir.toFile().exists());
-        Thermostat.main(new String[0]);
-        assertTrue(osgiDir.toFile().exists());
-    }
-
-    @Test
     public void testOSGIDirExists() throws Exception {
         Path osgiDir = tempDir.resolve("osgi");
         osgiDir.toFile().mkdirs();
@@ -94,18 +99,6 @@
         assertTrue(osgiDir.toFile().exists());
     }
 
-    @Test(expected=InternalError.class)
-    public void testCreateOSGIDirNotPossible() throws Exception {
-        try {
-            Path osgiDir = tempDir.resolve("osgi");
-            assertFalse(osgiDir.toFile().exists());
-            tempDir.toFile().setWritable(false);
-            Thermostat.main(new String[0]);
-        } finally {
-            tempDir.toFile().setWritable(true);
-        }
-    }
-
     @Test
     public void testFrameworkConfig() throws Exception {
         Thermostat.main(new String[0]);
--- a/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/Activator.java	Mon May 14 15:03:00 2012 +0200
+++ b/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/Activator.java	Mon May 14 16:34:08 2012 +0200
@@ -38,7 +38,10 @@
 
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
 
+import com.redhat.thermostat.client.osgi.service.ApplicationService;
 import com.redhat.thermostat.client.osgi.service.VmInformationService;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
 
@@ -46,8 +49,15 @@
 
     @Override
     public void start(BundleContext context) throws Exception {
-        ApplicationContext.getInstance().getViewFactory().setViewClass(VmClassStatView.class, VmClassStatPanel.class);
-        context.registerService(VmInformationService.class.getName(), new VmClassStatService(), null);
+        ServiceTracker tracker = new ServiceTracker(context, ApplicationService.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                ApplicationContext.getInstance().getViewFactory().setViewClass(VmClassStatView.class, VmClassStatPanel.class);
+                context.registerService(VmInformationService.class.getName(), new VmClassStatService(), null);
+                return super.addingService(reference);
+            }
+        };
+        tracker.open();
     }
 
     @Override
--- a/common/pom.xml	Mon May 14 15:03:00 2012 +0200
+++ b/common/pom.xml	Mon May 14 16:34:08 2012 +0200
@@ -46,7 +46,7 @@
   </parent>
   
   <artifactId>thermostat-common</artifactId>
-  <packaging>jar</packaging>
+  <packaging>bundle</packaging>
 
   <name>Thermostat Common</name>
   <url>${project.parent.url}</url>
@@ -58,6 +58,25 @@
         <filtering>true</filtering>
       </resource>
     </resources>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>1.4.0</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Embed-Dependency>*;scope=compile|runtime;artifactId=!org.apache.felix.framework|osgi_R4_core</Embed-Dependency>
+            <Embed-Transitive>true</Embed-Transitive>
+            <Import-Package>org.osgi.framework,!android.dalvik,!com.apple.*,!dalvik.system,!javax.mail.*,!javax.servlet.*,!junit.*,!org.testng.*,*</Import-Package>
+            <Private-Package>com.redhat.thermostat.*</Private-Package>
+            <Bundle-Activator>com.redhat.thermostat.osgi.OSGiActivator</Bundle-Activator>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Export-Package>com.redhat.thermostat.service.process</Export-Package>
+            </instructions>
+          </configuration>
+       </plugin>
+    </plugins>
   </build>
 
   <dependencies>
@@ -90,8 +109,14 @@
       <groupId>commons-cli</groupId>
       <artifactId>commons-cli</artifactId>
     </dependency>
+    
+    <dependency>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>org.apache.felix.framework</artifactId>
+    </dependency>
+    
   </dependencies>
-
+  
   <properties>
   	<argLine>-XX:-UseSplitVerifier</argLine>
   </properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/osgi/OSGiActivator.java	Mon May 14 16:34:08 2012 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.osgi;
+
+import java.util.Hashtable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.service.process.UNIXProcessHandler;
+import com.redhat.thermostat.tools.unix.UnixProcessUtilities;
+
+public class OSGiActivator implements BundleActivator {
+
+    private static final Logger logger = LoggingUtils.getLogger(OSGiActivator.class);
+    
+    @Override
+    public void start(BundleContext context) throws Exception {        
+        logger.log(Level.INFO, "activating thermostat-common bundles");
+        
+        Hashtable<String, String> props = new Hashtable<String, String>();
+        props.put(UNIXProcessHandler.ID, UNIXProcessHandler.ID);
+        
+        context.registerService(UNIXProcessHandler.class.getName(), UnixProcessUtilities.getInstance(), props);
+    }
+    
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        // TODO Auto-generated method stub
+        
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/osgi/OSGiRegistry.java	Mon May 14 16:34:08 2012 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.osgi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import com.redhat.thermostat.common.config.ConfigUtils;
+import com.redhat.thermostat.common.config.InvalidConfigurationException;
+
+public class OSGiRegistry {
+
+    public static String getOSGiPublicPackages() throws InvalidConfigurationException, FileNotFoundException, IOException {
+        String home = ConfigUtils.getThermostatHome();
+        File thermostatEtc = new File(home, "etc");
+        File osgiBundleDefinitions = new File(thermostatEtc, "osgi-export.properties");
+        
+        Properties bundles = new Properties();
+        bundles.load(new FileInputStream(osgiBundleDefinitions));
+        
+        StringBuilder publicPackages = new StringBuilder();
+        boolean firstPackage = true;
+        for (Object bundle : bundles.keySet()) {
+            if (!firstPackage) {
+                publicPackages.append(",\n");
+            }
+            firstPackage = false;
+            publicPackages.append(bundle).append("; version=").append(bundles.get(bundle));
+        }
+                
+        return publicPackages.toString();
+    }
+
+    public static List<String> getSystemBundles() throws InvalidConfigurationException, IOException {
+        
+        String home = ConfigUtils.getThermostatHome();
+        Path thermostatHome = new File(home, "libs").toPath();
+        OSGiBundlesVisitor visitor = new OSGiBundlesVisitor();
+        Files.walkFileTree(thermostatHome, visitor);
+        System.err.println("loading JARs: " + visitor.jars);
+        return visitor.jars;
+    }
+    
+    private static class OSGiBundlesVisitor extends SimpleFileVisitor<Path> {
+        
+        private List<String> jars = new ArrayList<>(); 
+        private PathMatcher matcher =
+                FileSystems.getDefault().getPathMatcher("glob:{thermostat-osgi,thermostat-common,thermostat-client}*.jar");
+        
+        @Override
+        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+            if (file.getFileName() != null && matcher.matches(file.getFileName())) {
+                jars.add("file:" + file.toAbsolutePath().toString());
+            }
+            return FileVisitResult.CONTINUE;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/service/process/UNIXProcessHandler.java	Mon May 14 16:34:08 2012 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.service.process;
+
+public interface UNIXProcessHandler {
+    
+    public static String ID = "com.redhat.thermostat.service.process.UNIXProcessHandler";
+
+    /**
+     * Sends the given {@link UNIXSignal} to the process indicated by
+     * {@code pid}.
+     */
+    public void sendSignal(String pid, UNIXSignal signal);
+    
+    /**
+     * Gets the process name given its {@code pid}.
+     */
+    public String getProcessName(String pid);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/com/redhat/thermostat/service/process/UNIXSignal.java	Mon May 14 16:34:08 2012 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.service.process;
+
+public enum UNIXSignal {
+
+    KILL;
+    
+    public String signalName() {
+        return name().toLowerCase();
+    }
+}
--- a/common/src/main/java/com/redhat/thermostat/tools/unix/UnixProcessUtilities.java	Mon May 14 15:03:00 2012 +0200
+++ b/common/src/main/java/com/redhat/thermostat/tools/unix/UnixProcessUtilities.java	Mon May 14 16:34:08 2012 +0200
@@ -47,9 +47,11 @@
 
 import com.redhat.thermostat.common.utils.LoggedExternalProcess;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.service.process.UNIXProcessHandler;
+import com.redhat.thermostat.service.process.UNIXSignal;
 import com.redhat.thermostat.tools.ApplicationException;
 
-public class UnixProcessUtilities {
+public class UnixProcessUtilities implements UNIXProcessHandler {
 
     private static final Logger logger = LoggingUtils.getLogger(UnixProcessUtilities.class);
     
@@ -60,10 +62,12 @@
     
     UnixProcessUtilities() {}
     
-    /**
-     * Returns the process name of the process with the given pid, or null
-     * if no process is running with the given pid.
-     */
+    @Override
+    public void sendSignal(String pid, UNIXSignal signal) {
+        System.err.println("yeah!");
+    }
+    
+    @Override
     public String getProcessName(String pid) {
         
         String result = null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/test/java/com/redhat/thermostat/osgi/OSGiRegistryTest.java	Mon May 14 16:34:08 2012 +0200
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.osgi;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Properties;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.config.InvalidConfigurationException;
+
+public class OSGiRegistryTest {
+
+    private Path tempDir;
+    private File someJars1;
+    private File someJars2;
+    
+    @Before
+    public void setUp() throws IOException {
+
+        tempDir = Files.createTempDirectory("test");
+        tempDir.toFile().deleteOnExit();
+        System.setProperty("THERMOSTAT_HOME", tempDir.toString());
+        
+        File tempEtc = new File(tempDir.toFile(), "etc");
+        tempEtc.mkdirs();
+        tempEtc.deleteOnExit();
+        
+        File tempProps = new File(tempEtc, "osgi-export.properties");
+        tempProps.createNewFile();
+        tempProps.deleteOnExit();
+        
+        File tempLibs = new File(tempDir.toFile(), "libs");
+        tempLibs.mkdirs();
+        tempLibs.deleteOnExit();
+        
+        someJars1 = new File(tempLibs, "thermostat-osgi-fluff1.jar");
+        someJars1.createNewFile();
+        someJars1.deleteOnExit();
+        
+        someJars2 = new File(tempLibs, "thermostat-osgi-fluff2.jar");
+        someJars2.createNewFile();
+        someJars2.deleteOnExit();
+        
+        File tmpConfigs = new File(tempEtc, "osgi-export.properties");     
+        tmpConfigs.deleteOnExit();
+        
+        Properties props = new Properties();            
+
+        props.setProperty("this.is.a.fluff.package", "0.0.0");
+        props.setProperty("this.is.even.more.a.fluff.package", "0.0.1");
+
+        props.store(new FileOutputStream(tmpConfigs), "thermostat osgi public api test properties");
+    }
+    
+    @Test
+    public void testBundles() throws InvalidConfigurationException, IOException {
+        
+        List<String> bundles = OSGiRegistry.getSystemBundles();
+        Assert.assertEquals(2, bundles.size());
+        Assert.assertTrue(bundles.contains("file:" + someJars1.getAbsolutePath()));
+        Assert.assertTrue(bundles.contains("file:" + someJars2.getAbsolutePath()));
+        
+        String publicApi = OSGiRegistry.getOSGiPublicPackages();
+        Assert.assertTrue(publicApi.contains("this.is.a.fluff.package; version=0.0.0"));
+        Assert.assertTrue(publicApi.contains("this.is.even.more.a.fluff.package; version=0.0.1"));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distribution/config/osgi-export.properties	Mon May 14 16:34:08 2012 +0200
@@ -0,0 +1,36 @@
+# Copyright 2012 Red Hat, Inc.
+#
+# This file is part of Thermostat.
+#
+# Thermostat is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation; either version 2, or (at your
+# option) any later version.
+#
+# Thermostat is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Thermostat; see the file COPYING.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+# Linking this code with other modules is making a combined work
+# based on this code.  Thus, the terms and conditions of the GNU
+# General Public License cover the whole combination.
+#
+# As a special exception, the copyright holders of this code give
+# you permission to link this code with independent modules to
+# produce an executable, regardless of the license terms of these
+# independent modules, and to copy and distribute the resulting
+# executable under terms of your choice, provided that you also
+# meet, for each linked independent module, the terms and conditions
+# of the license of that module.  An independent module is a module
+# which is not derived from or based on this code.  If you modify
+# this code, you may extend this exception to your version of the
+# library, but you are not obligated to do so.  If you do not wish
+# to do so, delete this exception statement from your version.
+
+# OSGi public API
+com.redhat.thermostat.service.process=1.0.0
\ No newline at end of file
--- a/distribution/pom.xml	Mon May 14 15:03:00 2012 +0200
+++ b/distribution/pom.xml	Mon May 14 16:34:08 2012 +0200
@@ -121,6 +121,7 @@
                   <filtering>true</filtering>
                   <includes>
                     <include>logging.properties</include>
+                    <include>osgi-export.properties</include>
                   </includes>
                 </resource>
               </resources>