changeset 580:c95cd9ae6db4

Remote kill-vm. This patch implements kill-vm via command channel. Similar to the heap dumper bundle there are now killvm agent/client bundles. Tests have been added where appropriate. Previously there were none :( Also added proper localization. PR1144 Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-August/003006.html
author Severin Gehwolf <sgehwolf@redhat.com>
date Thu, 30 Aug 2012 17:37:39 +0200
parents 4082ce718f9f
children b8a464e454a8
files agent/killvm/pom.xml agent/killvm/src/main/java/com/redhat/thermostat/agent/killvm/internal/Activator.java agent/killvm/src/main/java/com/redhat/thermostat/agent/killvm/internal/KillVmReceiver.java agent/killvm/src/test/java/com/redhat/thermostat/agent/killvm/internal/ActivatorTest.java agent/killvm/src/test/java/com/redhat/thermostat/agent/killvm/internal/KillVmReceiverTest.java agent/pom.xml client/killvm/pom.xml client/killvm/src/main/java/com/redhat/thermostat/client/killvm/Activator.java client/killvm/src/main/java/com/redhat/thermostat/client/killvm/KillVMAction.java client/killvm/src/main/java/com/redhat/thermostat/client/killvm/internal/Activator.java client/killvm/src/main/java/com/redhat/thermostat/client/killvm/internal/KillVMAction.java client/killvm/src/main/java/com/redhat/thermostat/client/killvm/internal/VMKilledListener.java client/killvm/src/main/java/com/redhat/thermostat/client/killvm/locale/LocaleResources.java client/killvm/src/main/resources/com/redhat/thermostat/client/killvm/locale/strings.properties client/killvm/src/test/java/com/redhat/thermostat/client/killvm/internal/ActivatorTest.java client/killvm/src/test/java/com/redhat/thermostat/client/killvm/internal/KillVMActionTest.java client/killvm/src/test/java/com/redhat/thermostat/client/killvm/locale/TranslateTest.java distribution/config/bundles.properties distribution/pom.xml
diffstat 19 files changed, 1073 insertions(+), 215 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/killvm/pom.xml	Thu Aug 30 17:37:39 2012 +0200
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.redhat.thermostat</groupId>
+    <artifactId>thermostat-agent</artifactId>
+    <version>0.4.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-agent-killvm</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Thermostat Agent Kill VM</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-agent-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-agent-command</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-launcher</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-Activator>com.redhat.thermostat.agent.killvm.internal.Activator</Bundle-Activator>
+            <Bundle-SymbolicName>com.redhat.thermostat.agent.killvm</Bundle-SymbolicName>
+            <Private-Package>com.redhat.thermostat.agent.killvm.internal</Private-Package>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/killvm/src/main/java/com/redhat/thermostat/agent/killvm/internal/Activator.java	Thu Aug 30 17:37:39 2012 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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.agent.killvm.internal;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.agent.command.ReceiverRegistry;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.service.process.UNIXProcessHandler;
+
+public class Activator implements BundleActivator {
+
+    private ReceiverRegistry registry;
+    private UNIXProcessHandler unixService;
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        unixService = OSGIUtils.getInstance().getService(UNIXProcessHandler.class);
+        registry = new ReceiverRegistry(context);
+        registry.registerReceiver(new KillVmReceiver(unixService));
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        // This only unregisters receivers which we've registered
+        // in start()
+        registry.unregisterReceivers();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/killvm/src/main/java/com/redhat/thermostat/agent/killvm/internal/KillVmReceiver.java	Thu Aug 30 17:37:39 2012 +0200
@@ -0,0 +1,70 @@
+/*
+ * 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.agent.killvm.internal;
+
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.agent.command.RequestReceiver;
+import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.command.Response;
+import com.redhat.thermostat.common.command.Response.ResponseType;
+import com.redhat.thermostat.service.process.UNIXProcessHandler;
+import com.redhat.thermostat.service.process.UNIXSignal;
+
+public class KillVmReceiver implements RequestReceiver {
+
+    private final UNIXProcessHandler unixService;
+    private static final Logger log = Logger.getLogger(KillVmReceiver.class.getName());
+    
+    public KillVmReceiver(UNIXProcessHandler unixService) {
+        this.unixService = unixService;
+    }
+    
+    @Override
+    public Response receive(Request request) {
+        if (unixService == null) {
+            // no dice, should have service by now
+            log.severe("Unix service null!");
+            return new Response(ResponseType.ERROR);
+        }
+        String vmId = request.getParameter("vm-id");
+        unixService.sendSignal(vmId, UNIXSignal.TERM);
+        log.fine("Killed VM with ID " + vmId);
+        return new Response(ResponseType.OK);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/killvm/src/test/java/com/redhat/thermostat/agent/killvm/internal/ActivatorTest.java	Thu Aug 30 17:37:39 2012 +0200
@@ -0,0 +1,87 @@
+/*
+ * 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.agent.killvm.internal;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Dictionary;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.redhat.thermostat.agent.command.RequestReceiver;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.service.process.UNIXProcessHandler;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(OSGIUtils.class)
+public class ActivatorTest {
+
+    /**
+     * Makes sure receiver is registered and unix service gets set.
+     * 
+     * @throws Exception
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void startStopTest() throws Exception {
+        OSGIUtils utils = mock(OSGIUtils.class);
+        PowerMockito.mockStatic(OSGIUtils.class);
+        when(OSGIUtils.getInstance()).thenReturn(utils);
+        BundleContext ctx = mock(BundleContext.class);
+        ServiceRegistration serviceReg = mock(ServiceRegistration.class);
+        when(ctx.registerService(anyString(), any(), any(Dictionary.class))).thenReturn(serviceReg);
+        Activator activator = new Activator();
+        activator.start(ctx);
+        verify(utils).getService(UNIXProcessHandler.class);
+        verify(ctx).registerService(eq(RequestReceiver.class.getName()), isA(KillVmReceiver.class), any(Dictionary.class));
+        activator.stop(ctx);
+        verify(serviceReg).unregister();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/killvm/src/test/java/com/redhat/thermostat/agent/killvm/internal/KillVmReceiverTest.java	Thu Aug 30 17:37:39 2012 +0200
@@ -0,0 +1,102 @@
+/*
+ * 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.agent.killvm.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.command.Response;
+import com.redhat.thermostat.common.command.Response.ResponseType;
+import com.redhat.thermostat.service.process.UNIXProcessHandler;
+
+public class KillVmReceiverTest {
+
+    @Test
+    public void receiverReturnsOk() {
+        UNIXProcessHandler proc = mock(UNIXProcessHandler.class);
+        KillVmReceiver receiver = new KillVmReceiver(proc);
+        Request req = mock(Request.class);
+        Response response = receiver.receive(req);
+        assertEquals(ResponseType.OK, response.getType());
+    }
+
+    @Test
+    public void receiverReturnsError() {
+        KillVmReceiver receiver = new KillVmReceiver(null);
+        Request req = mock(Request.class);
+        Response response = receiver.receive(req);
+        assertEquals(ResponseType.ERROR, response.getType());
+    }
+
+    /**
+     * When a request is issued the fully qualified receiver class name is set
+     * via {@link Request#setReceiver(String)}. This test makes sure that this
+     * class is actually where it's supposed to be.
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void killVmReceiverIsInAppropriatePackage() {
+        Class<?> receiver = null;
+        try {
+            // com.redhat.thermostat.client.killvm.internal.KillVMAction uses
+            // this class name.
+            receiver = Class
+                    .forName("com.redhat.thermostat.agent.killvm.internal.KillVmReceiver");
+        } catch (ClassNotFoundException e) {
+            fail("com.redhat.thermostat.agent.killvm.internal.KillVmReceiver class not found, but used by some request!");
+        }
+        try {
+            Constructor<?> constructor = receiver.getConstructor(UNIXProcessHandler.class);
+            UNIXProcessHandler service = mock(UNIXProcessHandler.class);
+            Object instance = constructor.newInstance(service);
+            Method m = receiver.getMethod("receive", Request.class);
+            Request req = mock(Request.class);
+            m.invoke(instance, req);
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail("cannot invoke receiver's receive method");
+        }
+    }
+}
--- a/agent/pom.xml	Fri Aug 31 17:49:45 2012 +0200
+++ b/agent/pom.xml	Thu Aug 30 17:37:39 2012 +0200
@@ -63,6 +63,7 @@
     <module>core</module>
     <module>command</module>
     <module>heapdumper</module>
+    <module>killvm</module>
   </modules>
 
 </project>
--- a/client/killvm/pom.xml	Fri Aug 31 17:49:45 2012 +0200
+++ b/client/killvm/pom.xml	Thu Aug 30 17:37:39 2012 +0200
@@ -18,9 +18,10 @@
         <configuration>
           <instructions>
             <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <Bundle-Activator>com.redhat.thermostat.client.killvm.Activator</Bundle-Activator>
+            <Bundle-Activator>com.redhat.thermostat.client.killvm.internal.Activator</Bundle-Activator>
             <Bundle-SymbolicName>com.redhat.thermostat.client.killvm</Bundle-SymbolicName>
-            <Private-Package>com.redhat.thermostat.client.killvm</Private-Package>
+            <Export-Package>com.redhat.thermostat.client.killvm.locale</Export-Package>
+            <Private-Package>com.redhat.thermostat.client.killvm.internal</Private-Package>
           </instructions>
           <!-- Do not autogenerate uses clauses in Manifests -->
           <_nouses>true</_nouses>
@@ -40,6 +41,16 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.easytesting</groupId>
       <artifactId>fest-swing</artifactId>
       <scope>test</scope>
@@ -70,6 +81,16 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-command</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-command</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
     	<groupId>com.redhat.thermostat</groupId>
     	<artifactId>thermostat-osgi-process-handler</artifactId>
     	<version>${project.version}</version>
--- a/client/killvm/src/main/java/com/redhat/thermostat/client/killvm/Activator.java	Fri Aug 31 17:49:45 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-/*
- * 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.killvm;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-
-import com.redhat.thermostat.client.osgi.service.ApplicationService;
-import com.redhat.thermostat.client.osgi.service.ContextAction;
-import com.redhat.thermostat.client.osgi.service.VMContextAction;
-import com.redhat.thermostat.service.process.UNIXProcessHandler;
-
-public class Activator implements BundleActivator {
-
-    private static final Logger logger = Logger.getLogger(Activator.class.getSimpleName());
-    
-    @Override
-    public void start(final BundleContext context) throws Exception {
-
-        // FIXME: there should be a better way than this
-        // also, we need to be prepared that the unix service may disappear...
-        ServiceListener listener = new ServiceListener() {
-            
-            private UNIXProcessHandler unixService;
-            private ApplicationService appService;
-            private boolean[] loaded = new boolean[3];
-            
-            @Override
-            public void serviceChanged(ServiceEvent event) {
-                
-                ServiceReference reference = event.getServiceReference();
-                Object service = context.getService(reference);
-                switch (event.getType()) {
-                case ServiceEvent.REGISTERED:
-                    if (service instanceof ContextAction) {
-                        loaded[0] = true;
-                    } else if (service instanceof UNIXProcessHandler) {
-                        loaded[1] = true;
-                        unixService = (UNIXProcessHandler) service;
-                    } else if (service instanceof ApplicationService) {
-                        loaded[2] = true;
-                        appService = (ApplicationService) service;
-                    }
-                    break;
-
-                default:
-                    break;
-                }
-                
-                if (loaded[0] && loaded[1] && loaded[2]) {
-                    context.registerService(VMContextAction.class.getName(),
-                                            new KillVMAction(unixService, appService.getDAOFactory()), null);
-                }
-            }
-        };
-        
-        try {
-            String filter = "(|(objectClass=" + ContextAction.class.getName() + ")" +
-                            "  (objectClass=" + UNIXProcessHandler.class.getName() + ")" +
-                            "  (objectClass=" + ApplicationService.class.getName() + "))";
-                    
-            context.addServiceListener(listener, filter);
-            ServiceReference[] services = context.getServiceReferences(null, null);
-            if (services != null) {
-                for(int i = 0; i < services.length; i++) {
-                    listener.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, services[i]));
-                }
-            }
-            
-        } catch (Exception e) {
-           logger.log(Level.WARNING, "Failed to set up listener for http", e);
-        }
-    }
-
-    @Override
-    public void stop(BundleContext context) throws Exception {
-        /* nothing to do here */
-    }
-}
--- a/client/killvm/src/main/java/com/redhat/thermostat/client/killvm/KillVMAction.java	Fri Aug 31 17:49:45 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-/*
- * 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.killvm;
-
-import com.redhat.thermostat.client.osgi.service.VMContextAction;
-import com.redhat.thermostat.client.osgi.service.VmFilter;
-import com.redhat.thermostat.common.dao.DAOFactory;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.model.VmInfo;
-import com.redhat.thermostat.service.process.UNIXProcessHandler;
-import com.redhat.thermostat.service.process.UNIXSignal;
-
-/**
- * Implements the {@link VMContextAction} entry point to provide a kill switch
- * for the currently selected Virtual Machine. 
- */
-public class KillVMAction implements VMContextAction {
-
-    private final UNIXProcessHandler unixService;
-    private final DAOFactory dao;
-
-    public KillVMAction(UNIXProcessHandler unixService, DAOFactory dao) {
-        this.unixService = unixService;
-        this.dao = dao;
-    }
-
-    @Override
-    public String getName() {
-        return "Kill Application";
-    }
-
-    @Override
-    public String getDescription() {
-        return "Kill the selected VM Process";
-    }
-
-    @Override
-    public void execute(VmRef reference) {
-        // TODO this should be executed on the agent-side
-        unixService.sendSignal(reference.getIdString(), UNIXSignal.TERM);
-    }
-
-    @Override
-    public VmFilter getFilter() {
-        return new LocalAndAliveFilter();
-    }
-
-    private class LocalAndAliveFilter implements VmFilter {
-
-        @Override
-        public boolean matches(VmRef ref) {
-            VmRef vm = ref;
-
-            // TODO implement local checking too
-            VmInfo vmInfo = dao.getVmInfoDAO().getVmInfo(vm);
-            return vmInfo.isAlive();
-        }
-
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/killvm/src/main/java/com/redhat/thermostat/client/killvm/internal/Activator.java	Thu Aug 30 17:37:39 2012 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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.killvm.internal;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.client.osgi.service.VMContextAction;
+
+public class Activator implements BundleActivator {
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        context.registerService(VMContextAction.class.getName(), new KillVMAction(), null);
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        // service automatically unregistered on bundle stop
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/killvm/src/main/java/com/redhat/thermostat/client/killvm/internal/KillVMAction.java	Thu Aug 30 17:37:39 2012 +0200
@@ -0,0 +1,113 @@
+/*
+ * 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.killvm.internal;
+
+import java.net.InetSocketAddress;
+
+import com.redhat.thermostat.client.command.RequestQueue;
+import com.redhat.thermostat.client.killvm.locale.LocaleResources;
+import com.redhat.thermostat.client.osgi.service.VMContextAction;
+import com.redhat.thermostat.client.osgi.service.VmFilter;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.command.Request.RequestType;
+import com.redhat.thermostat.common.dao.DAOFactory;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.VmInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+/**
+ * Implements the {@link VMContextAction} entry point to provide a kill switch
+ * for the currently selected Virtual Machine. 
+ */
+public class KillVMAction implements VMContextAction {
+
+    private static final String RECEIVER = "com.redhat.thermostat.agent.killvm.internal.KillVmReceiver";
+    private final DAOFactory dao;
+    private final Translate t;
+
+    public KillVMAction() {
+        this.dao = ApplicationContext.getInstance().getDAOFactory();
+        this.t = LocaleResources.createLocalizer();
+    }
+
+    @Override
+    public String getName() {
+        return t.localize(LocaleResources.ACTION_NAME);
+    }
+
+    @Override
+    public String getDescription() {
+        return t.localize(LocaleResources.ACTION_DESCRIPTION);
+    }
+
+    @Override
+    public void execute(VmRef reference) {
+        String address = dao.getStorage().getConfigListenAddress(reference.getAgent());
+        
+        String [] host = address.split(":");
+        InetSocketAddress target = new InetSocketAddress(host[0], Integer.parseInt(host[1]));
+        Request murderer = getKillRequest(target);
+        murderer.setParameter("vm-id", reference.getIdString());
+        murderer.setReceiver(RECEIVER);
+        murderer.addListener(new VMKilledListener());
+
+        RequestQueue queue = OSGIUtils.getInstance().getService(RequestQueue.class);
+        queue.putRequest(murderer);
+    }
+
+    // testing hook; keep this package private
+    Request getKillRequest(InetSocketAddress target) {
+        return new Request(RequestType.RESPONSE_EXPECTED, target);
+    }
+
+    @Override
+    public VmFilter getFilter() {
+        return new LocalAndAliveFilter();
+    }
+
+    private class LocalAndAliveFilter implements VmFilter {
+
+        @Override
+        public boolean matches(VmRef ref) {
+            VmInfo vmInfo = dao.getVmInfoDAO().getVmInfo(ref);
+            return vmInfo.isAlive();
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/killvm/src/main/java/com/redhat/thermostat/client/killvm/internal/VMKilledListener.java	Thu Aug 30 17:37:39 2012 +0200
@@ -0,0 +1,73 @@
+/*
+ * 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.killvm.internal;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.command.RequestResponseListener;
+import com.redhat.thermostat.common.command.Response;
+
+public class VMKilledListener implements RequestResponseListener {
+
+    private static final Logger logger = Logger.getLogger(VMKilledListener.class.getName());
+
+    @Override
+    public void fireComplete(Request request, Response response) {
+        switch (response.getType()) {
+        case NOOP:  // fall-through
+        case EXCEPTION: // fall-through
+        case NOK: {
+            logger.log(Level.SEVERE, "Unknown response from kill VM request.");
+            break;
+        }
+        case ERROR:
+            logger.log(Level.SEVERE, "Kill request error for VM ID " + request.getParameter("vm-id"));
+            break;
+        case PONG:  // fall-through, also OK :)
+        case OK:
+            // TODO: Report this to user somehow (notification?)
+            logger.log(Level.INFO, "VM with id " + request.getParameter("vm-id") + " killed on host " + request.getTarget().toString());
+            break;
+        default:
+            logger.log(Level.WARNING, "Unknown result from KILL VM command.");
+            break;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/killvm/src/main/java/com/redhat/thermostat/client/killvm/locale/LocaleResources.java	Thu Aug 30 17:37:39 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.client.killvm.locale;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public enum LocaleResources {
+
+    ACTION_NAME,
+    ACTION_DESCRIPTION,
+    MISSING_INFO;
+
+    public static final String RESOURCE_BUNDLE =
+            "com.redhat.thermostat.client.killvm.locale.strings";
+    
+    public static Translate createLocalizer() {
+        return new Translate(RESOURCE_BUNDLE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/killvm/src/main/resources/com/redhat/thermostat/client/killvm/locale/strings.properties	Thu Aug 30 17:37:39 2012 +0200
@@ -0,0 +1,3 @@
+ACTION_NAME = Kill Application
+ACTION_DESCRIPTION = Kill the selected VM Process
+MISSING_INFO = Missing Information
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/killvm/src/test/java/com/redhat/thermostat/client/killvm/internal/ActivatorTest.java	Thu Aug 30 17:37:39 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.client.killvm.internal;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Dictionary;
+
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import com.redhat.thermostat.client.osgi.service.VMContextAction;
+
+public class ActivatorTest {
+
+    @Test
+    public void startRegistersKillVMAction() throws Exception {
+        BundleContext ctx = mock(BundleContext.class);
+        ServiceRegistration serviceReg = mock(ServiceRegistration.class);
+        when(ctx.registerService(anyString(), any(), any(Dictionary.class)))
+                .thenReturn(serviceReg);
+        Activator activator = new Activator();
+        activator.start(ctx);
+        verify(ctx).registerService(eq(VMContextAction.class.getName()),
+                isA(KillVMAction.class), any(Dictionary.class));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/killvm/src/test/java/com/redhat/thermostat/client/killvm/internal/KillVMActionTest.java	Thu Aug 30 17:37:39 2012 +0200
@@ -0,0 +1,143 @@
+/*
+ * 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.killvm.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.InetSocketAddress;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.redhat.thermostat.client.command.RequestQueue;
+import com.redhat.thermostat.client.osgi.service.VmFilter;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
+import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.dao.DAOFactory;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.VmInfo;
+import com.redhat.thermostat.common.storage.Storage;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(OSGIUtils.class)
+public class KillVMActionTest {
+
+    private KillVMAction action;
+    private DAOFactory factory;
+
+    @Before
+    public void setUp() {
+        ApplicationContextUtil.resetApplicationContext();
+        factory = mock(DAOFactory.class);
+        ApplicationContext.getInstance().setDAOFactory(factory);
+        action = new KillVMAction();
+    }
+
+    @After
+    public void teardown() {
+        factory = null;
+        action = null;
+    }
+
+    @Test
+    public void killVMFilterOnlyMatchesLiveVMs() {
+        VmFilter filter = action.getFilter();
+        VmRef matching = mock(VmRef.class);
+        VmInfoDAO vmInfoDao = mock(VmInfoDAO.class);
+        VmInfo vmInfo = mock(VmInfo.class);
+        when(factory.getVmInfoDAO()).thenReturn(vmInfoDao);
+        when(vmInfoDao.getVmInfo(matching)).thenReturn(vmInfo);
+        when(vmInfo.isAlive()).thenReturn(true);
+        assertTrue(filter.matches(matching));
+        when(vmInfo.isAlive()).thenReturn(false);
+        assertFalse(filter.matches(matching));
+    }
+
+    @Test
+    public void canQueueKillRequest() {
+        Storage storage = mock(Storage.class);
+        when(factory.getStorage()).thenReturn(storage);
+        VmRef ref = mock(VmRef.class);
+        HostRef hostref = mock(HostRef.class);
+        when(ref.getAgent()).thenReturn(hostref);
+        String agentAddress = "127.0.0.1:8888";
+        when(storage.getConfigListenAddress(hostref)).thenReturn(agentAddress);
+        final Request req = mock(Request.class);
+        KillVMAction action = new KillVMAction() {
+            @Override
+            Request getKillRequest(InetSocketAddress target) {
+                return req;
+            }
+        };
+        OSGIUtils utils = mock(OSGIUtils.class);
+        PowerMockito.mockStatic(OSGIUtils.class);
+        when(OSGIUtils.getInstance()).thenReturn(utils);
+        RequestQueue queue = mock(RequestQueue.class);
+        when(utils.getService(RequestQueue.class)).thenReturn(queue);
+        action.execute(ref);
+        ArgumentCaptor<String> vmIdParamCaptor = ArgumentCaptor
+                .forClass(String.class);
+        verify(req).setParameter(vmIdParamCaptor.capture(), any(String.class));
+        assertEquals("vm-id", vmIdParamCaptor.getValue());
+        verify(req).addListener(isA(VMKilledListener.class));
+        ArgumentCaptor<String> receiverCaptor = ArgumentCaptor
+                .forClass(String.class);
+        verify(req).setReceiver(receiverCaptor.capture());
+        assertEquals(
+                "com.redhat.thermostat.agent.killvm.internal.KillVmReceiver",
+                receiverCaptor.getValue());
+        verify(queue).putRequest(req);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/killvm/src/test/java/com/redhat/thermostat/client/killvm/locale/TranslateTest.java	Thu Aug 30 17:37:39 2012 +0200
@@ -0,0 +1,90 @@
+/*
+ * 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.killvm.locale;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Properties;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public class TranslateTest {
+
+    private Locale lang;
+    private Translate t;
+
+    @Before
+    public void setUp() {
+        this.lang = Locale.getDefault();
+        Locale.setDefault(Locale.US);
+        t = LocaleResources.createLocalizer();
+    }
+
+    @After
+    public void tearDown() {
+        Locale.setDefault(lang);
+        t = null;
+    }
+    
+    @Test
+    public void testLocalizeWithoutArguments() {
+        String testString = t.localize(LocaleResources.MISSING_INFO);
+        Assert.assertEquals("Missing Information", testString);
+    }
+    
+    @Test
+    public void testLocalizedStringsArePresent() throws IOException {
+
+        String stringsResource = "/" + LocaleResources.RESOURCE_BUNDLE.replace(".", "/") + ".properties";
+
+        Properties props = new Properties();
+        props.load(getClass().getResourceAsStream(stringsResource));
+
+        Assert.assertEquals(LocaleResources.values().length, props.values().size());
+        for (LocaleResources resource : LocaleResources.values()) {
+            Assert.assertTrue("missing property from resource bound file: " + resource,
+                              props.containsKey(resource.name()));
+        }
+    }
+    
+}
--- a/distribution/config/bundles.properties	Fri Aug 31 17:49:45 2012 +0200
+++ b/distribution/config/bundles.properties	Thu Aug 30 17:37:39 2012 +0200
@@ -39,6 +39,7 @@
         thermostat-common-command-@project.version@.jar, \
         thermostat-agent-command-@project.version@.jar, \
         thermostat-agent-heapdumper-@project.version@.jar, \
+        thermostat-agent-killvm-@project.version@.jar, \
         thermostat-thread-collector-@project.version@.jar, \
         thermostat-thread-harvester-@project.version@.jar, \
         thermostat-client-command-@project.version@.jar
--- a/distribution/pom.xml	Fri Aug 31 17:49:45 2012 +0200
+++ b/distribution/pom.xml	Thu Aug 30 17:37:39 2012 +0200
@@ -292,6 +292,11 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-agent-killvm</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-common-core</artifactId>
       <version>${project.version}</version>
     </dependency>