492769: OsgiFilterUtils should escape filter values that come from ServiceReference properties
Signed-off-by: Olaf Otto <olaf@x100.de>
diff --git a/core/src/main/java/org/eclipse/gemini/blueprint/util/OsgiFilterUtils.java b/core/src/main/java/org/eclipse/gemini/blueprint/util/OsgiFilterUtils.java
index ab07ec9..0c16470 100644
--- a/core/src/main/java/org/eclipse/gemini/blueprint/util/OsgiFilterUtils.java
+++ b/core/src/main/java/org/eclipse/gemini/blueprint/util/OsgiFilterUtils.java
@@ -14,17 +14,17 @@
package org.eclipse.gemini.blueprint.util;
-import java.util.Collection;
-
-import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
+import org.osgi.framework.*;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
+import java.nio.CharBuffer;
+import java.util.Collection;
+
+import static java.lang.String.valueOf;
+import static java.nio.CharBuffer.allocate;
+
/**
* Utility class for creating OSGi filters. This class allows filter creation and concatenation from common parameters
* such as class names.
@@ -32,7 +32,6 @@
* @author Costin Leau
*/
public abstract class OsgiFilterUtils {
-
private static final char FILTER_BEGIN = '(';
private static final char FILTER_END = ')';
@@ -227,9 +226,6 @@
/**
* Creates a filter (as String) that matches the properties (expect the service id) of service reference.
- *
- * @param reference
- * @return
*/
public static String getFilter(ServiceReference reference) {
String[] propertyKeys = reference.getPropertyKeys();
@@ -240,15 +236,15 @@
if (!Constants.SERVICE_ID.equals(key)) {
Object value = reference.getProperty(key);
Class<?> cl = value.getClass();
- Iterable it;
+
// array
if (cl.isArray()) {
Object[] array = ObjectUtils.toObjectArray(value);
for (Object item : array) {
sb.append("(");
- sb.append(key);
+ sb.append(escapeFilterCharacters(key));
sb.append("=");
- sb.append(item);
+ sb.append(escapeFilterCharacters(valueOf(item)));
sb.append(")");
}
}
@@ -258,9 +254,9 @@
Collection<?> c = (Collection) value;
for (Object item : c) {
sb.append("(");
- sb.append(key);
+ sb.append(escapeFilterCharacters(key));
sb.append("=");
- sb.append(item);
+ sb.append(escapeFilterCharacters(valueOf(item)));
sb.append(")");
}
}
@@ -268,9 +264,9 @@
// scalar/primitive
else {
sb.append("(");
- sb.append(key);
+ sb.append(escapeFilterCharacters(key));
sb.append("=");
- sb.append(value);
+ sb.append(escapeFilterCharacters(valueOf(value)));
sb.append(")");
}
}
@@ -279,4 +275,18 @@
sb.append(")");
return sb.toString();
}
+
+ private static String escapeFilterCharacters(String value) {
+ CharBuffer buffer = allocate(value.length() * 2);
+ for ( char c : value.toCharArray()) {
+ switch (c) {
+ case '*' : buffer.append('\\'); break;
+ case '\\' : buffer.append('\\'); break;
+ case '(' : buffer.append('\\'); break;
+ case ')' : buffer.append('\\'); break;
+ }
+ buffer.append(c);
+ }
+ return buffer.flip().toString();
+ }
}
\ No newline at end of file
diff --git a/core/src/test/java/org/eclipse/gemini/blueprint/service/OsgiFilterUtilsTest.java b/core/src/test/java/org/eclipse/gemini/blueprint/service/OsgiFilterUtilsTest.java
index eed1fe5..1cd64f8 100644
--- a/core/src/test/java/org/eclipse/gemini/blueprint/service/OsgiFilterUtilsTest.java
+++ b/core/src/test/java/org/eclipse/gemini/blueprint/service/OsgiFilterUtilsTest.java
@@ -20,7 +20,9 @@
import junit.framework.TestCase;
+import org.eclipse.gemini.blueprint.mock.MockServiceReference;
import org.eclipse.gemini.blueprint.util.OsgiFilterUtils;
+import org.fest.assertions.Assertions;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.Filter;
@@ -174,6 +176,23 @@
}
+ /**
+ * As per OSGI r5 spec, https://www.scribd.com/document/137122057/osgi-core-5-0-0, the characters
+ * <code> \ * ( )</code> must be escaped using a \ character.
+ */
+ public void testFiltersFromServiceReferencesAreEscaped() {
+ MockServiceReference serviceReference = new MockServiceReference();
+ Dictionary<String, String> properties = new Hashtable<>();
+ properties.put("ds.target", "(thing=ball)");
+ properties.put("all.escapable", "*()\\");
+ serviceReference.setProperties(properties);
+
+ String actual = OsgiFilterUtils.getFilter(serviceReference);
+
+ Assertions.assertThat(actual).contains("(ds.target=\\(thing=ball\\)");
+ Assertions.assertThat(actual).contains("\\*\\(\\)\\");
+ }
+
protected BundleContext getBundleContext() {
return new MockBundleContext() {
public Filter createFilter(String filter) throws InvalidSyntaxException {