1 /*******************************************************************************
2  * Copyright (c) 2003, 2020 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 
15 package org.eclipse.osgi.internal.framework;
16 
17 import static java.util.Objects.requireNonNull;
18 
19 import java.lang.reflect.AccessibleObject;
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.Modifier;
23 import java.security.AccessController;
24 import java.security.PrivilegedAction;
25 import java.util.AbstractMap;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.Dictionary;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35 import org.eclipse.osgi.framework.util.CaseInsensitiveDictionaryMap;
36 import org.eclipse.osgi.internal.debug.Debug;
37 import org.eclipse.osgi.internal.messages.Msg;
38 import org.eclipse.osgi.internal.serviceregistry.ServiceReferenceImpl;
39 import org.eclipse.osgi.util.NLS;
40 import org.osgi.framework.Constants;
41 import org.osgi.framework.Filter;
42 import org.osgi.framework.InvalidSyntaxException;
43 import org.osgi.framework.ServiceReference;
44 import org.osgi.framework.Version;
45 
46 /**
47  * RFC 1960-based Filter. Filter objects can be created by calling the
48  * constructor with the desired filter string. A Filter object can be called
49  * numerous times to determine if the match argument matches the filter string
50  * that was used to create the Filter object.
51  * <p>
52  * The syntax of a filter string is the string representation of LDAP search
53  * filters as defined in RFC 1960: <i>A String Representation of LDAP Search
54  * Filters</i> (available at http://www.ietf.org/rfc/rfc1960.txt). It should be
55  * noted that RFC 2254: <i>A String Representation of LDAP Search Filters</i>
56  * (available at http://www.ietf.org/rfc/rfc2254.txt) supersedes RFC 1960 but
57  * only adds extensible matching and is not applicable for this API.
58  * <p>
59  * The string representation of an LDAP search filter is defined by the
60  * following grammar. It uses a prefix format.
61  *
62  * <pre>
63  *   &lt;filter&gt; ::= '(' &lt;filtercomp&gt; ')'
64  *   &lt;filtercomp&gt; ::= &lt;and&gt; | &lt;or&gt; | &lt;not&gt; | &lt;item&gt;
65  *   &lt;and&gt; ::= '&amp;' &lt;filterlist&gt;
66  *   &lt;or&gt; ::= '|' &lt;filterlist&gt;
67  *   &lt;not&gt; ::= '!' &lt;filter&gt;
68  *   &lt;filterlist&gt; ::= &lt;filter&gt; | &lt;filter&gt; &lt;filterlist&gt;
69  *   &lt;item&gt; ::= &lt;simple&gt; | &lt;present&gt; | &lt;substring&gt;
70  *   &lt;simple&gt; ::= &lt;attr&gt; &lt;filtertype&gt; &lt;value&gt;
71  *   &lt;filtertype&gt; ::= &lt;equal&gt; | &lt;approx&gt; | &lt;greater&gt; | &lt;less&gt;
72  *   &lt;equal&gt; ::= '='
73  *   &lt;approx&gt; ::= '&tilde;='
74  *   &lt;greater&gt; ::= '&gt;='
75  *   &lt;less&gt; ::= '&lt;='
76  *   &lt;present&gt; ::= &lt;attr&gt; '=*'
77  *   &lt;substring&gt; ::= &lt;attr&gt; '=' &lt;initial&gt; &lt;any&gt; &lt;final&gt;
78  *   &lt;initial&gt; ::= NULL | &lt;value&gt;
79  *   &lt;any&gt; ::= '*' &lt;starval&gt;
80  *   &lt;starval&gt; ::= NULL | &lt;value&gt; '*' &lt;starval&gt;
81  *   &lt;final&gt; ::= NULL | &lt;value&gt;
82  * </pre>
83  *
84  * {@code &lt;attr&gt;} is a string representing an attribute, or key, in the
85  * properties objects of the registered services. Attribute names are not case
86  * sensitive; that is cn and CN both refer to the same attribute.
87  * {@code &lt;value&gt;} is a string representing the value, or part of one, of
88  * a key in the properties objects of the registered services. If a
89  * {@code &lt;value&gt;} must contain one of the characters ' {@code *}' or
90  * '{@code (}' or '{@code )}', these characters should be escaped by preceding
91  * them with the backslash '{@code \}' character. Note that although both the
92  * {@code &lt;substring&gt;} and {@code &lt;present&gt;} productions can produce
93  * the {@code 'attr=*'} construct, this construct is used only to denote a
94  * presence filter.
95  * <p>
96  * Examples of LDAP filters are:
97  *
98  * <pre>
99  *   &quot;(cn=Babs Jensen)&quot;
100  *   &quot;(!(cn=Tim Howes))&quot;
101  *   &quot;(&amp;(&quot; + Constants.OBJECTCLASS + &quot;=Person)(|(sn=Jensen)(cn=Babs J*)))&quot;
102  *   &quot;(o=univ*of*mich*)&quot;
103  * </pre>
104  * <p>
105  * The approximate match ({@code ~=}) is implementation specific but should at
106  * least ignore case and white space differences. Optional are codes like
107  * soundex or other smart "closeness" comparisons.
108  * <p>
109  * Comparison of values is not straightforward. Strings are compared differently
110  * than numbers and it is possible for a key to have multiple values. Note that
111  * that keys in the match argument must always be strings. The comparison is
112  * defined by the object type of the key's value. The following rules apply for
113  * comparison: <blockquote>
114  * <TABLE BORDER=0>
115  * <TR>
116  * <TD><b>Property Value Type </b></TD>
117  * <TD><b>Comparison Type</b></TD>
118  * </TR>
119  * <TR>
120  * <TD>String</TD>
121  * <TD>String comparison</TD>
122  * </TR>
123  * <TR valign=top>
124  * <TD>Integer, Long, Float, Double, Byte, Short, BigInteger, BigDecimal</TD>
125  * <TD>numerical comparison</TD>
126  * </TR>
127  * <TR>
128  * <TD>Character</TD>
129  * <TD>character comparison</TD>
130  * </TR>
131  * <TR>
132  * <TD>Boolean</TD>
133  * <TD>equality comparisons only</TD>
134  * </TR>
135  * <TR>
136  * <TD>[] (array)</TD>
137  * <TD>recursively applied to values</TD>
138  * </TR>
139  * <TR>
140  * <TD>Collection</TD>
141  * <TD>recursively applied to values</TD>
142  * </TR>
143  * </TABLE>
144  * Note: arrays of primitives are also supported. </blockquote> A filter matches
145  * a key that has multiple values if it matches at least one of those values.
146  * For example,
147  *
148  * <pre>
149  * Dictionary d = new Hashtable();
150  * d.put(&quot;cn&quot;, new String[] {
151  * 		&quot;a&quot;, &quot;b&quot;, &quot;c&quot;
152  * });
153  * </pre>
154  *
155  * d will match {@code (cn=a)} and also {@code (cn=b)}
156  * <p>
157  * A filter component that references a key having an unrecognizable data type
158  * will evaluate to {@code false} .
159  */
160 public abstract class FilterImpl implements Filter {
161 	/* normalized filter string for Filter object */
162 	private transient String filterString;
163 
164 	/**
165 	 * Creates a {@link FilterImpl} object. This filter object may be used to
166 	 * match a {@link ServiceReference} or a Dictionary.
167 	 * <p>
168 	 * If the filter cannot be parsed, an {@link InvalidSyntaxException} will be
169 	 * thrown with a human readable message where the filter became unparsable.
170 	 *
171 	 * @param filterString the filter string.
172 	 * @throws InvalidSyntaxException If the filter parameter contains an
173 	 *             invalid filter string that cannot be parsed.
174 	 */
newInstance(String filterString)175 	public static FilterImpl newInstance(String filterString) throws InvalidSyntaxException {
176 		return newInstance(filterString, false);
177 	}
178 
newInstance(String filterString, boolean debug)179 	public static FilterImpl newInstance(String filterString, boolean debug) throws InvalidSyntaxException {
180 		return new Parser(filterString, debug).parse();
181 	}
182 
FilterImpl()183 	FilterImpl() {
184 		// empty constructor for subclasses
185 	}
186 
187 	/**
188 	 * Filter using a service's properties.
189 	 * <p>
190 	 * This {@code Filter} is executed using the keys and values of the
191 	 * referenced service's properties. The keys are looked up in a case
192 	 * insensitive manner.
193 	 *
194 	 * @param reference The reference to the service whose properties are used
195 	 *            in the match.
196 	 * @return {@code true} if the service's properties match this
197 	 *         {@code Filter}; {@code false} otherwise.
198 	 */
199 	@Override
match(ServiceReference<?> reference)200 	public boolean match(ServiceReference<?> reference) {
201 		return matches0((reference != null) ? ServiceReferenceMap.asMap(reference) : Collections.<String, Object> emptyMap());
202 	}
203 
204 	/**
205 	 * Filter using a {@code Dictionary} with case insensitive key lookup. This
206 	 * {@code Filter} is executed using the specified {@code Dictionary}'s keys
207 	 * and values. The keys are looked up in a case insensitive manner.
208 	 *
209 	 * @param dictionary The {@code Dictionary} whose key/value pairs are used
210 	 *            in the match.
211 	 * @return {@code true} if the {@code Dictionary}'s values match this
212 	 *         filter; {@code false} otherwise.
213 	 * @throws IllegalArgumentException If {@code dictionary} contains case
214 	 *             variants of the same key name.
215 	 */
216 	@Override
match(Dictionary<String, ?> dictionary)217 	public boolean match(Dictionary<String, ?> dictionary) {
218 		return matches0((dictionary != null) ? new CaseInsensitiveDictionaryMap<>(dictionary) : Collections.<String, Object> emptyMap());
219 	}
220 
221 	/**
222 	 * Filter using a {@code Dictionary}. This {@code Filter} is executed using
223 	 * the specified {@code Dictionary}'s keys and values. The keys are looked
224 	 * up in a normal manner respecting case.
225 	 *
226 	 * @param dictionary The {@code Dictionary} whose key/value pairs are used
227 	 *            in the match.
228 	 * @return {@code true} if the {@code Dictionary}'s values match this
229 	 *         filter; {@code false} otherwise.
230 	 * @since 1.3
231 	 */
232 	@Override
matchCase(Dictionary<String, ?> dictionary)233 	public boolean matchCase(Dictionary<String, ?> dictionary) {
234 		return matches0((dictionary != null) ? DictionaryMap.asMap(dictionary) : Collections.<String, Object> emptyMap());
235 	}
236 
237 	/**
238 	 * Filter using a {@code Map}. This {@code Filter} is executed using the
239 	 * specified {@code Map}'s keys and values. The keys are looked up in a
240 	 * normal manner respecting case.
241 	 *
242 	 * @param map The {@code Map} whose key/value pairs are used in the match.
243 	 *            Maps with {@code null} key or values are not supported. A
244 	 *            {@code null} value is considered not present to the filter.
245 	 * @return {@code true} if the {@code Map}'s values match this filter;
246 	 *         {@code false} otherwise.
247 	 * @since 1.6
248 	 */
249 	@Override
matches(Map<String, ?> map)250 	public boolean matches(Map<String, ?> map) {
251 		return matches0((map != null) ? map : Collections.<String, Object> emptyMap());
252 	}
253 
matches0(Map<String, ?> map)254 	abstract boolean matches0(Map<String, ?> map);
255 
256 	/**
257 	 * Returns this {@code Filter}'s filter string.
258 	 * <p>
259 	 * The filter string is normalized by removing whitespace which does not
260 	 * affect the meaning of the filter.
261 	 *
262 	 * @return This {@code Filter}'s filter string.
263 	 */
264 	@Override
toString()265 	public String toString() {
266 		String result = filterString;
267 		if (result == null) {
268 			filterString = result = normalize(new StringBuilder()).toString();
269 		}
270 		return result;
271 	}
272 
273 	/**
274 	 * Returns this {@code Filter}'s normalized filter string.
275 	 * <p>
276 	 * The filter string is normalized by removing whitespace which does not
277 	 * affect the meaning of the filter.
278 	 *
279 	 * @return This {@code Filter}'s filter string.
280 	 */
normalize(StringBuilder sb)281 	abstract StringBuilder normalize(StringBuilder sb);
282 
283 	/**
284 	 * Compares this {@code Filter} to another {@code Filter}.
285 	 * <p>
286 	 * This implementation returns the result of calling
287 	 * {@code this.toString().equals(obj.toString()}.
288 	 *
289 	 * @param obj The object to compare against this {@code Filter}.
290 	 * @return If the other object is a {@code Filter} object, then returns the
291 	 *         result of calling {@code this.toString().equals(obj.toString()};
292 	 *         {@code false} otherwise.
293 	 */
294 	@Override
equals(Object obj)295 	public boolean equals(Object obj) {
296 		if (obj == this) {
297 			return true;
298 		}
299 
300 		if (!(obj instanceof Filter)) {
301 			return false;
302 		}
303 
304 		return this.toString().equals(obj.toString());
305 	}
306 
307 	/**
308 	 * Returns the hashCode for this {@code Filter}.
309 	 * <p>
310 	 * This implementation returns the result of calling
311 	 * {@code this.toString().hashCode()}.
312 	 *
313 	 * @return The hashCode of this {@code Filter}.
314 	 */
315 	@Override
hashCode()316 	public int hashCode() {
317 		return this.toString().hashCode();
318 	}
319 
320 	static final class And extends FilterImpl {
321 		private final FilterImpl[] operands;
322 
And(FilterImpl[] operands)323 		And(FilterImpl[] operands) {
324 			this.operands = operands;
325 		}
326 
327 		@Override
matches0(Map<String, ?> map)328 		boolean matches0(Map<String, ?> map) {
329 			for (FilterImpl operand : operands) {
330 				if (!operand.matches0(map)) {
331 					return false;
332 				}
333 			}
334 			return true;
335 		}
336 
337 		@Override
normalize(StringBuilder sb)338 		StringBuilder normalize(StringBuilder sb) {
339 			sb.append('(').append('&');
340 			for (FilterImpl operand : operands) {
341 				operand.normalize(sb);
342 			}
343 			return sb.append(')');
344 		}
345 
346 		@Override
getPrimaryKeyValue(String primaryKey)347 		public String getPrimaryKeyValue(String primaryKey) {
348 			// just checking for simple filters here where primaryKey is the only attr or it is one attr of a base '&' clause
349 			// (primaryKey=org.acme.BrickService) OK
350 			// (&(primaryKey=org.acme.BrickService)(|(vendor=IBM)(vendor=SUN))) OK
351 			// (primaryKey=org.acme.*) NOT OK
352 			// (|(primaryKey=org.acme.BrickService)(primaryKey=org.acme.CementService)) NOT OK
353 			// (&(primaryKey=org.acme.BrickService)(primaryKey=org.acme.CementService)) OK but only the first primaryKey is returned
354 			for (FilterImpl operand : operands) {
355 				if (operand instanceof Equal) {
356 					String result = operand.getPrimaryKeyValue(primaryKey);
357 					if (result != null) {
358 						return result;
359 					}
360 				}
361 			}
362 			return null;
363 		}
364 
365 		@Override
getChildren()366 		public List<FilterImpl> getChildren() {
367 			return new ArrayList<>(Arrays.asList(operands));
368 		}
369 
370 		@Override
getAttributesInternal(List<String> results)371 		void getAttributesInternal(List<String> results) {
372 			for (FilterImpl operand : operands) {
373 				operand.getAttributesInternal(results);
374 			}
375 		}
376 
377 		@Override
addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not)378 		void addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not) {
379 			for (FilterImpl operand : operands) {
380 				operand.addAttributes(attributes, versionAttrs, false);
381 			}
382 		}
383 	}
384 
385 	static final class Or extends FilterImpl {
386 		private final FilterImpl[] operands;
387 
Or(FilterImpl[] operands)388 		Or(FilterImpl[] operands) {
389 			this.operands = operands;
390 		}
391 
392 		@Override
matches0(Map<String, ?> map)393 		boolean matches0(Map<String, ?> map) {
394 			for (FilterImpl operand : operands) {
395 				if (operand.matches0(map)) {
396 					return true;
397 				}
398 			}
399 			return false;
400 		}
401 
402 		@Override
normalize(StringBuilder sb)403 		StringBuilder normalize(StringBuilder sb) {
404 			sb.append('(').append('|');
405 			for (FilterImpl operand : operands) {
406 				operand.normalize(sb);
407 			}
408 			return sb.append(')');
409 		}
410 
411 		@Override
getChildren()412 		public List<FilterImpl> getChildren() {
413 			return new ArrayList<>(Arrays.asList(operands));
414 		}
415 
416 		@Override
getAttributesInternal(List<String> results)417 		void getAttributesInternal(List<String> results) {
418 			for (FilterImpl operand : operands) {
419 				operand.getAttributesInternal(results);
420 			}
421 		}
422 
423 		@Override
getStandardOSGiAttributes(String... versions)424 		public Map<String, String> getStandardOSGiAttributes(String... versions) {
425 			throw new IllegalArgumentException("Invalid filter for standard OSGi Attributes: OR"); //$NON-NLS-1$
426 		}
427 
428 		@Override
addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not)429 		void addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not) {
430 			throw new IllegalStateException("Invalid filter for standard OSGi requirements: OR"); //$NON-NLS-1$
431 		}
432 	}
433 
434 	static final class Not extends FilterImpl {
435 		private final FilterImpl operand;
436 
Not(FilterImpl operand)437 		Not(FilterImpl operand) {
438 			this.operand = operand;
439 		}
440 
441 		@Override
matches0(Map<String, ?> map)442 		boolean matches0(Map<String, ?> map) {
443 			return !operand.matches0(map);
444 		}
445 
446 		@Override
normalize(StringBuilder sb)447 		StringBuilder normalize(StringBuilder sb) {
448 			sb.append('(').append('!');
449 			operand.normalize(sb);
450 			return sb.append(')');
451 		}
452 
453 		@Override
getAttributesInternal(List<String> results)454 		void getAttributesInternal(List<String> results) {
455 			operand.getAttributesInternal(results);
456 		}
457 
458 		@Override
getStandardOSGiAttributes(String... versions)459 		public Map<String, String> getStandardOSGiAttributes(String... versions) {
460 			throw new IllegalArgumentException("Invalid filter for standard OSGi Attributes: NOT"); //$NON-NLS-1$
461 		}
462 
463 		@Override
addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not)464 		void addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not) {
465 			operand.addAttributes(attributes, versionAttrs, true);
466 		}
467 	}
468 
469 	static abstract class Item extends FilterImpl {
470 		/** debug mode */
471 		final boolean debug;
472 		final String attr;
473 
Item(String attr, boolean debug)474 		Item(String attr, boolean debug) {
475 			this.attr = attr;
476 			this.debug = debug;
477 		}
478 
479 		@Override
matches0(Map<String, ?> map)480 		boolean matches0(Map<String, ?> map) {
481 			return compare(map.get(attr));
482 		}
483 
operation()484 		abstract String operation();
485 
value()486 		abstract String value();
487 
compare(Object value1)488 		private boolean compare(Object value1) {
489 			if (debug) {
490 				if (value1 == null) {
491 					Debug.println("compare(" + value1 + "," + value() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
492 				} else if (!(value1.getClass().isArray() || (value1 instanceof Collection<?>))) {
493 					Debug.println(operation() + "(" + value1 + "," + value() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
494 				}
495 			}
496 			if (value1 == null) {
497 				return false;
498 			}
499 			if (value1 instanceof String) {
500 				return compare_String((String) value1);
501 			}
502 			if (value1 instanceof Version) {
503 				return compare_Version((Version) value1);
504 			}
505 
506 			Class<?> clazz = value1.getClass();
507 			if (clazz.isArray()) {
508 				Class<?> type = clazz.getComponentType();
509 				if (type.isPrimitive()) {
510 					return compare_PrimitiveArray(type, value1);
511 				}
512 				return compare_ObjectArray((Object[]) value1);
513 			}
514 			if (value1 instanceof Collection<?>) {
515 				return compare_Collection((Collection<?>) value1);
516 			}
517 			if (value1 instanceof Integer) {
518 				return compare_Integer(((Integer) value1).intValue());
519 			}
520 			if (value1 instanceof Long) {
521 				return compare_Long(((Long) value1).longValue());
522 			}
523 			if (value1 instanceof Byte) {
524 				return compare_Byte(((Byte) value1).byteValue());
525 			}
526 			if (value1 instanceof Short) {
527 				return compare_Short(((Short) value1).shortValue());
528 			}
529 			if (value1 instanceof Character) {
530 				return compare_Character(((Character) value1).charValue());
531 			}
532 			if (value1 instanceof Float) {
533 				return compare_Float(((Float) value1).floatValue());
534 			}
535 			if (value1 instanceof Double) {
536 				return compare_Double(((Double) value1).doubleValue());
537 			}
538 			if (value1 instanceof Boolean) {
539 				return compare_Boolean(((Boolean) value1).booleanValue());
540 			}
541 			if (value1 instanceof Comparable<?>) {
542 				@SuppressWarnings("unchecked")
543 				Comparable<Object> comparable = (Comparable<Object>) value1;
544 				return compare_Comparable(comparable);
545 			}
546 			return compare_Unknown(value1);
547 		}
548 
compare_Collection(Collection<?> collection)549 		private boolean compare_Collection(Collection<?> collection) {
550 			for (Object value1 : collection) {
551 				if (compare(value1)) {
552 					return true;
553 				}
554 			}
555 			return false;
556 		}
557 
compare_ObjectArray(Object[] array)558 		private boolean compare_ObjectArray(Object[] array) {
559 			for (Object value1 : array) {
560 				if (compare(value1)) {
561 					return true;
562 				}
563 			}
564 			return false;
565 		}
566 
compare_PrimitiveArray(Class<?> type, Object primarray)567 		private boolean compare_PrimitiveArray(Class<?> type, Object primarray) {
568 			if (Integer.TYPE.isAssignableFrom(type)) {
569 				int[] array = (int[]) primarray;
570 				for (int value1 : array) {
571 					if (debug) {
572 						Debug.println(operation() + "(" + value1 + "," + value() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
573 					}
574 					if (compare_Integer(value1)) {
575 						return true;
576 					}
577 				}
578 				return false;
579 			}
580 			if (Long.TYPE.isAssignableFrom(type)) {
581 				long[] array = (long[]) primarray;
582 				for (long value1 : array) {
583 					if (debug) {
584 						Debug.println(operation() + "(" + value1 + "," + value() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
585 					}
586 					if (compare_Long(value1)) {
587 						return true;
588 					}
589 				}
590 				return false;
591 			}
592 			if (Byte.TYPE.isAssignableFrom(type)) {
593 				byte[] array = (byte[]) primarray;
594 				for (byte value1 : array) {
595 					if (debug) {
596 						Debug.println(operation() + "(" + value1 + "," + value() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
597 					}
598 					if (compare_Byte(value1)) {
599 						return true;
600 					}
601 				}
602 				return false;
603 			}
604 			if (Short.TYPE.isAssignableFrom(type)) {
605 				short[] array = (short[]) primarray;
606 				for (short value1 : array) {
607 					if (debug) {
608 						Debug.println(operation() + "(" + value1 + "," + value() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
609 					}
610 					if (compare_Short(value1)) {
611 						return true;
612 					}
613 				}
614 				return false;
615 			}
616 			if (Character.TYPE.isAssignableFrom(type)) {
617 				char[] array = (char[]) primarray;
618 				for (char value1 : array) {
619 					if (debug) {
620 						Debug.println(operation() + "(" + value1 + "," + value() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
621 					}
622 					if (compare_Character(value1)) {
623 						return true;
624 					}
625 				}
626 				return false;
627 			}
628 			if (Float.TYPE.isAssignableFrom(type)) {
629 				float[] array = (float[]) primarray;
630 				for (float value1 : array) {
631 					if (debug) {
632 						Debug.println(operation() + "(" + value1 + "," + value() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
633 					}
634 					if (compare_Float(value1)) {
635 						return true;
636 					}
637 				}
638 				return false;
639 			}
640 			if (Double.TYPE.isAssignableFrom(type)) {
641 				double[] array = (double[]) primarray;
642 				for (double value1 : array) {
643 					if (debug) {
644 						Debug.println(operation() + "(" + value1 + "," + value() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
645 					}
646 					if (compare_Double(value1)) {
647 						return true;
648 					}
649 				}
650 				return false;
651 			}
652 			if (Boolean.TYPE.isAssignableFrom(type)) {
653 				boolean[] array = (boolean[]) primarray;
654 				for (boolean value1 : array) {
655 					if (debug) {
656 						Debug.println(operation() + "(" + value1 + "," + value() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
657 					}
658 					if (compare_Boolean(value1)) {
659 						return true;
660 					}
661 				}
662 				return false;
663 			}
664 			return false;
665 		}
666 
compare_String(String string)667 		boolean compare_String(String string) {
668 			return false;
669 		}
670 
compare_Version(Version value1)671 		boolean compare_Version(Version value1) {
672 			return false;
673 		}
674 
compare_Comparable(Comparable<Object> value1)675 		boolean compare_Comparable(Comparable<Object> value1) {
676 			return false;
677 		}
678 
compare_Unknown(Object value1)679 		boolean compare_Unknown(Object value1) {
680 			return false;
681 		}
682 
compare_Boolean(boolean boolval)683 		boolean compare_Boolean(boolean boolval) {
684 			return false;
685 		}
686 
compare_Byte(byte byteval)687 		boolean compare_Byte(byte byteval) {
688 			return false;
689 		}
690 
compare_Character(char charval)691 		boolean compare_Character(char charval) {
692 			return false;
693 		}
694 
compare_Double(double doubleval)695 		boolean compare_Double(double doubleval) {
696 			return false;
697 		}
698 
compare_Float(float floatval)699 		boolean compare_Float(float floatval) {
700 			return false;
701 		}
702 
compare_Integer(int intval)703 		boolean compare_Integer(int intval) {
704 			return false;
705 		}
706 
compare_Long(long longval)707 		boolean compare_Long(long longval) {
708 			return false;
709 		}
710 
compare_Short(short shortval)711 		boolean compare_Short(short shortval) {
712 			return false;
713 		}
714 
715 		/**
716 		 * Encode the value string such that '(', '*', ')' and '\' are escaped.
717 		 *
718 		 * @param value unencoded value string.
719 		 */
encodeValue(StringBuilder sb, String value)720 		static StringBuilder encodeValue(StringBuilder sb, String value) {
721 			for (int i = 0, len = value.length(); i < len; i++) {
722 				char c = value.charAt(i);
723 				switch (c) {
724 					case '(' :
725 					case '*' :
726 					case ')' :
727 					case '\\' :
728 						sb.append('\\');
729 						// FALL-THROUGH
730 					default :
731 						sb.append(c);
732 						break;
733 				}
734 			}
735 			return sb;
736 		}
737 
738 		@Override
getAttributesInternal(List<String> results)739 		void getAttributesInternal(List<String> results) {
740 			results.add(attr);
741 		}
742 
743 		@Override
addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not)744 		void addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not) {
745 			attributes.put(attr, value());
746 		}
747 	}
748 
749 	static final class Present extends Item {
Present(String attr, boolean debug)750 		Present(String attr, boolean debug) {
751 			super(attr, debug);
752 		}
753 
754 		@Override
matches0(Map<String, ?> map)755 		boolean matches0(Map<String, ?> map) {
756 			if (debug) {
757 				Debug.println("PRESENT(" + attr + ")"); //$NON-NLS-1$ //$NON-NLS-2$
758 			}
759 			return map.get(attr) != null;
760 		}
761 
762 		@Override
operation()763 		String operation() {
764 			return "PRESENT"; //$NON-NLS-1$
765 		}
766 
767 		@Override
value()768 		String value() {
769 			return "*"; //$NON-NLS-1$
770 		}
771 
772 		@Override
normalize(StringBuilder sb)773 		StringBuilder normalize(StringBuilder sb) {
774 			return sb.append('(').append(attr).append('=').append('*').append(')');
775 		}
776 	}
777 
778 	static final class Substring extends Item {
779 		final String[] substrings;
780 
Substring(String attr, String[] substrings, boolean debug)781 		Substring(String attr, String[] substrings, boolean debug) {
782 			super(attr, debug);
783 			this.substrings = substrings;
784 		}
785 
786 		@Override
operation()787 		String operation() {
788 			return "SUBSTRING"; //$NON-NLS-1$
789 		}
790 
791 		@Override
value()792 		String value() {
793 			return value(new StringBuilder()).toString();
794 		}
795 
796 		@Override
compare_String(String string)797 		boolean compare_String(String string) {
798 			int pos = 0;
799 			for (int i = 0, size = substrings.length; i < size; i++) {
800 				String substr = substrings[i];
801 				if (i + 1 < size) /* if this is not that last substr */ {
802 					if (substr == null) /* * */ {
803 						String substr2 = substrings[i + 1];
804 						if (substr2 == null) /* ** */
805 							continue; /* ignore first star */
806 						/* xxx */
807 						if (debug) {
808 							Debug.println("indexOf(\"" + substr2 + "\"," + pos + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
809 						}
810 						int index = string.indexOf(substr2, pos);
811 						if (index == -1) {
812 							return false;
813 						}
814 						pos = index + substr2.length();
815 						if (i + 2 < size) // if there are more
816 							// substrings, increment
817 							// over the string we just
818 							// matched; otherwise need
819 							// to do the last substr
820 							// check
821 							i++;
822 					} else /* xxx */ {
823 						int len = substr.length();
824 						if (debug) {
825 							Debug.println("regionMatches(" + pos + ",\"" + substr + "\")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
826 						}
827 						if (string.regionMatches(pos, substr, 0, len)) {
828 							pos += len;
829 						} else {
830 							return false;
831 						}
832 					}
833 				} else /* last substr */ {
834 					if (substr == null) /* * */ {
835 						return true;
836 					}
837 					/* xxx */
838 					if (debug) {
839 						Debug.println("regionMatches(" + pos + "," + substr + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
840 					}
841 					return string.endsWith(substr);
842 				}
843 			}
844 			return true;
845 		}
846 
847 		@Override
normalize(StringBuilder sb)848 		StringBuilder normalize(StringBuilder sb) {
849 			sb.append('(').append(attr).append('=');
850 			return value(sb).append(')');
851 		}
852 
value(StringBuilder sb)853 		private StringBuilder value(StringBuilder sb) {
854 			for (String substr : substrings) {
855 				if (substr == null) /* * */ {
856 					sb.append('*');
857 				} else /* xxx */ {
858 					encodeValue(sb, substr);
859 				}
860 			}
861 			return sb;
862 		}
863 	}
864 
865 	static class Equal extends Item {
866 		final String value;
867 
Equal(String attr, String value, boolean debug)868 		Equal(String attr, String value, boolean debug) {
869 			super(attr, debug);
870 			this.value = value;
871 		}
872 
873 		@Override
operation()874 		String operation() {
875 			return "EQUAL"; //$NON-NLS-1$
876 		}
877 
878 		@Override
value()879 		String value() {
880 			return value;
881 		}
882 
comparison(int compare)883 		boolean comparison(int compare) {
884 			return compare == 0;
885 		}
886 
887 		@Override
compare_String(String string)888 		boolean compare_String(String string) {
889 			return comparison((string == value) ? 0 : string.compareTo(value));
890 		}
891 
892 		@Override
compare_Version(Version value1)893 		boolean compare_Version(Version value1) {
894 			try {
895 				Version version2 = Version.valueOf(value);
896 				return comparison(value1.compareTo(version2));
897 			} catch (Exception e) {
898 				// if the valueOf or compareTo method throws an exception
899 				return false;
900 			}
901 		}
902 
903 		@Override
compare_Boolean(boolean boolval)904 		boolean compare_Boolean(boolean boolval) {
905 			boolean boolval2 = Boolean.parseBoolean(value.trim());
906 			return comparison(Boolean.compare(boolval, boolval2));
907 		}
908 
909 		@Override
compare_Byte(byte byteval)910 		boolean compare_Byte(byte byteval) {
911 			byte byteval2;
912 			try {
913 				byteval2 = Byte.parseByte(value.trim());
914 			} catch (IllegalArgumentException e) {
915 				return false;
916 			}
917 			return comparison(Byte.compare(byteval, byteval2));
918 		}
919 
920 		@Override
compare_Character(char charval)921 		boolean compare_Character(char charval) {
922 			char charval2;
923 			try {
924 				charval2 = value.charAt(0);
925 			} catch (IndexOutOfBoundsException e) {
926 				return false;
927 			}
928 			return comparison(Character.compare(charval, charval2));
929 		}
930 
931 		@Override
compare_Double(double doubleval)932 		boolean compare_Double(double doubleval) {
933 			double doubleval2;
934 			try {
935 				doubleval2 = Double.parseDouble(value.trim());
936 			} catch (IllegalArgumentException e) {
937 				return false;
938 			}
939 			return comparison(Double.compare(doubleval, doubleval2));
940 		}
941 
942 		@Override
compare_Float(float floatval)943 		boolean compare_Float(float floatval) {
944 			float floatval2;
945 			try {
946 				floatval2 = Float.parseFloat(value.trim());
947 			} catch (IllegalArgumentException e) {
948 				return false;
949 			}
950 			return comparison(Float.compare(floatval, floatval2));
951 		}
952 
953 		@Override
compare_Integer(int intval)954 		boolean compare_Integer(int intval) {
955 			int intval2;
956 			try {
957 				intval2 = Integer.parseInt(value.trim());
958 			} catch (IllegalArgumentException e) {
959 				return false;
960 			}
961 			return comparison(Integer.compare(intval, intval2));
962 		}
963 
964 		@Override
compare_Long(long longval)965 		boolean compare_Long(long longval) {
966 			long longval2;
967 			try {
968 				longval2 = Long.parseLong(value.trim());
969 			} catch (IllegalArgumentException e) {
970 				return false;
971 			}
972 			return comparison(Long.compare(longval, longval2));
973 		}
974 
975 		@Override
compare_Short(short shortval)976 		boolean compare_Short(short shortval) {
977 			short shortval2;
978 			try {
979 				shortval2 = Short.parseShort(value.trim());
980 			} catch (IllegalArgumentException e) {
981 				return false;
982 			}
983 			return comparison(Short.compare(shortval, shortval2));
984 		}
985 
986 		@Override
compare_Comparable(Comparable<Object> value1)987 		boolean compare_Comparable(Comparable<Object> value1) {
988 			Object value2 = valueOf(value1.getClass());
989 			if (value2 == null) {
990 				return false;
991 			}
992 			try {
993 				return comparison(value1.compareTo(value2));
994 			} catch (Exception e) {
995 				// if the compareTo method throws an exception; return false
996 				return false;
997 			}
998 		}
999 
1000 		@Override
compare_Unknown(Object value1)1001 		boolean compare_Unknown(Object value1) {
1002 			Object value2 = valueOf(value1.getClass());
1003 			if (value2 == null) {
1004 				return false;
1005 			}
1006 			try {
1007 				return value1.equals(value2);
1008 			} catch (Exception e) {
1009 				// if the equals method throws an exception; return false
1010 				return false;
1011 			}
1012 		}
1013 
1014 		@Override
normalize(StringBuilder sb)1015 		StringBuilder normalize(StringBuilder sb) {
1016 			sb.append('(').append(attr).append('=');
1017 			return encodeValue(sb, value).append(')');
1018 		}
1019 
valueOf(Class<?> target)1020 		Object valueOf(Class<?> target) {
1021 			do {
1022 				Method method;
1023 				try {
1024 					method = target.getMethod("valueOf", String.class); //$NON-NLS-1$
1025 				} catch (NoSuchMethodException e) {
1026 					break;
1027 				}
1028 				if (Modifier.isStatic(method.getModifiers()) && target.isAssignableFrom(method.getReturnType())) {
1029 					setAccessible(method);
1030 					try {
1031 						return method.invoke(null, value.trim());
1032 					} catch (Error e) {
1033 						throw e;
1034 					} catch (Throwable e) {
1035 						return null;
1036 					}
1037 				}
1038 			} while (false);
1039 
1040 			do {
1041 				Constructor<?> constructor;
1042 				try {
1043 					constructor = target.getConstructor(String.class);
1044 				} catch (NoSuchMethodException e) {
1045 					break;
1046 				}
1047 				setAccessible(constructor);
1048 				try {
1049 					return constructor.newInstance(value.trim());
1050 				} catch (Error e) {
1051 					throw e;
1052 				} catch (Throwable e) {
1053 					return null;
1054 				}
1055 			} while (false);
1056 
1057 			return null;
1058 		}
1059 
setAccessible(final AccessibleObject accessible)1060 		private static void setAccessible(final AccessibleObject accessible) {
1061 			if (!accessible.isAccessible()) {
1062 				AccessController.doPrivileged(new PrivilegedAction<Void>() {
1063 					@Override
1064 					public Void run() {
1065 						accessible.setAccessible(true);
1066 						return null;
1067 					}
1068 				});
1069 			}
1070 		}
1071 
1072 		@Override
getPrimaryKeyValue(String primaryKey)1073 		public String getPrimaryKeyValue(String primaryKey) {
1074 			if (attr.equalsIgnoreCase(primaryKey)) {
1075 				return value;
1076 			}
1077 			return null;
1078 		}
1079 
1080 		@Override
addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not)1081 		void addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not) {
1082 			if (!versionAttrs.containsKey(attr)) {
1083 				attributes.put(attr, value);
1084 			} else {
1085 				// this is an exact range e.g. [value,value]
1086 				Range currentRange = versionAttrs.get(attr);
1087 				if (currentRange != null) {
1088 					if (not) {
1089 						// this is an expanded form of the filter, e.g.:
1090 						// [1.0,2.0) -> (&(version>=1.0)(version<=2.0)(!(version=2.0)))
1091 						currentRange.addExclude(Version.valueOf(value));
1092 					} else {
1093 						throw new IllegalStateException("Invalid range for: " + attr); //$NON-NLS-1$
1094 					}
1095 				} else {
1096 					currentRange = new Range();
1097 					Version version = Version.valueOf(value);
1098 					currentRange.setLeft('[', version);
1099 					currentRange.setRight(']', version);
1100 					versionAttrs.put(attr, currentRange);
1101 				}
1102 			}
1103 		}
1104 	}
1105 
1106 	static final class LessEqual extends Equal {
LessEqual(String attr, String value, boolean debug)1107 		LessEqual(String attr, String value, boolean debug) {
1108 			super(attr, value, debug);
1109 		}
1110 
1111 		@Override
operation()1112 		String operation() {
1113 			return "LESS"; //$NON-NLS-1$
1114 		}
1115 
1116 		@Override
comparison(int compare)1117 		boolean comparison(int compare) {
1118 			return compare <= 0;
1119 		}
1120 
1121 		@Override
normalize(StringBuilder sb)1122 		StringBuilder normalize(StringBuilder sb) {
1123 			sb.append('(').append(attr).append('<').append('=');
1124 			return encodeValue(sb, value).append(')');
1125 		}
1126 
1127 		@Override
getPrimaryKeyValue(String primaryKey)1128 		public String getPrimaryKeyValue(String primaryKey) {
1129 			return null;
1130 		}
1131 
1132 		@Override
getStandardOSGiAttributes(String... versions)1133 		public Map<String, String> getStandardOSGiAttributes(String... versions) {
1134 			throw new IllegalArgumentException("Invalid filter for standard OSGi Attributes: " + operation()); //$NON-NLS-1$
1135 		}
1136 
1137 		@Override
addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not)1138 		void addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not) {
1139 			if (!versionAttrs.containsKey(attr)) {
1140 				throw new IllegalStateException("Invalid attribute: " + attr); //$NON-NLS-1$
1141 			}
1142 			Range currentRange = versionAttrs.get(attr);
1143 			if (currentRange == null) {
1144 				currentRange = new Range();
1145 				versionAttrs.put(attr, currentRange);
1146 			}
1147 			if (not) {
1148 				// this must be a range start "(value"
1149 				if (!currentRange.setLeft('(', Version.valueOf(value))) {
1150 					throw new IllegalStateException("range start is already processed for attribute: " + attr); //$NON-NLS-1$
1151 				}
1152 			} else {
1153 				// this must be a range end "value]"
1154 				if (!currentRange.setRight(']', Version.valueOf(value))) {
1155 					throw new IllegalStateException("range end is already processed for attribute: " + attr); //$NON-NLS-1$
1156 				}
1157 			}
1158 		}
1159 	}
1160 
1161 	static final class GreaterEqual extends Equal {
GreaterEqual(String attr, String value, boolean debug)1162 		GreaterEqual(String attr, String value, boolean debug) {
1163 			super(attr, value, debug);
1164 		}
1165 
1166 		@Override
operation()1167 		String operation() {
1168 			return "GREATER"; //$NON-NLS-1$
1169 		}
1170 
1171 		@Override
comparison(int compare)1172 		boolean comparison(int compare) {
1173 			return compare >= 0;
1174 		}
1175 
1176 		@Override
normalize(StringBuilder sb)1177 		StringBuilder normalize(StringBuilder sb) {
1178 			sb.append('(').append(attr).append('>').append('=');
1179 			return encodeValue(sb, value).append(')');
1180 		}
1181 
1182 		@Override
getPrimaryKeyValue(String primaryKey)1183 		public String getPrimaryKeyValue(String primaryKey) {
1184 			return null;
1185 		}
1186 
1187 		@Override
getStandardOSGiAttributes(String... versions)1188 		public Map<String, String> getStandardOSGiAttributes(String... versions) {
1189 			throw new IllegalArgumentException("Invalid filter for standard OSGi Attributes: " + operation()); //$NON-NLS-1$
1190 		}
1191 
1192 		@Override
addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not)1193 		void addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not) {
1194 			if (!versionAttrs.containsKey(attr)) {
1195 				throw new IllegalStateException("Invalid attribute: " + attr); //$NON-NLS-1$
1196 			}
1197 			Range currentRange = versionAttrs.get(attr);
1198 			if (currentRange == null) {
1199 				currentRange = new Range();
1200 				versionAttrs.put(attr, currentRange);
1201 			}
1202 			if (not) {
1203 				// this must be a range end "value)"
1204 				if (!currentRange.setRight(')', Version.valueOf(value))) {
1205 					throw new IllegalStateException("range end is already processed for attribute: " + attr); //$NON-NLS-1$
1206 				}
1207 			} else {
1208 				// this must be a range start "[value"
1209 				if (!currentRange.setLeft('[', Version.valueOf(value))) {
1210 					throw new IllegalStateException("range start is already processed for attribute: " + attr); //$NON-NLS-1$
1211 				}
1212 			}
1213 		}
1214 	}
1215 
1216 	static final class Approx extends Equal {
1217 		final String approx;
1218 
Approx(String attr, String value, boolean debug)1219 		Approx(String attr, String value, boolean debug) {
1220 			super(attr, value, debug);
1221 			this.approx = approxString(value);
1222 		}
1223 
1224 		@Override
operation()1225 		String operation() {
1226 			return "APPROX"; //$NON-NLS-1$
1227 		}
1228 
1229 		@Override
value()1230 		String value() {
1231 			return approx;
1232 		}
1233 
1234 		@Override
compare_String(String string)1235 		boolean compare_String(String string) {
1236 			string = approxString(string);
1237 			return string.equalsIgnoreCase(approx);
1238 		}
1239 
1240 		@Override
compare_Character(char charval)1241 		boolean compare_Character(char charval) {
1242 			char charval2;
1243 			try {
1244 				charval2 = approx.charAt(0);
1245 			} catch (IndexOutOfBoundsException e) {
1246 				return false;
1247 			}
1248 			return (charval == charval2) || (Character.toUpperCase(charval) == Character.toUpperCase(charval2)) || (Character.toLowerCase(charval) == Character.toLowerCase(charval2));
1249 		}
1250 
1251 		@Override
normalize(StringBuilder sb)1252 		StringBuilder normalize(StringBuilder sb) {
1253 			sb.append('(').append(attr).append('~').append('=');
1254 			return encodeValue(sb, approx).append(')');
1255 		}
1256 
1257 		/**
1258 		 * Map a string for an APPROX (~=) comparison. This implementation
1259 		 * removes white spaces. This is the minimum implementation allowed by
1260 		 * the OSGi spec.
1261 		 *
1262 		 * @param input Input string.
1263 		 * @return String ready for APPROX comparison.
1264 		 */
approxString(String input)1265 		static String approxString(String input) {
1266 			boolean changed = false;
1267 			char[] output = input.toCharArray();
1268 			int cursor = 0;
1269 			for (char c : output) {
1270 				if (Character.isWhitespace(c)) {
1271 					changed = true;
1272 					continue;
1273 				}
1274 
1275 				output[cursor] = c;
1276 				cursor++;
1277 			}
1278 
1279 			return changed ? new String(output, 0, cursor) : input;
1280 		}
1281 
1282 		@Override
getPrimaryKeyValue(String primaryKey)1283 		public String getPrimaryKeyValue(String primaryKey) {
1284 			return null;
1285 		}
1286 
1287 		@Override
getStandardOSGiAttributes(String... versions)1288 		public Map<String, String> getStandardOSGiAttributes(String... versions) {
1289 			throw new IllegalArgumentException("Invalid filter for standard OSGi Attributes: " + operation()); //$NON-NLS-1$
1290 		}
1291 	}
1292 
1293 	/**
1294 	 * Returns the leftmost required objectClass value for the filter to evaluate to true.
1295 	 *
1296 	 * @return The leftmost required objectClass value or null if none could be determined.
1297 	 */
getRequiredObjectClass()1298 	public String getRequiredObjectClass() {
1299 		return getPrimaryKeyValue(Constants.OBJECTCLASS);
1300 	}
1301 
1302 	/**
1303 	 * Returns the leftmost required primary key value for the filter to evaluate to true.
1304 	 * This is useful for indexing candidates to match against this filter.
1305 	 * @param primaryKey the primary key
1306 	 * @return The leftmost required primary key value or null if none could be determined.
1307 	 */
getPrimaryKeyValue(String primaryKey)1308 	public String getPrimaryKeyValue(String primaryKey) {
1309 		// just checking for simple filters here where primaryKey is the only attr or it is one attr of a base '&' clause
1310 		// (primaryKey=org.acme.BrickService) OK
1311 		// (&(primaryKey=org.acme.BrickService)(|(vendor=IBM)(vendor=SUN))) OK
1312 		// (primaryKey=org.acme.*) NOT OK
1313 		// (|(primaryKey=org.acme.BrickService)(primaryKey=org.acme.CementService)) NOT OK
1314 		// (&(primaryKey=org.acme.BrickService)(primaryKey=org.acme.CementService)) OK but only the first objectClass is returned
1315 		return null;
1316 	}
1317 
getChildren()1318 	public List<FilterImpl> getChildren() {
1319 		return Collections.emptyList();
1320 	}
1321 
1322 	/**
1323 	 * Returns all the attributes contained within this filter
1324 	 * @return all the attributes contained within this filter
1325 	 */
getAttributes()1326 	public String[] getAttributes() {
1327 		List<String> results = new ArrayList<>();
1328 		getAttributesInternal(results);
1329 		return results.toArray(new String[0]);
1330 	}
1331 
getAttributesInternal(List<String> results)1332 	abstract void getAttributesInternal(List<String> results);
1333 
getStandardOSGiAttributes(String... versions)1334 	public Map<String, String> getStandardOSGiAttributes(String... versions) {
1335 		Map<String, String> result = new HashMap<>();
1336 		Map<String, Range> versionAttrs = new HashMap<>();
1337 		if (versions != null) {
1338 			for (String versionAttr : versions) {
1339 				versionAttrs.put(versionAttr, null);
1340 			}
1341 		}
1342 		addAttributes(result, versionAttrs, false);
1343 		for (Map.Entry<String, Range> entry : versionAttrs.entrySet()) {
1344 			Range range = entry.getValue();
1345 			if (range != null) {
1346 				result.put(entry.getKey(), range.toString());
1347 			}
1348 		}
1349 
1350 		return result;
1351 	}
1352 
addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not)1353 	abstract void addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not);
1354 
1355 	/**
1356 	 * Parser class for OSGi filter strings. This class parses the complete
1357 	 * filter string and builds a tree of FilterImpl objects rooted at the
1358 	 * parent.
1359 	 */
1360 	static private final class Parser {
1361 		private final boolean debug;
1362 		private final String filterstring;
1363 		private final char[] filterChars;
1364 		private int pos;
1365 
Parser(String filterstring, boolean debug)1366 		Parser(String filterstring, boolean debug) {
1367 			this.debug = debug;
1368 			this.filterstring = filterstring;
1369 			filterChars = filterstring.toCharArray();
1370 			pos = 0;
1371 		}
1372 
parse()1373 		FilterImpl parse() throws InvalidSyntaxException {
1374 			FilterImpl filter;
1375 			try {
1376 				filter = parse_filter();
1377 			} catch (ArrayIndexOutOfBoundsException e) {
1378 				throw new InvalidSyntaxException(Msg.FILTER_TERMINATED_ABRUBTLY, filterstring, e);
1379 			}
1380 
1381 			if (pos != filterChars.length) {
1382 				throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_TRAILING_CHARACTERS, filterstring.substring(pos)), filterstring);
1383 			}
1384 			return filter;
1385 		}
1386 
parse_filter()1387 		private FilterImpl parse_filter() throws InvalidSyntaxException {
1388 			FilterImpl filter;
1389 			skipWhiteSpace();
1390 
1391 			if (filterChars[pos] != '(') {
1392 				throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_MISSING_LEFTPAREN, filterstring.substring(pos)), filterstring);
1393 			}
1394 
1395 			pos++;
1396 
1397 			filter = parse_filtercomp();
1398 
1399 			skipWhiteSpace();
1400 
1401 			if (filterChars[pos] != ')') {
1402 				throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_MISSING_RIGHTPAREN, filterstring.substring(pos)), filterstring);
1403 			}
1404 
1405 			pos++;
1406 
1407 			skipWhiteSpace();
1408 
1409 			return filter;
1410 		}
1411 
parse_filtercomp()1412 		private FilterImpl parse_filtercomp() throws InvalidSyntaxException {
1413 			skipWhiteSpace();
1414 
1415 			char c = filterChars[pos];
1416 
1417 			switch (c) {
1418 				case '&' : {
1419 					pos++;
1420 					return parse_and();
1421 				}
1422 				case '|' : {
1423 					pos++;
1424 					return parse_or();
1425 				}
1426 				case '!' : {
1427 					pos++;
1428 					return parse_not();
1429 				}
1430 			}
1431 			return parse_item();
1432 		}
1433 
parse_and()1434 		private FilterImpl parse_and() throws InvalidSyntaxException {
1435 			int lookahead = pos;
1436 			skipWhiteSpace();
1437 
1438 			if (filterChars[pos] != '(') {
1439 				pos = lookahead - 1;
1440 				return parse_item();
1441 			}
1442 
1443 			List<FilterImpl> operands = new ArrayList<>(10);
1444 
1445 			while (filterChars[pos] == '(') {
1446 				FilterImpl child = parse_filter();
1447 				operands.add(child);
1448 			}
1449 
1450 			return new FilterImpl.And(operands.toArray(new FilterImpl[0]));
1451 		}
1452 
parse_or()1453 		private FilterImpl parse_or() throws InvalidSyntaxException {
1454 			int lookahead = pos;
1455 			skipWhiteSpace();
1456 
1457 			if (filterChars[pos] != '(') {
1458 				pos = lookahead - 1;
1459 				return parse_item();
1460 			}
1461 
1462 			List<FilterImpl> operands = new ArrayList<>(10);
1463 
1464 			while (filterChars[pos] == '(') {
1465 				FilterImpl child = parse_filter();
1466 				operands.add(child);
1467 			}
1468 
1469 			return new FilterImpl.Or(operands.toArray(new FilterImpl[0]));
1470 		}
1471 
parse_not()1472 		private FilterImpl parse_not() throws InvalidSyntaxException {
1473 			int lookahead = pos;
1474 			skipWhiteSpace();
1475 
1476 			if (filterChars[pos] != '(') {
1477 				pos = lookahead - 1;
1478 				return parse_item();
1479 			}
1480 
1481 			FilterImpl child = parse_filter();
1482 
1483 			return new FilterImpl.Not(child);
1484 		}
1485 
parse_item()1486 		private FilterImpl parse_item() throws InvalidSyntaxException {
1487 			String attr = parse_attr();
1488 
1489 			skipWhiteSpace();
1490 
1491 			switch (filterChars[pos]) {
1492 				case '~' : {
1493 					if (filterChars[pos + 1] == '=') {
1494 						pos += 2;
1495 						return new FilterImpl.Approx(attr, parse_value(), debug);
1496 					}
1497 					break;
1498 				}
1499 				case '>' : {
1500 					if (filterChars[pos + 1] == '=') {
1501 						pos += 2;
1502 						return new FilterImpl.GreaterEqual(attr, parse_value(), debug);
1503 					}
1504 					break;
1505 				}
1506 				case '<' : {
1507 					if (filterChars[pos + 1] == '=') {
1508 						pos += 2;
1509 						return new FilterImpl.LessEqual(attr, parse_value(), debug);
1510 					}
1511 					break;
1512 				}
1513 				case '=' : {
1514 					if (filterChars[pos + 1] == '*') {
1515 						int oldpos = pos;
1516 						pos += 2;
1517 						skipWhiteSpace();
1518 						if (filterChars[pos] == ')') {
1519 							return new FilterImpl.Present(attr, debug);
1520 						}
1521 						pos = oldpos;
1522 					}
1523 
1524 					pos++;
1525 					String[] substrings = parse_substring();
1526 
1527 					int length = substrings.length;
1528 					if (length == 0) {
1529 						return new FilterImpl.Equal(attr, "", debug); //$NON-NLS-1$
1530 					}
1531 					if (length == 1) {
1532 						String single = substrings[0];
1533 						if (single != null) {
1534 							return new FilterImpl.Equal(attr, single, debug);
1535 						}
1536 					}
1537 					return new FilterImpl.Substring(attr, substrings, debug);
1538 				}
1539 			}
1540 
1541 			throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_INVALID_OPERATOR, filterstring.substring(pos)), filterstring);
1542 		}
1543 
parse_attr()1544 		private String parse_attr() throws InvalidSyntaxException {
1545 			skipWhiteSpace();
1546 
1547 			int begin = pos;
1548 			int end = pos;
1549 
1550 			char c = filterChars[pos];
1551 
1552 			while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') {
1553 				pos++;
1554 
1555 				if (!Character.isWhitespace(c)) {
1556 					end = pos;
1557 				}
1558 
1559 				c = filterChars[pos];
1560 			}
1561 
1562 			int length = end - begin;
1563 
1564 			if (length == 0) {
1565 				throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_MISSING_ATTR, filterstring.substring(pos)), filterstring);
1566 			}
1567 
1568 			return new String(filterChars, begin, length);
1569 		}
1570 
parse_value()1571 		private String parse_value() throws InvalidSyntaxException {
1572 			StringBuilder sb = new StringBuilder(filterChars.length - pos);
1573 
1574 			parseloop: while (true) {
1575 				char c = filterChars[pos];
1576 
1577 				switch (c) {
1578 					case ')' : {
1579 						break parseloop;
1580 					}
1581 
1582 					case '(' : {
1583 						throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_INVALID_VALUE, filterstring.substring(pos)), filterstring);
1584 					}
1585 
1586 					case '\\' : {
1587 						pos++;
1588 						c = filterChars[pos];
1589 						/* fall through into default */
1590 					}
1591 
1592 					default : {
1593 						sb.append(c);
1594 						pos++;
1595 						break;
1596 					}
1597 				}
1598 			}
1599 
1600 			if (sb.length() == 0) {
1601 				throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_MISSING_VALUE, filterstring.substring(pos)), filterstring);
1602 			}
1603 
1604 			return sb.toString();
1605 		}
1606 
parse_substring()1607 		private String[] parse_substring() throws InvalidSyntaxException {
1608 			StringBuilder sb = new StringBuilder(filterChars.length - pos);
1609 
1610 			List<String> operands = new ArrayList<>(10);
1611 
1612 			parseloop: while (true) {
1613 				char c = filterChars[pos];
1614 
1615 				switch (c) {
1616 					case ')' : {
1617 						if (sb.length() > 0) {
1618 							operands.add(sb.toString());
1619 						}
1620 
1621 						break parseloop;
1622 					}
1623 
1624 					case '(' : {
1625 						throw new InvalidSyntaxException(NLS.bind(Msg.FILTER_INVALID_VALUE, filterstring.substring(pos)), filterstring);
1626 					}
1627 
1628 					case '*' : {
1629 						if (sb.length() > 0) {
1630 							operands.add(sb.toString());
1631 						}
1632 
1633 						sb.setLength(0);
1634 
1635 						operands.add(null);
1636 						pos++;
1637 
1638 						break;
1639 					}
1640 
1641 					case '\\' : {
1642 						pos++;
1643 						c = filterChars[pos];
1644 						/* fall through into default */
1645 					}
1646 
1647 					default : {
1648 						sb.append(c);
1649 						pos++;
1650 						break;
1651 					}
1652 				}
1653 			}
1654 
1655 			return operands.toArray(new String[0]);
1656 		}
1657 
skipWhiteSpace()1658 		private void skipWhiteSpace() {
1659 			for (int length = filterChars.length; (pos < length) && Character.isWhitespace(filterChars[pos]);) {
1660 				pos++;
1661 			}
1662 		}
1663 	}
1664 
1665 	/**
1666 	 * This Map is used for key lookup during filter
1667 	 * evaluation. This Map implementation only supports the get operation using
1668 	 * a String key as no other operations are used by the Filter
1669 	 * implementation.
1670 	 */
1671 	private static final class DictionaryMap extends AbstractMap<String, Object> implements Map<String, Object> {
asMap(Dictionary<String, ?> dictionary)1672 		static Map<String, ?> asMap(Dictionary<String, ?> dictionary) {
1673 			if (dictionary instanceof Map) {
1674 				@SuppressWarnings("unchecked")
1675 				Map<String, ?> coerced = (Map<String, ?>) dictionary;
1676 				return coerced;
1677 			}
1678 			return new DictionaryMap(dictionary);
1679 		}
1680 
1681 		private final Dictionary<String, ?> dictionary;
1682 
1683 		/**
1684 		 * Create a case insensitive map from the specified dictionary.
1685 		 *
1686 		 * @param dictionary
1687 		 * @throws IllegalArgumentException If {@code dictionary} contains case
1688 		 *             variants of the same key name.
1689 		 */
DictionaryMap(Dictionary<String, ?> dictionary)1690 		DictionaryMap(Dictionary<String, ?> dictionary) {
1691 			this.dictionary = requireNonNull(dictionary);
1692 		}
1693 
1694 		@Override
get(Object key)1695 		public Object get(Object key) {
1696 			return dictionary.get(key);
1697 		}
1698 
1699 		@Override
entrySet()1700 		public Set<Entry<String, Object>> entrySet() {
1701 			throw new UnsupportedOperationException();
1702 		}
1703 	}
1704 
1705 	/**
1706 	 * This Map is used for key lookup from a ServiceReference during filter
1707 	 * evaluation. This Map implementation only supports the get operation using
1708 	 * a String key as no other operations are used by the Filter
1709 	 * implementation.
1710 	 */
1711 	private static final class ServiceReferenceMap extends AbstractMap<String, Object> implements Map<String, Object> {
asMap(ServiceReference<?> reference)1712 		static Map<String, ?> asMap(ServiceReference<?> reference) {
1713 			if (reference instanceof ServiceReferenceImpl) {
1714 				return ((ServiceReferenceImpl<?>) reference).getRegistration().getProperties();
1715 			}
1716 			return new ServiceReferenceMap(reference);
1717 		}
1718 
1719 		private final ServiceReference<?> reference;
1720 
ServiceReferenceMap(ServiceReference<?> reference)1721 		ServiceReferenceMap(ServiceReference<?> reference) {
1722 			this.reference = requireNonNull(reference);
1723 		}
1724 
1725 		@Override
get(Object key)1726 		public Object get(Object key) {
1727 			return reference.getProperty((String) key);
1728 		}
1729 
1730 		@Override
entrySet()1731 		public Set<Entry<String, Object>> entrySet() {
1732 			throw new UnsupportedOperationException();
1733 		}
1734 	}
1735 
1736 	static class Range {
1737 		private char leftRule = 0;
1738 		private Version leftVersion;
1739 		private Version rightVersion;
1740 		private char rightRule = 0;
1741 		private Collection<Version> excludes = new ArrayList<>(0);
1742 
1743 		@Override
toString()1744 		public String toString() {
1745 			if (rightVersion == null) {
1746 				return leftVersion.toString();
1747 			}
1748 			return leftRule + leftVersion.toString() + ',' + rightVersion.toString() + rightRule;
1749 		}
1750 
addExclude(Version exclude)1751 		void addExclude(Version exclude) {
1752 			this.excludes.add(exclude);
1753 			setLeft(leftRule, leftVersion);
1754 			setRight(rightRule, rightVersion);
1755 		}
1756 
setLeft(char leftRule, Version leftVersion)1757 		boolean setLeft(char leftRule, Version leftVersion) {
1758 			if (this.leftVersion != null && this.leftVersion != leftVersion)
1759 				return false;
1760 			this.leftRule = excludes.contains(leftVersion) ? '(' : leftRule;
1761 			this.leftVersion = leftVersion;
1762 			return true;
1763 		}
1764 
setRight(char rightRule, Version rightVersion)1765 		boolean setRight(char rightRule, Version rightVersion) {
1766 			if (this.rightVersion != null && this.rightVersion != rightVersion)
1767 				return false;
1768 			this.rightRule = excludes.contains(rightVersion) ? ')' : rightRule;
1769 			this.rightVersion = rightVersion;
1770 			return true;
1771 		}
1772 	}
1773 
1774 }
1775