We were not correctly checking attributes when resolving dynamic imports.
We were creating our requirement using a filter instead of directives and
attributes and a requirement constructed in this fashion does not check
anything other than what is in the filter. Changed dynamic import resolution
to use the directive/attribute constructor of Requirement instead. (FELIX-676)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@684886 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 a9bdd5d..b446e48 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -2956,7 +2956,6 @@
new Requirement(
ICapability.PACKAGE_NAMESPACE,
null,
- null,
new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, pkgName, false) }));
if (exporters != null)
@@ -2965,7 +2964,6 @@
Requirement req = new Requirement(ICapability.PACKAGE_NAMESPACE,
null,
- null,
new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, pkgName, false) });
for (int pkgIdx = 0; pkgIdx < exporters.length; pkgIdx++)
@@ -3088,7 +3086,6 @@
new Requirement(
ICapability.PACKAGE_NAMESPACE,
null,
- null,
new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, ((Capability) caps[capIdx]).getPackageName(), false) }));
// Search through the current providers to find the target
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
index b4f7892..9fddfa1 100755
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
@@ -38,6 +38,7 @@
import org.apache.felix.framework.util.Util;
import org.apache.felix.framework.util.manifestparser.Capability;
import org.apache.felix.framework.util.manifestparser.ManifestParser;
+import org.apache.felix.framework.util.manifestparser.R4Attribute;
import org.apache.felix.framework.util.manifestparser.R4Directive;
import org.apache.felix.framework.util.manifestparser.R4Library;
import org.apache.felix.framework.util.manifestparser.Requirement;
@@ -616,6 +617,46 @@
return null;
}
+ private IRequirement createDynamicRequirementTarget(
+ IRequirement dynReq, String pkgName)
+ {
+ IRequirement req = null;
+
+ // First check to see if the dynamic requirement matches the
+ // package name; this means we have to do wildcard matching.
+ String dynPkgName = ((Requirement) dynReq).getPackageName();
+ boolean wildcard = (dynPkgName.lastIndexOf(".*") >= 0);
+ dynPkgName = (wildcard)
+ ? dynPkgName.substring(0, dynPkgName.length() - 2) : dynPkgName;
+ // If the dynamic requirement matches the package name, then
+ // create a new requirement for the specific package.
+ if (dynPkgName.equals("*") ||
+ pkgName.equals(dynPkgName) ||
+ (wildcard && pkgName.startsWith(dynPkgName + ".")))
+ {
+ // Create a new requirement based on the dynamic requirement,
+ // but substitute the precise package name for which we are
+ // looking, because it is not possible to use the potentially
+ // wildcarded version in the dynamic requirement.
+ R4Directive[] dirs = ((Requirement) dynReq).getDirectives();
+ R4Attribute[] attrs = ((Requirement) dynReq).getAttributes();
+ R4Attribute[] newAttrs = new R4Attribute[attrs.length];
+ System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
+ for (int attrIdx = 0; attrIdx < newAttrs.length; attrIdx++)
+ {
+ if (newAttrs[attrIdx].getName().equals(ICapability.PACKAGE_PROPERTY))
+ {
+ newAttrs[attrIdx] = new R4Attribute(
+ ICapability.PACKAGE_PROPERTY, pkgName, false);
+ break;
+ }
+ }
+ req = new Requirement(ICapability.PACKAGE_NAMESPACE, dirs, newAttrs);
+ }
+
+ return req;
+ }
+
private IWire attemptDynamicImport(IModule importer, String pkgName)
{
R4Wire wire = null;
@@ -634,36 +675,12 @@
// there is a matching one for the package from which we want to
// load a class.
IRequirement[] dynamics = importer.getDefinition().getDynamicRequirements();
- for (int i = 0; (dynamics != null) && (i < dynamics.length); i++)
+ for (int dynIdx = 0; (dynamics != null) && (dynIdx < dynamics.length); dynIdx++)
{
- // Ignore any dynamic requirements whose packages don't match.
- String dynPkgName = ((Requirement) dynamics[i]).getPackageName();
- boolean wildcard = (dynPkgName.lastIndexOf(".*") >= 0);
- dynPkgName = (wildcard)
- ? dynPkgName.substring(0, dynPkgName.length() - 2) : dynPkgName;
- if (dynPkgName.equals("*") ||
- pkgName.equals(dynPkgName) ||
- (wildcard && pkgName.startsWith(dynPkgName + ".")))
+ IRequirement target =
+ createDynamicRequirementTarget(dynamics[dynIdx], pkgName);
+ if (target != null)
{
- // Constrain the current dynamic requirement to include
- // the precise package name for which we are searching; this
- // is necessary because we cannot easily determine which
- // package name a given dynamic requirement matches, since
- // it is only a filter.
-
- IRequirement req = null;
- try
- {
- req = new Requirement(
- ICapability.PACKAGE_NAMESPACE,
- "(&" + dynamics[i].getFilter().toString()
- + "(package=" + pkgName + "))");
- }
- catch (InvalidSyntaxException ex)
- {
- // This should never happen.
- }
-
// See if there is a candidate exporter that satisfies the
// constrained dynamic requirement.
try
@@ -673,8 +690,8 @@
{
// Get "in use" and "available" candidates and put
// the "in use" candidates first.
- PackageSource[] inuse = getInUseCandidates(req);
- PackageSource[] available = getUnusedCandidates(req);
+ PackageSource[] inuse = getInUseCandidates(target);
+ PackageSource[] available = getUnusedCandidates(target);
PackageSource[] candidates = new PackageSource[inuse.length + available.length];
System.arraycopy(inuse, 0, candidates, 0, inuse.length);
System.arraycopy(available, 0, candidates, inuse.length, available.length);
@@ -714,7 +731,7 @@
// Create the wire and add it to the module.
wire = new R4Wire(
- importer, dynamics[i], candidate.m_module, candidate.m_capability);
+ importer, dynamics[dynIdx], candidate.m_module, candidate.m_capability);
newWires[newWires.length - 1] = wire;
((ModuleImpl) importer).setWires(newWires);
m_logger.log(Logger.LOG_DEBUG, "WIRE: " + newWires[newWires.length - 1]);
@@ -1492,7 +1509,7 @@
* modules to resolve its dependencies violate any singleton constraints.
* Actually, it just creates a map of resolved singleton modules and then
* delegates all checking to another recursive method.
- *
+ *
* @param targetModule the module that is the root of the tree of modules to check.
* @param moduleMap a map to cache the package space of each module.
* @param candidatesMap a map containing the all candidates to resolve all
@@ -1523,7 +1540,7 @@
* dependency modules to verify that they do not violate a singleton constraint.
* If the target module is a singleton, then it checks that againts existing
* singletons. Then it checks all current unresolved candidates recursively.
- *
+ *
* @param targetModule the module that is the root of the tree of modules to check.
* @param singletonMap the current map of singleton symbolic names.
* @param moduleMap a map to cache the package space of each module.
@@ -3507,67 +3524,69 @@
}
*/
// Next, check to see if the package is dynamically imported by the module.
-// TODO: RB - Fix dynamic import diagnostic.
-// IRequirement imp = createDynamicImportTarget(module, pkgName);
- IRequirement imp = null;
- if (imp != null)
+ IRequirement[] dynamics = module.getDefinition().getDynamicRequirements();
+ for (int dynIdx = 0; dynIdx < dynamics.length; dynIdx++)
{
- // Try to see if there is an exporter available.
- PackageSource[] exporters = getInUseCandidates(imp);
- exporters = (exporters.length == 0)
- ? getUnusedCandidates(imp) : exporters;
-
- // An exporter might be available, but it may have attributes
- // that do not match the importer's required attributes, so
- // check that case by simply looking for an exporter of the
- // desired package without any attributes.
- if (exporters.length == 0)
+ IRequirement target = createDynamicRequirementTarget(dynamics[dynIdx], pkgName);
+ if (target != null)
{
- try
- {
- IRequirement pkgReq = new Requirement(
- ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")");
- exporters = getInUseCandidates(pkgReq);
- exporters = (exporters.length == 0)
- ? getUnusedCandidates(pkgReq) : exporters;
- }
- catch (InvalidSyntaxException ex)
- {
- // This should never happen.
- }
- }
+ // Try to see if there is an exporter available.
+ PackageSource[] exporters = getInUseCandidates(target);
+ exporters = (exporters.length == 0)
+ ? getUnusedCandidates(target) : exporters;
- long expId = (exporters.length == 0)
- ? -1 : Util.getBundleIdFromModuleId(exporters[0].m_module.getId());
-
- StringBuffer sb = new StringBuffer("*** Class '");
- sb.append(name);
- sb.append("' was not found, but this is likely normal since package '");
- sb.append(pkgName);
- sb.append("' is dynamically imported by bundle ");
- sb.append(impId);
- sb.append(".");
- if (exporters.length > 0)
- {
- try
+ // An exporter might be available, but it may have attributes
+ // that do not match the importer's required attributes, so
+ // check that case by simply looking for an exporter of the
+ // desired package without any attributes.
+ if (exporters.length == 0)
{
- if (!imp.isSatisfied(
- Util.getSatisfyingCapability(exporters[0].m_module,
- new Requirement(ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")"))))
+ try
{
- sb.append(" However, bundle ");
- sb.append(expId);
- sb.append(" does export this package with attributes that do not match.");
+ IRequirement pkgReq = new Requirement(
+ ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")");
+ exporters = getInUseCandidates(pkgReq);
+ exporters = (exporters.length == 0)
+ ? getUnusedCandidates(pkgReq) : exporters;
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ // This should never happen.
}
}
- catch (InvalidSyntaxException ex)
- {
- // This should never happen.
- }
- }
- sb.append(" ***");
- return sb.toString();
+ long expId = (exporters.length == 0)
+ ? -1 : Util.getBundleIdFromModuleId(exporters[0].m_module.getId());
+
+ StringBuffer sb = new StringBuffer("*** Class '");
+ sb.append(name);
+ sb.append("' was not found, but this is likely normal since package '");
+ sb.append(pkgName);
+ sb.append("' is dynamically imported by bundle ");
+ sb.append(impId);
+ sb.append(".");
+ if (exporters.length > 0)
+ {
+ try
+ {
+ if (!target.isSatisfied(
+ Util.getSatisfyingCapability(exporters[0].m_module,
+ new Requirement(ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")"))))
+ {
+ sb.append(" However, bundle ");
+ sb.append(expId);
+ sb.append(" does export this package with attributes that do not match.");
+ }
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ // This should never happen.
+ }
+ }
+ sb.append(" ***");
+
+ return sb.toString();
+ }
}
IRequirement pkgReq = null;
try
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 6b3d5a2..cceeae4 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
@@ -594,7 +594,6 @@
// and add version if missing.
m_requirements[reqIdx] = new Requirement(
ICapability.PACKAGE_NAMESPACE,
- (String) pkgName.getValue(),
null,
new R4Attribute[] { pkgName, pkgVersion });
}
@@ -636,10 +635,7 @@
map.put(
m_capabilities[i].getProperties().get(ICapability.PACKAGE_PROPERTY),
- new Requirement(
- ICapability.PACKAGE_NAMESPACE,
- (String) m_capabilities[i].getProperties().get(ICapability.PACKAGE_PROPERTY),
- null, attrs));
+ new Requirement(ICapability.PACKAGE_NAMESPACE, null, attrs));
}
}
m_requirements =
@@ -978,7 +974,6 @@
reqList.add(
new Requirement(
ICapability.PACKAGE_NAMESPACE,
- null,
(R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
newAttrs));
}
@@ -1033,7 +1028,6 @@
reqList.add(
new Requirement(
ICapability.MODULE_NAMESPACE,
- null,
(R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
newAttrs));
}
diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Requirement.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Requirement.java
index 7215118..14cdf2f 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Requirement.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/Requirement.java
@@ -42,7 +42,7 @@
m_filter = new FilterImpl(filterStr);
}
- public Requirement(String namespace, String pkgName, R4Directive[] directives, R4Attribute[] attributes)
+ public Requirement(String namespace, R4Directive[] directives, R4Attribute[] attributes)
{
m_namespace = namespace;
m_directives = directives;