Adds support for the standard symbolic name for the system bundle; however,
to actually allow bundles to require the system bundle it was necessary to
modify the system bundle so that it added the appropriate capability so that
it could be required like normal bundles. The utility of this is questionable,
but it is correct with respect to the spec. (FELIX-602)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@674382 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
index 96355eb..70dc4ae 100644
--- a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
+++ b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
@@ -39,6 +39,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.moduleloader.ICapability;
@@ -146,6 +147,8 @@
 
 // TODO: FRAMEWORK - Not all of this stuff really belongs here, probably only exports.
         // Populate system bundle header map.
+        // Note: This is a reference to the actual header map,
+        // so these changes are saved. Kind of hacky.
         Map map = ((SystemBundleArchive) m_systemBundleInfo.getArchive()).getManifestHeader(0);
         // Initialize header map as a case insensitive map.
         map.put(FelixConstants.BUNDLE_VERSION,
@@ -167,8 +170,10 @@
         // packages should be exported by the system bundle.
         try
         {
-            setCapabilities(ManifestParser.parseExportHeader(
-                (String) configMap.get(Constants.FRAMEWORK_SYSTEMPACKAGES)));
+            setCapabilities(
+                addModuleCapability(map,
+                    ManifestParser.parseExportHeader(
+                        (String) configMap.get(Constants.FRAMEWORK_SYSTEMPACKAGES))));
         }
         catch (Exception ex)
         {
@@ -180,6 +185,45 @@
         }
     }
 
+    private ICapability[] addModuleCapability(Map headerMap, ICapability[] caps)
+    {
+        try
+        {
+            // First parse the symbolic name header.
+            ICapability moduleCap = ManifestParser.parseBundleSymbolicName(headerMap);
+            // Create a copy of the module capability with the standard
+            // alias for the bundle symbolic name.
+            R4Directive[] dirs = ((Capability) moduleCap).getDirectives();
+            R4Attribute[] attrs = ((Capability) moduleCap).getAttributes();
+            R4Attribute[] attrsAlias = new R4Attribute[attrs.length];
+            System.arraycopy(attrs, 0, attrsAlias, 0, attrs.length);
+            // Modify the alias attributes to have the standard symbolic name.
+            for (int i = 0; i < attrsAlias.length; i++)
+            {
+                if (attrsAlias[i].getName().equalsIgnoreCase(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE))
+                {
+                    attrsAlias[i] = new R4Attribute(
+                        Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, Constants.SYSTEM_BUNDLE_SYMBOLICNAME, false);
+                }
+            }
+            // Create the alias capability.
+            ICapability aliasCap = new Capability(ICapability.MODULE_NAMESPACE, dirs, attrsAlias);
+            // Finally, add the module and alias capabilities to the
+            // existing capabilities.
+            ICapability[] temp = new ICapability[caps.length + 2];
+            System.arraycopy(caps, 0, temp, 2, caps.length);
+            temp[0] = moduleCap;
+            temp[1] = aliasCap;
+            return temp;
+        }
+        catch (BundleException ex)
+        {
+            // This should not happen, but in case it does, then just
+            // return the original array of capabilities.
+            return caps;
+        }
+    }
+
     public synchronized Object getSecurityContext()
     {
         return m_securityContext;
@@ -370,9 +414,10 @@
     {
         m_capabilities = capabilities;
 
+        // Note: This is a reference to the actual header map,
+        // so these changes are saved. Kind of hacky.
         Map map = ((SystemBundleArchive) m_systemBundleInfo.getArchive()).getManifestHeader(0);
         map.put(Constants.EXPORT_PACKAGE, convertCapabilitiesToHeaders(map));
-        ((SystemBundleArchive) m_systemBundleInfo.getArchive()).setManifestHeader(map);
     }
 
     public IRequirement[] getDynamicRequirements()
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 2fa01a3..4e87c95 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -563,7 +563,7 @@
 
     public String getSymbolicName()
     {
-        return Constants.SYSTEM_BUNDLE_LOCATION;
+        return Constants.SYSTEM_BUNDLE_SYMBOLICNAME;
     }
 
     public boolean hasPermission(Object obj)
@@ -842,7 +842,7 @@
             {
                 // This should never happen.
                 throw new BundleException(
-                    "Unresolved package in System Bundle:"
+                    "Unresolved constraint in System Bundle:"
                     + ex.getRequirement());
             }
 
@@ -1726,7 +1726,7 @@
             if (ex.getModule() != null)
             {
                 throw new BundleException(
-                    "Unresolved package in bundle "
+                    "Unresolved constraint in bundle "
                     + Util.getBundleIdFromModuleId(ex.getModule().getId())
                     + ": " + ex.getRequirement());
             }
diff --git a/framework/src/main/java/org/apache/felix/framework/SystemBundleArchive.java b/framework/src/main/java/org/apache/felix/framework/SystemBundleArchive.java
index 51d327f..da64e15 100644
--- a/framework/src/main/java/org/apache/felix/framework/SystemBundleArchive.java
+++ b/framework/src/main/java/org/apache/felix/framework/SystemBundleArchive.java
@@ -151,9 +151,4 @@
     {
         return m_headerMap;
     }
-
-    public void setManifestHeader(Map headerMap)
-    {
-        m_headerMap = headerMap;
-    }
 }
\ 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 1ead3bd..082e662 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
@@ -62,70 +62,37 @@
         Map dupeMap = new HashMap();
 
         //
-        // Get bundle version.
-        //
-
-        if (m_headerMap.get(Constants.BUNDLE_VERSION) != null)
-        {
-            try
-            {
-                m_bundleVersion = Version.parseVersion((String) m_headerMap.get(Constants.BUNDLE_VERSION));
-            }
-            catch (RuntimeException ex)
-            {
-                // R4 bundle versions must parse, R3 bundle version may not.
-                if (getManifestVersion().equals("2"))
-                {
-                    throw ex;
-                }
-                m_bundleVersion = Version.emptyVersion;
-            }
-        }
-
-        //
         // Parse bundle symbolic name.
         //
 
-        Object[][][] clauses = parseStandardHeader(
-            (String) headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
-        if (clauses.length > 0)
+        ICapability moduleCap = parseBundleSymbolicName(m_headerMap);
+        if (moduleCap != null)
         {
-            if (clauses.length > 1)
-            {
-                throw new BundleException(
-                    "Cannot have multiple symbolic names: "
-                        + headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
-            }
-            else if (clauses[0][CLAUSE_PATHS_INDEX].length > 1)
-            {
-                throw new BundleException(
-                    "Cannot have multiple symbolic names: "
-                        + headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
-            }
-            // Add a module capability.
+            m_bundleVersion = (Version)
+                moduleCap.getProperties().get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+            m_bundleSymbolicName = (String)
+                moduleCap.getProperties().get(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE);
+
+            // Add the module capability to all capabilities.
             // TODO: FRAGMENT - Fragment bundles cannot be required, so we
             //       should not add this capability, but for now we are using
             //       it to get the symbolic name.
-            m_bundleSymbolicName = (String) clauses[0][CLAUSE_PATHS_INDEX][0];
-            R4Attribute[] attrs = new R4Attribute[2];
-            attrs[0] = new R4Attribute(
-                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(moduleCap);
             // Add a host capability if the bundle is not a fragment. A host
             // capability is the same as a module capability, but with a
             // different capability namespace.
             if (headerMap.get(Constants.FRAGMENT_HOST) == null)
             {
-                capList.add(new Capability(ICapability.HOST_NAMESPACE, null, attrs));
+                capList.add(new Capability(
+                    ICapability.HOST_NAMESPACE, null,
+                    ((Capability) moduleCap).getAttributes()));
             }
         }
 
         //
         // Parse Fragment-Host.
         //
-        clauses = parseStandardHeader(
+        Object[][][] clauses = parseStandardHeader(
             (String) headerMap.get(Constants.FRAGMENT_HOST));
         if (clauses.length > 0)
         {
@@ -783,6 +750,58 @@
         }
     }
 
+    public static ICapability parseBundleSymbolicName(Map headerMap)
+        throws BundleException
+    {
+        Object[][][] clauses = parseStandardHeader(
+            (String) headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
+        if (clauses.length > 0)
+        {
+            if (clauses.length > 1)
+            {
+                throw new BundleException(
+                    "Cannot have multiple symbolic names: "
+                        + headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
+            }
+            else if (clauses[0][CLAUSE_PATHS_INDEX].length > 1)
+            {
+                throw new BundleException(
+                    "Cannot have multiple symbolic names: "
+                        + headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
+            }
+
+            // Get bundle version.
+            Version bundleVersion = null;
+            if (headerMap.get(Constants.BUNDLE_VERSION) != null)
+            {
+                try
+                {
+                    bundleVersion = Version.parseVersion((String) headerMap.get(Constants.BUNDLE_VERSION));
+                }
+                catch (RuntimeException ex)
+                {
+                    // R4 bundle versions must parse, R3 bundle version may not.
+                    if (((String) headerMap.get(Constants.BUNDLE_MANIFESTVERSION)).equals("2"))
+                    {
+                        throw ex;
+                    }
+                    bundleVersion = Version.emptyVersion;
+                }
+            }
+
+            // Create a module capability and return it.
+            String symName = (String) clauses[0][CLAUSE_PATHS_INDEX][0];
+            R4Attribute[] attrs = new R4Attribute[2];
+            attrs[0] = new R4Attribute(
+                Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, symName, false);
+            attrs[1] = new R4Attribute(
+                Constants.BUNDLE_VERSION_ATTRIBUTE, bundleVersion, false);
+            return new Capability(ICapability.MODULE_NAMESPACE, null, attrs);
+        }
+
+        return null;
+    }
+
     public static ICapability[] parseExportHeader(String header)
     {
         Object[][][] clauses = parseStandardHeader(header);