Obey fragment host version ranges. (FELIX-1795)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@828779 13f79535-47bb-0310-9956-ffa450edef68
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 df2eeb5..f9d9809 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
@@ -53,8 +53,7 @@
         m_headerMap = headerMap;
 
         // Verify that only manifest version 2 is specified.
-        String manifestVersion = (String) m_headerMap.get(Constants.BUNDLE_MANIFESTVERSION);
-        manifestVersion = (manifestVersion == null) ? null : manifestVersion.trim();
+        String manifestVersion = getManifestVersion(m_headerMap);
         if ((manifestVersion != null) && !manifestVersion.equals("2"))
         {
             throw new BundleException(
@@ -113,27 +112,6 @@
         }
 
         //
-        // Parse Fragment-Host.
-        //
-        Object[][][] clauses = parseStandardHeader(
-            (String) headerMap.get(Constants.FRAGMENT_HOST));
-        if (clauses.length > 0)
-        {
-            try
-            {
-                reqList.add(
-                    new Requirement(
-                        ICapability.HOST_NAMESPACE,
-                        "(" + Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE
-                            + "=" + clauses[0][CLAUSE_PATHS_INDEX][0] + ")"));
-            }
-            catch (InvalidSyntaxException ex)
-            {
-                ex.printStackTrace();
-            }
-        }
-
-        //
         // Parse Export-Package.
         //
 
@@ -160,6 +138,16 @@
         m_capabilities = (ICapability[]) capList.toArray(new ICapability[capList.size()]);
 
         //
+        // Parse Fragment-Host.
+        //
+
+        IRequirement req = parseFragmentHost(m_logger, m_headerMap);
+        if (req != null)
+        {
+            reqList.add(req);
+        }
+
+        //
         // Parse Require-Bundle
         //
 
@@ -274,8 +262,14 @@
 
     public String getManifestVersion()
     {
-        String manifestVersion = (String) m_headerMap.get(Constants.BUNDLE_MANIFESTVERSION);
-        return (manifestVersion == null) ? "1" : manifestVersion.trim();
+        String manifestVersion = getManifestVersion(m_headerMap);
+        return (manifestVersion == null) ? "1" : manifestVersion;
+    }
+
+    private static String getManifestVersion(Map headerMap)
+    {
+        String manifestVersion = (String) headerMap.get(Constants.BUNDLE_MANIFESTVERSION);
+        return (manifestVersion == null) ? null : manifestVersion.trim();
     }
 
     public int getActivationPolicy()
@@ -865,7 +859,8 @@
                 catch (RuntimeException ex)
                 {
                     // R4 bundle versions must parse, R3 bundle version may not.
-                    if (((String) headerMap.get(Constants.BUNDLE_MANIFESTVERSION)).equals("2"))
+                    String mv = getManifestVersion(headerMap);
+                    if (mv != null)
                     {
                         throw ex;
                     }
@@ -890,6 +885,70 @@
         return null;
     }
 
+    private static IRequirement parseFragmentHost(Logger logger, Map headerMap)
+        throws BundleException
+    {
+        IRequirement req = null;
+
+        String mv = getManifestVersion(headerMap);
+        if ((mv != null) && mv.equals("2"))
+        {
+            Object[][][] clauses = parseStandardHeader(
+                (String) headerMap.get(Constants.FRAGMENT_HOST));
+            if (clauses.length > 0)
+            {
+                // Make sure that only one fragment host symbolic name is specified.
+                if (clauses.length > 1)
+                {
+                    throw new BundleException(
+                        "Fragments cannot have multiple hosts: "
+                            + headerMap.get(Constants.FRAGMENT_HOST));
+                }
+                else if (clauses[0][CLAUSE_PATHS_INDEX].length > 1)
+                {
+                    throw new BundleException(
+                        "Fragments cannot have multiple hosts: "
+                            + headerMap.get(Constants.FRAGMENT_HOST));
+                }
+
+                // If the bundle version matching attribute is specified, then
+                // convert it to the proper type.
+                for (int attrIdx = 0;
+                    attrIdx < clauses[0][CLAUSE_ATTRIBUTES_INDEX].length;
+                    attrIdx++)
+                {
+                    R4Attribute attr = (R4Attribute) clauses[0][CLAUSE_ATTRIBUTES_INDEX][attrIdx];
+                    if (attr.getName().equals(Constants.BUNDLE_VERSION_ATTRIBUTE))
+                    {
+                        clauses[0][CLAUSE_ATTRIBUTES_INDEX][attrIdx] =
+                            new R4Attribute(
+                                Constants.BUNDLE_VERSION_ATTRIBUTE,
+                                VersionRange.parse(attr.getValue().toString()),
+                                attr.isMandatory());
+                    }
+                }
+
+                // Prepend the host symbolic name to the array of attributes.
+                R4Attribute[] attrs = (R4Attribute[]) clauses[0][CLAUSE_ATTRIBUTES_INDEX];
+                R4Attribute[] newAttrs = new R4Attribute[attrs.length + 1];
+                newAttrs[0] = new R4Attribute(
+                    Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE,
+                    clauses[0][CLAUSE_PATHS_INDEX][0], false);
+                System.arraycopy(attrs, 0, newAttrs, 1, attrs.length);
+
+                req = new Requirement(ICapability.HOST_NAMESPACE,
+                    (R4Directive[]) clauses[0][CLAUSE_DIRECTIVES_INDEX],
+                    newAttrs);
+            }
+        }
+        else
+        {
+            logger.log(Logger.LOG_WARNING, "Only R4 bundles can be fragments.");
+        }
+
+        return req;
+    }
+
     public static ICapability[] parseExportHeader(
         IModule owner, String header, String bsn, Version bv)
         throws BundleException