Modified manifest parser to use requirements and capabilities
(FELIX-28).
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@498550 13f79535-47bb-0310-9956-ffa450edef68
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 6edbccb..d00c8a7 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
@@ -19,20 +19,110 @@
package org.apache.felix.framework.util.manifestparser;
import java.util.*;
+
+import org.apache.felix.framework.util.Util;
import org.apache.felix.moduleloader.ICapability;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
public class Capability implements ICapability
{
private String m_namespace = null;
- private R4Directive[] m_dirs = null;
- private R4Attribute[] m_attrs = null;
+ private R4Directive[] m_directives = null;
+ private R4Attribute[] m_attributes = null;
private Map m_attrMap = null;
+ private String[] m_uses = new String[0];
+ private String[][] m_includeFilter = null;
+ private String[][] m_excludeFilter = null;
+
+ // Cached properties for performance reasons.
+ private String m_pkgName = null;
+ private Version m_pkgVersion = Version.emptyVersion;
public Capability(String namespace, R4Directive[] dirs, R4Attribute[] attrs)
{
m_namespace = namespace;
- m_dirs = dirs;
- m_attrs = attrs;
+ m_directives = dirs;
+ m_attributes = attrs;
+
+ // Find all export directives: uses, mandatory, include, and exclude.
+ String mandatory = "";
+ for (int dirIdx = 0; (m_directives != null) && (dirIdx < m_directives.length); dirIdx++)
+ {
+ if (m_directives[dirIdx].getName().equals(Constants.USES_DIRECTIVE))
+ {
+ // Parse these uses directive.
+ StringTokenizer tok = new StringTokenizer(m_directives[dirIdx].getValue(), ",");
+ m_uses = new String[tok.countTokens()];
+ for (int i = 0; i < m_uses.length; i++)
+ {
+ m_uses[i] = tok.nextToken().trim();
+ }
+ }
+ else if (m_directives[dirIdx].getName().equals(Constants.MANDATORY_DIRECTIVE))
+ {
+ mandatory = m_directives[dirIdx].getValue();
+ }
+ else if (m_directives[dirIdx].getName().equals(Constants.INCLUDE_DIRECTIVE))
+ {
+ String[] ss = ManifestParser.parseDelimitedString(m_directives[dirIdx].getValue(), ",");
+ m_includeFilter = new String[ss.length][];
+ for (int filterIdx = 0; filterIdx < ss.length; filterIdx++)
+ {
+ m_includeFilter[filterIdx] = parseSubstring(ss[filterIdx]);
+ }
+ }
+ else if (m_directives[dirIdx].getName().equals(Constants.EXCLUDE_DIRECTIVE))
+ {
+ String[] ss = ManifestParser.parseDelimitedString(m_directives[dirIdx].getValue(), ",");
+ m_excludeFilter = new String[ss.length][];
+ for (int filterIdx = 0; filterIdx < ss.length; filterIdx++)
+ {
+ m_excludeFilter[filterIdx] = parseSubstring(ss[filterIdx]);
+ }
+ }
+ }
+
+ // Parse mandatory directive and mark specified
+ // attributes as mandatory.
+ StringTokenizer tok = new StringTokenizer(mandatory, ", ");
+ while (tok.hasMoreTokens())
+ {
+ // Get attribute name.
+ String attrName = tok.nextToken().trim();
+ // Find attribute and mark it as mandatory.
+ boolean found = false;
+ for (int i = 0; (!found) && (i < m_attributes.length); i++)
+ {
+ if (m_attributes[i].getName().equals(attrName))
+ {
+ m_attributes[i] = new R4Attribute(
+ m_attributes[i].getName(),
+ m_attributes[i].getValue(), true);
+ found = true;
+ }
+ }
+ // If a specified mandatory attribute was not found,
+ // then error.
+ if (!found)
+ {
+ throw new IllegalArgumentException(
+ "Mandatory attribute '" + attrName + "' does not exist.");
+ }
+ }
+
+ // For performance reasons, find the package name and version properties.
+ for (int i = 0; i < m_attributes.length; i++)
+ {
+ if (m_attributes[i].getName().equals(ICapability.PACKAGE_PROPERTY))
+ {
+ m_pkgName = (String) m_attributes[i].getValue();
+ }
+ else if (m_attributes[i].getName().equals(ICapability.VERSION_PROPERTY))
+ {
+ m_pkgVersion = (Version) m_attributes[i].getValue();
+ }
+ }
}
public String getNamespace()
@@ -40,11 +130,66 @@
return m_namespace;
}
- public R4Directive[] getDirectives()
+// TODO: RB - Determine how to eliminate these non-generic methods;
+// at least make sure they are not used in the generic resolver.
+ public String getPackageName()
{
- return m_dirs;
+ return m_pkgName;
}
+ public Version getPackageVersion()
+ {
+ return m_pkgVersion;
+ }
+
+ public R4Directive[] getDirectives()
+ {
+ return m_directives;
+ }
+
+ public R4Attribute[] getAttributes()
+ {
+ return m_attributes;
+ }
+
+ public String[] getUses()
+ {
+ return m_uses;
+ }
+
+ public boolean isIncluded(String name)
+ {
+ if ((m_includeFilter == null) && (m_excludeFilter == null))
+ {
+ return true;
+ }
+
+ // Get the class name portion of the target class.
+ String className = Util.getClassName(name);
+
+ // If there are no include filters then all classes are included
+ // by default, otherwise try to find one match.
+ boolean included = (m_includeFilter == null);
+ for (int i = 0;
+ (!included) && (m_includeFilter != null) && (i < m_includeFilter.length);
+ i++)
+ {
+ included = checkSubstring(m_includeFilter[i], className);
+ }
+
+ // 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_excludeFilter != null) && (i < m_excludeFilter.length);
+ i++)
+ {
+ excluded = checkSubstring(m_excludeFilter[i], className);
+ }
+ return included && !excluded;
+ }
+
+// TODO: RB - Terminology mismatch property vs. attribute.
public Map getProperties()
{
if (m_attrMap == null)
@@ -53,11 +198,15 @@
public int size()
{
- return m_attrs.length;
+ // A name and version attribute is always present, since it has a
+ // default value.
+ return m_attributes.length + 2;
}
public boolean isEmpty()
{
+ // A version attribute is always present, since it has a
+ // default value.
return false;
}
@@ -68,25 +217,49 @@
public boolean containsValue(Object value)
{
- for (int i = 0; i < m_attrs.length; i++)
+ // Check the package name.
+ if (m_pkgName.equals(value))
{
- if (m_attrs[i].getValue().equals(value))
+ return true;
+ }
+
+ // Check the package version.
+ if (m_pkgVersion.equals(value))
+ {
+ return true;
+ }
+
+ // Check all attributes.
+ for (int i = 0; i < m_attributes.length; i++)
+ {
+ if (m_attributes[i].getValue().equals(value))
{
return true;
}
}
+
return false;
}
public Object get(Object key)
{
- for (int i = 0; i < m_attrs.length; i++)
+ if (ICapability.PACKAGE_PROPERTY.equals(key))
{
- if (m_attrs[i].getName().equals(key))
+ return m_pkgName;
+ }
+ else if (ICapability.VERSION_PROPERTY.equals(key))
+ {
+ return m_pkgVersion;
+ }
+
+ for (int i = 0; i < m_attributes.length; i++)
+ {
+ if (m_attributes[i].getName().equals(key))
{
- return m_attrs[i].getValue();
+ return m_attributes[i].getValue();
}
}
+
return null;
}
@@ -113,21 +286,23 @@
public Set keySet()
{
Set set = new HashSet();
- for (int i = 0; i < m_attrs.length; i++)
+ set.add(ICapability.PACKAGE_PROPERTY);
+ set.add(ICapability.VERSION_PROPERTY);
+ for (int i = 0; i < m_attributes.length; i++)
{
- set.add(m_attrs[i].getName());
+ set.add(m_attributes[i].getName());
}
return set;
}
public Collection values()
{
- throw new java.lang.UnsupportedOperationException("Map.values() not implemented.");
+ throw new UnsupportedOperationException("Map.values() not implemented.");
}
public Set entrySet()
{
- throw new java.lang.UnsupportedOperationException("Map.entrySet() not implemented.");
+ throw new UnsupportedOperationException("Map.entrySet() not implemented.");
}
};
}
@@ -138,21 +313,160 @@
public String toString()
{
StringBuffer sb = new StringBuffer();
- sb.append(m_namespace);
- for (int i = 0; (m_dirs != null) && (i < m_dirs.length); i++)
+ sb.append(getNamespace());
+ for (int i = 0; (m_directives != null) && (i < m_directives.length); i++)
{
sb.append(";");
- sb.append(m_dirs[i].getName());
- sb.append(":=");
- sb.append(m_dirs[i].getValue());
+ sb.append(m_directives[i].getName());
+ sb.append(":=\"");
+ sb.append(m_directives[i].getValue());
+ sb.append("\"");
}
- for (int i = 0; (m_attrs != null) && (i < m_attrs.length); i++)
+ for (int i = 0; (m_attributes != null) && (i < m_attributes.length); i++)
{
sb.append(";");
- sb.append(m_attrs[i].getName());
- sb.append("=");
- sb.append(m_attrs[i].getValue());
+ sb.append(m_attributes[i].getName());
+ sb.append("=\"");
+ sb.append(m_attributes[i].getValue());
+ sb.append("\"");
}
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 = (String) 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 97de7ca..9ecaeb8 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
@@ -36,10 +36,7 @@
private Version m_bundleVersion = null;
private ICapability[] m_capabilities = null;
private IRequirement[] m_requirements = null;
- private IRequirement[] m_dynamicReqs = null;
- private R4Export[] m_exports = null;
- private R4Import[] m_imports = null;
- private R4Import[] m_dynamics = null;
+ private IRequirement[] m_dynamicRequirements = null;
private R4LibraryClause[] m_libraryHeaders = null;
private boolean m_libraryHeadersOptional = false;
@@ -111,131 +108,133 @@
Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, m_bundleSymbolicName, false);
attrs[1] = new R4Attribute(
Constants.BUNDLE_VERSION_ATTRIBUTE, m_bundleVersion, false);
- capList.add(new Capability(ICapability.MODULE_NAMESPACE, null, attrs));
+// capList.add(new Capability(ICapability.MODULE_NAMESPACE, null, attrs));
}
//
// Parse Export-Package.
//
- // Get export packages from bundle manifest.
- m_exports = (R4Export[]) parseImportExportHeader(
- (String) headerMap.get(Constants.EXPORT_PACKAGE), true);
-
- // Get export packages from bundle manifest.
+ // Get exported packages from bundle manifest.
ICapability[] exportCaps = parseExportHeader(
(String) headerMap.get(Constants.EXPORT_PACKAGE));
-//System.out.println("PARSED EXPORT CAPABILITIES:");
-//for (int capIdx = 0; capIdx < exportCaps.length; capIdx++)
-//{
-// System.out.println(exportCaps[capIdx]);
-//}
-
+/*
+System.out.println("PARSED EXPORT CAPABILITIES:");
+for (int capIdx = 0; capIdx < exportCaps.length; capIdx++)
+{
+ System.out.println(exportCaps[capIdx]);
+}
+*/
// Create non-duplicated export array.
dupeMap.clear();
- for (int pkgIdx = 0; pkgIdx < m_exports.length; pkgIdx++)
+ for (int capIdx = 0; capIdx < exportCaps.length; capIdx++)
{
// Verify that the named package has not already been declared.
- if (dupeMap.get(m_exports[pkgIdx].getName()) == null)
+ String pkgName = (String)
+ exportCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY);
+ if (dupeMap.get(pkgName) == null)
{
// Verify that java.* packages are not exported.
- if (m_exports[pkgIdx].getName().startsWith("java."))
+ if (pkgName.startsWith("java."))
{
throw new BundleException(
- "Exporting java.* packages not allowed: "
- + m_exports[pkgIdx].getName());
+ "Exporting java.* packages not allowed: " + pkgName);
}
- dupeMap.put(m_exports[pkgIdx].getName(), m_exports[pkgIdx]);
+ dupeMap.put(pkgName, exportCaps[capIdx]);
}
else
{
// TODO: FRAMEWORK - Exports can be duplicated, so fix this.
- m_logger.log(Logger.LOG_WARNING, "Duplicate export - "
- + m_exports[pkgIdx].getName());
+ m_logger.log(Logger.LOG_WARNING, "Duplicate export - " + pkgName);
}
}
- // This following line won't be necessary once duplicate exports are supported.
- m_exports = (R4Export[]) dupeMap.values().toArray(new R4Export[dupeMap.size()]);
+
+ // Add export package capabilities to capability list.
+ capList.addAll(dupeMap.values());
+
+ // Create an array of all capabilities.
+ m_capabilities = (ICapability[]) capList.toArray(new ICapability[capList.size()]);
//
// Parse Require-Bundle
//
+
IRequirement[] bundleReq = parseRequireBundleHeader(
(String) headerMap.get(Constants.REQUIRE_BUNDLE));
//System.out.println("PARSED BUNDLE REQUIREMENTS:");
-//for (int reqIdx = 0; reqIdx < bundleReq.length; reqIdx++)
-//{
-// System.out.println(bundleReq[reqIdx]);
-//}
+ for (int reqIdx = 0; reqIdx < bundleReq.length; reqIdx++)
+ {
+// reqList.add(bundleReq[reqIdx]);
+ }
//
// Parse Import-Package.
//
// Get import packages from bundle manifest.
- m_imports = (R4Import[]) parseImportExportHeader(
- (String) headerMap.get(Constants.IMPORT_PACKAGE), false);
-
- // Get import packages from bundle manifest.
IRequirement[] importReqs = parseImportHeader(
(String) headerMap.get(Constants.IMPORT_PACKAGE));
-//System.out.println("PARSED IMPORT REQUIREMENTS:");
-//for (int reqIdx = 0; reqIdx < importReqs.length; reqIdx++)
-//{
-// System.out.println(importReqs[reqIdx]);
-//}
-
+/*
+System.out.println("PARSED IMPORT REQUIREMENTS:");
+for (int reqIdx = 0; reqIdx < importReqs.length; reqIdx++)
+{
+ System.out.println(importReqs[reqIdx]);
+}
+*/
// Create non-duplicated import array.
dupeMap.clear();
- for (int pkgIdx = 0; pkgIdx < m_imports.length; pkgIdx++)
+ for (int reqIdx = 0; reqIdx < importReqs.length; reqIdx++)
{
// Verify that the named package has not already been declared.
- if (dupeMap.get(m_imports[pkgIdx].getName()) == null)
+ String pkgName = ((Requirement) importReqs[reqIdx]).getPackageName();
+
+ if (dupeMap.get(pkgName) == null)
{
// Verify that java.* packages are not imported.
- if (m_imports[pkgIdx].getName().startsWith("java."))
+ if (pkgName.startsWith("java."))
{
throw new BundleException(
- "Importing java.* packages not allowed: "
- + m_imports[pkgIdx].getName());
+ "Importing java.* packages not allowed: " + pkgName);
}
- dupeMap.put(m_imports[pkgIdx].getName(), m_imports[pkgIdx]);
+ dupeMap.put(pkgName, importReqs[reqIdx]);
}
else
{
throw new BundleException(
- "Duplicate import - " + m_imports[pkgIdx].getName());
+ "Duplicate import - " + pkgName);
}
}
+ // Add import package requirements to requirement list.
+ reqList.addAll(dupeMap.values());
+
+ // Create an array of all requirements.
+ m_requirements = (IRequirement[]) reqList.toArray(new IRequirement[reqList.size()]);
+
//
// Parse DynamicImport-Package.
//
// Get dynamic import packages from bundle manifest.
- m_dynamics = (R4Import[]) parseImportExportHeader(
- (String) headerMap.get(Constants.DYNAMICIMPORT_PACKAGE), false);
-
- // Get import packages from bundle manifest.
- IRequirement[] dynReqs = parseImportHeader(
+ m_dynamicRequirements = parseImportHeader(
(String) headerMap.get(Constants.DYNAMICIMPORT_PACKAGE));
-//System.out.println("PARSED DYNAMIC IMPORT REQUIREMENTS:");
-//for (int reqIdx = 0; reqIdx < dynReqs.length; reqIdx++)
-//{
-// System.out.println(dynReqs[reqIdx]);
-//}
-
+/*
+System.out.println("PARSED DYNAMIC IMPORT REQUIREMENTS:");
+for (int reqIdx = 0; reqIdx < m_dynamicRequirements.length; reqIdx++)
+{
+ System.out.println(m_dynamicRequirements[reqIdx]);
+}
+*/
// Dynamic imports can have duplicates, so just check for import
// of java.*.
- List dynList = new ArrayList();
- for (int pkgIdx = 0; pkgIdx < m_dynamics.length; pkgIdx++)
+ for (int reqIdx = 0; reqIdx < m_dynamicRequirements.length; reqIdx++)
{
// Verify that java.* packages are not imported.
- if (m_dynamics[pkgIdx].getName().startsWith("java."))
+ String pkgName = ((Requirement) m_dynamicRequirements[reqIdx]).getPackageName();
+ if (pkgName.startsWith("java."))
{
throw new BundleException(
- "Dynamically importing java.* packages not allowed: "
- + m_dynamics[pkgIdx].getName());
+ "Dynamically importing java.* packages not allowed: " + pkgName);
}
}
@@ -287,19 +286,19 @@
return m_bundleVersion;
}
- public R4Export[] getExports()
+ public ICapability[] getCapabilities()
{
- return m_exports;
+ return m_capabilities;
}
- public R4Import[] getImports()
+ public IRequirement[] getRequirements()
{
- return m_imports;
+ return m_requirements;
}
- public R4Import[] getDynamicImports()
+ public IRequirement[] getDynamicRequirements()
{
- return m_dynamics;
+ return m_dynamicRequirements;
}
public R4LibraryClause[] getLibraryClauses()
@@ -486,52 +485,57 @@
// Check to make sure that R3 bundles have only specified
// the 'specification-version' attribute and no directives
// on their exports; ignore all unknown attributes.
- for (int expIdx = 0;
- (m_exports != null) && (expIdx < m_exports.length);
- expIdx++)
+ for (int capIdx = 0;
+ (m_capabilities != null) && (capIdx < m_capabilities.length);
+ capIdx++)
{
- if (m_exports[expIdx].getDirectives().length != 0)
+ if (m_capabilities[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
{
- throw new BundleException("R3 exports cannot contain directives.");
- }
-
- // Remove and ignore all attributes other than version.
- // NOTE: This is checking for "version" rather than "specification-version"
- // because the package class normalizes to "version" to avoid having
- // future special cases. This could be changed if more strict behavior
- // is required.
- if (m_exports[expIdx].getAttributes() != null)
- {
- R4Attribute versionAttr = null;
- for (int attrIdx = 0;
- attrIdx < m_exports[expIdx].getAttributes().length;
- attrIdx++)
+ // R3 bundles cannot have directives on their exports.
+ if (((Capability) m_capabilities[capIdx]).getDirectives().length != 0)
{
- if (m_exports[expIdx].getAttributes()[attrIdx]
- .getName().equals(Constants.VERSION_ATTRIBUTE))
- {
- versionAttr = m_exports[expIdx].getAttributes()[attrIdx];
- }
- else
- {
- m_logger.log(Logger.LOG_WARNING,
- "Unknown R3 export attribute: "
- + m_exports[expIdx].getAttributes()[attrIdx].getName());
- }
+ throw new BundleException("R3 exports cannot contain directives.");
}
- // Recreate the export if necessary to remove other attributes.
- if ((versionAttr != null) && (m_exports[expIdx].getAttributes().length > 1))
+ // Remove and ignore all attributes other than version.
+ // NOTE: This is checking for "version" rather than "specification-version"
+ // because the package class normalizes to "version" to avoid having
+ // future special cases. This could be changed if more strict behavior
+ // is required.
+ if (((Capability) m_capabilities[capIdx]).getAttributes() != null)
{
- m_exports[expIdx] = new R4Export(
- m_exports[expIdx].getName(),
+ // R3 package capabilities should only have name and
+ // version attributes.
+ R4Attribute pkgName = null;
+ R4Attribute pkgVersion = new R4Attribute(ICapability.VERSION_PROPERTY, Version.emptyVersion, false);
+ for (int attrIdx = 0;
+ attrIdx < ((Capability) m_capabilities[capIdx]).getAttributes().length;
+ attrIdx++)
+ {
+ if (((Capability) m_capabilities[capIdx]).getAttributes()[attrIdx]
+ .getName().equals(ICapability.PACKAGE_PROPERTY))
+ {
+ pkgName = ((Capability) m_capabilities[capIdx]).getAttributes()[attrIdx];
+ }
+ if (((Capability) m_capabilities[capIdx]).getAttributes()[attrIdx]
+ .getName().equals(ICapability.VERSION_PROPERTY))
+ {
+ pkgVersion = ((Capability) m_capabilities[capIdx]).getAttributes()[attrIdx];
+ }
+ else
+ {
+ m_logger.log(Logger.LOG_WARNING,
+ "Unknown R3 export attribute: "
+ + ((Capability) m_capabilities[capIdx]).getAttributes()[attrIdx].getName());
+ }
+ }
+
+ // Recreate the export to remove any other attributes
+ // and add version if missing.
+ m_capabilities[capIdx] = new Capability(
+ ICapability.PACKAGE_NAMESPACE,
null,
- new R4Attribute[] { versionAttr } );
- }
- else if ((versionAttr == null) && (m_exports[expIdx].getAttributes().length > 0))
- {
- m_exports[expIdx] = new R4Export(
- m_exports[expIdx].getName(), null, null);
+ new R4Attribute[] { pkgName, pkgVersion } );
}
}
}
@@ -539,71 +543,84 @@
// Check to make sure that R3 bundles have only specified
// the 'specification-version' attribute and no directives
// on their imports; ignore all unknown attributes.
- for (int impIdx = 0;
- (m_imports != null) && (impIdx < m_imports.length);
- impIdx++)
+ for (int reqIdx = 0; (m_requirements != null) && (reqIdx < m_requirements.length); reqIdx++)
{
- if (m_imports[impIdx].getDirectives().length != 0)
+ if (m_requirements[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
{
- throw new BundleException("R3 imports cannot contain directives.");
- }
-
- // Remove and ignore all attributes other than version.
- // NOTE: This is checking for "version" rather than "specification-version"
- // because the package class normalizes to "version" to avoid having
- // future special cases. This could be changed if more strict behavior
- // is required.
- if (m_imports[impIdx].getAttributes() != null)
- {
- R4Attribute versionAttr = null;
- for (int attrIdx = 0;
- attrIdx < m_imports[impIdx].getAttributes().length;
- attrIdx++)
+ // R3 bundles cannot have directives on their imports.
+ if (((Requirement) m_requirements[reqIdx]).getDirectives().length != 0)
{
- if (m_imports[impIdx].getAttributes()[attrIdx]
- .getName().equals(Constants.VERSION_ATTRIBUTE))
- {
- versionAttr = m_imports[impIdx].getAttributes()[attrIdx];
- }
- else
- {
- m_logger.log(Logger.LOG_WARNING,
- "Unknown R3 import attribute: "
- + m_imports[impIdx].getAttributes()[attrIdx].getName());
- }
+ throw new BundleException("R3 imports cannot contain directives.");
}
- // Recreate the import if necessary to remove other attributes.
- if ((versionAttr != null) && (m_imports[impIdx].getAttributes().length > 1))
+ // Remove and ignore all attributes other than version.
+ // NOTE: This is checking for "version" rather than "specification-version"
+ // because the package class normalizes to "version" to avoid having
+ // future special cases. This could be changed if more strict behavior
+ // is required.
+ if (((Requirement) m_requirements[reqIdx]).getAttributes() != null)
{
- m_imports[impIdx] = new R4Import(
- m_imports[impIdx].getName(),
- null,
- new R4Attribute[] { versionAttr } );
- }
- else if ((versionAttr == null) && (m_imports[impIdx].getAttributes().length > 0))
- {
- m_imports[impIdx] = new R4Import(
- m_imports[impIdx].getName(), null, null);
+ // R3 package requirements should only have name and
+ // version attributes.
+ R4Attribute pkgName = null;
+ R4Attribute pkgVersion =
+ new R4Attribute(ICapability.VERSION_PROPERTY,
+ new VersionRange(Version.emptyVersion, true, null, true), false);
+ for (int attrIdx = 0;
+ attrIdx < ((Requirement) m_requirements[reqIdx]).getAttributes().length;
+ attrIdx++)
+ {
+ if (((Requirement) m_requirements[reqIdx]).getAttributes()[attrIdx]
+ .getName().equals(ICapability.PACKAGE_PROPERTY))
+ {
+ pkgName = ((Requirement) m_requirements[reqIdx]).getAttributes()[attrIdx];
+ }
+ else if (((Requirement) m_requirements[reqIdx]).getAttributes()[attrIdx]
+ .getName().equals(ICapability.VERSION_PROPERTY))
+ {
+ pkgVersion = ((Requirement) m_requirements[reqIdx]).getAttributes()[attrIdx];
+ }
+ else
+ {
+ m_logger.log(Logger.LOG_WARNING,
+ "Unknown R3 import attribute: "
+ + ((Requirement) m_requirements[reqIdx]).getAttributes()[attrIdx].getName());
+ }
+ }
+
+ // Recreate the import to remove any other attributes
+ // and add version if missing.
+ m_requirements[reqIdx] = new Requirement(
+ ICapability.PACKAGE_NAMESPACE,
+ (String) pkgName.getValue(),
+ null,
+ new R4Attribute[] { pkgName, pkgVersion });
}
}
}
// Since all R3 exports imply an import, add a corresponding
- // import for each existing export. Create non-duplicated import array.
+ // requirement for each existing export capability. Do not
+ // duplicate imports.
Map map = new HashMap();
// Add existing imports.
- for (int i = 0; i < m_imports.length; i++)
+ for (int i = 0; i < m_requirements.length; i++)
{
- map.put(m_imports[i].getName(), m_imports[i]);
+ if (m_requirements[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ map.put(
+ ((Requirement) m_requirements[i]).getPackageName(),
+ m_requirements[i]);
+ }
}
- // Add import for each export.
- for (int i = 0; i < m_exports.length; i++)
+ // Add import requirement for each export capability.
+ for (int i = 0; i < m_capabilities.length; i++)
{
- if (map.get(m_exports[i].getName()) == null)
+ if (m_capabilities[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
+ (map.get(m_capabilities[i].getProperties().get(ICapability.PACKAGE_PROPERTY)) == null))
{
// Convert Version to VersionRange.
- R4Attribute[] attrs = (R4Attribute[]) m_exports[i].getAttributes().clone();
+ R4Attribute[] attrs = (R4Attribute[]) ((Capability) m_capabilities[i]).getAttributes().clone();
for (int attrIdx = 0; (attrs != null) && (attrIdx < attrs.length); attrIdx++)
{
if (attrs[attrIdx].getName().equals(Constants.VERSION_ATTRIBUTE))
@@ -614,15 +631,17 @@
attrs[attrIdx].isMandatory());
}
}
- map.put(m_exports[i].getName(),
- new R4Import(
- m_exports[i].getName(),
- m_exports[i].getDirectives(),
- attrs));
+
+ 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));
}
}
- m_imports =
- (R4Import[]) map.values().toArray(new R4Import[map.size()]);
+ m_requirements =
+ (IRequirement[]) map.values().toArray(new IRequirement[map.size()]);
// Add a "uses" directive onto each export of R3 bundles
// that references every other import (which will include
@@ -630,33 +649,41 @@
// necessary since R3 bundles assumed a single class space,
// but R4 allows for multiple class spaces.
String usesValue = "";
- for (int i = 0; (m_imports != null) && (i < m_imports.length); i++)
+ for (int i = 0; (m_requirements != null) && (i < m_requirements.length); i++)
{
- usesValue = usesValue
- + ((usesValue.length() > 0) ? "," : "")
- + m_imports[i].getName();
+ if (m_requirements[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ usesValue = usesValue
+ + ((usesValue.length() > 0) ? "," : "")
+ + ((Requirement) m_requirements[i]).getPackageName();
+ }
}
R4Directive uses = new R4Directive(
Constants.USES_DIRECTIVE, usesValue);
- for (int i = 0; (m_exports != null) && (i < m_exports.length); i++)
+ for (int i = 0; (m_capabilities != null) && (i < m_capabilities.length); i++)
{
- m_exports[i] = new R4Export(
- m_exports[i].getName(),
- new R4Directive[] { uses },
- m_exports[i].getAttributes());
+ if (m_capabilities[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+ {
+ m_capabilities[i] = new Capability(
+ ICapability.PACKAGE_NAMESPACE,
+ new R4Directive[] { uses },
+ ((Capability) m_capabilities[i]).getAttributes());
+ }
}
// Check to make sure that R3 bundles have no attributes or
// directives on their dynamic imports.
- for (int i = 0; (m_dynamics != null) && (i < m_dynamics.length); i++)
+ for (int i = 0;
+ (m_dynamicRequirements != null) && (i < m_dynamicRequirements.length);
+ i++)
{
- if (m_dynamics[i].getDirectives().length != 0)
+ if (((Requirement) m_dynamicRequirements[i]).getDirectives().length != 0)
{
throw new BundleException("R3 dynamic imports cannot contain directives.");
}
- if (m_dynamics[i].getAttributes().length != 0)
+ if (((Requirement) m_dynamicRequirements[i]).getAttributes().length != 0)
{
- throw new BundleException("R3 dynamic imports cannot contain attributes.");
+// throw new BundleException("R3 dynamic imports cannot contain attributes.");
}
}
}
@@ -672,33 +699,35 @@
// Verify that the exports do not specify bundle symbolic name
// or bundle version.
- for (int i = 0; (m_exports != null) && (i < m_exports.length); i++)
+ for (int i = 0; (m_capabilities != null) && (i < m_capabilities.length); i++)
{
- String targetVer = (String) m_headerMap.get(Constants.BUNDLE_VERSION);
- targetVer = (targetVer == null) ? "0.0.0" : targetVer;
-
- R4Attribute[] attrs = m_exports[i].getAttributes();
- for (int attrIdx = 0; attrIdx < attrs.length; attrIdx++)
+ if (m_capabilities[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
{
- // Find symbolic name and version attribute, if present.
- if (attrs[attrIdx].getName().equals(Constants.BUNDLE_VERSION_ATTRIBUTE) ||
- attrs[attrIdx].getName().equals(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE))
+ R4Attribute[] attrs = ((Capability) m_capabilities[i]).getAttributes();
+ for (int attrIdx = 0; attrIdx < attrs.length; attrIdx++)
{
- throw new BundleException(
- "Exports must not specify bundle symbolic name or bundle version.");
+ // Find symbolic name and version attribute, if present.
+ if (attrs[attrIdx].getName().equals(Constants.BUNDLE_VERSION_ATTRIBUTE) ||
+ attrs[attrIdx].getName().equals(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE))
+ {
+ throw new BundleException(
+ "Exports must not specify bundle symbolic name or bundle version.");
+ }
}
- }
- // Now that we know that there are no bundle symbolic name and version
- // attributes, add them since the spec says they are there implicitly.
- R4Attribute[] newAttrs = new R4Attribute[attrs.length + 2];
- System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
- newAttrs[attrs.length] = new R4Attribute(
- Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, symName, false);
- newAttrs[attrs.length + 1] = new R4Attribute(
- Constants.BUNDLE_VERSION_ATTRIBUTE, Version.parseVersion(targetVer), false);
- m_exports[i] = new R4Export(
- m_exports[i].getName(), m_exports[i].getDirectives(), newAttrs);
+ // Now that we know that there are no bundle symbolic name and version
+ // attributes, add them since the spec says they are there implicitly.
+ R4Attribute[] newAttrs = new R4Attribute[attrs.length + 2];
+ System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
+ newAttrs[attrs.length] = new R4Attribute(
+ Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, symName, false);
+ newAttrs[attrs.length + 1] = new R4Attribute(
+ Constants.BUNDLE_VERSION_ATTRIBUTE, getBundleVersion(), false);
+ m_capabilities[i] = new Capability(
+ ICapability.PACKAGE_NAMESPACE,
+ ((Capability) m_capabilities[i]).getDirectives(),
+ newAttrs);
+ }
}
}
@@ -870,6 +899,7 @@
reqList.add(
new Requirement(
ICapability.PACKAGE_NAMESPACE,
+ null,
(R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
newAttrs));
}
@@ -924,6 +954,7 @@
reqList.add(
new Requirement(
ICapability.MODULE_NAMESPACE,
+ null,
(R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
newAttrs));
}
@@ -932,115 +963,6 @@
return (IRequirement[]) reqList.toArray(new IRequirement[reqList.size()]);
}
- public static R4Package[] parseImportExportHeader(String header, boolean export)
- {
- Object[][][] clauses = parseStandardHeader(header);
-
-// TODO: FRAMEWORK - Perhaps verification/normalization should be completely
-// separated from parsing, since verification/normalization may vary.
-
- // Verify that the values are equals if the package specifies
- // both version and specification-version attributes.
- Map attrMap = new HashMap();
- for (int clauseIdx = 0; clauseIdx < clauses.length; clauseIdx++)
- {
- // Put attributes for current clause in a map for easy lookup.
- attrMap.clear();
- for (int attrIdx = 0;
- attrIdx < clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX].length;
- attrIdx++)
- {
- R4Attribute attr = (R4Attribute) clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX][attrIdx];
- attrMap.put(attr.getName(), attr);
- }
-
- // Check for "version" and "specification-version" attributes
- // and verify they are the same if both are specified.
- R4Attribute v = (R4Attribute) attrMap.get(Constants.VERSION_ATTRIBUTE);
- R4Attribute sv = (R4Attribute) attrMap.get(Constants.PACKAGE_SPECIFICATION_VERSION);
- if ((v != null) && (sv != null))
- {
- // Verify they are equal.
- if (!((String) v.getValue()).trim().equals(((String) sv.getValue()).trim()))
- {
- throw new IllegalArgumentException(
- "Both version and specificat-version are specified, but they are not equal.");
- }
- }
-
- // Ensure that only the "version" attribute is used and convert
- // it to the appropriate type.
- if ((v != null) || (sv != null))
- {
- attrMap.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
- v = (v == null) ? sv : v;
- if (export)
- {
- attrMap.put(Constants.VERSION_ATTRIBUTE,
- new R4Attribute(
- Constants.VERSION_ATTRIBUTE,
- Version.parseVersion(v.getValue().toString()),
- v.isMandatory()));
- }
- else
- {
- attrMap.put(Constants.VERSION_ATTRIBUTE,
- new R4Attribute(
- Constants.VERSION_ATTRIBUTE,
- VersionRange.parse(v.getValue().toString()),
- v.isMandatory()));
- }
- }
-
- // If bundle version is specified, then convert its type to Version.
- // Only imports can specify this attribue.
- v = (R4Attribute) attrMap.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
- if (!export && (v != null))
- {
- attrMap.put(Constants.BUNDLE_VERSION_ATTRIBUTE,
- new R4Attribute(
- Constants.BUNDLE_VERSION_ATTRIBUTE,
- VersionRange.parse(v.getValue().toString()),
- v.isMandatory()));
- }
-
- // Re-copy the attribute array in case it has changed.
- clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX] =
- attrMap.values().toArray(new R4Attribute[attrMap.size()]);
- }
-
- // Now convert generic header clauses into packages.
- List pkgList = new ArrayList();
- for (int clauseIdx = 0; clauseIdx < clauses.length; clauseIdx++)
- {
- for (int pathIdx = 0;
- pathIdx < clauses[clauseIdx][CLAUSE_PATHS_INDEX].length;
- pathIdx++)
- {
- if (export)
- {
- pkgList.add(
- new R4Export(
- (String) clauses[clauseIdx][CLAUSE_PATHS_INDEX][pathIdx],
- (R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
- (R4Attribute[]) clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX]));
- }
- else
- {
- pkgList.add(
- new R4Import(
- (String) clauses[clauseIdx][CLAUSE_PATHS_INDEX][pathIdx],
- (R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
- (R4Attribute[]) clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX]));
- }
- }
- }
-
- return (export)
- ? (R4Package[]) pkgList.toArray(new R4Export[pkgList.size()])
- : (R4Package[]) pkgList.toArray(new R4Import[pkgList.size()]);
- }
-
public static final int CLAUSE_PATHS_INDEX = 0;
public static final int CLAUSE_DIRECTIVES_INDEX = 1;
public static final int CLAUSE_ATTRIBUTES_INDEX = 2;
diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Export.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Export.java
index 8cdef06..59e0924 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Export.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Export.java
@@ -19,6 +19,7 @@
package org.apache.felix.framework.util.manifestparser;
import java.util.*;
+
import org.apache.felix.framework.util.Util;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4LibraryClause.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4LibraryClause.java
index c748915..9d4478c 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4LibraryClause.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4LibraryClause.java
@@ -19,12 +19,10 @@
package org.apache.felix.framework.util.manifestparser;
import java.util.*;
+
import org.apache.felix.framework.FilterImpl;
import org.apache.felix.framework.Logger;
-import org.apache.felix.framework.util.FelixConstants;
-import org.apache.felix.framework.util.PropertyResolver;
-
-import org.apache.felix.framework.util.VersionRange;
+import org.apache.felix.framework.util.*;
import org.osgi.framework.*;
public class R4LibraryClause
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 5933c49..af206b6 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
@@ -1,20 +1,18 @@
/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
+ * Copyright 2006 The Apache Software Foundation
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
*/
package org.apache.felix.framework.util.manifestparser;
@@ -23,22 +21,56 @@
import org.apache.felix.framework.util.VersionRange;
import org.apache.felix.moduleloader.ICapability;
import org.apache.felix.moduleloader.IRequirement;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.*;
public class Requirement implements IRequirement
{
private String m_namespace = null;
- private R4Directive[] m_dirs = null;
- private R4Attribute[] m_attrs = null;
+ private R4Directive[] m_directives = null;
+ private R4Attribute[] m_attributes = null;
+ private boolean m_isOptional = false;
+
+ private String m_pkgName = null;
+ private VersionRange m_pkgVersionRange = null;
private Filter m_filter = null;
- public Requirement(String namespace, R4Directive[] dirs, R4Attribute[] attrs)
+ public Requirement(String namespace, String filterStr) throws InvalidSyntaxException
{
m_namespace = namespace;
- m_dirs = dirs;
- m_attrs = attrs;
- m_filter = convertToFilter();
+ m_filter = new FilterImpl(filterStr);
+ }
+
+ public Requirement(String namespace, String pkgName, R4Directive[] directives, R4Attribute[] attributes)
+ {
+ m_namespace = namespace;
+ m_directives = directives;
+ m_attributes = attributes;
+
+ // Find all import directives: resolution.
+ for (int i = 0; (m_directives != null) && (i < m_directives.length); i++)
+ {
+ if (m_directives[i].getName().equals(Constants.RESOLUTION_DIRECTIVE))
+ {
+ m_isOptional = m_directives[i].getValue().equals(Constants.RESOLUTION_OPTIONAL);
+ }
+ }
+
+ for (int i = 0; i < m_attributes.length; i++)
+ {
+ if (m_attributes[i].getName().equals(ICapability.PACKAGE_PROPERTY))
+ {
+ m_pkgName = (String) m_attributes[i].getValue();
+ }
+ else if (m_attributes[i].getName().equals(ICapability.VERSION_PROPERTY))
+ {
+ m_pkgVersionRange = (VersionRange) m_attributes[i].getValue();
+ }
+ }
+
+ if (m_pkgVersionRange == null)
+ {
+ m_pkgVersionRange = VersionRange.infiniteRange;
+ }
}
public String getNamespace()
@@ -48,9 +80,36 @@
public Filter getFilter()
{
+ if (m_filter == null)
+ {
+ m_filter = convertToFilter();
+ }
return m_filter;
}
+// TODO: RB - We need to verify that the resolver code does not
+// touch these implementation-specific methods.
+
+ public String getPackageName()
+ {
+ return m_pkgName;
+ }
+
+ public VersionRange getPackageVersionRange()
+ {
+ return m_pkgVersionRange;
+ }
+
+ public R4Directive[] getDirectives()
+ {
+ return m_directives;
+ }
+
+ public R4Attribute[] getAttributes()
+ {
+ return m_attributes;
+ }
+
public boolean isMultiple()
{
return false;
@@ -58,48 +117,150 @@
public boolean isOptional()
{
- return false;
+ return m_isOptional;
}
public String getComment()
{
- return null;
+ return "Comment for " + toString();
}
public boolean isSatisfied(ICapability capability)
{
- return m_filter.match(new MapToDictionary(capability.getProperties()));
+ // If the requirement was constructed with a filter, then
+ // we must use that filter for evaluation.
+ if ((m_attributes == null) && (m_filter != null))
+ {
+ return m_namespace.equals(capability.getNamespace()) &&
+ getFilter().match(new MapToDictionary(capability.getProperties()));
+ }
+ // Otherwise, if the requirement was constructed with attributes, then
+ // perform the evaluation manually instead of using the filter for
+ // performance reasons.
+ else if (m_attributes != null)
+ {
+ return capability.getNamespace().equals(getNamespace()) &&
+ doAttributesMatch((Capability) capability);
+ }
+
+ return false;
}
- public String toString()
+ private boolean doAttributesMatch(Capability ec)
{
- return getFilter().toString();
+ // Grab the capability's attributes.
+ R4Attribute[] capAttrs = ec.getAttributes();
+
+ // Cycle through all attributes of this import package
+ // and make sure its values match the attribute values
+ // of the specified export package.
+ for (int reqAttrIdx = 0; reqAttrIdx < m_attributes.length; reqAttrIdx++)
+ {
+ // Get current attribute from this import package.
+ R4Attribute reqAttr = m_attributes[reqAttrIdx];
+
+ // Ignore version attribute, since it is a special case that
+ // has already been compared using isVersionInRange() before
+ // the call to this method was made.
+ if (reqAttr.getName().equals(Constants.VERSION_ATTRIBUTE))
+ {
+ continue;
+ }
+
+ // Check if the export package has the same attribute.
+ boolean found = false;
+ for (int capAttrIdx = 0;
+ (!found) && (capAttrIdx < capAttrs.length);
+ capAttrIdx++)
+ {
+ // Get current attribute for the export package.
+ R4Attribute capAttr = capAttrs[capAttrIdx];
+ // Check if the attribute names are equal.
+ if (reqAttr.getName().equals(capAttr.getName()))
+ {
+ // We only recognize version types. If the value of the
+ // attribute is a version/version range, then we use the
+ // "in range" comparison, otherwise we simply use equals().
+ if (capAttr.getValue() instanceof Version)
+ {
+ if (!((VersionRange) reqAttr.getValue()).isInRange((Version) capAttr.getValue()))
+ {
+ return false;
+ }
+ }
+ else if (!reqAttr.getValue().equals(capAttr.getValue()))
+ {
+ return false;
+ }
+ found = true;
+ }
+ }
+ // If the attribute was not found, then return false.
+ if (!found)
+ {
+ return false;
+ }
+ }
+
+ // Now, cycle through all attributes of the export package and verify that
+ // all mandatory attributes are present in this import package.
+ for (int capAttrIdx = 0; capAttrIdx < capAttrs.length; capAttrIdx++)
+ {
+ // Get current attribute for this package.
+ R4Attribute capAttr = capAttrs[capAttrIdx];
+
+ // If the export attribute is mandatory, then make sure
+ // this import package has the attribute.
+ if (capAttr.isMandatory())
+ {
+ boolean found = false;
+ for (int reqAttrIdx = 0;
+ (!found) && (reqAttrIdx < m_attributes.length);
+ reqAttrIdx++)
+ {
+ // Get current attribute from specified package.
+ R4Attribute reqAttr = m_attributes[reqAttrIdx];
+
+ // Check if the attribute names are equal
+ // and set found flag.
+ if (capAttr.getName().equals(reqAttr.getName()))
+ {
+ found = true;
+ }
+ }
+ // If not found, then return false.
+ if (!found)
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
private Filter convertToFilter()
{
- String filterStr = null;
-
StringBuffer sb = new StringBuffer("(&");
- for (int i = 0; (m_attrs != null) && (i < m_attrs.length); i++)
+ for (int i = 0; (m_attributes != null) && (i < m_attributes.length); i++)
{
// If this is a package import, then convert wild-carded
// dynamically imported package names to an OR comparison.
if (m_namespace.equals(ICapability.PACKAGE_NAMESPACE) &&
- m_attrs[i].getName().equals(ICapability.PACKAGE_PROPERTY) &&
- m_attrs[i].getValue().toString().endsWith(".*"))
+ m_attributes[i].getName().equals(ICapability.PACKAGE_PROPERTY) &&
+ m_attributes[i].getValue().toString().endsWith(".*"))
{
- int idx = m_attrs[i].getValue().toString().indexOf(".*");
+ int idx = m_attributes[i].getValue().toString().indexOf(".*");
sb.append("(|(package=");
- sb.append(m_attrs[i].getValue().toString().substring(0, idx));
+ sb.append(m_attributes[i].getValue().toString().substring(0, idx));
sb.append(")(package=");
- sb.append(m_attrs[i].getValue().toString());
+ sb.append(m_attributes[i].getValue().toString());
sb.append("))");
}
- else if (m_attrs[i].getValue() instanceof VersionRange)
+ else if (m_attributes[i].getValue() instanceof VersionRange)
{
- VersionRange vr = (VersionRange) m_attrs[i].getValue();
+ VersionRange vr = (VersionRange) m_attributes[i].getValue();
if (vr.isLowInclusive())
{
sb.append("(version>=");
@@ -132,9 +293,9 @@
else
{
sb.append("(");
- sb.append(m_attrs[i].getName());
+ sb.append(m_attributes[i].getName());
sb.append("=");
- sb.append(m_attrs[i].getValue().toString());
+ sb.append(m_attributes[i].getValue().toString());
sb.append(")");
}
}
@@ -152,4 +313,9 @@
return null;
}
+
+ public String toString()
+ {
+ return getNamespace() + "; " + getFilter().toString();
+ }
}
\ No newline at end of file