FELIX-3799 Apply patch by Henri Sagnior (thanks)
 - Add sorting before rendering the menu
 - Map preparation does not sort any more

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1425317 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java b/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
index 9162f60..21f297d 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
@@ -685,8 +685,9 @@
     {
         if ( menuMap != null )
         {
+            SortedMap categoryMap = sortMenuCategoryMap( menuMap, appRoot );
             pw.println( "<ul id=\"navmenu\">" );
-            renderSubmenu( menuMap, appRoot, pw, 0 );
+            renderSubmenu( categoryMap, appRoot, pw, 0 );
             pw.println( "</ul>" );
         }
     }
@@ -707,24 +708,19 @@
         while ( itr.hasNext() )
         {
             String key = ( String ) itr.next();
-            if ( key.startsWith( "category." ) )
+            MenuItem menuItem = ( MenuItem ) menuMap.get( key );
+            pw.println( "<li" + liStyleClass + ">" + menuItem.getLink() );
+            Map subMenu = menuItem.getSubMenu();
+            if ( subMenu != null )
             {
-                pw.println( "<li" + liStyleClass + "><a href=\"#\">" + key.substring( key.indexOf( '.' ) + 1 ) + "</a>" );
-                renderMenu( ( Map ) menuMap.get( key ), appRoot, pw, level + 1 );
-                pw.println( "</li>" );
+                renderMenu( subMenu, appRoot, pw, level + 1 );
             }
-            else
-            {
-                String label = key;
-                String title = ( String ) menuMap.get( label );
-                pw.println( "<li" + liStyleClass + "><a href=\"" + appRoot + "/" + label + "\">" + title + "</a></li>" );
-            }
+            pw.println( "</li>" );
         }
     }
 
 
-    private static final void printLocaleElement(PrintWriter pw, String appRoot,
-        Object langCode, Object langName)
+    private static final void printLocaleElement( PrintWriter pw, String appRoot, Object langCode, Object langName )
     {
         pw.print("  <img src='"); //$NON-NLS-1$
         pw.print(appRoot);
@@ -964,4 +960,89 @@
         return url;
     }
 
+
+    private SortedMap sortMenuCategoryMap( Map map, String appRoot )
+    {
+        SortedMap sortedMap = new TreeMap( String.CASE_INSENSITIVE_ORDER );
+        Iterator keys = map.keySet().iterator();
+        while ( keys.hasNext() )
+        {
+            String key = ( String ) keys.next();
+            if ( key.startsWith( "category." ) )
+            {
+                SortedMap categoryMap = sortMenuCategoryMap( ( Map ) map.get( key ), appRoot );
+                String title = key.substring( key.indexOf( '.' ) + 1 );
+                if ( sortedMap.containsKey( title ) )
+                {
+                    ( ( MenuItem ) sortedMap.get( title ) ).setSubMenu( categoryMap );
+                }
+                else
+                {
+                    String link = "<a href=\"#\">" + title + "</a>";
+                    MenuItem menuItem = new MenuItem( link, categoryMap );
+                    sortedMap.put( title, menuItem );
+                }
+            }
+            else
+            {
+                String title = ( String ) map.get( key );
+                String link = "<a href=\"" + appRoot + "/" + key + "\">" + title + "</a>";
+                if ( sortedMap.containsKey( title ) )
+                {
+                    ( ( MenuItem ) sortedMap.get( title ) ).setLink( link );
+                }
+                else
+                {
+                    MenuItem menuItem = new MenuItem( link );
+                    sortedMap.put( title, menuItem );
+                }
+            }
+
+        }
+        return sortedMap;
+    }
+
+    private static class MenuItem
+    {
+    private String link;
+        private Map subMenu;
+
+
+        public MenuItem( String link )
+        {
+            this.link = link;
+        }
+
+
+        public MenuItem( String link, Map subMenu )
+        {
+            super();
+            this.link = link;
+            this.subMenu = subMenu;
+        }
+
+
+        public String getLink()
+        {
+            return link;
+        }
+
+
+        public void setLink( String link )
+        {
+            this.link = link;
+        }
+
+
+        public Map getSubMenu()
+        {
+            return subMenu;
+        }
+
+
+        public void setSubMenu( Map subMenu )
+        {
+            this.subMenu = subMenu;
+        }
+    }
 }
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java
index e3a0970..494ceb6 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java
@@ -26,8 +26,6 @@
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.ResourceBundle;
-import java.util.SortedMap;
-import java.util.TreeMap;
 
 import javax.servlet.Servlet;
 import javax.servlet.ServletConfig;
@@ -237,7 +235,7 @@
      */
     Map getLocalizedLabelMap( final ResourceBundleManager resourceBundleManager, final Locale locale )
     {
-        final SortedMap map = new TreeMap( MENU_ITEM_ORDER );
+        final Map map = new HashMap();
         Plugin[] plugins = getPlugins();
         for ( int i = 0; i < plugins.length; i++ )
         {
@@ -249,7 +247,7 @@
             }
 
             // support only one level for now
-            SortedMap categoryMap = null;
+            Map categoryMap = null;
             String category = plugin.getCategory();
             if ( category == null || category.trim().length() == 0 )
             {
@@ -283,9 +281,9 @@
     }
 
 
-    private SortedMap findCategoryMap( Map map, String categoryPath )
+    private Map findCategoryMap( Map map, String categoryPath )
     {
-        SortedMap categoryMap = null;
+        Map categoryMap = null;
         Map searchMap = map;
 
         String categories[] = categoryPath.split( "/" );
@@ -295,11 +293,11 @@
             String categoryKey = "category." + categories[i];
             if ( searchMap.containsKey( categoryKey ) )
             {
-                categoryMap = ( SortedMap ) searchMap.get( categoryKey );
+                categoryMap = ( Map ) searchMap.get( categoryKey );
             }
             else
             {
-                categoryMap = new TreeMap( MENU_ITEM_ORDER );
+                categoryMap = new HashMap();
                 searchMap.put( categoryKey, categoryMap );
             }
             searchMap = categoryMap;
@@ -459,26 +457,6 @@
         return null;
     }
 
-    /**
-     * A comparator that will compare plugin menu items to other menu items including categories.
-     */
-    private static final Comparator MENU_ITEM_ORDER = new Comparator() {
-
-		public int compare(Object o1, Object o2) {
-			String s1 = getLabel(o1.toString());
-			String s2 = getLabel(o2.toString());
-			return s1.compareToIgnoreCase(s2);
-		}
-
-		private String getLabel(String s) {
-			if(s.startsWith("category."))
-				return s.substring(s.indexOf('.')+1);
-			else
-				return s;
-		}
-
-    };
-
     private static class Plugin implements ServletConfig
     {
         private final PluginHolder holder;