Package org.eclipse.osgi.framework.internal.core

Source Code of org.eclipse.osgi.framework.internal.core.FilterImpl$SetAccessibleAction

/*******************************************************************************
* 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>
*   &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 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;
    }
  }
}
TOP

Related Classes of org.eclipse.osgi.framework.internal.core.FilterImpl$SetAccessibleAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.