Repository: pinpoint-apm/pinpoint
Issue: Sort agent ids in containers by start timestamp in descending order
Labels: enhancement
module:web

#### Description
Sort container agent ids in Inspector View's agent list by their start timestamp in descending order.

Issue comments:

Pull request review comments:

Patch that resolved the issue:
diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsList.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsList.java
index 62529b25c1bc..2b12a9184c02 100644
--- a/web/src/main/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsList.java
+++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsList.java
@@ -22,6 +22,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -41,17 +42,48 @@ public enum GroupBy {
             protected GroupingKey extractKey(AgentInfo agentInfo) {
                 return new StringGroupingKey(agentInfo.getApplicationName());
             }
+
+            @Override
+            protected Comparator<AgentInfo> getComparator() {
+                return AgentInfo.AGENT_NAME_ASC_COMPARATOR;
+            }
         },
         HOST_NAME {
             @Override
             protected GroupingKey extractKey(AgentInfo agentInfo) {
                 return new HostNameContainerGroupingKey(agentInfo.getHostName(), agentInfo.isContainer());
             }
+
+            @Override
+            protected Comparator<AgentInfo> getComparator() {
+                return (agentInfo1, agentInfo2) -> {
+                    if (agentInfo1.isContainer() && agentInfo2.isContainer()) {
+                        // reverse start time order if both are containers
+                        return Long.compare(agentInfo2.getStartTimestamp(), agentInfo1.getStartTimestamp());
+                    }
+                    if (agentInfo1.isContainer()) {
+                        return -1;
+                    }
+                    if (agentInfo2.isContainer()) {
+                        return 1;
+                    }
+                    // agent id order if both are not containers
+                    return AgentInfo.AGENT_NAME_ASC_COMPARATOR.compare(agentInfo1, agentInfo2);
+                };
+            }
         };
 
         protected abstract GroupingKey extractKey(AgentInfo agentInfo);
+
+        /**
+         * Do not use this for sorted set and maps.
+         */
+        protected abstract Comparator<AgentInfo> getComparator();
     }
 
+    /**
+     * Implementations not consistent with <code>equals</code>, for internal use only.
+     */
     private interface GroupingKey<T extends GroupingKey<T>> extends Comparable<T> {
         String value();
     }
@@ -104,7 +136,7 @@ public List<ApplicationAgentList> getApplicationAgentLists() {
         for (Map.Entry<GroupingKey, List<AgentInfo>> e : agentsMap.entrySet()) {
             GroupingKey groupingKey = e.getKey();
             List<AgentInfo> applicationAgents = new ArrayList<>(e.getValue());
-            applicationAgents.sort(AgentInfo.AGENT_NAME_ASC_COMPARATOR);
+            applicationAgents.sort(groupBy.getComparator());
             applicationAgentLists.add(new ApplicationAgentList(groupingKey.value(), applicationAgents));
         }
         return applicationAgentLists;
@@ -175,10 +207,10 @@ public int compareTo(HostNameContainerGroupingKey o) {
                 return 0;
             }
             if (isContainer) {
-                return 1;
+                return -1;
             }
             if (o.isContainer) {
-                return -1;
+                return 1;
             }
             return hostNameGroupingKey.compareTo(o.hostNameGroupingKey);
         }


Test patch:
diff --git a/web/src/test/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsListTest.java b/web/src/test/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsListTest.java
index db813b604f05..a05f62b51b1b 100644
--- a/web/src/test/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsListTest.java
+++ b/web/src/test/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsListTest.java
@@ -57,44 +57,44 @@ public void groupByApplicationName() {
     }
 
     @Test
-    public void groupByHostNameShouldHaveContainersLastAndGroupedSeparately() {
+    public void groupByHostNameShouldHaveContainersFirstAndGroupedSeparatelyByAgentStartTimestampDescendingOrder() {
         ApplicationAgentsList applicationAgentsList = new ApplicationAgentsList(ApplicationAgentsList.GroupBy.HOST_NAME, ApplicationAgentsList.Filter.NONE);
         AgentInfo host1Agent1 = createAgentInfo("APP_1", "host1-agent1", "Host1", false);
         AgentInfo host2Agent1 = createAgentInfo("APP_1", "host2-agent1", "Host2", false);
-        AgentInfo containerAgent1 = createAgentInfo("APP_1", "container-agent1", "Host3", true);
-        AgentInfo containerAgent2 = createAgentInfo("APP_1", "container-agent2", "Host4", true);
+        AgentInfo containerAgent1 = createAgentInfo("APP_1", "container-agent1", "Host3", true, 1);
+        AgentInfo containerAgent2 = createAgentInfo("APP_1", "container-agent2", "Host4", true, 2);
         applicationAgentsList.addAll(shuffleAgentInfos(containerAgent1, host1Agent1, host2Agent1, containerAgent2));
 
         List<ApplicationAgentList> applicationAgentLists = applicationAgentsList.getApplicationAgentLists();
 
         Assert.assertEquals(3, applicationAgentLists.size());
 
-        ApplicationAgentList host1AgentList = applicationAgentLists.get(0);
+        ApplicationAgentList containerAgentList = applicationAgentLists.get(0);
+        Assert.assertEquals(ApplicationAgentsList.HostNameContainerGroupingKey.CONTAINER, containerAgentList.getGroupName());
+        List<AgentInfo> containerAgents = containerAgentList.getAgentInfos();
+        Assert.assertEquals(2, containerAgents.size());
+        Assert.assertEquals(containerAgent2, containerAgents.get(0));
+        Assert.assertEquals(containerAgent1, containerAgents.get(1));
+
+        ApplicationAgentList host1AgentList = applicationAgentLists.get(1);
         Assert.assertEquals("Host1", host1AgentList.getGroupName());
         List<AgentInfo> host1Agents = host1AgentList.getAgentInfos();
         Assert.assertEquals(1, host1Agents.size());
         Assert.assertEquals(host1Agent1, host1Agents.get(0));
 
-        ApplicationAgentList host2AgentList = applicationAgentLists.get(1);
+        ApplicationAgentList host2AgentList = applicationAgentLists.get(2);
         Assert.assertEquals("Host2", host2AgentList.getGroupName());
         List<AgentInfo> host2Agents = host2AgentList.getAgentInfos();
         Assert.assertEquals(1, host2Agents.size());
         Assert.assertEquals(host2Agent1, host2Agents.get(0));
-
-        ApplicationAgentList containerAgentList = applicationAgentLists.get(2);
-        Assert.assertEquals(ApplicationAgentsList.HostNameContainerGroupingKey.CONTAINER, containerAgentList.getGroupName());
-        List<AgentInfo> containerAgents = containerAgentList.getAgentInfos();
-        Assert.assertEquals(2, containerAgents.size());
-        Assert.assertEquals(containerAgent1, containerAgents.get(0));
-        Assert.assertEquals(containerAgent2, containerAgents.get(1));
     }
 
     @Test
     public void mergeLists() {
         AgentInfo host1Agent1 = createAgentInfo("APP_1", "host1-agent1", "Host1", false);
         AgentInfo host2Agent1 = createAgentInfo("APP_1", "host2-agent1", "Host2", false);
-        AgentInfo containerAgent1 = createAgentInfo("APP_1", "container-agent1", "Host3", true);
-        AgentInfo containerAgent2 = createAgentInfo("APP_1", "container-agent2", "Host4", true);
+        AgentInfo containerAgent1 = createAgentInfo("APP_1", "container-agent1", "Host3", true, 1);
+        AgentInfo containerAgent2 = createAgentInfo("APP_1", "container-agent2", "Host4", true, 2);
         List<AgentInfo> agentInfos = shuffleAgentInfos(containerAgent1, host1Agent1, host2Agent1, containerAgent2);
 
         ApplicationAgentsList applicationAgentsList = new ApplicationAgentsList(ApplicationAgentsList.GroupBy.HOST_NAME, ApplicationAgentsList.Filter.NONE);
@@ -107,24 +107,24 @@ public void mergeLists() {
 
         Assert.assertEquals(3, applicationAgentLists.size());
 
-        ApplicationAgentList host1AgentList = applicationAgentLists.get(0);
+        ApplicationAgentList containerAgentList = applicationAgentLists.get(0);
+        Assert.assertEquals(ApplicationAgentsList.HostNameContainerGroupingKey.CONTAINER, containerAgentList.getGroupName());
+        List<AgentInfo> containerAgents = containerAgentList.getAgentInfos();
+        Assert.assertEquals(2, containerAgents.size());
+        Assert.assertEquals(containerAgent2, containerAgents.get(0));
+        Assert.assertEquals(containerAgent1, containerAgents.get(1));
+
+        ApplicationAgentList host1AgentList = applicationAgentLists.get(1);
         Assert.assertEquals("Host1", host1AgentList.getGroupName());
         List<AgentInfo> host1Agents = host1AgentList.getAgentInfos();
         Assert.assertEquals(1, host1Agents.size());
         Assert.assertEquals(host1Agent1, host1Agents.get(0));
 
-        ApplicationAgentList host2AgentList = applicationAgentLists.get(1);
+        ApplicationAgentList host2AgentList = applicationAgentLists.get(2);
         Assert.assertEquals("Host2", host2AgentList.getGroupName());
         List<AgentInfo> host2Agents = host2AgentList.getAgentInfos();
         Assert.assertEquals(1, host2Agents.size());
         Assert.assertEquals(host2Agent1, host2Agents.get(0));
-
-        ApplicationAgentList containerAgentList = applicationAgentLists.get(2);
-        Assert.assertEquals(ApplicationAgentsList.HostNameContainerGroupingKey.CONTAINER, containerAgentList.getGroupName());
-        List<AgentInfo> containerAgents = containerAgentList.getAgentInfos();
-        Assert.assertEquals(2, containerAgents.size());
-        Assert.assertEquals(containerAgent1, containerAgents.get(0));
-        Assert.assertEquals(containerAgent2, containerAgents.get(1));
     }
 
     @Test
@@ -143,23 +143,23 @@ public void mergeListsGroupedDifferently() {
 
         Assert.assertEquals(3, applicationAgentLists.size());
 
-        ApplicationAgentList host1AgentList = applicationAgentLists.get(0);
+        ApplicationAgentList containerAgentList = applicationAgentLists.get(0);
+        Assert.assertEquals(ApplicationAgentsList.HostNameContainerGroupingKey.CONTAINER, containerAgentList.getGroupName());
+        List<AgentInfo> containerAgents = containerAgentList.getAgentInfos();
+        Assert.assertEquals(1, containerAgents.size());
+        Assert.assertEquals(agent3, containerAgents.get(0));
+
+        ApplicationAgentList host1AgentList = applicationAgentLists.get(1);
         Assert.assertEquals("Host1", host1AgentList.getGroupName());
         List<AgentInfo> host1Agents = host1AgentList.getAgentInfos();
         Assert.assertEquals(1, host1Agents.size());
         Assert.assertEquals(agent1, host1Agents.get(0));
 
-        ApplicationAgentList host2AgentList = applicationAgentLists.get(1);
+        ApplicationAgentList host2AgentList = applicationAgentLists.get(2);
         Assert.assertEquals("Host2", host2AgentList.getGroupName());
         List<AgentInfo> host2Agents = host2AgentList.getAgentInfos();
         Assert.assertEquals(1, host2Agents.size());
         Assert.assertEquals(agent2, host2Agents.get(0));
-
-        ApplicationAgentList containerAgentList = applicationAgentLists.get(2);
-        Assert.assertEquals(ApplicationAgentsList.HostNameContainerGroupingKey.CONTAINER, containerAgentList.getGroupName());
-        List<AgentInfo> containerAgents = containerAgentList.getAgentInfos();
-        Assert.assertEquals(1, containerAgents.size());
-        Assert.assertEquals(agent3, containerAgents.get(0));
     }
 
     private static List<AgentInfo> shuffleAgentInfos(AgentInfo... agentInfos) {
@@ -169,11 +169,16 @@ private static List<AgentInfo> shuffleAgentInfos(AgentInfo... agentInfos) {
     }
 
     private static AgentInfo createAgentInfo(String applicationName, String agentId, String hostname, boolean container) {
+        return createAgentInfo(applicationName, agentId, hostname, container, System.currentTimeMillis());
+    }
+
+    private static AgentInfo createAgentInfo(String applicationName, String agentId, String hostname, boolean container, long startTimestamp) {
         AgentInfo agentInfo = new AgentInfo();
         agentInfo.setApplicationName(applicationName);
         agentInfo.setAgentId(agentId);
         agentInfo.setHostName(hostname);
         agentInfo.setContainer(container);
+        agentInfo.setStartTimestamp(startTimestamp);
         return agentInfo;
     }
 }