Mercurial > hg > release > thermostat-0.9
changeset 1097:e31208c2d0c8
Publish JMX notification status to storage
Reviewed-by: neugens
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-May/006659.html
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"));