| /******************************************************************************* |
| * Copyright (c) 2003, 2009 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.osgi.framework.internal.core; |
| |
| import java.lang.reflect.*; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.util.*; |
| import org.eclipse.osgi.framework.debug.Debug; |
| import org.eclipse.osgi.framework.util.Headers; |
| import org.eclipse.osgi.internal.serviceregistry.ServiceReferenceImpl; |
| import org.eclipse.osgi.util.NLS; |
| import org.osgi.framework.*; |
| |
| /** |
| * 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> |
| * <filter> ::= '(' <filtercomp> ')' |
| * <filtercomp> ::= <and> | <or> | <not> | <item> |
| * <and> ::= '&' <filterlist> |
| * <or> ::= '|' <filterlist> |
| * <not> ::= '!' <filter> |
| * <filterlist> ::= <filter> | <filter> <filterlist> |
| * <item> ::= <simple> | <present> | <substring> |
| * <simple> ::= <attr> <filtertype> <value> |
| * <filtertype> ::= <equal> | <approx> | <greater> | <less> |
| * <equal> ::= '=' |
| * <approx> ::= '~=' |
| * <greater> ::= '>=' |
| * <less> ::= '<=' |
| * <present> ::= <attr> '=*' |
| * <substring> ::= <attr> '=' <initial> <any> <final> |
| * <initial> ::= NULL | <value> |
| * <any> ::= '*' <starval> |
| * <starval> ::= NULL | <value> '*' <starval> |
| * <final> ::= NULL | <value> |
| * </pre> |
| * |
| * <code><attr></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><value></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><value></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><substring></code> and |
| * <code><present></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> |
| * "(cn=Babs Jensen)" |
| * "(!(cn=Tim Howes))" |
| * "(&(" + Constants.OBJECTCLASS + "=Person)(|(sn=Jensen)(cn=Babs J*)))" |
| * "(o=univ*of*mich*)" |
| * </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 FilterImpl implements Filter /* since Framework 1.1 */{ |
| /* public methods in org.osgi.framework.Filter */ |
| |
| /** |
| * Constructs a {@link FilterImpl} object. This filter object may be used |
| * to match a {@link ServiceReferenceImpl} 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 filterString the filter string. |
| * @exception InvalidSyntaxException If the filter parameter contains |
| * an invalid filter string that cannot be parsed. |
| */ |
| public static FilterImpl newInstance(String filterString) throws InvalidSyntaxException { |
| return new Parser(filterString).parse(); |
| } |
| |
| /** |
| * Filter using a service's properties. |
| * <p> |
| * The filter is executed using the keys and values of the referenced |
| * service's properties. The keys are case insensitively matched with |
| * the filter. |
| * |
| * @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(ServiceReference reference) { |
| if (reference instanceof ServiceReferenceImpl) { |
| return match0(((ServiceReferenceImpl) reference).getRegistration().getProperties()); |
| } |
| return match0(new ServiceReferenceDictionary(reference)); |
| } |
| |
| /** |
| * Filter using a <code>Dictionary</code> object. The Filter is executed |
| * using the <code>Dictionary</code> object's keys and values. The keys |
| * are case insensitively matched with the filter. |
| * |
| * @param dictionary The <code>Dictionary</code> object whose keys are |
| * used in the match. |
| * @return <code>true</code> if the <code>Dictionary</code> object's |
| * keys and values match this filter; <code>false</code> |
| * otherwise. |
| * @throws IllegalArgumentException If <code>dictionary</code> contains |
| * case variants of the same key name. |
| */ |
| public boolean match(Dictionary dictionary) { |
| if (dictionary != null) { |
| dictionary = new Headers(dictionary); |
| } |
| |
| return match0(dictionary); |
| } |
| |
| /** |
| * Filter with case sensitivity using a <code>Dictionary</code> object. |
| * The Filter is executed using the <code>Dictionary</code> object's |
| * keys and values. The keys are case sensitively matched with the |
| * filter. |
| * |
| * @param dictionary The <code>Dictionary</code> object whose keys are |
| * used in the match. |
| * @return <code>true</code> if the <code>Dictionary</code> object's |
| * keys and values match this filter; <code>false</code> |
| * otherwise. |
| * @since 1.3 |
| */ |
| public boolean matchCase(Dictionary dictionary) { |
| return match0(dictionary); |
| } |
| |
| /** |
| * Returns this <code>Filter</code> object's filter string. |
| * <p> |
| * The filter string is normalized by removing whitespace which does not |
| * affect the meaning of the filter. |
| * |
| * @return Filter string. |
| */ |
| |
| public String toString() { |
| String result = filterString; |
| if (result == null) { |
| filterString = result = normalize(); |
| } |
| return result; |
| } |
| |
| /** |
| * Returns this <code>Filter</code>'s normalized filter string. |
| * <p> |
| * The filter string is normalized by removing whitespace which does not |
| * affect the meaning of the filter. |
| * |
| * @return This <code>Filter</code>'s filter string. |
| */ |
| private String normalize() { |
| StringBuffer sb = new StringBuffer(); |
| sb.append('('); |
| |
| switch (op) { |
| case AND : { |
| sb.append('&'); |
| |
| FilterImpl[] filters = (FilterImpl[]) value; |
| for (int i = 0, size = filters.length; i < size; i++) { |
| sb.append(filters[i].normalize()); |
| } |
| |
| break; |
| } |
| |
| case OR : { |
| sb.append('|'); |
| |
| FilterImpl[] filters = (FilterImpl[]) value; |
| for (int i = 0, size = filters.length; i < size; i++) { |
| sb.append(filters[i].normalize()); |
| } |
| |
| break; |
| } |
| |
| case NOT : { |
| sb.append('!'); |
| FilterImpl filter = (FilterImpl) value; |
| sb.append(filter.normalize()); |
| |
| break; |
| } |
| |
| case SUBSTRING : { |
| sb.append(attr); |
| sb.append('='); |
| |
| String[] substrings = (String[]) value; |
| |
| for (int i = 0, size = substrings.length; i < size; i++) { |
| String substr = substrings[i]; |
| |
| if (substr == null) /* * */{ |
| sb.append('*'); |
| } else /* xxx */{ |
| sb.append(encodeValue(substr)); |
| } |
| } |
| |
| break; |
| } |
| case EQUAL : { |
| sb.append(attr); |
| sb.append('='); |
| sb.append(encodeValue((String) value)); |
| |
| break; |
| } |
| case GREATER : { |
| sb.append(attr); |
| sb.append(">="); //$NON-NLS-1$ |
| sb.append(encodeValue((String) value)); |
| |
| break; |
| } |
| case LESS : { |
| sb.append(attr); |
| sb.append("<="); //$NON-NLS-1$ |
| sb.append(encodeValue((String) value)); |
| |
| break; |
| } |
| case APPROX : { |
| sb.append(attr); |
| sb.append("~="); //$NON-NLS-1$ |
| sb.append(encodeValue(approxString((String) value))); |
| |
| break; |
| } |
| |
| case PRESENT : { |
| sb.append(attr); |
| sb.append("=*"); //$NON-NLS-1$ |
| |
| break; |
| } |
| } |
| |
| sb.append(')'); |
| |
| return sb.toString(); |
| } |
| |
| /** |
| * Compares this <code>Filter</code> object to another object. |
| * |
| * @param obj The object to compare against this <code>Filter</code> |
| * object. |
| * @return If the other object is a <code>Filter</code> object, then |
| * returns <code>this.toString().equals(obj.toString()</code>; |
| * <code>false</code> otherwise. |
| */ |
| 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 <code>Filter</code> object. |
| * |
| * @return The hashCode of the filter string; that is, |
| * <code>this.toString().hashCode()</code>. |
| */ |
| public int hashCode() { |
| return this.toString().hashCode(); |
| } |
| |
| /* non public fields and methods for the Filter implementation */ |
| |
| /** filter operation */ |
| private final int op; |
| private static final int EQUAL = 1; |
| private static final int APPROX = 2; |
| private static final int GREATER = 3; |
| private static final int LESS = 4; |
| private static final int PRESENT = 5; |
| private static final int SUBSTRING = 6; |
| private static final int AND = 7; |
| private static final int OR = 8; |
| private static final int NOT = 9; |
| |
| /** filter attribute or null if operation AND, OR or NOT */ |
| private final String attr; |
| /** filter operands */ |
| private final Object value; |
| |
| /* normalized filter string for topLevel Filter object */ |
| private transient volatile String filterString; |
| |
| FilterImpl(int operation, String attr, Object value) { |
| this.op = operation; |
| this.attr = attr; |
| this.value = value; |
| } |
| |
| /** |
| * Internal match routine. |
| * Dictionary parameter must support case-insensitive get. |
| * |
| * @param properties 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>. |
| */ |
| private boolean match0(Dictionary properties) { |
| switch (op) { |
| case AND : { |
| FilterImpl[] filters = (FilterImpl[]) value; |
| for (int i = 0, size = filters.length; i < size; i++) { |
| if (!filters[i].match0(properties)) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| case OR : { |
| FilterImpl[] filters = (FilterImpl[]) value; |
| for (int i = 0, size = filters.length; i < size; i++) { |
| if (filters[i].match0(properties)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| case NOT : { |
| FilterImpl filter = (FilterImpl) 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(op, prop, value); |
| } |
| |
| case PRESENT : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("PRESENT(" + attr + ")"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| 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. |
| */ |
| private 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; |
| } |
| |
| private boolean compare(int operation, Object value1, Object value2) { |
| if (value1 == null) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("compare(" + value1 + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| return false; |
| } |
| |
| 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); |
| } |
| return compare_ObjectArray(operation, (Object[]) value1, value2); |
| } |
| |
| if (value1 instanceof Collection) { |
| return compare_Collection(operation, (Collection) 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); |
| } |
| |
| if (value1 instanceof Comparable) { |
| return compare_Comparable(operation, (Comparable) value1, value2); |
| } |
| |
| return compare_Unknown(operation, value1, value2); // RFC 59 |
| } |
| |
| private boolean compare_Collection(int operation, Collection collection, Object value2) { |
| for (Iterator iterator = collection.iterator(); iterator.hasNext();) { |
| if (compare(operation, iterator.next(), value2)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_ObjectArray(int operation, Object[] array, Object value2) { |
| for (int i = 0, size = array.length; i < size; i++) { |
| if (compare(operation, array[i], value2)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_PrimitiveArray(int operation, Class type, Object primarray, Object value2) { |
| if (Integer.TYPE.isAssignableFrom(type)) { |
| int[] array = (int[]) primarray; |
| for (int i = 0, size = array.length; i < size; i++) { |
| if (compare_Integer(operation, array[i], value2)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| if (Long.TYPE.isAssignableFrom(type)) { |
| long[] array = (long[]) primarray; |
| for (int i = 0, size = array.length; i < size; i++) { |
| if (compare_Long(operation, array[i], value2)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| if (Byte.TYPE.isAssignableFrom(type)) { |
| byte[] array = (byte[]) primarray; |
| for (int i = 0, size = array.length; i < size; i++) { |
| if (compare_Byte(operation, array[i], value2)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| if (Short.TYPE.isAssignableFrom(type)) { |
| short[] array = (short[]) primarray; |
| for (int i = 0, size = array.length; i < size; i++) { |
| if (compare_Short(operation, array[i], value2)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| if (Character.TYPE.isAssignableFrom(type)) { |
| char[] array = (char[]) primarray; |
| for (int i = 0, size = array.length; i < size; i++) { |
| if (compare_Character(operation, array[i], value2)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| if (Float.TYPE.isAssignableFrom(type)) { |
| float[] array = (float[]) primarray; |
| for (int i = 0, size = array.length; i < size; i++) { |
| if (compare_Float(operation, array[i], value2)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| if (Double.TYPE.isAssignableFrom(type)) { |
| double[] array = (double[]) primarray; |
| for (int i = 0, size = array.length; i < size; i++) { |
| if (compare_Double(operation, array[i], value2)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| if (Boolean.TYPE.isAssignableFrom(type)) { |
| boolean[] array = (boolean[]) primarray; |
| for (int i = 0, size = array.length; i < size; i++) { |
| if (compare_Boolean(operation, array[i], value2)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_String(int operation, String string, Object value2) { |
| switch (operation) { |
| case SUBSTRING : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("SUBSTRING(" + string + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| String[] substrings = (String[]) value2; |
| int pos = 0; |
| for (int i = 0, size = substrings.length; 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 */ |
| /* *xxx */ |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("indexOf(\"" + substr2 + "\"," + pos + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| int index = string.indexOf(substr2, pos); |
| if (index == -1) { |
| return false; |
| } |
| |
| pos = index + substr2.length(); |
| if (i + 2 < size) // if there are more substrings, increment over the string we just matched; otherwise need to do the last substr check |
| i++; |
| } else /* xxx */{ |
| int len = substr.length(); |
| |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("regionMatches(" + pos + ",\"" + substr + "\")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| if (string.regionMatches(pos, substr, 0, len)) { |
| pos += len; |
| } else { |
| return false; |
| } |
| } |
| } else /* last substr */{ |
| if (substr == null) /* * */{ |
| return true; |
| } |
| /* xxx */ |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("regionMatches(" + pos + "," + substr + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return string.endsWith(substr); |
| } |
| } |
| |
| return true; |
| } |
| case EQUAL : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("EQUAL(" + string + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return string.equals(value2); |
| } |
| case APPROX : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("APPROX(" + string + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| 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 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return string.compareTo((String) value2) >= 0; |
| } |
| case LESS : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("LESS(" + string + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return string.compareTo((String) value2) <= 0; |
| } |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_Integer(int operation, int intval, Object value2) { |
| if (operation == SUBSTRING) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("SUBSTRING(" + intval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return false; |
| } |
| |
| int intval2; |
| try { |
| intval2 = Integer.parseInt(((String) value2).trim()); |
| } catch (IllegalArgumentException e) { |
| return false; |
| } |
| switch (operation) { |
| case EQUAL : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("EQUAL(" + intval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return intval == intval2; |
| } |
| case APPROX : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("APPROX(" + intval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return intval == intval2; |
| } |
| case GREATER : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("GREATER(" + intval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return intval >= intval2; |
| } |
| case LESS : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("LESS(" + intval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return intval <= intval2; |
| } |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_Long(int operation, long longval, Object value2) { |
| if (operation == SUBSTRING) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("SUBSTRING(" + longval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return false; |
| } |
| |
| long longval2; |
| try { |
| longval2 = Long.parseLong(((String) value2).trim()); |
| } catch (IllegalArgumentException e) { |
| return false; |
| } |
| switch (operation) { |
| case EQUAL : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("EQUAL(" + longval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return longval == longval2; |
| } |
| case APPROX : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("APPROX(" + longval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return longval == longval2; |
| } |
| case GREATER : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("GREATER(" + longval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return longval >= longval2; |
| } |
| case LESS : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("LESS(" + longval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return longval <= longval2; |
| } |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_Byte(int operation, byte byteval, Object value2) { |
| if (operation == SUBSTRING) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("SUBSTRING(" + byteval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return false; |
| } |
| |
| byte byteval2; |
| try { |
| byteval2 = Byte.parseByte(((String) value2).trim()); |
| } catch (IllegalArgumentException e) { |
| return false; |
| } |
| switch (operation) { |
| case EQUAL : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("EQUAL(" + byteval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return byteval == byteval2; |
| } |
| case APPROX : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("APPROX(" + byteval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return byteval == byteval2; |
| } |
| case GREATER : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("GREATER(" + byteval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return byteval >= byteval2; |
| } |
| case LESS : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("LESS(" + byteval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return byteval <= byteval2; |
| } |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_Short(int operation, short shortval, Object value2) { |
| if (operation == SUBSTRING) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("SUBSTRING(" + shortval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return false; |
| } |
| |
| short shortval2; |
| try { |
| shortval2 = Short.parseShort(((String) value2).trim()); |
| } catch (IllegalArgumentException e) { |
| return false; |
| } |
| switch (operation) { |
| case EQUAL : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("EQUAL(" + shortval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return shortval == shortval2; |
| } |
| case APPROX : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("APPROX(" + shortval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return shortval == shortval2; |
| } |
| case GREATER : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("GREATER(" + shortval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return shortval >= shortval2; |
| } |
| case LESS : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("LESS(" + shortval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return shortval <= shortval2; |
| } |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_Character(int operation, char charval, Object value2) { |
| if (operation == SUBSTRING) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("SUBSTRING(" + charval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return false; |
| } |
| |
| char charval2; |
| try { |
| charval2 = ((String) value2).charAt(0); |
| } catch (IndexOutOfBoundsException e) { |
| return false; |
| } |
| switch (operation) { |
| case EQUAL : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("EQUAL(" + charval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return charval == charval2; |
| } |
| case APPROX : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("APPROX(" + charval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return (charval == charval2) || (Character.toUpperCase(charval) == Character.toUpperCase(charval2)) || (Character.toLowerCase(charval) == Character.toLowerCase(charval2)); |
| } |
| case GREATER : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("GREATER(" + charval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return charval >= charval2; |
| } |
| case LESS : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("LESS(" + charval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return charval <= charval2; |
| } |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_Boolean(int operation, boolean boolval, Object value2) { |
| if (operation == SUBSTRING) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("SUBSTRING(" + boolval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return false; |
| } |
| |
| boolean boolval2 = Boolean.valueOf(((String) value2).trim()).booleanValue(); |
| switch (operation) { |
| case EQUAL : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("EQUAL(" + boolval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return boolval == boolval2; |
| } |
| case APPROX : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("APPROX(" + boolval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return boolval == boolval2; |
| } |
| case GREATER : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("GREATER(" + boolval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return boolval == boolval2; |
| } |
| case LESS : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("LESS(" + boolval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return boolval == boolval2; |
| } |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_Float(int operation, float floatval, Object value2) { |
| if (operation == SUBSTRING) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("SUBSTRING(" + floatval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return false; |
| } |
| |
| float floatval2; |
| try { |
| floatval2 = Float.parseFloat(((String) value2).trim()); |
| } catch (IllegalArgumentException e) { |
| return false; |
| } |
| switch (operation) { |
| case EQUAL : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("EQUAL(" + floatval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return Float.compare(floatval, floatval2) == 0; |
| } |
| case APPROX : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("APPROX(" + floatval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return Float.compare(floatval, floatval2) == 0; |
| } |
| case GREATER : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("GREATER(" + floatval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return Float.compare(floatval, floatval2) >= 0; |
| } |
| case LESS : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("LESS(" + floatval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return Float.compare(floatval, floatval2) <= 0; |
| } |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_Double(int operation, double doubleval, Object value2) { |
| if (operation == SUBSTRING) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("SUBSTRING(" + doubleval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return false; |
| } |
| |
| double doubleval2; |
| try { |
| doubleval2 = Double.parseDouble(((String) value2).trim()); |
| } catch (IllegalArgumentException e) { |
| return false; |
| } |
| switch (operation) { |
| case EQUAL : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("EQUAL(" + doubleval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return Double.compare(doubleval, doubleval2) == 0; |
| } |
| case APPROX : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("APPROX(" + doubleval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return Double.compare(doubleval, doubleval2) == 0; |
| } |
| case GREATER : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("GREATER(" + doubleval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return Double.compare(doubleval, doubleval2) >= 0; |
| } |
| case LESS : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("LESS(" + doubleval + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return Double.compare(doubleval, doubleval2) <= 0; |
| } |
| } |
| |
| return false; |
| } |
| |
| private static final Class[] constructorType = new Class[] {String.class}; |
| |
| private boolean compare_Comparable(int operation, Comparable value1, Object value2) { |
| if (operation == SUBSTRING) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("SUBSTRING(" + value1 + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return false; |
| } |
| |
| Constructor constructor; |
| try { |
| constructor = value1.getClass().getConstructor(constructorType); |
| } catch (NoSuchMethodException e) { |
| return false; |
| } |
| try { |
| if (!constructor.isAccessible()) |
| AccessController.doPrivileged(new SetAccessibleAction(constructor)); |
| value2 = constructor.newInstance(new Object[] {((String) value2).trim()}); |
| } catch (IllegalAccessException e) { |
| return false; |
| } catch (InvocationTargetException e) { |
| return false; |
| } catch (InstantiationException e) { |
| return false; |
| } |
| |
| switch (operation) { |
| case EQUAL : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("EQUAL(" + value1 + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return value1.compareTo(value2) == 0; |
| } |
| case APPROX : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("APPROX(" + value1 + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return value1.compareTo(value2) == 0; |
| } |
| case GREATER : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("GREATER(" + value1 + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return value1.compareTo(value2) >= 0; |
| } |
| case LESS : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("LESS(" + value1 + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return value1.compareTo(value2) <= 0; |
| } |
| } |
| |
| return false; |
| } |
| |
| private boolean compare_Unknown(int operation, Object value1, Object value2) { //RFC 59 |
| if (operation == SUBSTRING) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("SUBSTRING(" + value1 + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return false; |
| } |
| |
| Constructor constructor; |
| try { |
| constructor = value1.getClass().getConstructor(constructorType); |
| } catch (NoSuchMethodException e) { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("Type not supported"); //$NON-NLS-1$ |
| } |
| return false; |
| } |
| try { |
| if (!constructor.isAccessible()) |
| AccessController.doPrivileged(new SetAccessibleAction(constructor)); |
| value2 = constructor.newInstance(new Object[] {((String) value2).trim()}); |
| } catch (IllegalAccessException e) { |
| return false; |
| } catch (InvocationTargetException e) { |
| return false; |
| } catch (InstantiationException e) { |
| return false; |
| } |
| |
| switch (operation) { |
| case EQUAL : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("EQUAL(" + value1 + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return value1.equals(value2); |
| } |
| case APPROX : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("APPROX(" + value1 + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return value1.equals(value2); |
| } |
| case GREATER : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("GREATER(" + value1 + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return value1.equals(value2); |
| } |
| case LESS : { |
| if (Debug.DEBUG && Debug.DEBUG_FILTER) { |
| Debug.println("LESS(" + value1 + "," + value2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| return value1.equals(value2); |
| } |
| } |
| |
| 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. |
| */ |
| private static String approxString(String input) { |
| boolean changed = false; |
| char[] output = input.toCharArray(); |
| int cursor = 0; |
| for (int i = 0, length = output.length; 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; |
| } |
| |
| /** |
| * Returns the leftmost required objectClass value for the filter to evaluate to true. |
| * |
| * @return The leftmost required objectClass value or null if none could be determined. |
| */ |
| public String getRequiredObjectClass() { |
| // just checking for simple filters here where objectClass is the only attr or it is one attr of a base '&' clause |
| // (objectClass=org.acme.BrickService) OK |
| // (&(objectClass=org.acme.BrickService)(|(vendor=IBM)(vendor=SUN))) OK |
| // (objectClass=org.acme.*) NOT OK |
| // (|(objectClass=org.acme.BrickService)(objectClass=org.acme.CementService)) NOT OK |
| // (&(objectClass=org.acme.BrickService)(objectClass=org.acme.CementService)) OK but only the first objectClass is returned |
| switch (op) { |
| case EQUAL : |
| if (attr.equalsIgnoreCase(org.osgi.framework.Constants.OBJECTCLASS) && (value instanceof String)) |
| return (String) value; |
| break; |
| case AND : |
| FilterImpl[] clauses = (FilterImpl[]) value; |
| for (int i = 0; i < clauses.length; i++) |
| if (clauses[i].op == EQUAL) { |
| String result = clauses[i].getRequiredObjectClass(); |
| if (result != null) |
| return result; |
| } |
| break; |
| } |
| return null; |
| } |
| |
| /** |
| * Returns all the attributes contained within this filter |
| * @return all the attributes contained within this filter |
| */ |
| public String[] getAttributes() { |
| ArrayList results = new ArrayList(); |
| getAttributesInternal(results); |
| return (String[]) results.toArray(new String[results.size()]); |
| } |
| |
| private void getAttributesInternal(ArrayList results) { |
| if (value instanceof FilterImpl[]) { |
| FilterImpl[] children = (FilterImpl[]) value; |
| for (int i = 0; i < children.length; i++) |
| children[i].getAttributesInternal(results); |
| return; |
| } else if (value instanceof FilterImpl) { |
| // The NOT operation only has one child filter (bug 188075) |
| ((FilterImpl) value).getAttributesInternal(results); |
| return; |
| } |
| if (attr != null) |
| results.add(attr); |
| } |
| |
| /** |
| * Parser class for OSGi filter strings. This class parses |
| * the complete filter string and builds a tree of Filter |
| * objects rooted at the parent. |
| */ |
| private static class Parser { |
| private final String filterstring; |
| private final char[] filterChars; |
| private int pos; |
| |
| Parser(String filterstring) { |
| this.filterstring = filterstring; |
| filterChars = filterstring.toCharArray(); |
| pos = 0; |
| } |
| |
| FilterImpl parse() throws InvalidSyntaxException { |
| FilterImpl filter; |
| try { |
| filter = parse_filter(); |
| } catch (ArrayIndexOutOfBoundsException e) { |
| throw new InvalidSyntaxException(Msg.FILTER_TERMINATED_ABRUBTLY, filterstring); |
| } |
| |
| if (pos != filterChars.length) { |
| throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_TRAILING_CHARACTERS, filterstring.substring(pos)), filterstring); |
| } |
| return filter; |
| } |
| |
| private FilterImpl parse_filter() throws InvalidSyntaxException { |
| FilterImpl filter; |
| skipWhiteSpace(); |
| |
| if (filterChars[pos] != '(') { |
| throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_MISSING_LEFTPAREN, filterstring.substring(pos)), filterstring); |
| } |
| |
| pos++; |
| |
| filter = parse_filtercomp(); |
| |
| skipWhiteSpace(); |
| |
| if (filterChars[pos] != ')') { |
| throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_MISSING_RIGHTPAREN, filterstring.substring(pos)), filterstring); |
| } |
| |
| pos++; |
| |
| skipWhiteSpace(); |
| |
| return filter; |
| } |
| |
| private FilterImpl parse_filtercomp() throws InvalidSyntaxException { |
| skipWhiteSpace(); |
| |
| char c = filterChars[pos]; |
| |
| switch (c) { |
| case '&' : { |
| pos++; |
| return parse_and(); |
| } |
| case '|' : { |
| pos++; |
| return parse_or(); |
| } |
| case '!' : { |
| pos++; |
| return parse_not(); |
| } |
| } |
| return parse_item(); |
| } |
| |
| private FilterImpl parse_and() throws InvalidSyntaxException { |
| int lookahead = pos; |
| skipWhiteSpace(); |
| |
| if (filterChars[pos] != '(') { |
| pos = lookahead - 1; |
| return parse_item(); |
| } |
| |
| List operands = new ArrayList(10); |
| |
| while (filterChars[pos] == '(') { |
| FilterImpl child = parse_filter(); |
| operands.add(child); |
| } |
| |
| return new FilterImpl(FilterImpl.AND, null, operands.toArray(new FilterImpl[operands.size()])); |
| } |
| |
| private FilterImpl parse_or() throws InvalidSyntaxException { |
| int lookahead = pos; |
| skipWhiteSpace(); |
| |
| if (filterChars[pos] != '(') { |
| pos = lookahead - 1; |
| return parse_item(); |
| } |
| |
| List operands = new ArrayList(10); |
| |
| while (filterChars[pos] == '(') { |
| FilterImpl child = parse_filter(); |
| operands.add(child); |
| } |
| |
| return new FilterImpl(FilterImpl.OR, null, operands.toArray(new FilterImpl[operands.size()])); |
| } |
| |
| private FilterImpl parse_not() throws InvalidSyntaxException { |
| int lookahead = pos; |
| skipWhiteSpace(); |
| |
| if (filterChars[pos] != '(') { |
| pos = lookahead - 1; |
| return parse_item(); |
| } |
| |
| FilterImpl child = parse_filter(); |
| |
| return new FilterImpl(FilterImpl.NOT, null, child); |
| } |
| |
| private FilterImpl parse_item() throws InvalidSyntaxException { |
| String attr = parse_attr(); |
| |
| skipWhiteSpace(); |
| |
| switch (filterChars[pos]) { |
| case '~' : { |
| if (filterChars[pos + 1] == '=') { |
| pos += 2; |
| return new FilterImpl(FilterImpl.APPROX, attr, parse_value()); |
| } |
| break; |
| } |
| case '>' : { |
| if (filterChars[pos + 1] == '=') { |
| pos += 2; |
| return new FilterImpl(FilterImpl.GREATER, attr, parse_value()); |
| } |
| break; |
| } |
| case '<' : { |
| if (filterChars[pos + 1] == '=') { |
| pos += 2; |
| return new FilterImpl(FilterImpl.LESS, attr, parse_value()); |
| } |
| break; |
| } |
| case '=' : { |
| if (filterChars[pos + 1] == '*') { |
| int oldpos = pos; |
| pos += 2; |
| skipWhiteSpace(); |
| if (filterChars[pos] == ')') { |
| return new FilterImpl(FilterImpl.PRESENT, attr, null); |
| } |
| pos = oldpos; |
| } |
| |
| pos++; |
| Object string = parse_substring(); |
| |
| if (string instanceof String) { |
| return new FilterImpl(FilterImpl.EQUAL, attr, string); |
| } |
| return new FilterImpl(FilterImpl.SUBSTRING, attr, string); |
| } |
| } |
| |
| throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_INVALID_OPERATOR, filterstring.substring(pos)), filterstring); |
| } |
| |
| private String parse_attr() throws InvalidSyntaxException { |
| skipWhiteSpace(); |
| |
| int begin = pos; |
| int end = pos; |
| |
| char c = filterChars[pos]; |
| |
| while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') { |
| pos++; |
| |
| if (!Character.isWhitespace(c)) { |
| end = pos; |
| } |
| |
| c = filterChars[pos]; |
| } |
| |
| int length = end - begin; |
| |
| if (length == 0) { |
| throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_MISSING_ATTR, filterstring.substring(pos)), filterstring); |
| } |
| |
| return new String(filterChars, begin, length); |
| } |
| |
| private String parse_value() throws InvalidSyntaxException { |
| StringBuffer sb = new StringBuffer(filterChars.length - pos); |
| |
| parseloop: while (true) { |
| char c = filterChars[pos]; |
| |
| switch (c) { |
| case ')' : { |
| break parseloop; |
| } |
| |
| case '(' : { |
| throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_INVALID_VALUE, filterstring.substring(pos)), filterstring); |
| } |
| |
| case '\\' : { |
| pos++; |
| c = filterChars[pos]; |
| /* fall through into default */ |
| } |
| |
| default : { |
| sb.append(c); |
| pos++; |
| break; |
| } |
| } |
| } |
| |
| if (sb.length() == 0) { |
| throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_MISSING_VALUE, filterstring.substring(pos)), filterstring); |
| } |
| |
| return sb.toString(); |
| } |
| |
| private Object parse_substring() throws InvalidSyntaxException { |
| StringBuffer sb = new StringBuffer(filterChars.length - pos); |
| |
| List operands = new ArrayList(10); |
| |
| parseloop: while (true) { |
| char c = filterChars[pos]; |
| |
| switch (c) { |
| case ')' : { |
| if (sb.length() > 0) { |
| operands.add(sb.toString()); |
| } |
| |
| break parseloop; |
| } |
| |
| case '(' : { |
| throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_INVALID_VALUE, filterstring.substring(pos)), filterstring); |
| } |
| |
| case '*' : { |
| if (sb.length() > 0) { |
| operands.add(sb.toString()); |
| } |
| |
| sb.setLength(0); |
| |
| operands.add(null); |
| pos++; |
| |
| break; |
| } |
| |
| case '\\' : { |
| pos++; |
| c = filterChars[pos]; |
| /* fall through into default */ |
| } |
| |
| default : { |
| sb.append(c); |
| pos++; |
| break; |
| } |
| } |
| } |
| |
| int size = operands.size(); |
| |
| if (size == 0) { |
| return ""; |
| } |
| |
| if (size == 1) { |
| Object single = operands.get(0); |
| |
| if (single != null) { |
| return single; |
| } |
| } |
| |
| return operands.toArray(new String[size]); |
| } |
| |
| private void skipWhiteSpace() { |
| for (int length = filterChars.length; (pos < length) && Character.isWhitespace(filterChars[pos]);) { |
| pos++; |
| } |
| } |
| } |
| |
| /** |
| * This Dictionary is used for key lookup from a ServiceReference during |
| * filter evaluation. This Dictionary implementation only supports the get |
| * operation using a String key as no other operations are used by the |
| * Filter implementation. |
| * |
| */ |
| private static class ServiceReferenceDictionary extends Dictionary { |
| private final ServiceReference reference; |
| |
| ServiceReferenceDictionary(ServiceReference reference) { |
| this.reference = reference; |
| } |
| |
| public Object get(Object key) { |
| if (reference == null) { |
| return null; |
| } |
| return reference.getProperty((String) key); |
| } |
| |
| public boolean isEmpty() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public Enumeration keys() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public Enumeration elements() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public Object put(Object key, Object value) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public Object remove(Object key) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public int size() { |
| throw new UnsupportedOperationException(); |
| } |
| } |
| |
| private static class SetAccessibleAction implements PrivilegedAction { |
| private final AccessibleObject accessible; |
| |
| SetAccessibleAction(AccessibleObject accessible) { |
| this.accessible = accessible; |
| } |
| |
| public Object run() { |
| accessible.setAccessible(true); |
| return null; |
| } |
| } |
| } |