You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pa...@apache.org on 2019/04/30 16:21:30 UTC
svn commit: r1858443 [3/3] - in /felix/trunk/connect: ./
src/main/java/org/apache/felix/connect/
src/main/java/org/apache/felix/connect/felix/framework/
src/main/java/org/apache/felix/connect/felix/framework/capabilityset/
src/main/java/org/apache/feli...
Modified: felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/capabilityset/SimpleFilter.java
URL: http://svn.apache.org/viewvc/felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/capabilityset/SimpleFilter.java?rev=1858443&r1=1858442&r2=1858443&view=diff
==============================================================================
--- felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/capabilityset/SimpleFilter.java (original)
+++ felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/capabilityset/SimpleFilter.java Tue Apr 30 16:21:29 2019
@@ -7,7 +7,7 @@
* "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
+ * 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
@@ -18,8 +18,12 @@
*/
package org.apache.felix.connect.felix.framework.capabilityset;
+import org.osgi.framework.VersionRange;
+
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
public class SimpleFilter
{
@@ -60,49 +64,51 @@ public class SimpleFilter
return m_op;
}
- @SuppressWarnings("unchecked")
public String toString()
{
String s = null;
switch (m_op)
{
- case AND:
- s = "(&" + toString((List) m_value) + ")";
- break;
- case OR:
- s = "(|" + toString((List) m_value) + ")";
- break;
- case NOT:
- s = "(!" + toString((List) m_value) + ")";
- break;
- case EQ:
- s = "(" + m_name + "=" + toEncodedString(m_value) + ")";
- break;
- case LTE:
- s = "(" + m_name + "<=" + toEncodedString(m_value) + ")";
- break;
- case GTE:
- s = "(" + m_name + ">=" + toEncodedString(m_value) + ")";
- break;
- case SUBSTRING:
- s = "(" + m_name + "=" + unparseSubstring((List<String>) m_value) + ")";
- break;
- case PRESENT:
- s = "(" + m_name + "=*)";
- break;
- case APPROX:
- s = "(" + m_name + "~=" + toEncodedString(m_value) + ")";
- break;
+ case AND:
+ s = "(&" + toString((List) m_value) + ")";
+ break;
+ case OR:
+ s = "(|" + toString((List) m_value) + ")";
+ break;
+ case NOT:
+ s = "(!" + toString((List) m_value) + ")";
+ break;
+ case EQ:
+ s = "(" + m_name + "=" + toEncodedString(m_value) + ")";
+ break;
+ case LTE:
+ s = "(" + m_name + "<=" + toEncodedString(m_value) + ")";
+ break;
+ case GTE:
+ s = "(" + m_name + ">=" + toEncodedString(m_value) + ")";
+ break;
+ case SUBSTRING:
+ s = "(" + m_name + "=" + unparseSubstring((List<String>) m_value) + ")";
+ break;
+ case PRESENT:
+ s = "(" + m_name + "=*)";
+ break;
+ case APPROX:
+ s = "(" + m_name + "~=" + toEncodedString(m_value) + ")";
+ break;
+ case MATCH_ALL:
+ s = "(*)";
+ break;
}
return s;
}
- private static String toString(List<?> list)
+ private static String toString(List list)
{
StringBuilder sb = new StringBuilder();
- for (Object aList : list)
+ for (int i = 0; i < list.size(); i++)
{
- sb.append(aList.toString());
+ sb.append(list.get(i).toString());
}
return sb.toString();
}
@@ -150,31 +156,28 @@ public class SimpleFilter
return o.toString();
}
- @SuppressWarnings("unchecked")
public static SimpleFilter parse(String filter)
{
int idx = skipWhitespace(filter, 0);
- if ((filter == null) || (filter.length() == 0)
- || (idx >= filter.length()))
+ if ((filter == null) || (filter.length() == 0) || (idx >= filter.length()))
{
throw new IllegalArgumentException("Null or empty filter.");
}
else if (filter.charAt(idx) != '(')
{
- throw new IllegalArgumentException("Missing opening parenthesis: "
- + filter);
+ throw new IllegalArgumentException("Missing opening parenthesis: " + filter);
}
SimpleFilter sf = null;
- List<Object> stack = new ArrayList<Object>();
+ List stack = new ArrayList();
boolean isEscaped = false;
while (idx < filter.length())
{
if (sf != null)
{
throw new IllegalArgumentException(
- "Only one top-level operation allowed: " + filter);
+ "Only one top-level operation allowed: " + filter);
}
if (!isEscaped && (filter.charAt(idx) == '('))
@@ -188,12 +191,11 @@ public class SimpleFilter
if (filter.charAt(peek) == '(')
{
idx = peek - 1;
- stack.add(0, new SimpleFilter(null, new ArrayList(),
- SimpleFilter.AND));
+ stack.add(0, new SimpleFilter(null, new ArrayList(), SimpleFilter.AND));
}
else
{
- stack.add(0, idx);
+ stack.add(0, new Integer(idx));
}
}
else if (filter.charAt(idx) == '|')
@@ -202,12 +204,11 @@ public class SimpleFilter
if (filter.charAt(peek) == '(')
{
idx = peek - 1;
- stack.add(0, new SimpleFilter(null, new ArrayList(),
- SimpleFilter.OR));
+ stack.add(0, new SimpleFilter(null, new ArrayList(), SimpleFilter.OR));
}
else
{
- stack.add(0, idx);
+ stack.add(0, new Integer(idx));
}
}
else if (filter.charAt(idx) == '!')
@@ -216,17 +217,16 @@ public class SimpleFilter
if (filter.charAt(peek) == '(')
{
idx = peek - 1;
- stack.add(0, new SimpleFilter(null, new ArrayList(),
- SimpleFilter.NOT));
+ stack.add(0, new SimpleFilter(null, new ArrayList(), SimpleFilter.NOT));
}
else
{
- stack.add(0, idx);
+ stack.add(0, new Integer(idx));
}
}
else
{
- stack.add(0, idx);
+ stack.add(0, new Integer(idx));
}
}
else if (!isEscaped && (filter.charAt(idx) == ')'))
@@ -236,7 +236,7 @@ public class SimpleFilter
{
if (!stack.isEmpty() && (stack.get(0) instanceof SimpleFilter))
{
- ((List<Object>) ((SimpleFilter) stack.get(0)).m_value).add(top);
+ ((List) ((SimpleFilter) stack.get(0)).m_value).add(top);
}
else
{
@@ -245,17 +245,21 @@ public class SimpleFilter
}
else if (!stack.isEmpty() && (stack.get(0) instanceof SimpleFilter))
{
- ((List<Object>) ((SimpleFilter) stack.get(0)).m_value)
- .add(SimpleFilter.subfilter(filter, (Integer) top, idx));
+ ((List) ((SimpleFilter) stack.get(0)).m_value).add(
+ SimpleFilter.subfilter(filter, ((Integer) top).intValue(), idx));
}
else
{
- sf = SimpleFilter.subfilter(filter, (Integer) top, idx);
+ sf = SimpleFilter.subfilter(filter, ((Integer) top).intValue(), idx);
}
}
+ else if (!isEscaped && (filter.charAt(idx) == '\\'))
+ {
+ isEscaped = true;
+ }
else
{
- isEscaped = !isEscaped && (filter.charAt(idx) == '\\');
+ isEscaped = false;
}
idx = skipWhitespace(filter, idx + 1);
@@ -269,8 +273,7 @@ public class SimpleFilter
return sf;
}
- private static SimpleFilter subfilter(String filter, int startIdx,
- int endIdx)
+ private static SimpleFilter subfilter(String filter, int startIdx, int endIdx)
{
final String opChars = "=<>~";
@@ -290,8 +293,8 @@ public class SimpleFilter
}
if (attrEndIdx == startIdx)
{
- throw new IllegalArgumentException("Missing attribute name: "
- + filter.substring(startIdx, endIdx));
+ throw new IllegalArgumentException(
+ "Missing attribute name: " + filter.substring(startIdx, endIdx));
}
String attr = filter.substring(startIdx, attrEndIdx);
@@ -299,43 +302,43 @@ public class SimpleFilter
startIdx = skipWhitespace(filter, attrEndIdx);
// Determine the operator type.
- int op;
+ int op = -1;
switch (filter.charAt(startIdx))
{
- case '=':
- op = EQ;
- startIdx++;
- break;
- case '<':
- if (filter.charAt(startIdx + 1) != '=')
- {
- throw new IllegalArgumentException("Unknown operator: "
- + filter.substring(startIdx, endIdx));
- }
- op = LTE;
- startIdx += 2;
- break;
- case '>':
- if (filter.charAt(startIdx + 1) != '=')
- {
- throw new IllegalArgumentException("Unknown operator: "
- + filter.substring(startIdx, endIdx));
- }
- op = GTE;
- startIdx += 2;
- break;
- case '~':
- if (filter.charAt(startIdx + 1) != '=')
- {
- throw new IllegalArgumentException("Unknown operator: "
- + filter.substring(startIdx, endIdx));
- }
- op = APPROX;
- startIdx += 2;
- break;
- default:
- throw new IllegalArgumentException("Unknown operator: "
- + filter.substring(startIdx, endIdx));
+ case '=':
+ op = EQ;
+ startIdx++;
+ break;
+ case '<':
+ if (filter.charAt(startIdx + 1) != '=')
+ {
+ throw new IllegalArgumentException(
+ "Unknown operator: " + filter.substring(startIdx, endIdx));
+ }
+ op = LTE;
+ startIdx += 2;
+ break;
+ case '>':
+ if (filter.charAt(startIdx + 1) != '=')
+ {
+ throw new IllegalArgumentException(
+ "Unknown operator: " + filter.substring(startIdx, endIdx));
+ }
+ op = GTE;
+ startIdx += 2;
+ break;
+ case '~':
+ if (filter.charAt(startIdx + 1) != '=')
+ {
+ throw new IllegalArgumentException(
+ "Unknown operator: " + filter.substring(startIdx, endIdx));
+ }
+ op = APPROX;
+ startIdx += 2;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown operator: " + filter.substring(startIdx, endIdx));
}
// Parse value.
@@ -347,8 +350,9 @@ public class SimpleFilter
{
String valueStr = filter.substring(startIdx, endIdx);
List<String> values = parseSubstring(valueStr);
- if ((values.size() == 2) && (values.get(0).length() == 0)
- && (values.get(1).length() == 0))
+ if ((values.size() == 2)
+ && (values.get(0).length() == 0)
+ && (values.get(1).length() == 0))
{
op = PRESENT;
}
@@ -364,7 +368,7 @@ public class SimpleFilter
public static List<String> parseSubstring(String value)
{
- List<String> pieces = new ArrayList<String>();
+ List<String> pieces = new ArrayList();
StringBuilder ss = new StringBuilder();
// int kind = SIMPLE; // assume until proven otherwise
boolean wasStar = false; // indicates last piece was a star
@@ -375,7 +379,7 @@ public class SimpleFilter
// We assume (sub)strings can contain leading and trailing blanks
boolean escaped = false;
- for (; ; )
+loop: for (;;)
{
if (idx >= value.length())
{
@@ -393,36 +397,30 @@ public class SimpleFilter
// the string "" (!=null)
}
ss.setLength(0);
- break;
+ break loop;
}
// Read the next character and account for escapes.
char c = value.charAt(idx++);
- if (!escaped && ((c == '(') || (c == ')')))
+ if (!escaped && (c == '*'))
{
- throw new IllegalArgumentException("Illegal value: " + value);
- }
- else if (!escaped && (c == '*'))
- {
- if (wasStar)
+ // If we have successive '*' characters, then we can
+ // effectively collapse them by ignoring succeeding ones.
+ if (!wasStar)
{
- // encountered two successive stars;
- // I assume this is illegal
- throw new IllegalArgumentException(
- "Invalid filter string: " + value);
- }
- if (ss.length() > 0)
- {
- pieces.add(ss.toString()); // accumulate the pieces
- // between '*' occurrences
- }
- ss.setLength(0);
- // if this is a leading star, then track it
- if (pieces.size() == 0)
- {
- leftstar = true;
+ if (ss.length() > 0)
+ {
+ pieces.add(ss.toString()); // accumulate the pieces
+ // between '*' occurrences
+ }
+ ss.setLength(0);
+ // if this is a leading star, then track it
+ if (pieces.isEmpty())
+ {
+ leftstar = true;
+ }
+ wasStar = true;
}
- wasStar = true;
}
else if (!escaped && (c == '\\'))
{
@@ -487,7 +485,7 @@ public class SimpleFilter
int index = 0;
- for (int i = 0; i < len; i++)
+loop: for (int i = 0; i < len; i++)
{
String piece = pieces.get(i);
@@ -498,16 +496,23 @@ public class SimpleFilter
if (!s.startsWith(piece))
{
result = false;
- break;
+ break loop;
}
}
// If this is the last piece, then make sure the
// string ends with it.
- if (i == len - 1)
+ if (i == (len - 1))
{
- result = s.endsWith(piece);
- break;
+ if (s.endsWith(piece) && (s.length() >= (index + piece.length())))
+ {
+ result = true;
+ }
+ else
+ {
+ result = false;
+ }
+ break loop;
}
// If this is neither the first or last piece, then
@@ -518,7 +523,7 @@ public class SimpleFilter
if (index < 0)
{
result = false;
- break;
+ break loop;
}
}
@@ -538,4 +543,109 @@ public class SimpleFilter
}
return startIdx;
}
+
+ /**
+ * Converts a attribute map to a filter. The filter is created by iterating
+ * over the map's entry set. If ordering of attributes is important (e.g.,
+ * for hitting attribute indices), then the map's entry set should iterate
+ * in the desired order. Equality testing is assumed for all attribute types
+ * other than version ranges, which are handled appropriated. If the attribute
+ * map is empty, then a filter that matches anything is returned.
+ * @param attrs Map of attributes to convert to a filter.
+ * @return A filter corresponding to the attributes.
+ */
+ public static SimpleFilter convert(Map<String, Object> attrs)
+ {
+ // Rather than building a filter string to be parsed into a SimpleFilter,
+ // we will just create the parsed SimpleFilter directly.
+
+ List<SimpleFilter> filters = new ArrayList<SimpleFilter>();
+
+ for (Entry<String, Object> entry : attrs.entrySet())
+ {
+ if (entry.getValue() instanceof VersionRange)
+ {
+ VersionRange vr = (VersionRange) entry.getValue();
+ if (vr.getLeftType() == VersionRange.LEFT_CLOSED)
+ {
+ filters.add(
+ new SimpleFilter(
+ entry.getKey(),
+ vr.getLeft().toString(),
+ SimpleFilter.GTE));
+ }
+ else
+ {
+ SimpleFilter not =
+ new SimpleFilter(null, new ArrayList(), SimpleFilter.NOT);
+ ((List) not.getValue()).add(
+ new SimpleFilter(
+ entry.getKey(),
+ vr.getLeft().toString(),
+ SimpleFilter.LTE));
+ filters.add(not);
+ }
+
+ if (vr.getRight() != null)
+ {
+ if (vr.getRightType() == VersionRange.RIGHT_CLOSED)
+ {
+ filters.add(
+ new SimpleFilter(
+ entry.getKey(),
+ vr.getRight().toString(),
+ SimpleFilter.LTE));
+ }
+ else
+ {
+ SimpleFilter not =
+ new SimpleFilter(null, new ArrayList(), SimpleFilter.NOT);
+ ((List) not.getValue()).add(
+ new SimpleFilter(
+ entry.getKey(),
+ vr.getRight().toString(),
+ SimpleFilter.GTE));
+ filters.add(not);
+ }
+ }
+ }
+ else
+ {
+ List<String> values = SimpleFilter.parseSubstring(entry.getValue().toString());
+ if (values.size() > 1)
+ {
+ filters.add(
+ new SimpleFilter(
+ entry.getKey(),
+ values,
+ SimpleFilter.SUBSTRING));
+ }
+ else
+ {
+ filters.add(
+ new SimpleFilter(
+ entry.getKey(),
+ values.get(0),
+ SimpleFilter.EQ));
+ }
+ }
+ }
+
+ SimpleFilter sf = null;
+
+ if (filters.size() == 1)
+ {
+ sf = filters.get(0);
+ }
+ else if (attrs.size() > 1)
+ {
+ sf = new SimpleFilter(null, filters, SimpleFilter.AND);
+ }
+ else if (filters.isEmpty())
+ {
+ sf = new SimpleFilter(null, null, SimpleFilter.MATCH_ALL);
+ }
+
+ return sf;
+ }
}
\ No newline at end of file
Modified: felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/EventDispatcher.java
URL: http://svn.apache.org/viewvc/felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/EventDispatcher.java?rev=1858443&r1=1858442&r2=1858443&view=diff
==============================================================================
--- felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/EventDispatcher.java (original)
+++ felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/EventDispatcher.java Tue Apr 30 16:21:29 2019
@@ -532,7 +532,7 @@ public class EventDispatcher
}
// Create a whitelist of bundle context, if we have hooks.
Set<BundleContext> whitelist = null;
- Set<ServiceReference<EventHook>> hooks = m_registry.getHooks(EventHook.class);
+ Set<ServiceReference<EventHook>> hooks = m_registry.getHookRegistry().getHooks(EventHook.class);
if ((hooks != null) && !hooks.isEmpty())
{
whitelist = new HashSet<BundleContext>();
@@ -545,7 +545,7 @@ public class EventDispatcher
{
try
{
- EventHook eh = m_registry.getService(bundle, sr);
+ EventHook eh = m_registry.getService(bundle, sr, false);
if (eh != null)
{
try
@@ -559,7 +559,7 @@ public class EventDispatcher
}
finally
{
- m_registry.ungetService(bundle, sr);
+ m_registry.ungetService(bundle, sr, null);
}
}
}
@@ -603,9 +603,9 @@ public class EventDispatcher
}
Set<ServiceReference<org.osgi.framework.hooks.service.EventHook>> ehs =
- m_registry.getHooks(org.osgi.framework.hooks.service.EventHook.class);
+ m_registry.getHookRegistry().getHooks(org.osgi.framework.hooks.service.EventHook.class);
Set<ServiceReference<EventListenerHook>> elhs =
- m_registry.getHooks(EventListenerHook.class);
+ m_registry.getHookRegistry().getHooks(EventListenerHook.class);
if ((ehs == null || ehs.isEmpty()) && (elhs == null || elhs.isEmpty()))
{
@@ -631,7 +631,7 @@ public class EventDispatcher
{
try
{
- org.osgi.framework.hooks.service.EventHook eh = m_registry.getService(framework, sr);
+ org.osgi.framework.hooks.service.EventHook eh = m_registry.getService(framework, sr, false);
if (eh != null)
{
try
@@ -645,7 +645,7 @@ public class EventDispatcher
}
finally
{
- m_registry.ungetService(framework, sr);
+ m_registry.ungetService(framework, sr, null);
}
}
}
@@ -666,7 +666,7 @@ public class EventDispatcher
{
try
{
- EventListenerHook elh = m_registry.getService(framework, sr);
+ EventListenerHook elh = m_registry.getService(framework, sr, false);
if (elh != null)
{
try
@@ -680,7 +680,7 @@ public class EventDispatcher
}
finally
{
- m_registry.ungetService(framework, sr);
+ m_registry.ungetService(framework, sr, null);
}
}
}
Modified: felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/StringComparator.java
URL: http://svn.apache.org/viewvc/felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/StringComparator.java?rev=1858443&r1=1858442&r2=1858443&view=diff
==============================================================================
--- felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/StringComparator.java (original)
+++ felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/StringComparator.java Tue Apr 30 16:21:29 2019
@@ -7,7 +7,7 @@
* "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
+ * 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
@@ -22,28 +22,52 @@ import java.util.Comparator;
public class StringComparator implements Comparator<String>
{
- private final boolean m_isCaseSensitive;
- public StringComparator(boolean b)
- {
- m_isCaseSensitive = b;
- }
+ public static final StringComparator COMPARATOR = new StringComparator();
- @Override
- public int compare(String o1, String o2)
+ public int compare(String s1, String s2)
{
- if (m_isCaseSensitive)
- {
- return o1.compareTo(o2);
- }
- else
+ int n1 = s1.length();
+ int n2 = s2.length();
+ int min = n1 < n2 ? n1 : n2;
+ for ( int i = 0; i < min; i++ )
{
- return o1.compareToIgnoreCase(o2);
+ char c1 = s1.charAt( i );
+ char c2 = s2.charAt( i );
+ if ( c1 != c2 )
+ {
+ // Fast check for simple ascii codes
+ if ( c1 <= 128 && c2 <= 128 )
+ {
+ c1 = toLowerCaseFast(c1);
+ c2 = toLowerCaseFast(c2);
+ if ( c1 != c2 )
+ {
+ return c1 - c2;
+ }
+ }
+ else
+ {
+ c1 = Character.toUpperCase( c1 );
+ c2 = Character.toUpperCase( c2 );
+ if ( c1 != c2 )
+ {
+ c1 = Character.toLowerCase( c1 );
+ c2 = Character.toLowerCase( c2 );
+ if ( c1 != c2 )
+ {
+ // No overflow because of numeric promotion
+ return c1 - c2;
+ }
+ }
+ }
+ }
}
+ return n1 - n2;
}
- public boolean isCaseSensitive()
+ private static char toLowerCaseFast( char ch )
{
- return m_isCaseSensitive;
+ return ( ch >= 'A' && ch <= 'Z' ) ? ( char ) ( ch + 'a' - 'A' ) : ch;
}
}
\ No newline at end of file
Modified: felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/StringMap.java
URL: http://svn.apache.org/viewvc/felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/StringMap.java?rev=1858443&r1=1858442&r2=1858443&view=diff
==============================================================================
--- felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/StringMap.java (original)
+++ felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/StringMap.java Tue Apr 30 16:21:29 2019
@@ -7,7 +7,7 @@
* "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
+ * 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
@@ -18,130 +18,32 @@
*/
package org.apache.felix.connect.felix.framework.util;
-import java.util.Collection;
import java.util.Map;
-import java.util.Set;
import java.util.TreeMap;
/**
- * Simple utility class that creates a map for string-based keys. This map can
- * be set to use case-sensitive or case-insensitive comparison when searching
- * for the key. Any keys put into this 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<T> implements Map<String, T>
+ * Simple utility class that creates a map for string-based keys.
+ * This map can be set to use case-sensitive or case-insensitive
+ * comparison when searching for the key. Any keys put into this
+ * 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 extends TreeMap<String, Object>
{
- private TreeMap<String, T> m_map;
public StringMap()
{
- this(true);
- }
-
- public StringMap(boolean caseSensitive)
- {
- m_map = new TreeMap<String, T>(new StringComparator(caseSensitive));
- }
-
- public StringMap(Map<? extends String, ? extends T> 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<String, T> map = new TreeMap<String, T>(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);
- }
-
- @Override
- public boolean containsValue(Object arg0)
- {
- return m_map.containsValue(arg0);
+ super(StringComparator.COMPARATOR);
}
- @Override
- public T get(Object arg0)
+ public StringMap(Map<?, ?> map)
{
- return m_map.get(arg0);
- }
-
- @Override
- public T put(String key, T value)
- {
- return m_map.put(key, value);
- }
-
- @Override
- public void putAll(Map<? extends String, ? extends T> map)
- {
- for (Entry<? extends String, ? extends T> entry : map.entrySet())
+ this();
+ for (Map.Entry<?, ?> e : map.entrySet())
{
- put(entry.getKey(), entry.getValue());
+ put(e.getKey().toString(), e.getValue());
}
}
- @Override
- public T remove(Object arg0)
- {
- return m_map.remove(arg0);
- }
-
- @Override
- public void clear()
- {
- m_map.clear();
- }
-
- @Override
- public Set<String> keySet()
- {
- return m_map.keySet();
- }
-
- @Override
- public Collection<T> values()
- {
- return m_map.values();
- }
-
- @Override
- public Set<Entry<String, T>> entrySet()
- {
- return m_map.entrySet();
- }
-
- public String toString()
- {
- return m_map.toString();
- }
-}
\ No newline at end of file
+}
Modified: felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/Util.java
URL: http://svn.apache.org/viewvc/felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/Util.java?rev=1858443&r1=1858442&r2=1858443&view=diff
==============================================================================
--- felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/Util.java (original)
+++ felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/util/Util.java Tue Apr 30 16:21:29 2019
@@ -24,7 +24,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -515,4 +518,116 @@ public class Util
return val;
}
+ public static List<String> parseDelimitedString(String value, String delim)
+ {
+ return parseDelimitedString(value, delim, true);
+ }
+
+ /**
+ * Parses delimited string and returns an array containing the tokens. This
+ * parser obeys quotes, so the delimiter character will be ignored if it is
+ * inside of a quote. This method assumes that the quote character is not
+ * included in the set of delimiter characters.
+ * @param value the delimited string to parse.
+ * @param delim the characters delimiting the tokens.
+ * @return a list of string or an empty list if there are none.
+ **/
+ public static List<String> parseDelimitedString(String value, String delim, boolean trim)
+ {
+ if (value == null)
+ {
+ value = "";
+ }
+
+ List<String> list = new ArrayList<String>();
+
+ int CHAR = 1;
+ int DELIMITER = 2;
+ int STARTQUOTE = 4;
+ int ENDQUOTE = 8;
+
+ StringBuilder sb = new StringBuilder();
+
+ int expecting = (CHAR | DELIMITER | STARTQUOTE);
+
+ boolean isEscaped = false;
+ for (int i = 0; i < value.length(); i++)
+ {
+ char c = value.charAt(i);
+
+ boolean isDelimiter = (delim.indexOf(c) >= 0);
+
+ if (!isEscaped && (c == '\\'))
+ {
+ isEscaped = true;
+ continue;
+ }
+
+ if (isEscaped)
+ {
+ sb.append(c);
+ }
+ else if (isDelimiter && ((expecting & DELIMITER) > 0))
+ {
+ if (trim)
+ {
+ list.add(sb.toString().trim());
+ }
+ else
+ {
+ list.add(sb.toString());
+ }
+ sb.delete(0, sb.length());
+ expecting = (CHAR | DELIMITER | STARTQUOTE);
+ }
+ else if ((c == '"') && ((expecting & STARTQUOTE) > 0))
+ {
+ sb.append(c);
+ expecting = CHAR | ENDQUOTE;
+ }
+ else if ((c == '"') && ((expecting & ENDQUOTE) > 0))
+ {
+ sb.append(c);
+ expecting = (CHAR | STARTQUOTE | DELIMITER);
+ }
+ else if ((expecting & CHAR) > 0)
+ {
+ sb.append(c);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Invalid delimited string: " + value);
+ }
+
+ isEscaped = false;
+ }
+
+ if (sb.length() > 0)
+ {
+ if (trim)
+ {
+ list.add(sb.toString().trim());
+ }
+ else
+ {
+ list.add(sb.toString());
+ }
+ }
+
+ return list;
+ }
+
+
+ private static final List EMPTY_LIST = Collections.unmodifiableList(Collections.EMPTY_LIST);
+ private static final Map EMPTY_MAP = Collections.unmodifiableMap(Collections.EMPTY_MAP);
+
+ public static <T> List<T> newImmutableList(List<T> list)
+ {
+ return list == null || list.isEmpty() ? EMPTY_LIST : Collections.unmodifiableList(list);
+ }
+
+ public static <K,V> Map<K,V> newImmutableMap(Map<K,V> map)
+ {
+ return map == null || map.isEmpty() ? EMPTY_MAP : Collections.unmodifiableMap(map);
+ }
}
\ No newline at end of file
Added: felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/wiring/BundleCapabilityImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/wiring/BundleCapabilityImpl.java?rev=1858443&view=auto
==============================================================================
--- felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/wiring/BundleCapabilityImpl.java (added)
+++ felix/trunk/connect/src/main/java/org/apache/felix/connect/felix/framework/wiring/BundleCapabilityImpl.java Tue Apr 30 16:21:29 2019
@@ -0,0 +1,203 @@
+/*
+ * 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.connect.felix.framework.wiring;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import org.apache.felix.connect.felix.framework.capabilityset.SimpleFilter;
+import org.apache.felix.connect.felix.framework.util.Util;
+import org.osgi.framework.Constants;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRevision;
+
+public class BundleCapabilityImpl implements BundleCapability
+{
+ public static final String VERSION_ATTR = "version";
+
+ private final BundleRevision m_revision;
+ private final String m_namespace;
+ private final Map<String, String> m_dirs;
+ private final Map<String, Object> m_attrs;
+ private final List<String> m_uses;
+ private final List<List<String>> m_includeFilter;
+ private final List<List<String>> m_excludeFilter;
+ private final Set<String> m_mandatory;
+
+ public BundleCapabilityImpl(BundleRevision revision, String namespace,
+ Map<String, String> dirs, Map<String, Object> attrs)
+ {
+ m_namespace = namespace;
+ m_revision = revision;
+ m_dirs = Util.newImmutableMap(dirs);
+ m_attrs = Util.newImmutableMap(attrs);
+
+ // Find all export directives: uses, mandatory, include, and exclude.
+
+ List<String> uses = Collections.EMPTY_LIST;
+ String value = m_dirs.get(Constants.USES_DIRECTIVE);
+ if (value != null)
+ {
+ // Parse these uses directive.
+ StringTokenizer tok = new StringTokenizer(value, ",");
+ uses = new ArrayList(tok.countTokens());
+ while (tok.hasMoreTokens())
+ {
+ uses.add(tok.nextToken().trim());
+ }
+ }
+ m_uses = uses;
+
+ value = m_dirs.get(Constants.INCLUDE_DIRECTIVE);
+ if (value != null)
+ {
+ List<String> filters = Util.parseDelimitedString(value, ",");
+ m_includeFilter = new ArrayList<List<String>>(filters.size());
+ for (int filterIdx = 0; filterIdx < filters.size(); filterIdx++)
+ {
+ List<String> substrings = SimpleFilter.parseSubstring(filters.get(filterIdx));
+ m_includeFilter.add(substrings);
+ }
+ }
+ else
+ {
+ m_includeFilter = null;
+ }
+
+ value = m_dirs.get(Constants.EXCLUDE_DIRECTIVE);
+ if (value != null)
+ {
+ List<String> filters = Util.parseDelimitedString(value, ",");
+ m_excludeFilter = new ArrayList<List<String>>(filters.size());
+ for (int filterIdx = 0; filterIdx < filters.size(); filterIdx++)
+ {
+ List<String> substrings = SimpleFilter.parseSubstring(filters.get(filterIdx));
+ m_excludeFilter.add(substrings);
+ }
+ }
+ else
+ {
+ m_excludeFilter = null;
+ }
+
+ Set<String> mandatory = Collections.EMPTY_SET;
+ value = m_dirs.get(Constants.MANDATORY_DIRECTIVE);
+ if (value != null)
+ {
+ List<String> names = Util.parseDelimitedString(value, ",");
+ mandatory = new HashSet<String>(names.size());
+ for (String name : names)
+ {
+ // If attribute exists, then record it as mandatory.
+ if (m_attrs.containsKey(name))
+ {
+ mandatory.add(name);
+ }
+ // Otherwise, report an error.
+ else
+ {
+ throw new IllegalArgumentException(
+ "Mandatory attribute '" + name + "' does not exist.");
+ }
+ }
+ }
+ m_mandatory = mandatory;
+ }
+
+ public BundleRevision getResource()
+ {
+ return m_revision;
+ }
+
+ public BundleRevision getRevision()
+ {
+ return m_revision;
+ }
+
+ public String getNamespace()
+ {
+ return m_namespace;
+ }
+
+ public Map<String, String> getDirectives()
+ {
+ return m_dirs;
+ }
+
+ public Map<String, Object> getAttributes()
+ {
+ return m_attrs;
+ }
+
+ public boolean isAttributeMandatory(String name)
+ {
+ return !m_mandatory.isEmpty() && m_mandatory.contains(name);
+ }
+
+ public List<String> getUses()
+ {
+ return m_uses;
+ }
+
+ public boolean isIncluded(String name)
+ {
+ if ((m_includeFilter == null) && (m_excludeFilter == null))
+ {
+ return true;
+ }
+
+ // Get the class name portion of the target class.
+ String className = Util.getClassName(name);
+
+ // If there are no include filters then all classes are included
+ // by default, otherwise try to find one match.
+ boolean included = (m_includeFilter == null);
+ for (int i = 0;
+ (!included) && (m_includeFilter != null) && (i < m_includeFilter.size());
+ i++)
+ {
+ included = SimpleFilter.compareSubstring(m_includeFilter.get(i), className);
+ }
+
+ // If there are no exclude filters then no classes are excluded
+ // by default, otherwise try to find one match.
+ boolean excluded = false;
+ for (int i = 0;
+ (!excluded) && (m_excludeFilter != null) && (i < m_excludeFilter.size());
+ i++)
+ {
+ excluded = SimpleFilter.compareSubstring(m_excludeFilter.get(i), className);
+ }
+ return included && !excluded;
+ }
+
+ @Override
+ public String toString()
+ {
+ if (m_revision == null)
+ {
+ return m_attrs.toString();
+ }
+ return "[" + m_revision + "] " + m_namespace + "; " + m_attrs;
+ }
+}
\ No newline at end of file