Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Filter.java')
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Filter.java1837
1 files changed, 1837 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Filter.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Filter.java
new file mode 100644
index 000000000..e73fcda6c
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Filter.java
@@ -0,0 +1,1837 @@
+/*******************************************************************************
+ * Copyright (c) 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.framework.internal.core;
+
+import java.util.Dictionary;
+import java.util.Vector;
+
+import org.eclipse.osgi.framework.debug.Debug;
+import org.eclipse.osgi.framework.util.*;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * RFC 1960-based Filter. Filter objects can be created by calling
+ * the constructor with the desired filter string.
+ * A Filter object can be called numerous times to determine if the
+ * match argument matches the filter string that was used to create the Filter
+ * object.
+ *
+ * <p>The syntax of a filter string is the string representation
+ * of LDAP search filters as defined in RFC 1960:
+ * <i>A String Representation of LDAP Search Filters</i> (available at
+ * http://www.ietf.org/rfc/rfc1960.txt).
+ * It should be noted that RFC 2254:
+ * <i>A String Representation of LDAP Search Filters</i>
+ * (available at http://www.ietf.org/rfc/rfc2254.txt) supersedes
+ * RFC 1960 but only adds extensible matching and is not applicable for this
+ * API.
+ *
+ * <p>The string representation of an LDAP search filter is defined by the
+ * following grammar. It uses a prefix format.
+ * <pre>
+ * &lt;filter&gt; ::= '(' &lt;filtercomp&gt; ')'
+ * &lt;filtercomp&gt; ::= &lt;and&gt; | &lt;or&gt; | &lt;not&gt; | &lt;item&gt;
+ * &lt;and&gt; ::= '&' &lt;filterlist&gt;
+ * &lt;or&gt; ::= '|' &lt;filterlist&gt;
+ * &lt;not&gt; ::= '!' &lt;filter&gt;
+ * &lt;filterlist&gt; ::= &lt;filter&gt; | &lt;filter&gt; &lt;filterlist&gt;
+ * &lt;item&gt; ::= &lt;simple&gt; | &lt;present&gt; | &lt;substring&gt;
+ * &lt;simple&gt; ::= &lt;attr&gt; &lt;filtertype&gt; &lt;value&gt;
+ * &lt;filtertype&gt; ::= &lt;equal&gt; | &lt;approx&gt; | &lt;greater&gt; | &lt;less&gt;
+ * &lt;equal&gt; ::= '='
+ * &lt;approx&gt; ::= '~='
+ * &lt;greater&gt; ::= '&gt;='
+ * &lt;less&gt; ::= '&lt;='
+ * &lt;present&gt; ::= &lt;attr&gt; '=*'
+ * &lt;substring&gt; ::= &lt;attr&gt; '=' &lt;initial&gt; &lt;any&gt; &lt;final&gt;
+ * &lt;initial&gt; ::= NULL | &lt;value&gt;
+ * &lt;any&gt; ::= '*' &lt;starval&gt;
+ * &lt;starval&gt; ::= NULL | &lt;value&gt; '*' &lt;starval&gt;
+ * &lt;final&gt; ::= NULL | &lt;value&gt;
+ * </pre>
+ *
+ * <code>&lt;attr&gt;</code> is a string representing an attribute, or
+ * key, in the properties objects of the registered services.
+ * Attribute names are not case sensitive;
+ * that is cn and CN both refer to the same attribute.
+ * <code>&lt;value&gt;</code> is a string representing the value, or part of
+ * one, of a key in the properties objects of the registered services.
+ * If a <code>&lt;value&gt;</code> must
+ * contain one of the characters '<code>*</code>' or '<code>(</code>'
+ * or '<code>)</code>', these characters
+ * should be escaped by preceding them with the backslash '<code>\</code>'
+ * character.
+ * Note that although both the <code>&lt;substring&gt;</code> and
+ * <code>&lt;present&gt;</code> productions can
+ * produce the <code>'attr=*'</code> construct, this construct is used only to
+ * denote a presence filter.
+ *
+ * <p>Examples of LDAP filters are:
+ *
+ * <pre>
+ * &quot;(cn=Babs Jensen)&quot;
+ * &quot;(!(cn=Tim Howes))&quot;
+ * &quot;(&(&quot; + Constants.OBJECTCLASS + &quot;=Person)(|(sn=Jensen)(cn=Babs J*)))&quot;
+ * &quot;(o=univ*of*mich*)&quot;
+ * </pre>
+ *
+ * <p>The approximate match (<code>~=</code>) is implementation specific but
+ * should at least ignore case and white space differences. Optional are
+ * codes like soundex or other smart "closeness" comparisons.
+ *
+ * <p>Comparison of values is not straightforward. Strings
+ * are compared differently than numbers and it is
+ * possible for a key to have multiple values. Note that
+ * that keys in the match argument must always be strings.
+ * The comparison is defined by the object type of the key's
+ * value. The following rules apply for comparison:
+ *
+ * <blockquote>
+ * <TABLE BORDER=0>
+ * <TR><TD><b>Property Value Type </b></TD><TD><b>Comparison Type</b></TD></TR>
+ * <TR><TD>String </TD><TD>String comparison</TD></TR>
+ * <TR valign=top><TD>Integer, Long, Float, Double, Byte, Short, BigInteger, BigDecimal </TD><TD>numerical comparison</TD></TR>
+ * <TR><TD>Character </TD><TD>character comparison</TD></TR>
+ * <TR><TD>Boolean </TD><TD>equality comparisons only</TD></TR>
+ * <TR><TD>[] (array)</TD><TD>recursively applied to values </TD></TR>
+ * <TR><TD>Vector</TD><TD>recursively applied to elements </TD></TR>
+ * </TABLE>
+ * Note: arrays of primitives are also supported.
+ * </blockquote>
+ *
+ * A filter matches a key that has multiple values if it
+ * matches at least one of those values. For example,
+ * <pre>
+ * Dictionary d = new Hashtable();
+ * d.put( "cn", new String[] { "a", "b", "c" } );
+ * </pre>
+ * d will match <code>(cn=a)</code> and also <code>(cn=b)</code>
+ *
+ * <p>A filter component that references a key having an unrecognizable
+ * data type will evaluate to <code>false</code> .
+ */
+
+public class Filter
+ implements org.osgi.framework.Filter /* since Framework 1.1 */
+{
+ /* public methods in org.osgi.framework.Filter */
+
+ /**
+ * Constructs a {@link Filter} object. This filter object may be used
+ * to match a {@link ServiceReference} or a Dictionary.
+ *
+ * <p> If the filter cannot be parsed, an {@link InvalidSyntaxException}
+ * will be thrown with a human readable message where the
+ * filter became unparsable.
+ *
+ * @param filter the filter string.
+ * @exception InvalidSyntaxException If the filter parameter contains
+ * an invalid filter string that cannot be parsed.
+ */
+ public Filter(String filter) throws InvalidSyntaxException
+ {
+ topLevel = true;
+ new Parser(filter).parse(this);
+ }
+
+ /**
+ * Filter using a service's properties.
+ * The Filter is executed using the referenced service's
+ * properties.
+ *
+ * @param reference the reference to the service whose
+ * properties are used in the match.
+ * @return <code>true</code> if the service's properties match this filter;
+ * <code>false</code> otherwise.
+ */
+ public boolean match(org.osgi.framework.ServiceReference reference)
+ {
+ return(match0(((ServiceReference)reference).registration.properties));
+ }
+
+ /**
+ * Filter using a Dictionary.
+ * The Filter is executed using the Dictionary's keys.
+ *
+ * @param dictionary the dictionary whose keys are used in the match.
+ * @return <code>true</code> if the Dictionary's keys match this filter;
+ * <code>false</code> otherwise.
+ */
+ public boolean match(Dictionary dictionary)
+ {
+ if (dictionary != null)
+ {
+ dictionary = new Headers(dictionary);
+ }
+
+ return(match0(dictionary));
+ }
+
+ /**
+ * Returns this Filter object's filter string.
+ * The filter string is normalized by removing
+ * whitespace which does not affect the meaning of the filter.
+ *
+ * @return filter string.
+ */
+ public String toString()
+ {
+ if (this.filter == null)
+ {
+ StringBuffer filter = new StringBuffer();
+ filter.append('(');
+
+ switch (operation)
+ {
+ case AND:
+ {
+ filter.append('&');
+
+ Filter[] filters = (Filter[])value;
+ int size = filters.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ filter.append(filters[i].toString());
+ }
+
+ break;
+ }
+
+ case OR:
+ {
+ filter.append('|');
+
+ Filter[] filters = (Filter[])value;
+ int size = filters.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ filter.append(filters[i].toString());
+ }
+
+ break;
+ }
+
+ case NOT:
+ {
+ filter.append('!');
+ filter.append(value.toString());
+
+ break;
+ }
+
+ case SUBSTRING:
+ {
+ filter.append(attr);
+ filter.append('=');
+
+ String[] substrings = (String[])value;
+
+ int size = substrings.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ String substr = substrings[i];
+
+ if (substr == null) /* * */
+ {
+ filter.append('*');
+ }
+ else /* xxx */
+ {
+ filter.append(encodeValue(substr));
+ }
+ }
+
+ break;
+ }
+ case EQUAL:
+ {
+ filter.append(attr);
+ filter.append('=');
+ filter.append(encodeValue(value.toString()));
+
+ break;
+ }
+ case GREATER:
+ {
+ filter.append(attr);
+ filter.append(">=");
+ filter.append(encodeValue(value.toString()));
+
+ break;
+ }
+ case LESS:
+ {
+ filter.append(attr);
+ filter.append("<=");
+ filter.append(encodeValue(value.toString()));
+
+ break;
+ }
+ case APPROX:
+ {
+ filter.append(attr);
+ filter.append("~=");
+ filter.append(encodeValue(approxString(value.toString())));
+
+ break;
+ }
+
+ case PRESENT:
+ {
+ filter.append(attr);
+ filter.append("=*");
+
+ break;
+ }
+ }
+
+ filter.append(')');
+
+ if (topLevel) /* only hold onto String object at toplevel */
+ {
+ this.filter = filter.toString();
+ }
+ else
+ {
+ return(filter.toString());
+ }
+ }
+
+ return(this.filter);
+ }
+
+ /**
+ * Compares this Filter object to another object.
+ *
+ * @param obj the object to compare.
+ * @return If the other object is a Filter object, then
+ * returns <code>this.toString().equals(obj.toString())</code>,
+ * otherwise <code>false</code>.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return (true);
+ }
+
+ if (!(obj instanceof Filter))
+ {
+ return (false);
+ }
+
+ return(this.toString().equals(obj.toString()));
+ }
+
+ /**
+ * Returns the hashCode for this Filter object.
+ *
+ * @return The hashCode of the filter string, <i>i.e.</i>
+ * <code>this.toString().hashCode()</code>.
+ */
+ public int hashCode()
+ {
+ return(this.toString().hashCode());
+ }
+
+
+ /* Protected fields and methods for the Filter implementation */
+
+ /** filter operation */
+ protected int operation;
+ protected static final int EQUAL = 1;
+ protected static final int APPROX = 2;
+ protected static final int GREATER = 3;
+ protected static final int LESS = 4;
+ protected static final int PRESENT = 5;
+ protected static final int SUBSTRING = 6;
+ protected static final int AND = 7;
+ protected static final int OR = 8;
+ protected static final int NOT = 9;
+
+ /** filter attribute or null if operation AND, OR or NOT */
+ protected String attr;
+ /** filter operands */
+ protected Object value;
+
+ /* normalized filter string for topLevel Filter object */
+ protected String filter;
+
+ /* true if root Filter object */
+ protected boolean topLevel;
+
+ protected Filter()
+ {
+ topLevel = false;
+ }
+
+ protected void setFilter(int operation, String attr, Object value)
+ {
+ this.operation = operation;
+ this.attr = attr;
+ this.value = value;
+ }
+
+ /**
+ * Filter using a service's properties.
+ * The Filter is executed using the referenced service's
+ * properties.
+ *
+ * @param reference A reference to the service whose
+ * properties are used in the match.
+ * @return If the service's properties match the filter,
+ * return <code>true</code>. Otherwise, return <code>false</code>.
+ */
+ protected boolean match(ServiceReference reference)
+ {
+ return(match0(reference.registration.properties));
+ }
+
+ /**
+ * Internal match routine.
+ * Dictionary parameter must support case-insensitive get.
+ *
+ * @param dictionary A dictionary whose
+ * keys are used in the match.
+ * @return If the Dictionary's keys match the filter,
+ * return <code>true</code>. Otherwise, return <code>false</code>.
+ */
+ protected boolean match0(Dictionary properties)
+ {
+ switch (operation)
+ {
+ case AND:
+ {
+ Filter[] filters = (Filter[])value;
+ int size = filters.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (!filters[i].match0(properties))
+ {
+ return(false);
+ }
+ }
+
+ return(true);
+ }
+
+ case OR:
+ {
+ Filter[] filters = (Filter[])value;
+ int size = filters.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (filters[i].match0(properties))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ case NOT:
+ {
+ Filter filter = (Filter)value;
+
+ return(!filter.match0(properties));
+ }
+
+ case SUBSTRING:
+ case EQUAL:
+ case GREATER:
+ case LESS:
+ case APPROX:
+ {
+ Object prop = (properties == null) ? null : properties.get(attr);
+
+ return(compare(operation, prop, value));
+ }
+
+ case PRESENT:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("PRESENT("+attr+")");
+ }
+
+ Object prop = (properties == null) ? null : properties.get(attr);
+
+ return(prop != null);
+ }
+ }
+
+ return(false);
+ }
+
+ /**
+ * Encode the value string such that '(', '*', ')'
+ * and '\' are escaped.
+ *
+ * @param value unencoded value string.
+ * @return encoded value string.
+ */
+ protected static String encodeValue(String value)
+ {
+ boolean encoded = false;
+ int inlen = value.length();
+ int outlen = inlen << 1; /* inlen * 2 */
+
+ char[] output = new char[outlen];
+ value.getChars(0, inlen, output, inlen);
+
+ int cursor = 0;
+ for (int i = inlen; i < outlen; i++)
+ {
+ char c = output[i];
+
+ switch (c)
+ {
+ case '(':
+ case '*':
+ case ')':
+ case '\\':
+ {
+ output[cursor] = '\\';
+ cursor++;
+ encoded = true;
+
+ break;
+ }
+ }
+
+ output[cursor] = c;
+ cursor++;
+ }
+
+ return(encoded ? new String(output, 0, cursor) : value);
+ }
+
+ protected boolean compare(int operation, Object value1, Object value2)
+ {
+ if (value1 == null)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("compare("+value1+","+value2+")");
+ }
+
+ return(false);
+ }
+
+ try
+ {
+ if (value1 instanceof String)
+ {
+ return(compare_String(operation, (String)value1, value2));
+ }
+
+ Class clazz = value1.getClass();
+
+ if (clazz.isArray())
+ {
+ Class type = clazz.getComponentType();
+
+ if (type.isPrimitive())
+ {
+ return(compare_PrimitiveArray(operation, type, value1, value2));
+ }
+ else
+ {
+ return(compare_ObjectArray(operation, (Object[])value1, value2));
+ }
+
+ }
+
+ if (value1 instanceof Vector)
+ {
+ return(compare_Vector(operation, (Vector)value1, value2));
+ }
+
+ if (value1 instanceof Integer)
+ {
+ return(compare_Integer(operation, ((Integer)value1).intValue(), value2));
+ }
+
+ if (value1 instanceof Long)
+ {
+ return(compare_Long(operation, ((Long)value1).longValue(), value2));
+ }
+
+ if (value1 instanceof Byte)
+ {
+ return(compare_Byte(operation, ((Byte)value1).byteValue(), value2));
+ }
+
+ if (value1 instanceof Short)
+ {
+ return(compare_Short(operation, ((Short)value1).shortValue(), value2));
+ }
+
+ if (value1 instanceof Character)
+ {
+ return(compare_Character(operation, ((Character)value1).charValue(), value2));
+ }
+
+ if (value1 instanceof Float)
+ {
+ return(compare_Float(operation, ((Float)value1).floatValue(), value2));
+ }
+
+ if (value1 instanceof Double)
+ {
+ return(compare_Double(operation, ((Double)value1).doubleValue(), value2));
+ }
+
+ if (value1 instanceof Boolean)
+ {
+ return(compare_Boolean(operation, ((Boolean)value1).booleanValue(), value2));
+ }
+
+ try
+ {
+ if (value1 instanceof Comparable)
+ {
+ return(compare_Comparable(operation, (Comparable)value1, value2));
+ }
+ }
+ catch (NoClassDefFoundError notype)
+ {
+ }
+
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("Type not supported");
+ }
+ }
+ catch (Throwable t)
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.printStackTrace(t);
+ }
+ }
+
+ return(false);
+ }
+
+
+ protected boolean compare_Vector(int operation, Vector vector, Object value2)
+ {
+ int size = vector.size();
+
+ for (int i = 0; i < size; i++)
+ {
+ if (compare(operation, vector.elementAt(i), value2))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_ObjectArray(int operation, Object[] array, Object value2)
+ {
+ int size = array.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (compare(operation, array[i], value2))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_PrimitiveArray(int operation, Class type, Object primarray, Object value2)
+ {
+ if (Integer.TYPE.isAssignableFrom(type))
+ {
+ int[] array = (int[])primarray;
+
+ int size = array.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (compare_Integer(operation, array[i], value2))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ if (Long.TYPE.isAssignableFrom(type))
+ {
+ long[] array = (long[])primarray;
+
+ int size = array.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (compare_Long(operation, array[i], value2))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ if (Byte.TYPE.isAssignableFrom(type))
+ {
+ byte[] array = (byte[])primarray;
+
+ int size = array.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (compare_Byte(operation, array[i], value2))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ if (Short.TYPE.isAssignableFrom(type))
+ {
+ short[] array = (short[])primarray;
+
+ int size = array.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (compare_Short(operation, array[i], value2))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ if (Character.TYPE.isAssignableFrom(type))
+ {
+ char[] array = (char[])primarray;
+
+ int size = array.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (compare_Character(operation, array[i], value2))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ if (Float.TYPE.isAssignableFrom(type))
+ {
+ float[] array = (float[])primarray;
+
+ int size = array.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (compare_Float(operation, array[i], value2))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ if (Double.TYPE.isAssignableFrom(type))
+ {
+ double[] array = (double[])primarray;
+
+ int size = array.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (compare_Double(operation, array[i], value2))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ if (Boolean.TYPE.isAssignableFrom(type))
+ {
+ boolean[] array = (boolean[])primarray;
+
+ int size = array.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (compare_Boolean(operation, array[i], value2))
+ {
+ return(true);
+ }
+ }
+
+ return(false);
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_String(int operation, String string, Object value2)
+ {
+ switch (operation)
+ {
+ case SUBSTRING:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("SUBSTRING("+string+","+value2+")");
+ }
+
+ String[] substrings = (String[])value2;
+ int pos = 0;
+
+ int size = substrings.length;
+
+ for (int i = 0; i < size; i++)
+ {
+ String substr = substrings[i];
+
+ if (i+1 < size) /* if this is not that last substr */
+ {
+ if (substr == null) /* * */
+ {
+ String substr2 = substrings[i+1];
+
+ if (substr2 == null) /* ** */
+ {
+ continue; /* ignore first star */
+ }
+ else /* *xxx */
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("indexOf(\""+substr2+"\","+pos+")");
+ }
+ int index = string.indexOf(substr2, pos);
+ if (index == -1)
+ {
+ return(false);
+ }
+
+ i++;
+ pos = index + substr2.length();
+ }
+ }
+ else /* xxx */
+ {
+ int len = substr.length();
+
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("regionMatches("+pos+",\""+substr+"\")");
+ }
+ if (string.regionMatches(pos, substr, 0, len))
+ {
+ pos += len;
+ }
+ else
+ {
+ return(false);
+ }
+ }
+ }
+ else /* last substr */
+ {
+ if (substr == null) /* * */
+ {
+ return(true);
+ }
+ else /* xxx */
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("regionMatches("+pos+","+substr+")");
+ }
+ return(string.regionMatches(pos, substr, 0, substr.length()));
+ }
+ }
+ }
+
+ return(true);
+ }
+ case EQUAL:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("EQUAL("+string+","+value2+")");
+ }
+ return(string.equals(value2));
+ }
+ case APPROX:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("APPROX("+string+","+value2+")");
+ }
+
+ string = approxString(string);
+ String string2 = approxString((String)value2);
+
+ return(string.equalsIgnoreCase(string2));
+ }
+ case GREATER:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("GREATER("+string+","+value2+")");
+ }
+ return(string.compareTo((String)value2) >= 0);
+ }
+ case LESS:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("LESS("+string+","+value2+")");
+ }
+ return(string.compareTo((String)value2) <= 0);
+ }
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_Integer(int operation, int intval, Object value2)
+ {
+ int intval2 = Integer.parseInt(((String)value2).trim());
+
+ switch (operation)
+ {
+ case SUBSTRING:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("SUBSTRING("+intval+","+value2+")");
+ }
+ return(false);
+ }
+ case EQUAL:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("EQUAL("+intval+","+value2+")");
+ }
+ return(intval == intval2);
+ }
+ case APPROX:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("APPROX("+intval+","+value2+")");
+ }
+ return(intval == intval2);
+ }
+ case GREATER:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("GREATER("+intval+","+value2+")");
+ }
+ return(intval >= intval2);
+ }
+ case LESS:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("LESS("+intval+","+value2+")");
+ }
+ return(intval <= intval2);
+ }
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_Long(int operation, long longval, Object value2)
+ {
+ long longval2 = Long.parseLong(((String)value2).trim());
+
+ switch (operation)
+ {
+ case SUBSTRING:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("SUBSTRING("+longval+","+value2+")");
+ }
+ return(false);
+ }
+ case EQUAL:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("EQUAL("+longval+","+value2+")");
+ }
+ return(longval == longval2);
+ }
+ case APPROX:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("APPROX("+longval+","+value2+")");
+ }
+ return(longval == longval2);
+ }
+ case GREATER:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("GREATER("+longval+","+value2+")");
+ }
+ return(longval >= longval2);
+ }
+ case LESS:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("LESS("+longval+","+value2+")");
+ }
+ return(longval <= longval2);
+ }
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_Byte(int operation, byte byteval, Object value2)
+ {
+ byte byteval2 = Byte.parseByte(((String)value2).trim());
+
+ switch (operation)
+ {
+ case SUBSTRING:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("SUBSTRING("+byteval+","+value2+")");
+ }
+ return(false);
+ }
+ case EQUAL:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("EQUAL("+byteval+","+value2+")");
+ }
+ return(byteval == byteval2);
+ }
+ case APPROX:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("APPROX("+byteval+","+value2+")");
+ }
+ return(byteval == byteval2);
+ }
+ case GREATER:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("GREATER("+byteval+","+value2+")");
+ }
+ return(byteval >= byteval2);
+ }
+ case LESS:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("LESS("+byteval+","+value2+")");
+ }
+ return(byteval <= byteval2);
+ }
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_Short(int operation, short shortval, Object value2)
+ {
+ short shortval2 = Short.parseShort(((String)value2).trim());
+
+ switch (operation)
+ {
+ case SUBSTRING:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("SUBSTRING("+shortval+","+value2+")");
+ }
+ return(false);
+ }
+ case EQUAL:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("EQUAL("+shortval+","+value2+")");
+ }
+ return(shortval == shortval2);
+ }
+ case APPROX:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("APPROX("+shortval+","+value2+")");
+ }
+ return(shortval == shortval2);
+ }
+ case GREATER:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("GREATER("+shortval+","+value2+")");
+ }
+ return(shortval >= shortval2);
+ }
+ case LESS:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("LESS("+shortval+","+value2+")");
+ }
+ return(shortval <= shortval2);
+ }
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_Character(int operation, char charval, Object value2)
+ {
+ char charval2 = (((String)value2).trim()).charAt(0);
+
+ switch (operation)
+ {
+ case SUBSTRING:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("SUBSTRING("+charval+","+value2+")");
+ }
+ return(false);
+ }
+ case EQUAL:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("EQUAL("+charval+","+value2+")");
+ }
+ return(charval == charval2);
+ }
+ case APPROX:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("APPROX("+charval+","+value2+")");
+ }
+ return(Character.toLowerCase(charval) == Character.toLowerCase(charval2));
+ }
+ case GREATER:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("GREATER("+charval+","+value2+")");
+ }
+ return(charval >= charval2);
+ }
+ case LESS:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("LESS("+charval+","+value2+")");
+ }
+ return(charval <= charval2);
+ }
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_Boolean(int operation, boolean boolval, Object value2)
+ {
+ boolean boolval2 = new Boolean(((String)value2).trim()).booleanValue();
+
+ switch (operation)
+ {
+ case SUBSTRING:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("SUBSTRING("+boolval+","+value2+")");
+ }
+ return(false);
+ }
+ case EQUAL:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("EQUAL("+boolval+","+value2+")");
+ }
+ return(boolval == boolval2);
+ }
+ case APPROX:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("APPROX("+boolval+","+value2+")");
+ }
+ return(boolval == boolval2);
+ }
+ case GREATER:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("GREATER("+boolval+","+value2+")");
+ }
+ return(boolval == boolval2);
+ }
+ case LESS:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("LESS("+boolval+","+value2+")");
+ }
+ return(boolval == boolval2);
+ }
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_Float(int operation, float floatval, Object value2)
+ {
+ float floatval2 = Float.parseFloat(((String)value2).trim());
+
+ switch (operation)
+ {
+ case SUBSTRING:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("SUBSTRING("+floatval+","+value2+")");
+ }
+ return(false);
+ }
+ case EQUAL:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("EQUAL("+floatval+","+value2+")");
+ }
+ return(floatval == floatval2);
+ }
+ case APPROX:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("APPROX("+floatval+","+value2+")");
+ }
+ return(floatval == floatval2);
+ }
+ case GREATER:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("GREATER("+floatval+","+value2+")");
+ }
+ return(floatval >= floatval2);
+ }
+ case LESS:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("LESS("+floatval+","+value2+")");
+ }
+ return(floatval <= floatval2);
+ }
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_Double(int operation, double doubleval, Object value2)
+ {
+ double doubleval2 = Double.parseDouble(((String)value2).trim());
+
+ switch (operation)
+ {
+ case SUBSTRING:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("SUBSTRING("+doubleval+","+value2+")");
+ }
+ return(false);
+ }
+ case EQUAL:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("EQUAL("+doubleval+","+value2+")");
+ }
+ return(doubleval == doubleval2);
+ }
+ case APPROX:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("APPROX("+doubleval+","+value2+")");
+ }
+ return(doubleval == doubleval2);
+ }
+ case GREATER:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("GREATER("+doubleval+","+value2+")");
+ }
+ return(doubleval >= doubleval2);
+ }
+ case LESS:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("LESS("+doubleval+","+value2+")");
+ }
+ return(doubleval <= doubleval2);
+ }
+ }
+
+ return(false);
+ }
+
+ protected boolean compare_Comparable(int operation, Comparable value1, Object value2)
+ {
+
+ try
+ {
+ java.lang.reflect.Constructor constructor =
+ value1.getClass().getConstructor(new Class[] {value2.getClass()});
+ value2 = constructor.newInstance(new Object[] {((String)value2).trim()});
+ }
+ catch (Throwable t)
+ {
+ return(false);
+ }
+
+ switch (operation)
+ {
+ case SUBSTRING:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("SUBSTRING("+value1+","+value2+")");
+ }
+ return(false);
+ }
+ case EQUAL:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("EQUAL("+value1+","+value2+")");
+ }
+ return(value1.compareTo(value2) == 0);
+ }
+ case APPROX:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("APPROX("+value1+","+value2+")");
+ }
+ return(value1.compareTo(value2) == 0);
+ }
+ case GREATER:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("GREATER("+value1+","+value2+")");
+ }
+ return(value1.compareTo(value2) >= 0);
+ }
+ case LESS:
+ {
+ if (Debug.DEBUG && Debug.DEBUG_FILTER)
+ {
+ Debug.println("LESS("+value1+","+value2+")");
+ }
+ return(value1.compareTo(value2) <= 0);
+ }
+ }
+
+ return(false);
+ }
+
+ /**
+ * Map a string for an APPROX (~=) comparison.
+ *
+ * This implementation removes white spaces.
+ * This is the minimum implementation allowed by
+ * the OSGi spec.
+ *
+ * @param input Input string.
+ * @return String ready for APPROX comparison.
+ */
+ protected static String approxString(String input)
+ {
+ boolean changed = false;
+ char[] output = input.toCharArray();
+
+ int length = output.length;
+
+ int cursor = 0;
+ for (int i = 0; i < length; i++)
+ {
+ char c = output[i];
+
+ if (Character.isWhitespace(c))
+ {
+ changed = true;
+ continue;
+ }
+
+ output[cursor] = c;
+ cursor++;
+ }
+
+ return(changed ? new String(output, 0, cursor) : input);
+ }
+
+
+ /**
+ * Parser class for OSGi filter strings. This class parses
+ * the complete filter string and builds a tree of Filter
+ * objects rooted at the parent.
+ */
+ static class Parser
+ {
+ protected String filterstring;
+ protected char[] filter;
+ protected int pos;
+
+ protected Parser(String filterstring)
+ {
+ this.filterstring = filterstring;
+ filter = filterstring.toCharArray();
+ pos = 0;
+ }
+
+ protected void parse(Filter parent) throws InvalidSyntaxException
+ {
+ try
+ {
+ parse_filter(parent);
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_TERMINATED_ABRUBTLY"), filterstring);
+ }
+
+ if (pos != filter.length)
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_TRAILING_CHARACTERS", pos), filterstring);
+ }
+ }
+
+ protected void parse_filter(Filter parent) throws InvalidSyntaxException
+ {
+ skipWhiteSpace();
+
+ if (filter[pos] != '(')
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_MISSING_LEFTPAREN", pos), filterstring);
+ }
+
+ pos++;
+
+ parse_filtercomp(parent);
+
+ skipWhiteSpace();
+
+ if (filter[pos] != ')')
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_MISSING_RIGHTPAREN", pos), filterstring);
+ }
+
+ pos++;
+
+ skipWhiteSpace();
+ }
+
+ protected void parse_filtercomp(Filter parent) throws InvalidSyntaxException
+ {
+ skipWhiteSpace();
+
+ char c = filter[pos];
+
+ switch (c)
+ {
+ case '&':
+ {
+ pos++;
+ parse_and(parent);
+ break;
+ }
+ case '|':
+ {
+ pos++;
+ parse_or(parent);
+ break;
+ }
+ case '!':
+ {
+ pos++;
+ parse_not(parent);
+ break;
+ }
+ default:
+ {
+ parse_item(parent);
+ break;
+ }
+ }
+ }
+
+ protected void parse_and(Filter parent) throws InvalidSyntaxException
+ {
+ skipWhiteSpace();
+
+ if (filter[pos] != '(')
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_MISSING_LEFTPAREN", pos), filterstring);
+ }
+
+ Vector operands = new Vector(10, 10);
+
+ while (filter[pos] == '(')
+ {
+ Filter child = new Filter();
+ parse_filter(child);
+ operands.addElement(child);
+ }
+
+ int size = operands.size();
+
+ Filter[] children = new Filter[size];
+
+ operands.copyInto(children);
+
+ parent.setFilter(Filter.AND, null, children);
+ }
+
+ protected void parse_or(Filter parent) throws InvalidSyntaxException
+ {
+ skipWhiteSpace();
+
+ if (filter[pos] != '(')
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_MISSING_LEFTPAREN", pos), filterstring);
+ }
+
+ Vector operands = new Vector(10, 10);
+
+ while (filter[pos] == '(')
+ {
+ Filter child = new Filter();
+ parse_filter(child);
+ operands.addElement(child);
+ }
+
+ int size = operands.size();
+
+ Filter[] children = new Filter[size];
+
+ operands.copyInto(children);
+
+ parent.setFilter(Filter.OR, null, children);
+ }
+
+ protected void parse_not(Filter parent) throws InvalidSyntaxException
+ {
+ skipWhiteSpace();
+
+ if (filter[pos] != '(')
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_MISSING_LEFTPAREN", pos), filterstring);
+ }
+
+ Filter child = new Filter();
+ parse_filter(child);
+
+ parent.setFilter(Filter.NOT, null, child);
+ }
+
+ protected void parse_item(Filter parent) throws InvalidSyntaxException
+ {
+ String attr = parse_attr();
+
+ skipWhiteSpace();
+
+ switch (filter[pos])
+ {
+ case '~':
+ {
+ if (filter[pos+1] == '=')
+ {
+ pos += 2;
+ parent.setFilter(Filter.APPROX, attr, parse_value());
+ return;
+ }
+ break;
+ }
+ case '>':
+ {
+ if (filter[pos+1] == '=')
+ {
+ pos += 2;
+ parent.setFilter(Filter.GREATER, attr, parse_value());
+ return;
+ }
+ break;
+ }
+ case '<':
+ {
+ if (filter[pos+1] == '=')
+ {
+ pos += 2;
+ parent.setFilter(Filter.LESS, attr, parse_value());
+ return;
+ }
+ break;
+ }
+ case '=':
+ {
+ if (filter[pos+1] == '*')
+ {
+ int oldpos = pos;
+ pos += 2;
+ skipWhiteSpace();
+ if (filter[pos] == ')')
+ {
+ parent.setFilter(Filter.PRESENT, attr, null);
+ return; /* present */
+ }
+ pos = oldpos;
+ }
+
+ pos++;
+ Object string = parse_substring();
+
+ if (string instanceof String)
+ {
+ parent.setFilter(Filter.EQUAL, attr, string);
+ }
+ else
+ {
+ parent.setFilter(Filter.SUBSTRING, attr, string);
+ }
+
+ return;
+ }
+ }
+
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_INVALID_OPERATOR", pos), filterstring);
+ }
+
+ protected String parse_attr() throws InvalidSyntaxException
+ {
+ skipWhiteSpace();
+
+ int begin = pos;
+ int end = pos;
+
+ char c = filter[pos];
+
+ while ("~<>=()".indexOf(c) == -1)
+ {
+ pos++;
+
+ if (!Character.isWhitespace(c))
+ {
+ end = pos;
+ }
+
+ c = filter[pos];
+ }
+
+ int length = end - begin;
+
+ if (length == 0)
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString(".FILTER_MISSING_ATTR", pos), filterstring);
+ }
+
+ return(new String(filter, begin, length));
+ }
+
+ protected String parse_value() throws InvalidSyntaxException
+ {
+ StringBuffer sb = new StringBuffer(filter.length - pos);
+
+ parseloop:
+ while (true)
+ {
+ char c = filter[pos];
+
+ switch (c)
+ {
+ case ')':
+ {
+ break parseloop;
+ }
+
+ case '(':
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_INVALID_VALUE", pos), filterstring);
+ }
+
+ case '\\':
+ {
+ pos++;
+ c = filter[pos];
+ /* fall through into default */
+ }
+
+ default:
+ {
+ sb.append(c);
+ pos++;
+ break;
+ }
+ }
+ }
+
+ if (sb.length() == 0)
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_MISSING_VALUE", pos), filterstring);
+ }
+
+ return(sb.toString());
+ }
+
+ protected Object parse_substring() throws InvalidSyntaxException
+ {
+ StringBuffer sb = new StringBuffer(filter.length - pos);
+
+ Vector operands = new Vector(10, 10);
+
+ parseloop:
+ while (true)
+ {
+ char c = filter[pos];
+
+ switch (c)
+ {
+ case ')':
+ {
+ if (sb.length() > 0)
+ {
+ operands.addElement(sb.toString());
+ }
+
+ break parseloop;
+ }
+
+ case '(':
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_INVALID_VALUE", pos), filterstring);
+ }
+
+ case '*':
+ {
+ if (sb.length() > 0)
+ {
+ operands.addElement(sb.toString());
+ }
+
+ sb.setLength(0);
+
+ operands.addElement(null);
+ pos++;
+
+ break;
+ }
+
+ case '\\':
+ {
+ pos++;
+ c = filter[pos];
+ /* fall through into default */
+ }
+
+ default:
+ {
+ sb.append(c);
+ pos++;
+ break;
+ }
+ }
+ }
+
+ int size = operands.size();
+
+ if (size == 0)
+ {
+ throw new InvalidSyntaxException(Msg.formatter.getString("FILTER_MISSING_VALUE", pos), filterstring);
+ }
+
+ if (size == 1)
+ {
+ Object single = operands.elementAt(0);
+
+ if (single != null)
+ {
+ return(single);
+ }
+ }
+
+ String[] strings = new String[size];
+
+ operands.copyInto(strings);
+
+ return(strings);
+ }
+
+ protected void skipWhiteSpace()
+ {
+ int length = filter.length;
+
+ while ((pos < length) && Character.isWhitespace(filter[pos]))
+ {
+ pos++;
+ }
+ }
+ }
+}

Back to the top