changeset 827:518cc2809bd2

Indicate error on action failure There is currently no feedback to the user if some of the command-channel using actions fail. Fix it by displaying appropriate messages to the user. Reviewed-by: vanaltj Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-December/004391.html
author Omair Majid <omajid@redhat.com>
date Fri, 07 Dec 2012 17:31:35 -0500
parents 94c8e4c8a97c
children a03d6e46b29d
files agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/StorageCommand.java agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/AgentApplicationTest.java agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ServiceCommandTest.java agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/StorageCommandTest.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapView.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/LocaleResources.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommand.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommand.java client/heapdumper/core/src/main/resources/com/redhat/thermostat/client/heap/strings.properties client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommandTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommandTest.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java client/memory-stats-panel/swing/src/test/java/com/redhat/thermostat/client/stats/memory/swing/MemoryStatsPanelActivatorTest.java vm-gc/remote-collector-client-common/src/main/java/com/redhat/thermostat/gc/remote/common/GCRequest.java vm-gc/remote-collector-client-common/src/test/java/com/redhat/thermostat/gc/remote/common/GCRequestTest.java vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/GCCommandReceiver.java vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/internal/GC.java vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/internal/GCException.java vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/core/MemoryStatsView.java vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/core/internal/MemoryStatsController.java vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/locale/LocaleResources.java vm-memory/client-core/src/main/resources/com/redhat/thermostat/vm/memory/client/locale/strings.properties vm-memory/client-core/src/test/java/com/redhat/thermostat/vm/memory/client/core/internal/MemoryStatsControllerTest.java vm-memory/client-swing/src/main/java/com/redhat/thermostat/vm/memory/client/swing/MemoryStatsViewImpl.java
diffstat 21 files changed, 207 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java	Fri Dec 07 17:31:35 2012 -0500
@@ -163,6 +163,14 @@
                         public void run() {
                             view.notifyHeapDumpComplete();
                         }
+                    }, new Runnable() {
+                        @Override
+                        public void run() {
+                            view.displayWarning(translator.localize(
+                                    LocaleResources.HEAP_DUMP_ERROR,
+                                    ref.getAgent().getAgentId(),
+                                    ref.getIdString()));
+                        }
                     });
                     
                     break;
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapView.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapView.java	Fri Dec 07 17:31:35 2012 -0500
@@ -78,4 +78,6 @@
 
     public abstract void updateHeapDumpList(List<HeapDump> heapDumps);
 
+    public abstract void displayWarning(String string);
+
 }
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/LocaleResources.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/LocaleResources.java	Fri Dec 07 17:31:35 2012 -0500
@@ -57,6 +57,7 @@
     HEAP_ID_NOT_FOUND,
     HEAP_ID_REQUIRED,
     SEARCH_TERM_REQUIRED,
+    HEAP_DUMP_ERROR,
 
     COMMAND_HEAP_DUMP_DONE,
 
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommand.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommand.java	Fri Dec 07 17:31:35 2012 -0500
@@ -71,28 +71,33 @@
     }
 
     @Override
-    public void run(CommandContext ctx) throws CommandException {
+    public void run(final CommandContext ctx) throws CommandException {
         HostVMArguments args = new HostVMArguments(ctx.getArguments());
 
         final Semaphore s = new Semaphore(0);
-        Runnable r = new Runnable() {
-            
+        Runnable successHandler = new Runnable() {
             @Override
             public void run() {
+                ctx.getConsole().getOutput().println(translator.localize(LocaleResources.COMMAND_HEAP_DUMP_DONE));
                 s.release();
             }
         };
+        Runnable errorHandler = new Runnable() {
+            public void run() {
+                ctx.getConsole().getError().println(translator.localize(LocaleResources.HEAP_DUMP_ERROR));
+                s.release();
+            }
+        };
+
         AgentInfoDAO service = serviceProvider.getService(AgentInfoDAO.class);
         if (service == null) {
             throw new CommandException("Unable to access agent information");
         }
-        implementation.execute(service, args.getVM(), r);
+        implementation.execute(service, args.getVM(), successHandler, errorHandler);
         serviceProvider.ungetService(AgentInfoDAO.class, service);
 
         try {
             s.acquire();
-            ctx.getConsole().getOutput().print(translator.localize(LocaleResources.COMMAND_HEAP_DUMP_DONE));
-            ctx.getConsole().getOutput().print("\n");
         } catch (InterruptedException ex) {
             // Nothing to do here, just return ASAP.
         }
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommand.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommand.java	Fri Dec 07 17:31:35 2012 -0500
@@ -43,6 +43,7 @@
 import com.redhat.thermostat.common.command.Request.RequestType;
 import com.redhat.thermostat.common.command.RequestResponseListener;
 import com.redhat.thermostat.common.command.Response;
+import com.redhat.thermostat.common.command.Response.ResponseType;
 import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmRef;
@@ -55,20 +56,30 @@
 
     private class HeapDumpListener implements RequestResponseListener {
 
-        private Runnable heapDumpCompleteAction;
+        private Runnable successAction;
+        private Runnable failureAction;
 
-        private HeapDumpListener(Runnable heapDumpCompleteAction) {
-            this.heapDumpCompleteAction = heapDumpCompleteAction;
+        private HeapDumpListener(Runnable heapDumpSuccessfulAction, Runnable heapDumpFailureAction) {
+            this.successAction = heapDumpSuccessfulAction;
+            this.failureAction = heapDumpFailureAction;
         }
 
         @Override
         public void fireComplete(Request request, Response response) {
-            heapDumpCompleteAction.run();
+            if (response.getType() == ResponseType.ERROR) {
+                if (failureAction != null) {
+                    failureAction.run();
+                }
+            } else {
+                if (successAction != null) {
+                    successAction.run();
+                }
+            }
         }
-        
+
     }
 
-    public void execute(AgentInfoDAO agentInfoDAO, VmRef reference, Runnable heapDumpCompleteAction) {
+    public void execute(AgentInfoDAO agentInfoDAO, VmRef reference, Runnable heapDumpSuccessAction, Runnable heapDumpFailureAction) {
 
         HostRef targetHostRef = reference.getAgent();
         String address = agentInfoDAO.getAgentInformation(targetHostRef).getConfigListenAddress();
@@ -78,7 +89,7 @@
         Request req = new Request(RequestType.RESPONSE_EXPECTED, target);
         req.setReceiver(RECEIVER_CLASS_NAME);
         req.setParameter(VM_ID_PARAM, reference.getIdString());
-        req.addListener(new HeapDumpListener(heapDumpCompleteAction));
+        req.addListener(new HeapDumpListener(heapDumpSuccessAction, heapDumpFailureAction));
 
         RequestQueue queue = OSGIUtils.getInstance().getService(RequestQueue.class);
         queue.putRequest(req);
--- a/client/heapdumper/core/src/main/resources/com/redhat/thermostat/client/heap/strings.properties	Fri Dec 07 17:24:23 2012 -0500
+++ b/client/heapdumper/core/src/main/resources/com/redhat/thermostat/client/heap/strings.properties	Fri Dec 07 17:31:35 2012 -0500
@@ -15,7 +15,7 @@
 HEAP_ID_NOT_FOUND = Heap ID not found: {0}
 HEAP_ID_REQUIRED = Heap ID required
 SEARCH_TERM_REQUIRED = A search term is required
-
+HEAP_DUMP_ERROR = Error dumping heap (agent: {0}, vm: {1})
 
 COMMAND_HEAP_DUMP_DONE = Done
 
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java	Fri Dec 07 17:31:35 2012 -0500
@@ -68,6 +68,7 @@
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.HeapDAO;
+import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.common.heap.HeapDump;
@@ -162,7 +163,14 @@
         ApplicationCache cache = mock(ApplicationCache.class);
         when(appService.getApplicationCache()).thenReturn(cache);
         setUpTimers();
+
+        HostRef hostRef = mock(HostRef.class);
+        when(hostRef.getAgentId()).thenReturn("agent-id");
+
         VmRef ref = mock(VmRef.class);
+        when(ref.getIdString()).thenReturn("vm-id");
+        when(ref.getAgent()).thenReturn(hostRef);
+
         heapDumperCommand = mock(HeapDumperCommand.class);
         controller = new HeapDumpController(agentDao, vmDao, heapDao, ref, appService,
                 heapDumperCommand, viewProvider, detailsViewProvider,
@@ -285,12 +293,23 @@
         heapDumperListener.actionPerformed(new ActionEvent<HeapDumperAction>(view, HeapDumperAction.DUMP_REQUESTED));
 
         ArgumentCaptor<Runnable> heapDumpCompleteAction = ArgumentCaptor.forClass(Runnable.class);
-        verify(heapDumperCommand).execute(same(agentDao), any(VmRef.class), heapDumpCompleteAction.capture());
+        verify(heapDumperCommand).execute(same(agentDao), any(VmRef.class), heapDumpCompleteAction.capture(), any(Runnable.class));
         heapDumpCompleteAction.getValue().run();
         verify(view).notifyHeapDumpComplete();
-
     }
- 
+
+    @Test
+    public void testRequestHeapDumpFails() {
+        setUpListeners();
+
+        heapDumperListener.actionPerformed(new ActionEvent<HeapDumperAction>(view, HeapDumperAction.DUMP_REQUESTED));
+
+        ArgumentCaptor<Runnable> heapDumpFailedAction = ArgumentCaptor.forClass(Runnable.class);
+        verify(heapDumperCommand).execute(same(agentDao), any(VmRef.class), any(Runnable.class), heapDumpFailedAction.capture());
+        heapDumpFailedAction.getValue().run();
+        verify(view).displayWarning("Error dumping heap (agent: agent-id, vm: vm-id)");
+    }
+
     @SuppressWarnings("unchecked")
 	@Test
     public void testTimerChecksForNewHeapDumps() {
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommandTest.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommandTest.java	Fri Dec 07 17:31:35 2012 -0500
@@ -77,15 +77,15 @@
         when(osgi.getService(AgentInfoDAO.class)).thenReturn(agentInfoDao);
 
         HeapDumperCommand impl = mock(HeapDumperCommand.class);
-        final ArgumentCaptor<Runnable> arg = ArgumentCaptor.forClass(Runnable.class);
+        final ArgumentCaptor<Runnable> successHandler = ArgumentCaptor.forClass(Runnable.class);
         doAnswer(new Answer<Void>() {
 
             @Override
             public Void answer(InvocationOnMock invocation) throws Throwable {
-                arg.getValue().run();
+                successHandler.getValue().run();
                 return null;
             }
-        }).when(impl).execute(eq(agentInfoDao), any(VmRef.class), arg.capture());
+        }).when(impl).execute(eq(agentInfoDao), any(VmRef.class), successHandler.capture(), any(Runnable.class));
 
         DumpHeapCommand command = new DumpHeapCommand(osgi, impl);
 
@@ -97,7 +97,7 @@
 
         command.run(factory.createContext(args));
 
-        verify(impl).execute(eq(agentInfoDao), isA(VmRef.class), any(Runnable.class));
+        verify(impl).execute(eq(agentInfoDao), isA(VmRef.class), any(Runnable.class), any(Runnable.class));
         assertEquals("Done\n", factory.getOutput());
     }
 
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommandTest.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommandTest.java	Fri Dec 07 17:31:35 2012 -0500
@@ -38,6 +38,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -70,6 +71,7 @@
     private VmRef vmRef;
     private RequestQueue reqQueue;
     private Runnable heapDumpCompleteAction;
+    private Runnable heapDumpFailedAction;
 
     @Before
     public void setUp() {
@@ -91,7 +93,7 @@
         when(vmRef.getIdString()).thenReturn("123");
         when(vmRef.getAgent()).thenReturn(host);
         heapDumpCompleteAction = mock(Runnable.class);
-
+        heapDumpFailedAction = mock(Runnable.class);
     }
 
     @After
@@ -105,7 +107,7 @@
     @Test
 	public void testExecute() {
 
-        cmd.execute(agentInfoDao, vmRef, heapDumpCompleteAction);
+        cmd.execute(agentInfoDao, vmRef, heapDumpCompleteAction, heapDumpFailedAction);
 
 		ArgumentCaptor<Request> reqArg = ArgumentCaptor.forClass(Request.class);
 		verify(reqQueue).putRequest(reqArg.capture());
@@ -121,6 +123,29 @@
 		    l.fireComplete(req, new Response(ResponseType.OK));
 		}
 		verify(heapDumpCompleteAction).run();
+		verify(heapDumpFailedAction, times(0)).run();
+    }
+
+    @Test
+    public void testExecuteFailure() {
+
+        cmd.execute(agentInfoDao, vmRef, heapDumpCompleteAction, heapDumpFailedAction);
+
+        ArgumentCaptor<Request> reqArg = ArgumentCaptor.forClass(Request.class);
+        verify(reqQueue).putRequest(reqArg.capture());
+        Request req = reqArg.getValue();
+        assertEquals("com.redhat.thermostat.agent.heapdumper.internal.HeapDumpReceiver", req.getReceiver());
+        verifyClassExists(req.getReceiver());
+        assertEquals(RequestType.RESPONSE_EXPECTED, req.getType());
+        assertEquals("123", req.getParameter("vmId"));
+        assertEquals(new InetSocketAddress("test", 123), req.getTarget());
+
+        Collection<RequestResponseListener> ls = req.getListeners();
+        for (RequestResponseListener l : ls) {
+            l.fireComplete(req, new Response(ResponseType.ERROR));
+        }
+        verify(heapDumpCompleteAction, times(0)).run();
+        verify(heapDumpFailedAction).run();
     }
 
     private void verifyClassExists(String receiver) {
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java	Fri Dec 07 17:31:35 2012 -0500
@@ -43,6 +43,7 @@
 import java.util.List;
 
 import javax.swing.BoxLayout;
+import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
 import javax.swing.event.ListSelectionEvent;
@@ -227,4 +228,9 @@
             }
         });
     }
+
+    @Override
+    public void displayWarning(String string) {
+        JOptionPane.showMessageDialog(visiblePane, string, "Warning", JOptionPane.WARNING_MESSAGE);
+    }
 }
--- a/vm-gc/remote-collector-client-common/src/main/java/com/redhat/thermostat/gc/remote/common/GCRequest.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/vm-gc/remote-collector-client-common/src/main/java/com/redhat/thermostat/gc/remote/common/GCRequest.java	Fri Dec 07 17:31:35 2012 -0500
@@ -40,6 +40,7 @@
 
 import com.redhat.thermostat.client.command.RequestQueue;
 import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.command.RequestResponseListener;
 import com.redhat.thermostat.common.command.Request.RequestType;
 import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.HostRef;
@@ -53,7 +54,7 @@
         this.queue = queue;
     }
         
-    public void sendGCRequestToAgent(VmRef vm, AgentInfoDAO agentDAO) {
+    public void sendGCRequestToAgent(VmRef vm, AgentInfoDAO agentDAO, RequestResponseListener responseListener) {
                 
         HostRef targetHostRef = vm.getAgent();
 
@@ -68,6 +69,8 @@
         gcRequest.setParameter(GCCommand.class.getName(), GCCommand.REQUEST_GC.name());
         gcRequest.setParameter(GCCommand.VM_ID, vm.getIdString());
         
+        gcRequest.addListener(responseListener);
+
         queue.putRequest(gcRequest);
     }
     
--- a/vm-gc/remote-collector-client-common/src/test/java/com/redhat/thermostat/gc/remote/common/GCRequestTest.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/vm-gc/remote-collector-client-common/src/test/java/com/redhat/thermostat/gc/remote/common/GCRequestTest.java	Fri Dec 07 17:31:35 2012 -0500
@@ -48,6 +48,7 @@
 
 import com.redhat.thermostat.client.command.RequestQueue;
 import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.command.RequestResponseListener;
 import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.VmRef;
@@ -62,6 +63,7 @@
 
     private GCRequest gcRequest;
     private Request request;
+    private RequestResponseListener listener;
     
     @Before
     public void setUp() {
@@ -70,6 +72,8 @@
 
         request = mock(Request.class);
         
+        listener = mock(RequestResponseListener.class);
+
         HostRef ref = mock(HostRef.class);        
         when(vm.getAgent()).thenReturn(ref);
         when(vm.getIdString()).thenReturn("123456");
@@ -101,7 +105,7 @@
             }
         };
         
-        gcRequest.sendGCRequestToAgent(vm, agentDAO);
+        gcRequest.sendGCRequestToAgent(vm, agentDAO, listener);
         verify(vm).getAgent();
         verify(vm).getIdString();
         
@@ -112,6 +116,7 @@
         verify(request).setReceiver(GCCommand.RECEIVER);
         verify(request).setParameter(GCCommand.class.getName(), GCCommand.REQUEST_GC.name());
         verify(request).setParameter(GCCommand.VM_ID, "123456");
+        verify(request).addListener(listener);
         
         verify(queue).putRequest(request);
     }
--- a/vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/GCCommandReceiver.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/GCCommandReceiver.java	Fri Dec 07 17:31:35 2012 -0500
@@ -41,6 +41,7 @@
 import com.redhat.thermostat.common.command.Response;
 import com.redhat.thermostat.common.command.Response.ResponseType;
 import com.redhat.thermostat.gc.remote.command.internal.GC;
+import com.redhat.thermostat.gc.remote.command.internal.GCException;
 import com.redhat.thermostat.gc.remote.common.command.GCCommand;
 import com.redhat.thermostat.utils.management.MXBeanConnector;
 
@@ -48,18 +49,22 @@
 
     @Override
     public Response receive(Request request) {
+        Response response = new Response(ResponseType.OK);
         
         String command = request.getParameter(GCCommand.class.getName());
         switch (GCCommand.valueOf(command)) {
         case REQUEST_GC:
-            String vmId = request.getParameter(GCCommand.VM_ID);
-            MXBeanConnector connector = new MXBeanConnector(vmId);
-            new GC(connector).gc();
+            try {
+                String vmId = request.getParameter(GCCommand.VM_ID);
+                MXBeanConnector connector = new MXBeanConnector(vmId);
+                new GC(connector).gc();
+            } catch (GCException gce) {
+                response = new Response(ResponseType.ERROR);
+            }
             break;
-        
         default:
             break;
         }
-        return new Response(ResponseType.OK);
+        return response;
     }
 }
--- a/vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/internal/GC.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/internal/GC.java	Fri Dec 07 17:31:35 2012 -0500
@@ -54,7 +54,8 @@
         this.connector = connector;
     }
     
-    public void gc() {
+    public void gc() throws GCException {
+        Exception exceptionInGc = null;
         boolean closeAfter = false;
         if (!connector.isAttached()) {
             closeAfter = true; 
@@ -75,12 +76,17 @@
             bean.gc();
 
         } catch (Exception ex) {
+            exceptionInGc = ex;
             logger.log(Level.SEVERE, "can't get MXBeanConnection connection", ex);
         }
         
         if (closeAfter) {
             closeConnection();
         }
+
+        if (exceptionInGc != null) {
+            throw new GCException("error performing gc", exceptionInGc);
+        }
     }
     
     private void closeConnection() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-gc/remote-collector-command/src/main/java/com/redhat/thermostat/gc/remote/command/internal/GCException.java	Fri Dec 07 17:31:35 2012 -0500
@@ -0,0 +1,44 @@
+/*
+ * 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.gc.remote.command.internal;
+
+public class GCException extends Exception {
+
+    public GCException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
--- a/vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/core/MemoryStatsView.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/core/MemoryStatsView.java	Fri Dec 07 17:31:35 2012 -0500
@@ -48,5 +48,8 @@
     
     public abstract void addGCActionListener(ActionListener<GCCommand> listener);
     
-    public abstract void requestRepaint();    
+    public abstract void requestRepaint();
+
+    public abstract void displayWarning(String string);
+
 }
--- a/vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/core/internal/MemoryStatsController.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/core/internal/MemoryStatsController.java	Fri Dec 07 17:31:35 2012 -0500
@@ -50,6 +50,10 @@
 import com.redhat.thermostat.common.NotImplementedException;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.command.RequestResponseListener;
+import com.redhat.thermostat.common.command.Response;
+import com.redhat.thermostat.common.command.Response.ResponseType;
 import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
 import com.redhat.thermostat.common.dao.VmRef;
@@ -68,6 +72,8 @@
 
 public class MemoryStatsController implements VmInformationServiceController {
 
+    private static final Translate<LocaleResources> translate = LocaleResources.createLocalizer();
+
     private final MemoryStatsView view;
     private final VmMemoryStatDAO vmDao;
    
@@ -186,7 +192,18 @@
         view.addGCActionListener(new ActionListener<GCCommand>() {
             @Override
             public void actionPerformed(ActionEvent<GCCommand> actionEvent) {
-                gcRequest.sendGCRequestToAgent(ref, agentDAO);
+                RequestResponseListener listener = new RequestResponseListener() {
+                    @Override
+                    public void fireComplete(Request request, Response response) {
+                        if (response.getType() == ResponseType.ERROR) {
+                            view.displayWarning(translate.localize(
+                                    LocaleResources.ERROR_PERFORMING_GC,
+                                    ref.getAgent().getAgentId(),
+                                    ref.getIdString()));
+                        }
+                    }
+                };
+                gcRequest.sendGCRequestToAgent(ref, agentDAO, listener);
             }
         });
     }
--- a/vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/locale/LocaleResources.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/locale/LocaleResources.java	Fri Dec 07 17:31:35 2012 -0500
@@ -41,6 +41,8 @@
 public enum LocaleResources {
 
     VM_INFO_TAB_MEMORY,
+    ERROR_PERFORMING_GC,
+
     RESOURCE_MISSING;
     
     public static final String RESOURCE_BUNDLE =
--- a/vm-memory/client-core/src/main/resources/com/redhat/thermostat/vm/memory/client/locale/strings.properties	Fri Dec 07 17:24:23 2012 -0500
+++ b/vm-memory/client-core/src/main/resources/com/redhat/thermostat/vm/memory/client/locale/strings.properties	Fri Dec 07 17:31:35 2012 -0500
@@ -1,2 +1,4 @@
 RESOURCE_MISSING = Missing translation!
-VM_INFO_TAB_MEMORY = Memory
\ No newline at end of file
+VM_INFO_TAB_MEMORY = Memory
+
+ERROR_PERFORMING_GC = Error performing Garbage Collection (agent: {0}, vm: {1})
\ No newline at end of file
--- a/vm-memory/client-core/src/test/java/com/redhat/thermostat/vm/memory/client/core/internal/MemoryStatsControllerTest.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/vm-memory/client-core/src/test/java/com/redhat/thermostat/vm/memory/client/core/internal/MemoryStatsControllerTest.java	Fri Dec 07 17:31:35 2012 -0500
@@ -40,6 +40,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isA;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
@@ -63,6 +64,7 @@
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.Timer.SchedulingType;
 import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.common.command.RequestResponseListener;
 import com.redhat.thermostat.common.dao.AgentInfoDAO;
 import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
 import com.redhat.thermostat.common.dao.VmRef;
@@ -182,7 +184,7 @@
     @Test
     public void testGCInvoked() {
         gcActionListener.actionPerformed(new ActionEvent<>(view, GCCommand.REQUEST_GC));
-        verify(gcRequest).sendGCRequestToAgent(ref, agentDAO);
+        verify(gcRequest).sendGCRequestToAgent(eq(ref), eq(agentDAO), isA(RequestResponseListener.class));
     }
     
     @Test
--- a/vm-memory/client-swing/src/main/java/com/redhat/thermostat/vm/memory/client/swing/MemoryStatsViewImpl.java	Fri Dec 07 17:24:23 2012 -0500
+++ b/vm-memory/client-swing/src/main/java/com/redhat/thermostat/vm/memory/client/swing/MemoryStatsViewImpl.java	Fri Dec 07 17:31:35 2012 -0500
@@ -44,6 +44,7 @@
 
 import javax.swing.Box;
 import javax.swing.BoxLayout;
+import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
 
@@ -148,6 +149,11 @@
     }
 
     @Override
+    public void displayWarning(String string) {
+        JOptionPane.showMessageDialog(visiblePanel, string, "Warning", JOptionPane.WARNING_MESSAGE);
+    }
+
+    @Override
     public Component getUiComponent() {
         return visiblePanel;
     }