Fix a bug in the Framework FilterImpl which makes it not thread safe on execution (FELIX-338).
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@566323 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/FilterImpl.java b/framework/src/main/java/org/apache/felix/framework/FilterImpl.java
index 07dd9eb..8a5a95f 100644
--- a/framework/src/main/java/org/apache/felix/framework/FilterImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/FilterImpl.java
@@ -21,6 +21,7 @@
import java.io.CharArrayReader;
import java.io.IOException;
import java.util.*;
+import java.lang.ref.SoftReference;
import org.apache.felix.framework.util.StringMap;
import org.apache.felix.framework.util.ldap.*;
@@ -34,10 +35,10 @@
**/
public class FilterImpl implements Filter
{
- private Logger m_logger = null;
- private String m_toString = null;
- private Evaluator m_evaluator = null;
- private SimpleMapper m_mapper = null;
+ private final ThreadLocal m_cache = new ThreadLocal();
+ private final Logger m_logger;
+ private final Object[] m_program;
+ private volatile String m_toString;
// TODO: FilterImpl needs a logger, this is a hack for FrameworkUtil.
public FilterImpl(String expr) throws InvalidSyntaxException
@@ -57,32 +58,28 @@
throw new InvalidSyntaxException("Filter cannot be null", null);
}
- if (expr != null)
+ CharArrayReader car = new CharArrayReader(expr.toCharArray());
+ LdapLexer lexer = new LdapLexer(car);
+ Parser parser = new Parser(lexer);
+ try
{
- CharArrayReader car = new CharArrayReader(expr.toCharArray());
- LdapLexer lexer = new LdapLexer(car);
- Parser parser = new Parser(lexer);
- try
- {
- if (!parser.start())
- {
- throw new InvalidSyntaxException(
- "Failed to parse LDAP query.", expr);
- }
- }
- catch (ParseException ex)
+ if (!parser.start())
{
throw new InvalidSyntaxException(
- ex.getMessage(), expr);
+ "Failed to parse LDAP query.", expr);
}
- catch (IOException ex)
- {
- throw new InvalidSyntaxException(
- ex.getMessage(), expr);
- }
- m_evaluator = new Evaluator(parser.getProgram());
- m_mapper = new SimpleMapper();
}
+ catch (ParseException ex)
+ {
+ throw new InvalidSyntaxException(
+ ex.getMessage(), expr);
+ }
+ catch (IOException ex)
+ {
+ throw new InvalidSyntaxException(
+ ex.getMessage(), expr);
+ }
+ m_program = parser.getProgram();
}
/**
@@ -114,6 +111,71 @@
return toString().hashCode();
}
+ private boolean match(Dictionary dict, ServiceReference ref, boolean caseSensitive)
+ throws IllegalArgumentException
+ {
+ SoftReference tupleRef = (SoftReference) m_cache.get();
+ Evaluator evaluator = null;
+ SimpleMapper mapper = null;
+ Object[] tuple = null;
+
+ if (tupleRef != null)
+ {
+ tuple = (Object[]) tupleRef.get();
+ }
+
+ if (tuple == null)
+ {
+ evaluator = new Evaluator(m_program);
+ mapper = new SimpleMapper();
+ }
+ else
+ {
+ evaluator = (Evaluator) tuple[0];
+ mapper = (SimpleMapper) tuple[1];
+ }
+
+ try
+ {
+ if (dict != null)
+ {
+ mapper.setSource(dict, caseSensitive);
+ }
+ else
+ {
+ mapper.setSource(ref);
+ }
+
+ return evaluator.evaluate(mapper);
+ }
+ catch (AttributeNotFoundException ex)
+ {
+ log(Logger.LOG_DEBUG, "FilterImpl: Attribute not found.", ex);
+ }
+ catch (EvaluationException ex)
+ {
+ log(Logger.LOG_ERROR, "FilterImpl: " + toString(), ex);
+ }
+ finally
+ {
+ if (dict != null)
+ {
+ mapper.setSource(null, caseSensitive);
+ }
+ else
+ {
+ mapper.setSource(null);
+ }
+
+ if (tuple == null)
+ {
+ m_cache.set(new SoftReference(new Object[] {evaluator, mapper}));
+ }
+ }
+
+ return false;
+ }
+
/**
* Filter using a <tt>Dictionary</tt> object. The <tt>Filter</tt>
* is executed using the <tt>Dictionary</tt> object's keys and values.
@@ -127,25 +189,7 @@
public boolean match(Dictionary dict)
throws IllegalArgumentException
{
- try
- {
- // Since the mapper instance is reused, we should
- // null the source after use to avoid potential
- // garbage collection issues.
- m_mapper.setSource(dict, false);
- boolean result = m_evaluator.evaluate(m_mapper);
- m_mapper.setSource(null, false);
- return result;
- }
- catch (AttributeNotFoundException ex)
- {
- log(Logger.LOG_DEBUG, "FilterImpl: Attribute not found.", ex);
- }
- catch (EvaluationException ex)
- {
- log(Logger.LOG_ERROR, "FilterImpl: " + toString(), ex);
- }
- return false;
+ return match(dict, null, false);
}
/**
@@ -158,48 +202,12 @@
**/
public boolean match(ServiceReference ref)
{
- try
- {
- // Since the mapper instance is reused, we should
- // null the source after use to avoid potential
- // garbage collection issues.
- m_mapper.setSource(ref);
- boolean result = m_evaluator.evaluate(m_mapper);
- m_mapper.setSource(null);
- return result;
- }
- catch (AttributeNotFoundException ex)
- {
- log(Logger.LOG_DEBUG, "FilterImpl: Attribute not found.", ex);
- }
- catch (EvaluationException ex)
- {
- log(Logger.LOG_ERROR, "FilterImpl: " + toString(), ex);
- }
- return false;
+ return match(null, ref, false);
}
public boolean matchCase(Dictionary dict)
{
- try
- {
- // Since the mapper instance is reused, we should
- // null the source after use to avoid potential
- // garbage collection issues.
- m_mapper.setSource(dict, true);
- boolean result = m_evaluator.evaluate(m_mapper);
- m_mapper.setSource(null, true);
- return result;
- }
- catch (AttributeNotFoundException ex)
- {
- log(Logger.LOG_DEBUG, "FilterImpl: Attribute not found.", ex);
- }
- catch (EvaluationException ex)
- {
- log(Logger.LOG_ERROR, "FilterImpl: " + toString(), ex);
- }
- return false;
+ return match(dict, null, true);
}
/**
@@ -210,11 +218,23 @@
{
if (m_toString == null)
{
- m_toString = m_evaluator.toStringInfix();
+ m_toString = new Evaluator(m_program).toStringInfix();
}
return m_toString;
}
+ private void log(int flag, String msg, Throwable th)
+ {
+ if (m_logger == null)
+ {
+ System.out.println(msg + ": " + th);
+ }
+ else
+ {
+ m_logger.log(flag, msg, th);
+ }
+ }
+
static class SimpleMapper implements Mapper
{
private ServiceReference m_ref = null;
@@ -272,16 +292,4 @@
return m_map.get(name);
}
}
-
- private void log(int flag, String msg, Throwable th)
- {
- if (m_logger == null)
- {
- System.out.println(msg + ": " + th);
- }
- else
- {
- m_logger.log(flag, msg, th);
- }
- }
}
\ No newline at end of file