changeset 1097:e31208c2d0c8

Publish JMX notification status to storage Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-May/006659.html
author Omair Majid <omajid@redhat.com>
date Fri, 17 May 2013 16:18:36 -0400
parents e9abee8e0f3c
children 2471ea5c679c
files vm-jmx/agent/src/main/java/com/redhat/thermostat/vm/jmx/agent/internal/JmxBackend.java vm-jmx/client-core/src/main/java/com/redhat/thermostat/vm/jmx/client/core/internal/JmxNotificationsViewController.java vm-jmx/client-core/src/test/java/com/redhat/thermostat/vm/jmx/client/core/internal/JmxNotificationsViewControllerTest.java vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/JmxNotificationDAO.java vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/JmxNotificationStatus.java vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImpl.java vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplTest.java
diffstat 7 files changed, 211 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/vm-jmx/agent/src/main/java/com/redhat/thermostat/vm/jmx/agent/internal/JmxBackend.java	Fri May 17 14:22:28 2013 -0400
+++ b/vm-jmx/agent/src/main/java/com/redhat/thermostat/vm/jmx/agent/internal/JmxBackend.java	Fri May 17 16:18:36 2013 -0400
@@ -56,12 +56,15 @@
 import com.redhat.thermostat.agent.command.ReceiverRegistry;
 import com.redhat.thermostat.agent.command.RequestReceiver;
 import com.redhat.thermostat.backend.BaseBackend;
+import com.redhat.thermostat.common.Clock;
+import com.redhat.thermostat.common.SystemClock;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.utils.management.MXBeanConnection;
 import com.redhat.thermostat.utils.management.MXBeanConnectionPool;
 import com.redhat.thermostat.vm.jmx.common.JmxNotification;
 import com.redhat.thermostat.vm.jmx.common.JmxNotificationDAO;
+import com.redhat.thermostat.vm.jmx.common.JmxNotificationStatus;
 
 public class JmxBackend extends BaseBackend {
 
@@ -71,6 +74,7 @@
     private final RequestReceiver receiver;
     private final JmxNotificationDAO dao;
     private final MXBeanConnectionPool pool;
+    private final Clock clock;
 
     private final NotificationListener registrationNotificationListener;
     private final NotificationListener notificationWriter;
@@ -80,11 +84,16 @@
     private boolean isActive = false;
 
     public JmxBackend(Version version, ReceiverRegistry registry, JmxNotificationDAO dao, MXBeanConnectionPool pool, RequestReceiver receiver) {
+        this(version, registry, dao, pool, receiver, new SystemClock());
+    }
+
+    public JmxBackend(Version version, ReceiverRegistry registry, JmxNotificationDAO dao, MXBeanConnectionPool pool, RequestReceiver receiver, Clock clock) {
         super("VM JMX Backend", "gathers JMX information using JMX", "Red Hat, Inc.", version.getVersionNumber());
 
         this.registry = registry;
         this.pool = pool;
         this.dao = dao;
+        this.clock = clock;
 
         this.registrationNotificationListener = new RegistrationNotificationListener();
         this.notificationWriter = new NotificationWriter();
@@ -140,6 +149,11 @@
                     addNotificationListenerToMBean(pid, server, name);
                 }
             }
+            JmxNotificationStatus update = new JmxNotificationStatus();
+            update.setVmId(pid);
+            update.setEnabled(true);
+            update.setTimeStamp(clock.getRealTimeMillis());
+            dao.addNotifcationStatus(update);
         } catch (Exception e) {
             logger.log(Level.WARNING, "Unable to connect to the mx bean connector", e);
         }
@@ -149,6 +163,13 @@
         int pid = Integer.valueOf(vmId);
 
         MXBeanConnection connection = connections.get(pid);
+
+        JmxNotificationStatus update = new JmxNotificationStatus();
+        update.setVmId(pid);
+        update.setEnabled(false);
+        update.setTimeStamp(clock.getRealTimeMillis());
+        dao.addNotifcationStatus(update);
+
         try {
             pool.release(pid, connection);
         } catch (Exception e) {
--- a/vm-jmx/client-core/src/main/java/com/redhat/thermostat/vm/jmx/client/core/internal/JmxNotificationsViewController.java	Fri May 17 14:22:28 2013 -0400
+++ b/vm-jmx/client-core/src/main/java/com/redhat/thermostat/vm/jmx/client/core/internal/JmxNotificationsViewController.java	Fri May 17 16:18:36 2013 -0400
@@ -49,17 +49,14 @@
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.Timer;
 import com.redhat.thermostat.common.TimerFactory;
-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.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.AgentInfoDAO;
 import com.redhat.thermostat.vm.jmx.client.core.JmxNotificationsView;
+import com.redhat.thermostat.vm.jmx.client.core.JmxNotificationsView.NotificationAction;
 import com.redhat.thermostat.vm.jmx.client.core.JmxNotificationsViewProvider;
-import com.redhat.thermostat.vm.jmx.client.core.JmxNotificationsView.NotificationAction;
+import com.redhat.thermostat.vm.jmx.common.JmxNotification;
 import com.redhat.thermostat.vm.jmx.common.JmxNotificationDAO;
-import com.redhat.thermostat.vm.jmx.common.JmxNotification;
+import com.redhat.thermostat.vm.jmx.common.JmxNotificationStatus;
 
 public class JmxNotificationsViewController implements InformationServiceController<VmRef> {
 
@@ -69,7 +66,7 @@
     private final AgentInfoDAO agentDAO;
     private final VmRef vm;
 
-    private final AtomicBoolean toEnable = new AtomicBoolean(true);;
+    private final AtomicBoolean notificationsEnabled = new AtomicBoolean(false);
 
     public JmxNotificationsViewController(AgentInfoDAO agent, JmxNotificationDAO notification,
             TimerFactory timerFactory, final RequestQueue queue,
@@ -102,16 +99,11 @@
             @Override
             public void actionPerformed(ActionEvent<NotificationAction> actionEvent) {
                 if (actionEvent.getActionId() == NotificationAction.TOGGLE_NOTIFICATIONS) {
-                    new JmxToggleNotificationRequest(queue).sendEnableNotificationsRequestToAgent(vm, agentDAO, toEnable.get(),
-                            new RequestResponseListener() {
-                                @Override
-                                public void fireComplete(Request request, Response response) {
-                                    if (response.getType() == ResponseType.OK) {
-                                        view.setNotificationsEnabled(toEnable.get());
-                                        toEnable.set(!toEnable.get());
-                                    }
-                                }
-                            });
+                    notificationsEnabled.set(!notificationsEnabled.get());
+
+                    new JmxToggleNotificationRequest(queue).sendEnableNotificationsRequestToAgent(vm, agentDAO, notificationsEnabled.get(), null);
+
+                    view.setNotificationsEnabled(notificationsEnabled.get());
                 }
             }
         });
@@ -129,6 +121,10 @@
 
             @Override
             public void run() {
+                JmxNotificationStatus status = dao.getLatestNotificationStatus(vm);
+                notificationsEnabled.set(status.isEnabled());
+                view.setNotificationsEnabled(notificationsEnabled.get());
+
                 List<JmxNotification> notifications = dao.getNotifications(vm, lastTimeStamp);
                 for (JmxNotification notification : notifications) {
                     lastTimeStamp = Math.max(lastTimeStamp, notification.getTimeStamp());
--- a/vm-jmx/client-core/src/test/java/com/redhat/thermostat/vm/jmx/client/core/internal/JmxNotificationsViewControllerTest.java	Fri May 17 14:22:28 2013 -0400
+++ b/vm-jmx/client-core/src/test/java/com/redhat/thermostat/vm/jmx/client/core/internal/JmxNotificationsViewControllerTest.java	Fri May 17 16:18:36 2013 -0400
@@ -66,6 +66,7 @@
 import com.redhat.thermostat.vm.jmx.client.core.JmxNotificationsViewProvider;
 import com.redhat.thermostat.vm.jmx.common.JmxNotification;
 import com.redhat.thermostat.vm.jmx.common.JmxNotificationDAO;
+import com.redhat.thermostat.vm.jmx.common.JmxNotificationStatus;
 
 public class JmxNotificationsViewControllerTest {
 
@@ -124,6 +125,8 @@
 
         JmxNotification data = mock(JmxNotification.class);
         when(notificationDao.getNotifications(vm, Long.MIN_VALUE)).thenReturn(Arrays.asList(data));
+        JmxNotificationStatus status = mock(JmxNotificationStatus.class);
+        when(notificationDao.getLatestNotificationStatus(vm)).thenReturn(status);
 
         timerAction.run();
 
--- a/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/JmxNotificationDAO.java	Fri May 17 14:22:28 2013 -0400
+++ b/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/JmxNotificationDAO.java	Fri May 17 16:18:36 2013 -0400
@@ -42,6 +42,10 @@
 
 public interface JmxNotificationDAO {
 
+    void addNotifcationStatus(JmxNotificationStatus notificationsStatus);
+
+    JmxNotificationStatus getLatestNotificationStatus(VmRef statusFor);
+
     void addNotification(JmxNotification notification);
 
     List<JmxNotification> getNotifications(VmRef notificationsFor, long timeStampSince);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/JmxNotificationStatus.java	Fri May 17 16:18:36 2013 -0400
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012, 2013 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.vm.jmx.common;
+
+import com.redhat.thermostat.storage.core.Entity;
+import com.redhat.thermostat.storage.core.Persist;
+import com.redhat.thermostat.storage.model.BasePojo;
+import com.redhat.thermostat.storage.model.TimeStampedPojo;
+
+@Entity
+public class JmxNotificationStatus extends BasePojo implements TimeStampedPojo {
+
+    private long timeStamp = 0;
+    private int vmId = 0;
+    private boolean enabled = false;
+
+    @Persist
+    public int getVmId() {
+        return vmId;
+    }
+
+    @Persist
+    public void setVmId(int vmId) {
+        this.vmId = vmId;
+    }
+
+    @Persist
+    @Override
+    public long getTimeStamp() {
+        return timeStamp;
+    }
+
+    @Persist
+    public void setTimeStamp(long timeStamp) {
+        this.timeStamp = timeStamp;
+    }
+
+    @Persist
+    public boolean isEnabled() {
+        return this.enabled;
+    }
+
+    @Persist
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+}
--- a/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImpl.java	Fri May 17 14:22:28 2013 -0400
+++ b/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImpl.java	Fri May 17 16:18:36 2013 -0400
@@ -45,13 +45,21 @@
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Query.Criteria;
+import com.redhat.thermostat.storage.core.Query.SortDirection;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.VmRef;
+import com.redhat.thermostat.vm.jmx.common.JmxNotification;
 import com.redhat.thermostat.vm.jmx.common.JmxNotificationDAO;
-import com.redhat.thermostat.vm.jmx.common.JmxNotification;
+import com.redhat.thermostat.vm.jmx.common.JmxNotificationStatus;
 
 public class JmxNotificationDAOImpl implements JmxNotificationDAO {
 
+    private static final Key<Boolean> NOTIFICATIONS_ENABLED = new Key<>("notififcationsEnabled", false);
+
+    static final Category<JmxNotificationStatus> NOTIFICATION_STATUS =
+            new Category<>("vm-jmx-notification-status", JmxNotificationStatus.class,
+                    Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, NOTIFICATIONS_ENABLED);
+
     // TODO: private static final Key IMPORTANCE = new Key<>("importance",
     // false);
 
@@ -68,10 +76,33 @@
 
     public JmxNotificationDAOImpl(Storage storage) {
         this.storage = storage;
+        storage.registerCategory(NOTIFICATION_STATUS);
         storage.registerCategory(NOTIFICATIONS);
     }
 
     @Override
+    public void addNotifcationStatus(JmxNotificationStatus status) {
+        Add add = storage.createAdd(NOTIFICATION_STATUS);
+        add.setPojo(status);
+        add.apply();
+    }
+
+    @Override
+    public JmxNotificationStatus getLatestNotificationStatus(VmRef statusFor) {
+        Query<JmxNotificationStatus> query = storage.createQuery(NOTIFICATION_STATUS);
+        query.where(Key.AGENT_ID, Criteria.EQUALS, statusFor.getAgent().getAgentId());
+        query.where(Key.VM_ID, Criteria.EQUALS, statusFor.getId());
+
+        query.sort(Key.TIMESTAMP, SortDirection.DESCENDING);
+        Cursor<JmxNotificationStatus> results = query.execute();
+        if (results.hasNext()) {
+            return results.next();
+        }
+
+        return null;
+    }
+
+    @Override
     public void addNotification(JmxNotification notification) {
         Add add = storage.createAdd(NOTIFICATIONS);
         add.setPojo(notification);
--- a/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplTest.java	Fri May 17 14:22:28 2013 -0400
+++ b/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplTest.java	Fri May 17 16:18:36 2013 -0400
@@ -38,6 +38,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -45,6 +46,8 @@
 
 import java.util.List;
 
+import javax.swing.SortOrder;
+
 import org.junit.Before;
 import org.junit.Test;
 
@@ -54,24 +57,74 @@
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Query;
 import com.redhat.thermostat.storage.core.Query.Criteria;
+import com.redhat.thermostat.storage.core.Query.SortDirection;
 import com.redhat.thermostat.storage.core.Storage;
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.vm.jmx.common.JmxNotification;
+import com.redhat.thermostat.vm.jmx.common.JmxNotificationStatus;
 
 public class JmxNotificationDAOImplTest {
 
+    private final String AGENT_ID = "an-agent's-id";
+    private final int VM_ID = -1;
+
     private Storage storage;
 
     private JmxNotificationDAOImpl dao;
+    private HostRef host;
+    private VmRef vm;
 
     @Before
     public void setUp() {
+        host = mock(HostRef.class);
+        when(host.getAgentId()).thenReturn(AGENT_ID);
+
+        vm = mock(VmRef.class);
+        when(vm.getAgent()).thenReturn(host);
+        when(vm.getId()).thenReturn(VM_ID);
+
         storage = mock(Storage.class);
 
         dao = new JmxNotificationDAOImpl(storage);
     }
 
     @Test
+    public void verifyAddNotificationStatus() {
+        Add add = mock(Add.class);
+        when(storage.createAdd(JmxNotificationDAOImpl.NOTIFICATION_STATUS)).thenReturn(add);
+
+        JmxNotificationStatus data = mock(JmxNotificationStatus.class);
+
+        dao.addNotifcationStatus(data);
+
+        verify(add).setPojo(data);
+        verify(add).apply();
+        verifyNoMoreInteractions(add);
+    }
+
+    @Test
+    public void verifyGetLatestNotificationStatus() {
+        JmxNotificationStatus data = new JmxNotificationStatus();
+
+        Query<JmxNotificationStatus> query = mock(Query.class);
+        when(storage.createQuery(JmxNotificationDAOImpl.NOTIFICATION_STATUS)).thenReturn(query);
+
+        Cursor<JmxNotificationStatus> cursor = mock(Cursor.class);
+        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(data).thenThrow(new AssertionError("should not be called"));
+
+        when(query.execute()).thenReturn(cursor);
+
+        JmxNotificationStatus result = dao.getLatestNotificationStatus(vm);
+
+        verify(query).where(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID);
+        verify(query).where(Key.VM_ID, Criteria.EQUALS, VM_ID);
+        verify(query).sort(Key.TIMESTAMP, SortDirection.DESCENDING);
+        
+        assertTrue(result == data);
+    }
+
+    @Test
     public void verfiyAddNotification() {
         Add add = mock(Add.class);
         when(storage.createAdd(JmxNotificationDAOImpl.NOTIFICATIONS)).thenReturn(add);
@@ -86,23 +139,15 @@
     }
 
     @Test
-    public void testGetNotificationsForVmSince() {
-        final String AGENT_ID = "an-agent's-id";
-        HostRef host = mock(HostRef.class);
-        when(host.getAgentId()).thenReturn(AGENT_ID);
-
-        final int VM_ID = -1;
-        VmRef vm = mock(VmRef.class);
-        when(vm.getAgent()).thenReturn(host);
-        when(vm.getId()).thenReturn(VM_ID);
+    public void verifyGetNotificationsForVmSince() {
         long timeStamp = 10;
 
         JmxNotification data = mock(JmxNotification.class);
 
-        Query query = mock(Query.class);
+        Query<JmxNotification> query = mock(Query.class);
         when(storage.createQuery(JmxNotificationDAOImpl.NOTIFICATIONS)).thenReturn(query);
 
-        Cursor cursor = mock(Cursor.class);
+        Cursor<JmxNotification> cursor = mock(Cursor.class);
         when(cursor.hasNext()).thenReturn(true).thenReturn(false);
         when(cursor.next()).thenReturn(data).thenThrow(new AssertionError("not supposed to be called again"));