Implement include/exclude directives for activation policy. (FELIX-749)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@784258 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index 5a68525..09c00ff 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -1518,7 +1518,7 @@
// been triggered, then activate the bundle immediately.
if (!bundle.isDeclaredActivationPolicyUsed()
|| (bundle.getCurrentModule().getDeclaredActivationPolicy() != IModule.LAZY_ACTIVATION)
- || ((ModuleImpl) bundle.getCurrentModule()).isActivationTrigger())
+ || ((ModuleImpl) bundle.getCurrentModule()).isActivationTriggered())
{
// Record the event type for the final event and activate.
eventType = BundleEvent.STARTED;
diff --git a/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java b/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
index 316fbab..c5900d7 100644
--- a/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
@@ -78,6 +78,9 @@
private final IRequirement[] m_dynamicRequirements;
private final R4Library[] m_nativeLibraries;
private final int m_declaredActivationPolicy;
+ private final String[] m_activationIncludes;
+ private final String[] m_activationExcludes;
+
private final Bundle m_bundle;
private IModule[] m_fragments = null;
@@ -140,6 +143,8 @@
m_dynamicRequirements = null;
m_nativeLibraries = null;
m_declaredActivationPolicy = EAGER_ACTIVATION;
+ m_activationExcludes = null;
+ m_activationIncludes = null;
}
public ModuleImpl(
@@ -172,6 +177,12 @@
m_dynamicRequirements = mp.getDynamicRequirements();
m_nativeLibraries = mp.getLibraries();
m_declaredActivationPolicy = mp.getActivationPolicy();
+ m_activationExcludes = (mp.getActivationExcludeDirective() == null)
+ ? null
+ : ManifestParser.parseDelimitedString(mp.getActivationExcludeDirective(), ",");
+ m_activationIncludes = (mp.getActivationIncludeDirective() == null)
+ ? null
+ : ManifestParser.parseDelimitedString(mp.getActivationIncludeDirective(), ",");
m_symbolicName = mp.getSymbolicName();
m_isExtension = mp.isExtension();
@@ -311,6 +322,40 @@
return m_declaredActivationPolicy;
}
+ synchronized boolean isActivationTriggered()
+ {
+ return m_isActivationTriggered;
+ }
+
+ boolean isActivationTrigger(String pkgName)
+ {
+ if ((m_activationIncludes == null) && (m_activationExcludes == null))
+ {
+ return true;
+ }
+
+ // If there are no include filters then all classes are included
+ // by default, otherwise try to find one match.
+ boolean included = (m_activationIncludes == null);
+ for (int i = 0;
+ (!included) && (m_activationIncludes != null) && (i < m_activationIncludes.length);
+ i++)
+ {
+ included = m_activationIncludes[i].equals(pkgName);
+ }
+
+ // If there are no exclude filters then no classes are excluded
+ // by default, otherwise try to find one match.
+ boolean excluded = false;
+ for (int i = 0;
+ (!excluded) && (m_activationExcludes != null) && (i < m_activationExcludes.length);
+ i++)
+ {
+ excluded = m_activationExcludes[i].equals(pkgName);
+ }
+ return included && !excluded;
+ }
+
//
// Run-time data access.
//
@@ -1178,11 +1223,6 @@
return m_id;
}
- synchronized boolean isActivationTrigger()
- {
- return m_isActivationTriggered;
- }
-
private synchronized ModuleClassLoader getClassLoader()
{
if (m_classLoader == null)
@@ -1543,6 +1583,9 @@
if (bytes != null)
{
+ // Get package name.
+ String pkgName = Util.getClassPackage(name);
+
// Before we actually attempt to define the class, grab
// the lock for this class loader and make sure than no
// other thread has defined this class in the meantime.
@@ -1559,8 +1602,13 @@
// If the module is using deferred activation, then if
// we load this class from this module we need to activate
- // the module before returning the class.
+ // the module before returning the class. We will short
+ // circuit the trigger matching if the trigger is already
+ // tripped.
+ boolean isTriggerClass = m_isActivationTriggered
+ ? false : isActivationTrigger(pkgName);
if (!m_isActivationTriggered
+ && isTriggerClass
&& (activationPolicy == IModule.LAZY_ACTIVATION)
&& (getBundle().getState() == Bundle.STARTING))
{
@@ -1573,9 +1621,8 @@
deferredList.add(new Object[] { name, getBundle() });
}
// We need to try to define a Package object for the class
- // before we call defineClass(). Get the package name and
- // see if we have already created the package.
- String pkgName = Util.getClassPackage(name);
+ // before we call defineClass() if we haven't already
+ // created it.
if (pkgName.length() > 0)
{
if (getPackage(pkgName) == null)
@@ -1630,9 +1677,9 @@
}
}
- // At this point if we have a class, then the deferred
+ // At this point if we have a trigger class, then the deferred
// activation trigger has tripped.
- if (!m_isActivationTriggered && (clazz != null))
+ if (!m_isActivationTriggered && isTriggerClass && (clazz != null))
{
m_isActivationTriggered = true;
}
diff --git a/framework/src/main/java/org/apache/felix/framework/util/Util.java b/framework/src/main/java/org/apache/felix/framework/util/Util.java
index 685ddba..1c37219 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/Util.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/Util.java
@@ -527,4 +527,142 @@
Map headerMap = module.getHeaders();
return headerMap.containsKey(Constants.FRAGMENT_HOST);
}
+
+
+ //
+ // The following substring-related code was lifted and modified
+ // from the LDAP parser code.
+ //
+
+ public static String[] parseSubstring(String target)
+ {
+ List pieces = new ArrayList();
+ StringBuffer ss = new StringBuffer();
+ // int kind = SIMPLE; // assume until proven otherwise
+ boolean wasStar = false; // indicates last piece was a star
+ boolean leftstar = false; // track if the initial piece is a star
+ boolean rightstar = false; // track if the final piece is a star
+
+ int idx = 0;
+
+ // We assume (sub)strings can contain leading and trailing blanks
+loop: for (;;)
+ {
+ if (idx >= target.length())
+ {
+ if (wasStar)
+ {
+ // insert last piece as "" to handle trailing star
+ rightstar = true;
+ }
+ else
+ {
+ pieces.add(ss.toString());
+ // accumulate the last piece
+ // note that in the case of
+ // (cn=); this might be
+ // the string "" (!=null)
+ }
+ ss.setLength(0);
+ break loop;
+ }
+
+ char c = target.charAt(idx++);
+ if (c == '*')
+ {
+ if (wasStar)
+ {
+ // encountered two successive stars;
+ // I assume this is illegal
+ throw new IllegalArgumentException("Invalid filter string: " + target);
+ }
+ if (ss.length() > 0)
+ {
+ pieces.add(ss.toString()); // accumulate the pieces
+ // between '*' occurrences
+ }
+ ss.setLength(0);
+ // if this is a leading star, then track it
+ if (pieces.size() == 0)
+ {
+ leftstar = true;
+ }
+ ss.setLength(0);
+ wasStar = true;
+ }
+ else
+ {
+ wasStar = false;
+ ss.append(c);
+ }
+ }
+ if (leftstar || rightstar || pieces.size() > 1)
+ {
+ // insert leading and/or trailing "" to anchor ends
+ if (rightstar)
+ {
+ pieces.add("");
+ }
+ if (leftstar)
+ {
+ pieces.add(0, "");
+ }
+ }
+ return (String[]) pieces.toArray(new String[pieces.size()]);
+ }
+
+ public static boolean checkSubstring(String[] pieces, String s)
+ {
+ // Walk the pieces to match the string
+ // There are implicit stars between each piece,
+ // and the first and last pieces might be "" to anchor the match.
+ // assert (pieces.length > 1)
+ // minimal case is <string>*<string>
+
+ boolean result = false;
+ int len = pieces.length;
+
+loop: for (int i = 0; i < len; i++)
+ {
+ String piece = pieces[i];
+ int index = 0;
+ if (i == len - 1)
+ {
+ // this is the last piece
+ if (s.endsWith(piece))
+ {
+ result = true;
+ }
+ else
+ {
+ result = false;
+ }
+ break loop;
+ }
+ // initial non-star; assert index == 0
+ else if (i == 0)
+ {
+ if (!s.startsWith(piece))
+ {
+ result = false;
+ break loop;
+ }
+ }
+ // assert i > 0 && i < len-1
+ else
+ {
+ // Sure wish stringbuffer supported e.g. indexOf
+ index = s.indexOf(piece, index);
+ if (index < 0)
+ {
+ result = false;
+ break loop;
+ }
+ }
+ // start beyond the matching piece
+ index += piece.length();
+ }
+
+ return result;
+ }
}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Capability.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Capability.java
index 765da51..91451b0 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Capability.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Capability.java
@@ -69,7 +69,7 @@
m_includeFilter = new String[ss.length][];
for (int filterIdx = 0; filterIdx < ss.length; filterIdx++)
{
- m_includeFilter[filterIdx] = parseSubstring(ss[filterIdx]);
+ m_includeFilter[filterIdx] = Util.parseSubstring(ss[filterIdx]);
}
}
else if (m_directives[dirIdx].getName().equals(Constants.EXCLUDE_DIRECTIVE))
@@ -78,7 +78,7 @@
m_excludeFilter = new String[ss.length][];
for (int filterIdx = 0; filterIdx < ss.length; filterIdx++)
{
- m_excludeFilter[filterIdx] = parseSubstring(ss[filterIdx]);
+ m_excludeFilter[filterIdx] = Util.parseSubstring(ss[filterIdx]);
}
}
}
@@ -177,7 +177,7 @@
(!included) && (m_includeFilter != null) && (i < m_includeFilter.length);
i++)
{
- included = checkSubstring(m_includeFilter[i], className);
+ included = Util.checkSubstring(m_includeFilter[i], className);
}
// If there are no exclude filters then no classes are excluded
@@ -187,7 +187,7 @@
(!excluded) && (m_excludeFilter != null) && (i < m_excludeFilter.length);
i++)
{
- excluded = checkSubstring(m_excludeFilter[i], className);
+ excluded = Util.checkSubstring(m_excludeFilter[i], className);
}
return included && !excluded;
}
@@ -335,141 +335,4 @@
}
return sb.toString();
}
-
- //
- // The following substring-related code was lifted and modified
- // from the LDAP parser code.
- //
-
- private static String[] parseSubstring(String target)
- {
- List pieces = new ArrayList();
- StringBuffer ss = new StringBuffer();
- // int kind = SIMPLE; // assume until proven otherwise
- boolean wasStar = false; // indicates last piece was a star
- boolean leftstar = false; // track if the initial piece is a star
- boolean rightstar = false; // track if the final piece is a star
-
- int idx = 0;
-
- // We assume (sub)strings can contain leading and trailing blanks
-loop: for (;;)
- {
- if (idx >= target.length())
- {
- if (wasStar)
- {
- // insert last piece as "" to handle trailing star
- rightstar = true;
- }
- else
- {
- pieces.add(ss.toString());
- // accumulate the last piece
- // note that in the case of
- // (cn=); this might be
- // the string "" (!=null)
- }
- ss.setLength(0);
- break loop;
- }
-
- char c = target.charAt(idx++);
- if (c == '*')
- {
- if (wasStar)
- {
- // encountered two successive stars;
- // I assume this is illegal
- throw new IllegalArgumentException("Invalid filter string: " + target);
- }
- if (ss.length() > 0)
- {
- pieces.add(ss.toString()); // accumulate the pieces
- // between '*' occurrences
- }
- ss.setLength(0);
- // if this is a leading star, then track it
- if (pieces.size() == 0)
- {
- leftstar = true;
- }
- ss.setLength(0);
- wasStar = true;
- }
- else
- {
- wasStar = false;
- ss.append(c);
- }
- }
- if (leftstar || rightstar || pieces.size() > 1)
- {
- // insert leading and/or trailing "" to anchor ends
- if (rightstar)
- {
- pieces.add("");
- }
- if (leftstar)
- {
- pieces.add(0, "");
- }
- }
- return (String[]) pieces.toArray(new String[pieces.size()]);
- }
-
- private static boolean checkSubstring(String[] pieces, String s)
- {
- // Walk the pieces to match the string
- // There are implicit stars between each piece,
- // and the first and last pieces might be "" to anchor the match.
- // assert (pieces.length > 1)
- // minimal case is <string>*<string>
-
- boolean result = false;
- int len = pieces.length;
-
-loop: for (int i = 0; i < len; i++)
- {
- String piece = pieces[i];
- int index = 0;
- if (i == len - 1)
- {
- // this is the last piece
- if (s.endsWith(piece))
- {
- result = true;
- }
- else
- {
- result = false;
- }
- break loop;
- }
- // initial non-star; assert index == 0
- else if (i == 0)
- {
- if (!s.startsWith(piece))
- {
- result = false;
- break loop;
- }
- }
- // assert i > 0 && i < len-1
- else
- {
- // Sure wish stringbuffer supported e.g. indexOf
- index = s.indexOf(piece, index);
- if (index < 0)
- {
- result = false;
- break loop;
- }
- }
- // start beyond the matching piece
- index += piece.length();
- }
-
- return result;
- }
}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
index e5e8eb2..cce6f45 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
@@ -34,6 +34,8 @@
private final Map m_configMap;
private final Map m_headerMap;
private volatile int m_activationPolicy = IModule.EAGER_ACTIVATION;
+ private volatile String m_activationIncludeDir;
+ private volatile String m_activationExcludeDir;
private volatile boolean m_isExtension = false;
private volatile String m_bundleSymbolicName;
private volatile Version m_bundleVersion;
@@ -255,7 +257,9 @@
// Parse activation policy.
//
- m_activationPolicy = parseActivationPolicy(headerMap);
+ // This sets m_activationPolicy, m_includedPolicyClasses, and
+ // m_excludedPolicyClasses.
+ parseActivationPolicy(headerMap);
// Do final checks and normalization of manifest.
if (getManifestVersion().equals("2"))
@@ -311,6 +315,16 @@
return m_activationPolicy;
}
+ public String getActivationIncludeDirective()
+ {
+ return m_activationIncludeDir;
+ }
+
+ public String getActivationExcludeDirective()
+ {
+ return m_activationExcludeDir;
+ }
+
public boolean isExtension()
{
return m_isExtension;
@@ -1188,9 +1202,9 @@
return result;
}
- private static int parseActivationPolicy(Map headerMap)
+ private void parseActivationPolicy(Map headerMap)
{
- int policy = IModule.EAGER_ACTIVATION;
+ m_activationPolicy = IModule.EAGER_ACTIVATION;
Object[][][] clauses = parseStandardHeader(
(String) headerMap.get(Constants.BUNDLE_ACTIVATIONPOLICY));
@@ -1205,13 +1219,23 @@
{
if (clauses[0][CLAUSE_PATHS_INDEX][i].equals(Constants.ACTIVATION_LAZY))
{
- policy = IModule.LAZY_ACTIVATION;
+ m_activationPolicy = IModule.LAZY_ACTIVATION;
+ for (int j = 0; j < clauses[0][CLAUSE_DIRECTIVES_INDEX].length; j++)
+ {
+ R4Directive dir = (R4Directive) clauses[0][CLAUSE_DIRECTIVES_INDEX][j];
+ if (dir.getName().equalsIgnoreCase(Constants.INCLUDE_DIRECTIVE))
+ {
+ m_activationIncludeDir = dir.getValue();
+ }
+ else if (dir.getName().equalsIgnoreCase(Constants.EXCLUDE_DIRECTIVE))
+ {
+ m_activationExcludeDir = dir.getValue();
+ }
+ }
break;
}
}
}
-
- return policy;
}
public static final int CLAUSE_PATHS_INDEX = 0;