FELIX-2136: a few further optimisations to improve OBR speeed. - insertion of a resource in the repository does not create a full copy of the array + sorting, this is now done lazily
 - avoid case insensitive filters and maps (those string comparisons are really costly)
 - caches the Resource hash code
 - use interned strings for capabilities / requirements namespaces

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@916284 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java
index ddde6cc..20d596a 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java
@@ -27,16 +27,10 @@
 {
     private Resource m_resource;
     private String m_name = null;
-    private Map m_map = null;
+    private final Map m_map = new HashMap();
 
     public CapabilityImpl()
     {
-        m_map = new TreeMap(new Comparator() {
-            public int compare(Object o1, Object o2)
-            {
-                return o1.toString().compareToIgnoreCase(o2.toString());
-            }
-        });
     }
 
     public Resource getResource()
@@ -56,7 +50,7 @@
 
     public void setName(String name)
     {
-        m_name = name;
+        m_name = name.intern();
     }
 
     public Map getProperties()
@@ -66,11 +60,11 @@
 
     protected void addP(PropertyImpl prop)
     {
-        m_map.put(prop.getN(), prop.getV());
+        addP(prop.getN(), prop.getV());
     }
 
     protected void addP(String name, Object value)
     {
-        m_map.put(name, value);
+        m_map.put(name.toLowerCase(), value);
     }
 }
\ No newline at end of file
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/FilterImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/FilterImpl.java
index 90bb8a0..b1b52e4 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/FilterImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/FilterImpl.java
@@ -88,7 +88,12 @@
      */
     static FilterImpl newInstance(String filterString)
             throws InvalidSyntaxException {
-        return new Parser(filterString).parse();
+        return newInstance(filterString, false);
+    }
+
+    static FilterImpl newInstance(String filterString, boolean ignoreCase)
+            throws InvalidSyntaxException {
+        return new Parser(filterString, ignoreCase).parse();
     }
 
     FilterImpl(int operation, String attr, Object value) {
@@ -101,7 +106,7 @@
             {
                 conv = getSet(value);
             }
-            else if ("version".equals(attr))
+            else if ("version".equalsIgnoreCase(attr))
             {
                 if (value instanceof String) {
                     conv = new Version((String) value);
@@ -178,7 +183,7 @@
      * @throws IllegalArgumentException If <code>map</code> contains
      *         case variants of the same key name.
      */
-    public boolean match(Map map) {
+    public boolean matchCase(Map map) {
         return match0(map);
     }
 
@@ -1151,11 +1156,13 @@
      */
     private static class Parser {
         private final String	filterstring;
+        private final boolean   ignoreCase;
         private final char[]	filterChars;
         private int				pos;
 
-        Parser(String filterstring) {
+        Parser(String filterstring, boolean ignoreCase) {
             this.filterstring = filterstring;
+            this.ignoreCase = ignoreCase;
             filterChars = filterstring.toCharArray();
             pos = 0;
         }
@@ -1384,7 +1391,12 @@
                         + filterstring.substring(pos), filterstring);
             }
 
-            return new String(filterChars, begin, length);
+            String str = new String(filterChars, begin, length);
+            if (ignoreCase)
+            {
+                str = str.toLowerCase();
+            }
+            return str;
         }
 
         private String parse_value() throws InvalidSyntaxException {
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
index f4e6c04..5635619 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
@@ -30,7 +30,10 @@
 import java.security.PrivilegedExceptionAction;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
@@ -53,6 +56,7 @@
     private Resource[] m_resources = null;
     private Referral[] m_referrals = null;
     private RepositoryAdminImpl m_repoAdmin = null;
+    private List m_resourceList;
 
     // Reusable comparator for sorting resources by name.
     private ResourceComparator m_nameComparator = new ResourceComparator();
@@ -69,6 +73,7 @@
         m_repoAdmin = repoAdmin;
         m_url = url;
         m_logger = logger;
+        m_resourceList = new ArrayList();
         try
         {
             AccessController.doPrivileged(new PrivilegedExceptionAction()
@@ -98,6 +103,10 @@
 
     public Resource[] getResources()
     {
+        if (m_resources == null) {
+            Collections.sort(m_resourceList, m_nameComparator);
+            m_resources = (Resource[]) m_resourceList.toArray(new Resource[m_resourceList.size()]);
+        }
         return m_resources;
     }
 
@@ -107,19 +116,8 @@
         ((ResourceImpl) resource).setRepository(this);
 
         // Add to resource array.
-        if (m_resources == null)
-        {
-            m_resources = new Resource[] { resource };
-        }
-        else
-        {
-            Resource[] newResources = new Resource[m_resources.length + 1];
-            System.arraycopy(m_resources, 0, newResources, 0, m_resources.length);
-            newResources[m_resources.length] = resource;
-            m_resources = newResources;
-        }
-
-        Arrays.sort(m_resources, m_nameComparator);
+        m_resourceList.add(resource);
+        m_resources = null;
     }
 
     public Referral[] getReferrals()
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java
index 87ed2ef..fcc1ae9 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/RequirementImpl.java
@@ -29,9 +29,8 @@
     private boolean m_extend = false;
     private boolean m_multiple = false;
     private boolean m_optional = false;
-    private Filter m_filter = null;
+    private FilterImpl m_filter = null;
     private String m_comment = null;
-    private MapToDictionary m_dict = new MapToDictionary(null);
 
     public RequirementImpl()
     {
@@ -44,7 +43,9 @@
 
     public synchronized void setName(String name)
     {
-        m_name = name;
+        // Name of capabilities and requirements are interned for performances
+        // (with a very slow inter consumption as there are only a handful of values)
+        m_name = name.intern();
     }
 
     public synchronized String getFilter()
@@ -54,13 +55,12 @@
 
     public synchronized void setFilter(String filter) throws InvalidSyntaxException
     {
-        m_filter = FilterImpl.newInstance(filter);
+        m_filter = FilterImpl.newInstance(filter, true);
     }
 
     public synchronized boolean isSatisfied(Capability capability)
     {
-        m_dict.setSourceMap(capability.getProperties());
-        return m_filter.match(m_dict);
+        return m_filter.matchCase(capability.getProperties());
     }
 
     public synchronized boolean isExtend()
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
index cc89181..6cfda8b 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
@@ -29,8 +29,8 @@
 {
     private final String URI = "uri";
 
+    private final Map m_map = new HashMap();
     private Repository m_repo = null;
-    private Map m_map = null;
     private List m_capList = new ArrayList();
     private List m_reqList = new ArrayList();
 
@@ -41,6 +41,8 @@
     private String m_javadocURI = null;
     private boolean m_converted = false;
 
+    private int m_hash;
+
     public ResourceImpl()
     {
         this(null);
@@ -48,13 +50,6 @@
 
     public ResourceImpl(ResourceImpl resource)
     {
-        m_map = new TreeMap(new Comparator() {
-            public int compare(Object o1, Object o2)
-            {
-                return o1.toString().compareToIgnoreCase(o2.toString());
-            }
-        });
-
         if (resource != null)
         {
             m_map.putAll(resource.getProperties());
@@ -79,11 +74,18 @@
 
     public int hashCode()
     {
-        if (getSymbolicName() == null || getVersion() == null)
+        if (m_hash == 0)
         {
-            return super.hashCode();
+            if (getSymbolicName() == null || getVersion() == null)
+            {
+                m_hash =  super.hashCode();
+            }
+            else
+            {
+                m_hash = getSymbolicName().hashCode() ^ getVersion().hashCode();
+            }
         }
-        return getSymbolicName().hashCode() ^ getVersion().hashCode();
+        return m_hash;
     }
 
     public Map getProperties()
@@ -183,6 +185,9 @@
     **/
     protected Object put(Object key, Object value)
     {
+        key = key.toString().toLowerCase();
+        m_converted = false;
+        m_hash = 0;
         // Capture the URIs since they might be relative, so we
         // need to defer setting the actual URL value until they
         // are used so that we will know our repository and its