Modified manifest parsing and import/export matching to support bundle
versions as attributes.


git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@425060 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Attribute.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Attribute.java
index d2c0217..a8658c3 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Attribute.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Attribute.java
@@ -1,5 +1,5 @@
 /*
- *   Copyright 2005 The Apache Software Foundation
+ *   Copyright 2006 The Apache Software Foundation
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
  *   you may not use this file except in compliance with the License.
@@ -19,10 +19,10 @@
 public class R4Attribute
 {
     private String m_name = "";
-    private String m_value = "";
+    private Object m_value = null;
     private boolean m_isMandatory = false;
     
-    public R4Attribute(String name, String value, boolean isMandatory)
+    public R4Attribute(String name, Object value, boolean isMandatory)
     {
         m_name = name;
         m_value = value;
@@ -34,7 +34,7 @@
         return m_name;
     }
 
-    public String getValue()
+    public Object getValue()
     {
         return m_value;
     }
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Export.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Export.java
index c40a192..b0d8510 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Export.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Export.java
@@ -20,6 +20,7 @@
 
 import org.apache.felix.framework.util.Util;
 import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
 
 public class R4Export extends R4Package
 {
@@ -104,26 +105,26 @@
             }
         }
 
-        // Convert version, if present.
-        String rangeStr = "0.0.0";
+        // Find the version, if present, and convert to Version.
+        // The version attribute value may be a String or a Version,
+        // since the value may be coming from an R4Export that already
+        // converted it to Version.
+        m_version = Version.emptyVersion;
         for (int i = 0; i < m_attrs.length; i++)
         {
-            // Find and parse version attribute, if present.
-            if (m_attrs[i].getName().equals(Constants.VERSION_ATTRIBUTE) ||
-                m_attrs[i].getName().equals(Constants.PACKAGE_SPECIFICATION_VERSION))
+            if (m_attrs[i].getName().equals(Constants.VERSION_ATTRIBUTE))
             {
-                // Normalize version attribute name.
+                String versionStr = (m_attrs[i].getValue() instanceof Version)
+                    ? ((Version) m_attrs[i].getValue()).toString()
+                    : (String) m_attrs[i].getValue();
+                m_version = Version.parseVersion(versionStr);
                 m_attrs[i] = new R4Attribute(
-                    Constants.VERSION_ATTRIBUTE, m_attrs[i].getValue(),
+                    m_attrs[i].getName(),
+                    m_version,
                     m_attrs[i].isMandatory());
-                rangeStr = m_attrs[i].getValue();
                 break;
             }
         }
-        
-        VersionRange range = VersionRange.parse(rangeStr);
-        // For now, ignore if we have a version range.
-        m_version = range.getLow();
     }
 
     public String[] getUses()
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Import.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Import.java
index 6b56936..5293368 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Import.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Import.java
@@ -16,7 +16,7 @@
  */
 package org.apache.felix.framework.searchpolicy;
 
-import org.apache.felix.framework.util.FelixConstants;
+import org.osgi.framework.Constants;
 import org.osgi.framework.Version;
 
 public class R4Import extends R4Package
@@ -36,30 +36,43 @@
         // Find all import directives: resolution.
         for (int i = 0; i < m_directives.length; i++)
         {
-            if (m_directives[i].getName().equals(FelixConstants.RESOLUTION_DIRECTIVE))
+            if (m_directives[i].getName().equals(Constants.RESOLUTION_DIRECTIVE))
             {
-                m_isOptional = m_directives[i].getValue().equals(FelixConstants.RESOLUTION_OPTIONAL);
+                m_isOptional = m_directives[i].getValue().equals(Constants.RESOLUTION_OPTIONAL);
             }
         }
 
-        // Find and parse version attribute, if present.
-        String rangeStr = "0.0.0";
+        // Convert version and bundle version attributes to VersionRange.
+        // The attribute value may be a String or a Version, since the
+        // value may be coming from an R4Export that already converted
+        // it to Version.
+        m_versionRange = VersionRange.parse(Version.emptyVersion.toString());
+        m_version = m_versionRange.getLow();
         for (int i = 0; i < m_attrs.length; i++)
         {
-            if (m_attrs[i].getName().equals(FelixConstants.VERSION_ATTRIBUTE) ||
-                m_attrs[i].getName().equals(FelixConstants.PACKAGE_SPECIFICATION_VERSION))
+            if (m_attrs[i].getName().equals(Constants.VERSION_ATTRIBUTE))
             {
-                // Normalize version attribute name.
+                String versionStr = (m_attrs[i].getValue() instanceof Version)
+                    ? ((Version) m_attrs[i].getValue()).toString()
+                    : (String) m_attrs[i].getValue();
+                m_versionRange = VersionRange.parse(versionStr);
+                m_version = m_versionRange.getLow();
                 m_attrs[i] = new R4Attribute(
-                    FelixConstants.VERSION_ATTRIBUTE, m_attrs[i].getValue(),
+                    m_attrs[i].getName(),
+                    m_versionRange,
                     m_attrs[i].isMandatory());
-                rangeStr = m_attrs[i].getValue();
-                break;
+            }
+            else if (m_attrs[i].getName().equals(Constants.BUNDLE_VERSION_ATTRIBUTE))
+            {
+                String versionStr = (m_attrs[i].getValue() instanceof Version)
+                    ? ((Version) m_attrs[i].getValue()).toString()
+                    : (String) m_attrs[i].getValue();
+                m_attrs[i] = new R4Attribute(
+                    m_attrs[i].getName(),
+                    VersionRange.parse(versionStr),
+                    m_attrs[i].isMandatory());
             }
         }
-        
-        m_versionRange = VersionRange.parse(rangeStr);
-        m_version = m_versionRange.getLow();
     }
 
     public Version getVersionHigh()
@@ -108,7 +121,7 @@
             // 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 (impAttr.getName().equals(FelixConstants.VERSION_ATTRIBUTE))
+            if (impAttr.getName().equals(Constants.VERSION_ATTRIBUTE))
             {
                 continue;
             }
@@ -124,13 +137,17 @@
                 // Check if the attribute names are equal.
                 if (impAttr.getName().equals(expAttr.getName()))
                 {
-                    // If the values are not equal, then return false immediately.
-                    // We should not compare version values here, since they are
-                    // a special case and have already been compared by a call to
-                    // isVersionInRange() before getting here; however, it is
-                    // possible for version to be mandatory, so make sure it is
-                    // present below.
-                    if (!impAttr.getValue().equals(expAttr.getValue()))
+                    // 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 (expAttr.getValue() instanceof Version)
+                    {
+                        if (!((VersionRange) impAttr.getValue()).isInRange((Version) expAttr.getValue()))
+                        {
+                            return false;
+                        }
+                    }
+                    else if (!impAttr.getValue().equals(expAttr.getValue()))
                     {
                         return false;
                     }
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
index 95e51b7..f0d5a8c 100755
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
@@ -33,8 +33,10 @@
     public R4Package(String name, R4Directive[] directives, R4Attribute[] attrs)
     {
         m_name = name;
-        m_directives = (directives == null) ? new R4Directive[0] : directives;
-        m_attrs = (attrs == null) ? new R4Attribute[0] : attrs;
+        m_directives = (directives == null)
+            ? new R4Directive[0] : (R4Directive[]) directives.clone();
+        m_attrs = (attrs == null)
+            ? new R4Attribute[0] : (R4Attribute[]) attrs.clone();
     }
 
     public String getName()
@@ -191,13 +193,25 @@
             if ((v != null) && (sv != null))
             {
                 // Verify they are equal.
-                if (!v.getValue().trim().equals(sv.getValue().trim()))
+                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.");
                 }
-                // Remove spec-version since it isn't needed.
+            }
+
+            // Ensure that only the "version" attribute is used 
+            if (sv != null)
+            {
                 attrsMap.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
+                if (v == null)
+                {
+                    attrsMap.put(Constants.VERSION_ATTRIBUTE,
+                        new R4Attribute(
+                            Constants.VERSION_ATTRIBUTE,
+                            sv.getValue(),
+                            sv.isMandatory()));
+                }
             }
 
             // Create directive array.
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java
index fe6c56b..39fc343 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java
@@ -47,7 +47,10 @@
         }
 
         // Verify bundle version syntax.
-        Version.parseVersion(get(Constants.BUNDLE_VERSION));
+        if (get(Constants.BUNDLE_VERSION) != null)
+        {
+            Version.parseVersion(get(Constants.BUNDLE_VERSION));
+        }
 
         // Create map to check for duplicate imports/exports.
         Map dupeMap = new HashMap();
@@ -212,7 +215,7 @@
                     (!m_exports[i].getAttributes()[0].getName().equals(Constants.VERSION_ATTRIBUTE))))
             {
                 throw new BundleException(
-                    "Export does not conform to R3 syntax: " + m_exports[i]);
+                    "R3 export syntax does not support attributes: " + m_exports[i]);
             }
         }
         
@@ -235,7 +238,7 @@
                     (!m_imports[i].getAttributes()[0].getName().equals(Constants.VERSION_ATTRIBUTE))))
             {
                 throw new BundleException(
-                    "Import does not conform to R3 syntax: " + m_imports[i]);
+                    "R3 import syntax does not support attributes: " + m_imports[i]);
             }
         }
 
@@ -304,18 +307,17 @@
             throw new BundleException("R4 bundle manifests must include bundle symbolic name.");
         }
 
-        // Verify that there are no duplicate directives.
+        // 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++)
         {
             String targetVer = get(Constants.BUNDLE_VERSION);
             targetVer = (targetVer == null) ? "0.0.0" : targetVer;
 
-            // First verify that the exports do not specify
-            // bundle symbolic name or bundle version.
             R4Attribute[] attrs = m_exports[i].getAttributes();
             for (int attrIdx = 0; attrIdx < attrs.length; attrIdx++)
             {
-                // Find and parse version attribute, if present.
+                // 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))
                 {
@@ -331,24 +333,7 @@
             newAttrs[attrs.length] = new R4Attribute(
                 Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, symName, false);
             newAttrs[attrs.length + 1] = new R4Attribute(
-                Constants.BUNDLE_VERSION_ATTRIBUTE, targetVer, false);
-            m_exports[i] = new R4Export(
-                m_exports[i].getName(), m_exports[i].getDirectives(), newAttrs);
-        }
-
-        // Need to add symbolic name and bundle version to all R4 exports.
-        for (int i = 0; (m_exports != null) && (i < m_exports.length); i++)
-        {
-            String targetVer = get(Constants.BUNDLE_VERSION);
-            targetVer = (targetVer == null) ? "0.0.0" : targetVer;
-
-            R4Attribute[] attrs = m_exports[i].getAttributes();
-            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, targetVer, false);
+                Constants.BUNDLE_VERSION_ATTRIBUTE, Version.parseVersion(targetVer), false);
             m_exports[i] = new R4Export(
                 m_exports[i].getName(), m_exports[i].getDirectives(), newAttrs);
         }