changeset 886:e8357a536e22

Create Ordered interface, sort Backends by ordering This commit follows up on the addition of a ordering mechanism to sort views in the Swing GUI. Since there are potentially many cases where we want to order registered services when displaying information to the user, I have moved the ordering mechanism to an interface that can be used in each of these cases. The primary motivation for doing this is the Backends table that is shown in the Agent information window. Currently this only contains the System Backend, but subsequent commites will split this up creating several Backends. This ordering mechanism will allow us to display the Backends to the user in a predetermined order. Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-January/004974.html
author Elliott Baron <ebaron@redhat.com>
date Thu, 03 Jan 2013 16:49:53 -0500
parents 7c97a7125993
children 32045c272fcf
files agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java agent/core/src/main/java/com/redhat/thermostat/backend/Backend.java client/core/src/main/java/com/redhat/thermostat/client/core/InformationService.java client/core/src/main/java/com/redhat/thermostat/client/core/internal/InformationServiceComparator.java client/core/src/main/java/com/redhat/thermostat/client/ui/AgentInformationDisplayController.java client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java client/core/src/main/java/com/redhat/thermostat/client/ui/VmInformationController.java client/core/src/test/java/com/redhat/thermostat/client/core/internal/InformationServiceComparatorTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/HostInformationControllerTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/VmInformationControllerTest.java common/core/src/main/java/com/redhat/thermostat/common/Ordered.java common/core/src/main/java/com/redhat/thermostat/common/OrderedComparator.java common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java common/core/src/test/java/com/redhat/thermostat/common/OrderedComparatorTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/core/HostCpuService.java host-memory/client-core/src/main/java/com/redhat/thermostat/host/memory/client/core/HostMemoryService.java host-overview/client-core/src/main/java/com/redhat/thermostat/host/overview/client/core/HostOverviewService.java storage/core/src/main/java/com/redhat/thermostat/storage/model/BackendInformation.java system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationService.java vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/core/VmClassStatService.java vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/VmCpuService.java vm-gc/client-core/src/main/java/com/redhat/thermostat/vm/gc/client/core/VmGcService.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumperService.java vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/core/MemoryStatsService.java vm-overview/client-core/src/main/java/com/redhat/thermostat/vm/overview/client/core/VmOverviewService.java
diffstat 28 files changed, 353 insertions(+), 270 deletions(-) [+]
line wrap: on
line diff
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/Agent.java	Thu Jan 03 16:49:53 2013 -0500
@@ -179,6 +179,7 @@
         backendInfo.setObserveNewJvm(backend.getObserveNewJvm());
         backendInfo.setActive(true);
         backendInfo.setPids(new int[0]);
+        backendInfo.setOrderValue(backend.getOrderValue());
         
         return backendInfo;
     }
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/Backend.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/agent/core/src/main/java/com/redhat/thermostat/backend/Backend.java	Thu Jan 03 16:49:53 2013 -0500
@@ -41,6 +41,7 @@
 import java.util.Map.Entry;
 
 import com.redhat.thermostat.common.LaunchException;
+import com.redhat.thermostat.common.Ordered;
 import com.redhat.thermostat.common.dao.DAOFactory;
 import com.redhat.thermostat.storage.core.Storage;
 
@@ -48,11 +49,10 @@
  * Represents a plugin that runs on the agent and performs monitoring of host
  * and applications.
  */
-public abstract class Backend {
+public abstract class Backend implements Ordered {
 
     private boolean initialConfigurationComplete = false;
     protected DAOFactory df = null;
-    private Storage storage = null;
     private boolean observeNewJvm = attachToNewProcessByDefault();
 
     private String version;
@@ -89,7 +89,6 @@
 
     public final void setDAOFactory(DAOFactory df) {
         this.df = df;
-        this.storage = df.getStorage();
         setDAOFactoryAction();
     }
 
--- a/client/core/src/main/java/com/redhat/thermostat/client/core/InformationService.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/client/core/src/main/java/com/redhat/thermostat/client/core/InformationService.java	Thu Jan 03 16:49:53 2013 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Red Hat, Inc.
+ * Copyright 2013 Red Hat, Inc.
  *
  * This file is part of Thermostat.
  *
@@ -37,6 +37,7 @@
 package com.redhat.thermostat.client.core;
 
 import com.redhat.thermostat.client.core.controllers.InformationServiceController;
+import com.redhat.thermostat.common.Ordered;
 import com.redhat.thermostat.common.dao.Ref;
 
 
@@ -46,57 +47,9 @@
  * An {@code InformationService} provides some sort of information about
  * something. Plug-ins should normally implement this as a entry point.
  */
-public interface InformationService<T extends Ref> {
+public interface InformationService<T extends Ref> extends Ordered {
     
     /**
-     * Priority group for services that provide generic overview information
-     * about a Host or VM.
-     */
-    public static final int PRIORITY_DEFAULT_GROUP = 0;
-    /**
-     * Priority group for services that provide information about a Host
-     * or VM's CPU usage.
-     */
-    public static final int PRIORITY_CPU_GROUP = 100;
-    /**
-     * Priority group for services that provide information about a Host
-     * or VM's memory usage.
-     */
-    public static final int PRIORITY_MEMORY_GROUP = 200;
-    /**
-     * Priority group for services that provide information about a Host
-     * or VM's network usage.
-     */
-    public static final int PRIORITY_NETWORK_GROUP = 300;
-    /**
-     * Priority group for services that provide information about a Host
-     * or VM's I/O usage.
-     */
-    public static final int PRIORITY_IO_GROUP = 400;
-    /**
-     * Priority group for services that provide information about a Host
-     * or VM's threads.
-     */
-    public static final int PRIORITY_THREAD_GROUP = 500;
-    /**
-     * Priority group for user-defined services. This should always be
-     * the last priority group.
-     */
-    public static final int PRIORITY_USER_GROUP = 5000;
-
-    /**
-     * Defines a priority to be used for assigning an order to
-     * InformationServices. A service with a lower-valued priority will
-     * be processed before a service of a higher-valued priority. This
-     * ordering is used, for example, to sort views in a client's UI.
-     * 
-     * The priority value should be offset from one of the provided
-     * constants in this class. Such as {@link #PRIORITY_DEFAULT_GROUP}.
-     * @return the priority value
-     */
-    public int getPriority();
-
-    /**
      * Returns a {@link Filter} that is used to determine if this information
      * source can provide information for a given target.
      */
--- a/client/core/src/main/java/com/redhat/thermostat/client/core/internal/InformationServiceComparator.java	Thu Jan 03 10:23:48 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +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.core.internal;
-
-import java.util.Comparator;
-
-import com.redhat.thermostat.client.core.InformationService;
-
-@SuppressWarnings("rawtypes")
-public class InformationServiceComparator<T extends InformationService>
-        implements Comparator<T> {
-
-    @Override
-    public int compare(T o1, T o2) {
-        int result = o1.getPriority() - o2.getPriority();
-        // Break ties using class name
-        if (result == 0) {
-            result = getName(o1).compareTo(getName(o2));
-        }
-        return result;
-    }
-    
-    /*
-     * Extracted for testing purposes.
-     */
-    String getName(T object) {
-        return object.getClass().getName();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/AgentInformationDisplayController.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/AgentInformationDisplayController.java	Thu Jan 03 16:49:53 2013 -0500
@@ -39,7 +39,7 @@
 import java.text.DateFormat;
 import java.util.Collection;
 import java.util.Date;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
@@ -137,7 +137,8 @@
             view.setSelectedAgentStopTime(translator.localize(LocaleResources.AGENT_INFO_AGENT_RUNNING));
         }
 
-        Map<String, String> map = new HashMap<>();
+        // Linked to enforce order
+        Map<String, String> map = new LinkedHashMap<>();
         for (BackendInformation backendInfo : model.getBackends(agentId)) {
             String status = backendInfo.isActive() ?
                     translator.localize(LocaleResources.AGENT_INFO_BACKEND_STATUS_ACTIVE)
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java	Thu Jan 03 16:49:53 2013 -0500
@@ -41,10 +41,10 @@
 
 import com.redhat.thermostat.client.core.InformationService;
 import com.redhat.thermostat.client.core.controllers.InformationServiceController;
-import com.redhat.thermostat.client.core.internal.InformationServiceComparator;
 import com.redhat.thermostat.client.core.views.BasicView;
 import com.redhat.thermostat.client.core.views.HostInformationView;
 import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
+import com.redhat.thermostat.common.OrderedComparator;
 import com.redhat.thermostat.common.dao.HostRef;
 
 public class HostInformationController {
@@ -55,7 +55,7 @@
         view = provider.createView();
 
         List<InformationService<HostRef>> hostInfoServices = uiFacadeFactory.getHostInformationServices();
-        Collections.sort(hostInfoServices, new InformationServiceComparator<InformationService<HostRef>>());
+        Collections.sort(hostInfoServices, new OrderedComparator<InformationService<HostRef>>());
         for (InformationService<HostRef> hostInfoService : hostInfoServices) {
             if (hostInfoService.getFilter().matches(ref)) {
                 InformationServiceController<HostRef> ctrl = hostInfoService.getInformationServiceController(ref);
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmInformationController.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/VmInformationController.java	Thu Jan 03 16:49:53 2013 -0500
@@ -41,10 +41,10 @@
 
 import com.redhat.thermostat.client.core.InformationService;
 import com.redhat.thermostat.client.core.controllers.InformationServiceController;
-import com.redhat.thermostat.client.core.internal.InformationServiceComparator;
 import com.redhat.thermostat.client.core.views.BasicView;
 import com.redhat.thermostat.client.core.views.VmInformationView;
 import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
+import com.redhat.thermostat.common.OrderedComparator;
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.common.utils.OSGIUtils;
 
@@ -60,7 +60,7 @@
         view = provider.createView();
 
         List<InformationService<VmRef>> vmInfoServices = uiFacadeFactory.getVmInformationServices();
-        Collections.sort(vmInfoServices, new InformationServiceComparator<InformationService<VmRef>>());
+        Collections.sort(vmInfoServices, new OrderedComparator<InformationService<VmRef>>());
         for (InformationService<VmRef> vmInfoService : vmInfoServices) {
             if (vmInfoService.getFilter().matches(vmRef)) {
                 InformationServiceController<VmRef> ctrl = vmInfoService.getInformationServiceController(vmRef);
--- a/client/core/src/test/java/com/redhat/thermostat/client/core/internal/InformationServiceComparatorTest.java	Thu Jan 03 10:23:48 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +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.core.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.client.core.InformationService;
-
-public class InformationServiceComparatorTest {
-
-    @Test
-    public void testServiceOrderTie() {
-        int[] priorities = { 45, 20, 0, 90, 20 };
-
-        final List<InformationService> services = mockServices(priorities);
-        
-        // Override the getName method to give predetermined class names to
-        // the services with equal priority
-        InformationServiceComparator<InformationService> comparator = new InformationServiceComparator<InformationService>() {
-            @Override
-            String getName(InformationService object) {
-                String result;
-                if (object.equals(services.get(1))) {
-                    result = "TheirService";
-                }
-                else if (object.equals(services.get(4))) {
-                    result = "MyService";
-                }
-                else {
-                    result = super.getName(object); 
-                }
-                return result;
-            }
-        };
-        
-        List<InformationService> sorted = new ArrayList<>(services);
-        Collections.sort(sorted, comparator);
-        
-        // Ensure MyService comes before TheirService
-        assertEquals(services.get(2), sorted.get(0));
-        assertEquals(services.get(4), sorted.get(1));
-        assertEquals(services.get(1), sorted.get(2));
-        assertEquals(services.get(0), sorted.get(3));
-        assertEquals(services.get(3), sorted.get(4));
-    }
-
-    private List<InformationService> mockServices(int[] priorities) {
-        List<InformationService> services = new ArrayList<>();
-        for (int priority : priorities) {
-            InformationService service = mock(InformationService.class);
-            when(service.getPriority()).thenReturn(priority);
-            services.add(service);
-        }
-        return services;
-    }
-
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/HostInformationControllerTest.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/HostInformationControllerTest.java	Thu Jan 03 16:49:53 2013 -0500
@@ -75,10 +75,10 @@
 
     @Test
     public void testServiceOrder() {
-        int[] priorities = { 45, 20, 0, 90, 53 };
+        int[] orderValues = { 45, 20, 0, 90, 53 };
 
         // Mock services
-        List<InformationService<HostRef>> services = mockServices(priorities);
+        List<InformationService<HostRef>> services = mockServices(orderValues);
 
         new HostInformationController(uiFacadeFactory, ref, provider);
 
@@ -91,15 +91,15 @@
         verifyService(services.get(3), order);
     }
 
-    private List<InformationService<HostRef>> mockServices(int[] priorities) {
+    private List<InformationService<HostRef>> mockServices(int[] orderValues) {
         List<InformationService<HostRef>> services = new ArrayList<>();
-        for (int priority : priorities) {
+        for (int order : orderValues) {
             InformationService<HostRef> service = mock(InformationService.class);
             InformationServiceController<HostRef> controller = mock(InformationServiceController.class);
             when(service.getFilter()).thenReturn(FILTER);
             when(service.getInformationServiceController(ref)).thenReturn(
                     controller);
-            when(service.getPriority()).thenReturn(priority);
+            when(service.getOrderValue()).thenReturn(order);
             services.add(service);
         }
         // Return copy
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/VmInformationControllerTest.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/VmInformationControllerTest.java	Thu Jan 03 16:49:53 2013 -0500
@@ -75,10 +75,10 @@
 
     @Test
     public void testServiceOrder() {
-        int[] priorities = { 45, 20, 0, 90, 53 };
+        int[] orderValues = { 45, 20, 0, 90, 53 };
 
         // Mock services
-        List<InformationService<VmRef>> services = mockServices(priorities);
+        List<InformationService<VmRef>> services = mockServices(orderValues);
 
         new VmInformationController(uiFacadeFactory, ref, provider);
 
@@ -91,15 +91,15 @@
         verifyService(services.get(3), order);
     }
 
-    private List<InformationService<VmRef>> mockServices(int[] priorities) {
+    private List<InformationService<VmRef>> mockServices(int[] orderValues) {
         List<InformationService<VmRef>> services = new ArrayList<>();
-        for (int priority : priorities) {
+        for (int order : orderValues) {
             InformationService<VmRef> service = mock(InformationService.class);
             InformationServiceController<VmRef> controller = mock(InformationServiceController.class);
             when(service.getFilter()).thenReturn(FILTER);
             when(service.getInformationServiceController(ref)).thenReturn(
                     controller);
-            when(service.getPriority()).thenReturn(priority);
+            when(service.getOrderValue()).thenReturn(order);
             services.add(service);
         }
         // Return copy
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/Ordered.java	Thu Jan 03 16:49:53 2013 -0500
@@ -0,0 +1,93 @@
+/*
+ * Copyright 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.common;
+
+/**
+ * This interface defines a standard way for Thermostat plug-ins to specify
+ * an ordering for their services in relation to others of the same type.
+ */
+public interface Ordered {
+    
+    /**
+     * Order group for services that provide generic overview information
+     * about a Host or VM.
+     */
+    public static final int ORDER_DEFAULT_GROUP = 0;
+    /**
+     * Order group for services that provide information about a Host
+     * or VM's CPU usage.
+     */
+    public static final int ORDER_CPU_GROUP = 100;
+    /**
+     * Order group for services that provide information about a Host
+     * or VM's memory usage.
+     */
+    public static final int ORDER_MEMORY_GROUP = 200;
+    /**
+     * Order group for services that provide information about a Host
+     * or VM's network usage.
+     */
+    public static final int ORDER_NETWORK_GROUP = 300;
+    /**
+     * Order group for services that provide information about a Host
+     * or VM's I/O usage.
+     */
+    public static final int ORDER_IO_GROUP = 400;
+    /**
+     * Order group for services that provide information about a Host
+     * or VM's threads.
+     */
+    public static final int ORDER_THREAD_GROUP = 500;
+    /**
+     * Order group for user-defined services. This should always be
+     * the last order group.
+     */
+    public static final int ORDER_USER_GROUP = 5000;
+
+    /**
+     * Defines a value to be used for assigning an order to
+     * services. A service with a lower order value will
+     * be processed before a service of a higher order value. This
+     * ordering is used, for example, to sort views in a client's UI.
+     * 
+     * The order value should be offset from one of the provided
+     * constants in this class. Such as {@link #ORDER_DEFAULT_GROUP}.
+     * @return the order value
+     */
+    public int getOrderValue();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/OrderedComparator.java	Thu Jan 03 16:49:53 2013 -0500
@@ -0,0 +1,61 @@
+/*
+ * Copyright 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.common;
+
+import java.util.Comparator;
+
+
+public class OrderedComparator<T extends Ordered> implements Comparator<T> {
+
+    @Override
+    public int compare(T o1, T o2) {
+        int result = o1.getOrderValue() - o2.getOrderValue();
+        // Break ties using class name
+        if (result == 0) {
+            result = getName(o1).compareTo(getName(o2));
+        }
+        return result;
+    }
+    
+    /*
+     * Extracted for testing purposes.
+     */
+    String getName(T object) {
+        return object.getClass().getName();
+    }
+
+}
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAO.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAO.java	Thu Jan 03 16:49:53 2013 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Red Hat, Inc.
+ * Copyright 2013 Red Hat, Inc.
  *
  * This file is part of Thermostat.
  *
@@ -49,6 +49,7 @@
     static final Key<Boolean> IS_ACTIVE = new Key<>("active", false);
     static final Key<Boolean> SHOULD_MONITOR_NEW_PROCESSES = new Key<>("observeNewJvm", false);
     static final Key<List<Integer>> PIDS_TO_MONITOR = new Key<>("pids", false);
+    static final Key<Integer> ORDER_VALUE = new Key<>("orderValue", false);
 
     static final Category CATEGORY = new Category("backend-info",
             Key.AGENT_ID,
@@ -56,7 +57,8 @@
             BACKEND_DESCRIPTION,
             IS_ACTIVE,
             SHOULD_MONITOR_NEW_PROCESSES,
-            PIDS_TO_MONITOR);
+            PIDS_TO_MONITOR,
+            ORDER_VALUE);
 
     List<BackendInformation> getBackendInformation(HostRef host);
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/BackendInfoDAOImpl.java	Thu Jan 03 16:49:53 2013 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Red Hat, Inc.
+ * Copyright 2013 Red Hat, Inc.
  *
  * This file is part of Thermostat.
  *
@@ -37,14 +37,16 @@
 package com.redhat.thermostat.common.dao;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 import com.redhat.thermostat.storage.core.Cursor;
 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.Remove;
 import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Query.Criteria;
 import com.redhat.thermostat.storage.model.BackendInformation;
 
 public class BackendInfoDAOImpl implements BackendInfoDAO {
@@ -58,6 +60,7 @@
 
     @Override
     public List<BackendInformation> getBackendInformation(HostRef host) {
+        // Sort by order value
         Query query = storage.createQuery()
                 .from(CATEGORY)
                 .where(Key.AGENT_ID, Criteria.EQUALS, host.getAgentId());
@@ -68,6 +71,23 @@
             BackendInformation backendInfo = cursor.next();
             results.add(backendInfo);
         }
+        
+        // Sort before returning
+        Collections.sort(results, new Comparator<BackendInformation>() {
+
+            // TODO Use OrderedComparator when common-core
+            // doesn't depend on storage-core
+            @Override
+            public int compare(BackendInformation o1, BackendInformation o2) {
+                int result = o1.getOrderValue() - o2.getOrderValue();
+                // Break ties using class name
+                if (result == 0) {
+                    result = o1.getClass().getName().compareTo(o2.getClass().getName());
+                }
+                return result;
+            }
+        });
+        
         return results;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/OrderedComparatorTest.java	Thu Jan 03 16:49:53 2013 -0500
@@ -0,0 +1,97 @@
+/*
+ * Copyright 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.common;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+public class OrderedComparatorTest {
+
+    @Test
+    public void testServiceOrderTie() {
+        int[] orderValues = { 45, 20, 0, 90, 20 };
+
+        final List<Ordered> services = mockServices(orderValues);
+        
+        // Override the getName method to give predetermined class names to
+        // the services with equal order value
+        OrderedComparator<Ordered> comparator = new OrderedComparator<Ordered>() {
+            @Override
+            String getName(Ordered object) {
+                String result;
+                if (object.equals(services.get(1))) {
+                    result = "TheirService";
+                }
+                else if (object.equals(services.get(4))) {
+                    result = "MyService";
+                }
+                else {
+                    result = super.getName(object); 
+                }
+                return result;
+            }
+        };
+        
+        List<Ordered> sorted = new ArrayList<>(services);
+        Collections.sort(sorted, comparator);
+        
+        // Ensure MyService comes before TheirService
+        assertEquals(services.get(2), sorted.get(0));
+        assertEquals(services.get(4), sorted.get(1));
+        assertEquals(services.get(1), sorted.get(2));
+        assertEquals(services.get(0), sorted.get(3));
+        assertEquals(services.get(3), sorted.get(4));
+    }
+
+    private List<Ordered> mockServices(int[] orderValues) {
+        List<Ordered> services = new ArrayList<>();
+        for (int value : orderValues) {
+            Ordered service = mock(Ordered.class);
+            when(service.getOrderValue()).thenReturn(value);
+            services.add(service);
+        }
+        return services;
+    }
+
+}
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/BackendInfoDAOTest.java	Thu Jan 03 16:49:53 2013 -0500
@@ -75,6 +75,7 @@
         backendInfo1.setActive(true);
         backendInfo1.setObserveNewJvm(true);
         backendInfo1.setPids(new int[] { -1, 0, 1});
+        backendInfo1.setOrderValue(100);
 
         backend1 = new BackendInformation();
         backend1.setName("backend-name");
@@ -82,7 +83,7 @@
         backend1.setActive(true);
         backend1.setObserveNewJvm(true);
         backend1.setPids(new int[] { -1, 0, 1});
-        
+        backend1.setOrderValue(100);
     }
 
     @Test
@@ -102,6 +103,7 @@
         assertTrue(keys.contains(BackendInfoDAO.IS_ACTIVE));
         assertTrue(keys.contains(BackendInfoDAO.PIDS_TO_MONITOR));
         assertTrue(keys.contains(BackendInfoDAO.SHOULD_MONITOR_NEW_PROCESSES));
+        assertTrue(keys.contains(BackendInfoDAO.ORDER_VALUE));
     }
 
     @Test
--- a/host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/core/HostCpuService.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/core/HostCpuService.java	Thu Jan 03 16:49:53 2013 -0500
@@ -49,7 +49,7 @@
 
 public class HostCpuService implements InformationService<HostRef> {
     
-    private static final int PRIORITY = PRIORITY_CPU_GROUP;
+    private static final int ORDER = ORDER_CPU_GROUP;
     private static final Filter<HostRef> FILTER = new NameMatchingRefFilter<>();
 
     private ApplicationService appSvc;
@@ -75,8 +75,8 @@
     }
 
     @Override
-    public int getPriority() {
-        return PRIORITY;
+    public int getOrderValue() {
+        return ORDER;
     }
 
 }
--- a/host-memory/client-core/src/main/java/com/redhat/thermostat/host/memory/client/core/HostMemoryService.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/host-memory/client-core/src/main/java/com/redhat/thermostat/host/memory/client/core/HostMemoryService.java	Thu Jan 03 16:49:53 2013 -0500
@@ -49,7 +49,7 @@
 
 public class HostMemoryService implements InformationService<HostRef> {
     
-    private static final int PRIORITY = PRIORITY_MEMORY_GROUP;
+    private static final int ORDER = ORDER_MEMORY_GROUP;
     private static final Filter<HostRef> FILTER = new NameMatchingRefFilter<>();
 
     private ApplicationService appSvc;
@@ -75,8 +75,8 @@
     }
 
     @Override
-    public int getPriority() {
-        return PRIORITY;
+    public int getOrderValue() {
+        return ORDER;
     }
 
 }
--- a/host-overview/client-core/src/main/java/com/redhat/thermostat/host/overview/client/core/HostOverviewService.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/host-overview/client-core/src/main/java/com/redhat/thermostat/host/overview/client/core/HostOverviewService.java	Thu Jan 03 16:49:53 2013 -0500
@@ -49,7 +49,7 @@
 
 public class HostOverviewService implements InformationService<HostRef> {
     
-    private static final int PRIORITY = PRIORITY_DEFAULT_GROUP;
+    private static final int ORDER = ORDER_DEFAULT_GROUP;
     private static final Filter<HostRef> FILTER = new NameMatchingRefFilter<>();
 
     private ApplicationService appSvc;
@@ -75,8 +75,8 @@
     }
 
     @Override
-    public int getPriority() {
-        return PRIORITY;
+    public int getOrderValue() {
+        return ORDER;
     }
 
 }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/model/BackendInformation.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/model/BackendInformation.java	Thu Jan 03 16:49:53 2013 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Red Hat, Inc.
+ * Copyright 2013 Red Hat, Inc.
  *
  * This file is part of Thermostat.
  *
@@ -52,6 +52,7 @@
     private boolean isActive;
     private boolean observeNewJvm;
     private int[] pids;
+    private int orderValue;
     private Map<String, String> configuration = new HashMap<String,String>();
 
     @Persist
@@ -107,6 +108,16 @@
     public void setActive(boolean active) {
         this.isActive = active;
     }
+    
+    @Persist
+    public int getOrderValue() {
+        return orderValue;
+    }
+    
+    @Persist
+    public void setOrderValue(int orderValue) {
+        this.orderValue = orderValue;
+    }
 
     @Override
     public boolean equals(Object obj) {
@@ -125,12 +136,13 @@
                 Objects.equals(this.configuration, other.configuration) &&
                 Objects.equals(this.isActive, other.isActive) &&
                 Objects.equals(this.observeNewJvm, other.observeNewJvm) &&
-                Arrays.equals(this.pids, other.pids);
+                Arrays.equals(this.pids, other.pids) &&
+                Objects.equals(this.orderValue, other.orderValue);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(name, description, configuration, isActive, observeNewJvm, pids);
+        return Objects.hash(name, description, configuration, isActive, observeNewJvm, pids, orderValue);
     }
 
 }
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Thu Jan 03 16:49:53 2013 -0500
@@ -238,4 +238,9 @@
         pidsToMonitor.remove(vmId);
         vmCpuBuilder.forgetAbout(vmId);
     }
+
+    @Override
+    public int getOrderValue() {
+        return ORDER_DEFAULT_GROUP;
+    }
 }
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationService.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationService.java	Thu Jan 03 16:49:53 2013 -0500
@@ -48,7 +48,7 @@
 
 public class ThreadInformationService implements InformationService<VmRef> {
 
-    private static final int PRIORITY = PRIORITY_THREAD_GROUP;
+    private static final int ORDER = ORDER_THREAD_GROUP;
     
     private Filter<VmRef> filter = new NameMatchingRefFilter<>();
     private ApplicationService service;
@@ -77,8 +77,8 @@
     }
 
     @Override
-    public int getPriority() {
-        return PRIORITY;
+    public int getOrderValue() {
+        return ORDER;
     }
 
 }
--- a/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/core/VmClassStatService.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/vm-classstat/client-core/src/main/java/com/redhat/thermostat/vm/classstat/client/core/VmClassStatService.java	Thu Jan 03 16:49:53 2013 -0500
@@ -48,7 +48,7 @@
 
 public class VmClassStatService implements InformationService<VmRef> {
 
-    private static final int PRIORITY = PRIORITY_MEMORY_GROUP + 20;
+    private static final int ORDER = ORDER_MEMORY_GROUP + 20;
     private Filter<VmRef> filter = new NameMatchingRefFilter<>();
 
     private ApplicationService appSvc;
@@ -71,7 +71,7 @@
     }
 
     @Override
-    public int getPriority() {
-        return PRIORITY;
+    public int getOrderValue() {
+        return ORDER;
     }
 }
--- a/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/VmCpuService.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/VmCpuService.java	Thu Jan 03 16:49:53 2013 -0500
@@ -48,7 +48,7 @@
 
 public class VmCpuService implements InformationService<VmRef> {
     
-    private static final int PRIORITY = PRIORITY_CPU_GROUP;
+    private static final int ORDER = ORDER_CPU_GROUP;
     private static final Filter<VmRef> FILTER = new NameMatchingRefFilter<>();
 
     private ApplicationService appSvc;
@@ -72,8 +72,8 @@
     }
 
     @Override
-    public int getPriority() {
-        return PRIORITY;
+    public int getOrderValue() {
+        return ORDER;
     }
 
 }
--- a/vm-gc/client-core/src/main/java/com/redhat/thermostat/vm/gc/client/core/VmGcService.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/vm-gc/client-core/src/main/java/com/redhat/thermostat/vm/gc/client/core/VmGcService.java	Thu Jan 03 16:49:53 2013 -0500
@@ -49,7 +49,7 @@
 
 public class VmGcService implements InformationService<VmRef> {
     
-    private static final int PRIORITY = PRIORITY_MEMORY_GROUP;
+    private static final int ORDER = ORDER_MEMORY_GROUP;
     private static final Filter<VmRef> FILTER = new NameMatchingRefFilter<>();
 
     private ApplicationService appSvc;
@@ -75,8 +75,8 @@
     }
 
     @Override
-    public int getPriority() {
-        return PRIORITY;
+    public int getOrderValue() {
+        return ORDER;
     }
 
 }
--- a/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumperService.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumperService.java	Thu Jan 03 16:49:53 2013 -0500
@@ -49,7 +49,7 @@
 
 public class HeapDumperService implements InformationService<VmRef> {
     
-    private static final int PRIORITY = PRIORITY_MEMORY_GROUP + 60;
+    private static final int ORDER = ORDER_MEMORY_GROUP + 60;
     private ApplicationService appService;
     private VmMemoryStatDAO vmMemoryStatDao;
     private HeapDAO heapDao;
@@ -78,7 +78,7 @@
     }
 
     @Override
-    public int getPriority() {
-        return PRIORITY;
+    public int getOrderValue() {
+        return ORDER;
     }
 }
--- a/vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/core/MemoryStatsService.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/vm-memory/client-core/src/main/java/com/redhat/thermostat/vm/memory/client/core/MemoryStatsService.java	Thu Jan 03 16:49:53 2013 -0500
@@ -51,7 +51,7 @@
 
 public class MemoryStatsService implements InformationService<VmRef> {
     
-    private static final int PRIORITY = PRIORITY_MEMORY_GROUP + 40;
+    private static final int ORDER = ORDER_MEMORY_GROUP + 40;
     private Filter<VmRef> filter = new NameMatchingRefFilter<>();
 
     private ApplicationService appSvc;
@@ -80,7 +80,7 @@
     }
 
     @Override
-    public int getPriority() {
-        return PRIORITY;
+    public int getOrderValue() {
+        return ORDER;
     }
 }
--- a/vm-overview/client-core/src/main/java/com/redhat/thermostat/vm/overview/client/core/VmOverviewService.java	Thu Jan 03 10:23:48 2013 -0500
+++ b/vm-overview/client-core/src/main/java/com/redhat/thermostat/vm/overview/client/core/VmOverviewService.java	Thu Jan 03 16:49:53 2013 -0500
@@ -48,7 +48,7 @@
 
 public class VmOverviewService implements InformationService<VmRef> {
     
-    private static final int PRIORITY = PRIORITY_DEFAULT_GROUP;
+    private static final int ORDER = ORDER_DEFAULT_GROUP;
     private static final Filter<VmRef> FILTER = new NameMatchingRefFilter<>();
 
     private ApplicationService appSvc;
@@ -72,8 +72,8 @@
     }
 
     @Override
-    public int getPriority() {
-        return PRIORITY;
+    public int getOrderValue() {
+        return ORDER;
     }
 
 }