Apply patch (FELIX-3447) to introduce specific immutable collections.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1311317 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
index ba0ea97..13a323b 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
@@ -40,7 +40,6 @@
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.TreeSet;
-
import org.apache.felix.framework.cache.Content;
import org.apache.felix.framework.cache.JarContent;
import org.apache.felix.framework.capabilityset.SimpleFilter;
@@ -48,6 +47,7 @@
import org.apache.felix.framework.resolver.ResourceNotFoundException;
import org.apache.felix.framework.util.CompoundEnumeration;
import org.apache.felix.framework.util.FelixConstants;
+import org.apache.felix.framework.util.ImmutableList;
import org.apache.felix.framework.util.SecurityManagerEx;
import org.apache.felix.framework.util.Util;
import org.apache.felix.framework.util.manifestparser.ManifestParser;
@@ -161,7 +161,7 @@
m_revision = revision;
m_importedPkgs = importedPkgs;
m_requiredPkgs = requiredPkgs;
- m_wires = Collections.unmodifiableList(wires);
+ m_wires = ImmutableList.newInstance(wires);
// We need to sort the fragments and add ourself as a dependent of each one.
// We also need to create an array of fragment contents to attach to our
@@ -246,7 +246,7 @@
}
}
}
- m_resolvedReqs = Collections.unmodifiableList(reqList);
+ m_resolvedReqs = ImmutableList.newInstance(reqList);
// Calculate resolved list of capabilities, which includes:
// 1. All capabilities from host and any fragments except for exported
@@ -372,7 +372,7 @@
}
}
- m_resolvedCaps = Collections.unmodifiableList(capList);
+ m_resolvedCaps = ImmutableList.newInstance(capList);
m_includedPkgFilters = (includedPkgFilters.isEmpty())
? Collections.EMPTY_MAP : includedPkgFilters;
m_excludedPkgFilters = (excludedPkgFilters.isEmpty())
@@ -400,7 +400,7 @@
// could not be found when resolving the bundle.
m_resolvedNativeLibs = (libList.isEmpty())
? null
- : Collections.unmodifiableList(libList);
+ : ImmutableList.newInstance(libList);
ClassLoader bootLoader = m_defBootClassLoader;
if (revision.getBundle().getBundleId() != 0)
@@ -599,7 +599,7 @@
// Technically, there is a window here where readers won't see
// both values updates at the same time, but it seems unlikely
// to cause any issues.
- m_wires = Collections.unmodifiableList(wires);
+ m_wires = ImmutableList.newInstance(wires);
m_importedPkgs = importedPkgs;
}
@@ -673,7 +673,7 @@
{
entries.add(e.nextElement());
}
- return Collections.unmodifiableList(entries);
+ return ImmutableList.newInstance(entries);
}
return Collections.EMPTY_LIST;
}
diff --git a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
index 5981be4..ff328b2 100644
--- a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
+++ b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
@@ -24,7 +24,6 @@
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
-import java.security.AccessControlException;
import java.security.AllPermission;
import java.util.ArrayList;
import java.util.Collections;
@@ -37,8 +36,8 @@
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
-
import org.apache.felix.framework.util.FelixConstants;
+import org.apache.felix.framework.util.ImmutableList;
import org.apache.felix.framework.util.StringMap;
import org.apache.felix.framework.util.Util;
import org.apache.felix.framework.util.manifestparser.ManifestParser;
@@ -494,7 +493,7 @@
new ArrayList<BundleCapability>(m_capabilities.size() + caps.size());
newCaps.addAll(m_capabilities);
newCaps.addAll(caps);
- m_capabilities = Collections.unmodifiableList(newCaps);
+ m_capabilities = ImmutableList.newInstance(newCaps);
m_headerMap.put(Constants.EXPORT_PACKAGE, convertCapabilitiesToHeaders(m_headerMap));
}
@@ -598,6 +597,7 @@
};
}
+ @Override
protected InetAddress getHostAddress(URL u)
{
// the extension URLs do not address real hosts
diff --git a/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java b/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java
index 8402d80..2f44e5a 100644
--- a/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java
@@ -21,14 +21,12 @@
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
+import org.apache.felix.framework.util.ImmutableList;
import org.apache.felix.framework.util.manifestparser.ManifestParser;
-import org.apache.felix.framework.util.manifestparser.ParsedHeaderClause;
import org.osgi.framework.AdminPermission;
-import org.osgi.framework.Constants;
import org.osgi.framework.hooks.weaving.WovenClass;
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleWiring;
@@ -55,8 +53,8 @@
m_definedClass = definedClass;
m_bytes = (bytes == null) ? m_bytes : bytes;
m_imports = (imports == null)
- ? Collections.unmodifiableList(m_imports)
- : Collections.unmodifiableList(imports);
+ ? ImmutableList.newInstance(m_imports)
+ : ImmutableList.newInstance(imports);
}
public synchronized byte[] getBytes()
@@ -365,7 +363,7 @@
return m_imports.subList(i, i1);
}
- byte[] _getBytes()
+ byte[] _getBytes()
{
byte[] bytes = m_bytes;
if (m_isComplete)
diff --git a/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java
index 81c41ee..bdd2a2d 100644
--- a/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java
+++ b/framework/src/main/java/org/apache/felix/framework/resolver/WrappedRevision.java
@@ -19,8 +19,8 @@
package org.apache.felix.framework.resolver;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
+import org.apache.felix.framework.util.ImmutableList;
import org.apache.felix.framework.wiring.BundleCapabilityImpl;
import org.apache.felix.framework.wiring.BundleRequirementImpl;
import org.osgi.framework.Bundle;
@@ -88,7 +88,7 @@
}
}
}
- m_cachedCapabilities = Collections.unmodifiableList(caps);
+ m_cachedCapabilities = ImmutableList.newInstance(caps);
}
return m_cachedCapabilities;
}
@@ -119,7 +119,7 @@
}
}
}
- m_cachedRequirements = Collections.unmodifiableList(reqs);
+ m_cachedRequirements = ImmutableList.newInstance(reqs);
}
return m_cachedRequirements;
}
@@ -139,6 +139,7 @@
return m_host.getBundle();
}
+ @Override
public String toString()
{
return m_host.toString();
diff --git a/framework/src/main/java/org/apache/felix/framework/util/ImmutableList.java b/framework/src/main/java/org/apache/felix/framework/util/ImmutableList.java
new file mode 100644
index 0000000..f0a1a9c
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/util/ImmutableList.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.framework.util;
+
+import java.util.AbstractList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.RandomAccess;
+
+public class ImmutableList<E> extends AbstractList<E> implements RandomAccess
+{
+ final Object[] elements;
+
+ public static <E> ImmutableList<E> newInstance(E... elements)
+ {
+ return new ImmutableList<E>(elements);
+ }
+
+ public static <E> ImmutableList<E> newInstance(Collection<? extends E> elements)
+ {
+ if (elements instanceof ImmutableList)
+ {
+ return (ImmutableList<E>) elements;
+ }
+ else
+ {
+ return new ImmutableList<E>(elements);
+ }
+ }
+
+ protected ImmutableList(E... elements)
+ {
+ this.elements = elements.clone();
+ }
+
+ protected ImmutableList(Collection<? extends E> elements)
+ {
+ this.elements = elements.toArray();
+ }
+
+ public E get(int index)
+ {
+ return (E) elements[index];
+ }
+
+ public int size()
+ {
+ return elements.length;
+ }
+
+ @Override
+ public boolean remove(Object o)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> clctn)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Iterator<E> iterator()
+ {
+ return listIterator();
+ }
+
+ @Override
+ public ListIterator<E> listIterator(int index)
+ {
+ return new ListItr(index);
+ }
+
+ private class ListItr implements ListIterator<E>
+ {
+ int cursor;
+
+ private ListItr(int cursor)
+ {
+ this.cursor = cursor;
+ }
+
+ public boolean hasNext()
+ {
+ return cursor != size();
+ }
+
+ public E next()
+ {
+ return (E) elements[cursor++];
+ }
+
+ public boolean hasPrevious()
+ {
+ return cursor != 0;
+ }
+
+ public E previous()
+ {
+ return (E) elements[--cursor];
+ }
+
+ public int nextIndex()
+ {
+ return cursor;
+ }
+
+ public int previousIndex()
+ {
+ return cursor - 1;
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void set(E e)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void add(E e)
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/util/ImmutableMap.java b/framework/src/main/java/org/apache/felix/framework/util/ImmutableMap.java
new file mode 100644
index 0000000..1ee3140
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/util/ImmutableMap.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.framework.util;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public class ImmutableMap<K, V> extends AbstractMap<K, V>
+{
+ final Entry<K, V>[] entries;
+
+ public static <K, V> ImmutableMap<K, V> newInstance(Entry<K, V>... entries)
+ {
+ return new ImmutableMap<K, V>(entries);
+ }
+
+ public static <K, V> ImmutableMap<K, V> newInstance(Map<K, V> entries)
+ {
+ if (entries instanceof ImmutableMap)
+ {
+ return (ImmutableMap<K, V>) entries;
+ }
+ else
+ {
+ return new ImmutableMap<K, V>(entries);
+ }
+ }
+
+ protected ImmutableMap(Entry<K, V>[] entries)
+ {
+ this.entries = entries.clone();
+ }
+
+ protected ImmutableMap(Map<K, V> map)
+ {
+ this.entries = map.entrySet().toArray(new Entry[map.size()]);
+ }
+
+ @Override
+ public V get(Object key)
+ {
+ if (key == null)
+ {
+ for (int i = 0; i < entries.length; i++)
+ {
+ if (entries[i].getKey() == null)
+ {
+ return entries[i].getValue();
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < entries.length; i++)
+ {
+ if (key.equals(entries[i].getKey()))
+ {
+ return entries[i].getValue();
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Set<Entry<K, V>> entrySet()
+ {
+ return new EntrySet();
+ }
+
+ private class EntrySet extends AbstractSet<Entry<K, V>>
+ {
+ @Override
+ public Iterator<Entry<K, V>> iterator()
+ {
+ return new EntryItr(0);
+ }
+
+ @Override
+ public int size()
+ {
+ return entries.length;
+ }
+ }
+
+ private class EntryItr implements Iterator<Entry<K, V>>
+ {
+ int cursor;
+
+ private EntryItr(int cursor)
+ {
+ this.cursor = cursor;
+ }
+
+ public boolean hasNext()
+ {
+ return cursor != size();
+ }
+
+ public Entry<K, V> next()
+ {
+ return entries[cursor++];
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/util/StringMap.java b/framework/src/main/java/org/apache/felix/framework/util/StringMap.java
index 7ad7f78..dd040fd 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/StringMap.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/StringMap.java
@@ -27,108 +27,141 @@
* map will be converted to a <tt>String</tt> using the
* <tt>toString()</tt> method, since it is only intended to
* compare strings.
-**/
-public class StringMap implements Map
+ **/
+public class StringMap extends AbstractMap<String, Object>
{
- private TreeMap m_map;
-
- public StringMap()
- {
- this(true);
- }
+ private final TreeMap<String, KeyValueEntry> m_map = new TreeMap<String, KeyValueEntry>();
public StringMap(boolean caseSensitive)
{
- m_map = new TreeMap(new StringComparator(caseSensitive));
}
public StringMap(Map map, boolean caseSensitive)
{
- this(caseSensitive);
putAll(map);
}
- public boolean isCaseSensitive()
- {
- return ((StringComparator) m_map.comparator()).isCaseSensitive();
- }
-
- public void setCaseSensitive(boolean b)
- {
- if (isCaseSensitive() != b)
- {
- TreeMap map = new TreeMap(new StringComparator(b));
- map.putAll(m_map);
- m_map = map;
- }
- }
-
+ @Override
public int size()
{
return m_map.size();
}
+ @Override
public boolean isEmpty()
{
return m_map.isEmpty();
}
+ @Override
public boolean containsKey(Object arg0)
{
- return m_map.containsKey(arg0);
+ return m_map.containsKey(arg0.toString().toUpperCase());
}
+ @Override
public boolean containsValue(Object arg0)
{
return m_map.containsValue(arg0);
}
+ @Override
public Object get(Object arg0)
{
- return m_map.get(arg0);
+ KeyValueEntry kve = m_map.get(arg0.toString().toUpperCase());
+ return (kve != null) ? kve.value : null;
}
- public Object put(Object key, Object value)
+ @Override
+ public Object put(String key, Object value)
{
- return m_map.put(key.toString(), value);
+ KeyValueEntry kve = (KeyValueEntry) m_map.put(key.toUpperCase(), new KeyValueEntry(key, value));
+ return (kve != null) ? kve.value : null;
}
- public void putAll(Map map)
+ @Override
+ public void putAll(Map<? extends String, ? extends Object> map)
{
- for (Iterator it = map.entrySet().iterator(); it.hasNext(); )
+ for (Map.Entry<? extends String, ? extends Object> e : map.entrySet())
{
- Map.Entry entry = (Map.Entry) it.next();
- put(entry.getKey(), entry.getValue());
+ put(e.getKey(), e.getValue());
}
}
+ @Override
public Object remove(Object arg0)
{
- return m_map.remove(arg0);
+ KeyValueEntry kve = m_map.remove(arg0.toString().toUpperCase());
+ return (kve != null) ? kve.value : null;
}
+ @Override
public void clear()
{
m_map.clear();
}
- public Set keySet()
+ public Set<Entry<String, Object>> entrySet()
{
- return m_map.keySet();
+ return new AbstractSet<Entry<String, Object>>()
+ {
+ @Override
+ public Iterator<Entry<String, Object>> iterator()
+ {
+ return new Iterator<Entry<String, Object>>()
+ {
+ Iterator<Entry<String, KeyValueEntry>> it = m_map.entrySet().iterator();
+
+ public boolean hasNext()
+ {
+ return it.hasNext();
+ }
+
+ public Entry<String, Object> next()
+ {
+ return it.next().getValue();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public int size()
+ {
+ return m_map.size();
+ }
+ };
}
- public Collection values()
+ private class KeyValueEntry implements Entry<String, Object>
{
- return m_map.values();
- }
+ private KeyValueEntry(String key, Object value)
+ {
+ this.key = key;
+ this.value = value;
+ }
- public Set entrySet()
- {
- return m_map.entrySet();
- }
+ public String getKey()
+ {
+ return key;
+ }
- public String toString()
- {
- return m_map.toString();
+ public Object getValue()
+ {
+ return value;
+ }
+
+ public Object setValue(Object value)
+ {
+ Object v = this.value;
+ this.value = value;
+ return v;
+ }
+ String key;
+ Object value;
}
}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java b/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java
index ba36535..dd08ba5 100644
--- a/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java
@@ -26,6 +26,7 @@
import java.util.List;
import java.util.StringTokenizer;
import org.apache.felix.framework.capabilityset.SimpleFilter;
+import org.apache.felix.framework.util.ImmutableMap;
import org.apache.felix.framework.util.Util;
import org.apache.felix.framework.util.manifestparser.ManifestParser;
import org.osgi.framework.Constants;
@@ -50,8 +51,8 @@
{
m_namespace = namespace;
m_revision = revision;
- m_dirs = Collections.unmodifiableMap(dirs);
- m_attrs = Collections.unmodifiableMap(attrs);
+ m_dirs = ImmutableMap.newInstance(dirs);
+ m_attrs = ImmutableMap.newInstance(attrs);
// Find all export directives: uses, mandatory, include, and exclude.
@@ -187,6 +188,7 @@
return included && !excluded;
}
+ @Override
public String toString()
{
if (m_revision == null)
diff --git a/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java b/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java
index eabd5bc..0477c70 100644
--- a/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java
@@ -18,14 +18,11 @@
*/
package org.apache.felix.framework.wiring;
-import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import org.apache.felix.framework.capabilityset.CapabilitySet;
import org.apache.felix.framework.capabilityset.SimpleFilter;
-import org.apache.felix.framework.util.VersionRange;
+import org.apache.felix.framework.util.ImmutableMap;
import org.osgi.framework.Constants;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRequirement;
@@ -46,8 +43,8 @@
{
m_revision = revision;
m_namespace = namespace;
- m_dirs = Collections.unmodifiableMap(dirs);
- m_attrs = Collections.unmodifiableMap(attrs);
+ m_dirs = ImmutableMap.newInstance(dirs);
+ m_attrs = ImmutableMap.newInstance(attrs);
m_filter = filter;
// Find resolution import directives.
@@ -102,6 +99,7 @@
return m_filter;
}
+ @Override
public String toString()
{
return "[" + m_revision + "] " + m_namespace + "; " + getFilter().toString();