FELIX-3868 : Adding osgi.identity namespace to bundles (resources). Apply patch from David Bosschaert

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1550009 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 dc7819a..482bfad 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
@@ -20,23 +20,27 @@
 
 import java.util.*;
 import java.util.Map.Entry;
-import org.apache.felix.framework.BundleRevisionImpl;
 
+import org.apache.felix.framework.BundleRevisionImpl;
 import org.apache.felix.framework.Logger;
 import org.apache.felix.framework.capabilityset.SimpleFilter;
-import org.apache.felix.framework.wiring.BundleCapabilityImpl;
 import org.apache.felix.framework.util.FelixConstants;
 import org.apache.felix.framework.util.VersionRange;
+import org.apache.felix.framework.wiring.BundleCapabilityImpl;
 import org.apache.felix.framework.wiring.BundleRequirementImpl;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
 import org.osgi.framework.Version;
+import org.osgi.framework.namespace.BundleNamespace;
+import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.framework.wiring.BundleCapability;
 import org.osgi.framework.wiring.BundleRequirement;
 import org.osgi.framework.wiring.BundleRevision;
 
 public class ManifestParser
 {
+    private static final String BUNDLE_LICENSE_HEADER = "Bundle-License"; // No constant defined by OSGi...
+
     private final Logger m_logger;
     private final Map m_configMap;
     private final Map m_headerMap;
@@ -129,6 +133,14 @@
                         bundleCap.getDirectives(),
                         hostAttrs));
                 }
+
+                //
+                // Add the osgi.identity capability.
+                // TODO support this for fragments. The main thing with supporting this
+                // for fragments is that the identity capability should not be exposed
+                // through the host's bundle wiring.
+                //
+                capList.add(addIdentityCapability(owner, headerMap, bundleCap));
             }
         }
 
@@ -1299,6 +1311,55 @@
         return null;
     }
 
+    private static BundleCapabilityImpl addIdentityCapability(BundleRevision owner,
+        Map headerMap, BundleCapabilityImpl bundleCap)
+    {
+        Map<String, Object> attrs = new HashMap<String, Object>();
+
+        attrs.put(IdentityNamespace.IDENTITY_NAMESPACE,
+            bundleCap.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE));
+        attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE,
+            headerMap.get(Constants.FRAGMENT_HOST) == null
+            ? IdentityNamespace.TYPE_BUNDLE
+            : IdentityNamespace.TYPE_FRAGMENT);
+        attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE,
+            bundleCap.getAttributes().get(Constants.BUNDLE_VERSION_ATTRIBUTE));
+
+        if (headerMap.get(Constants.BUNDLE_COPYRIGHT) != null)
+        {
+            attrs.put(IdentityNamespace.CAPABILITY_COPYRIGHT_ATTRIBUTE,
+                headerMap.get(Constants.BUNDLE_COPYRIGHT));
+        }
+
+        if (headerMap.get(Constants.BUNDLE_DESCRIPTION) != null)
+        {
+            attrs.put(IdentityNamespace.CAPABILITY_DESCRIPTION_ATTRIBUTE,
+                headerMap.get(Constants.BUNDLE_DESCRIPTION));
+        }
+        if (headerMap.get(Constants.BUNDLE_DOCURL) != null)
+        {
+            attrs.put(IdentityNamespace.CAPABILITY_DOCUMENTATION_ATTRIBUTE,
+                headerMap.get(Constants.BUNDLE_DOCURL));
+        }
+        if (headerMap.get(BUNDLE_LICENSE_HEADER) != null)
+        {
+            attrs.put(IdentityNamespace.CAPABILITY_LICENSE_ATTRIBUTE,
+                headerMap.get(BUNDLE_LICENSE_HEADER));
+        }
+
+        Map<String, String> dirs;
+        if (bundleCap.getDirectives().get(Constants.SINGLETON_DIRECTIVE) != null)
+        {
+            dirs = Collections.singletonMap(IdentityNamespace.CAPABILITY_SINGLETON_DIRECTIVE,
+                    bundleCap.getDirectives().get(Constants.SINGLETON_DIRECTIVE));
+        }
+        else
+        {
+            dirs = Collections.emptyMap();
+        }
+        return new BundleCapabilityImpl(owner, IdentityNamespace.IDENTITY_NAMESPACE, dirs, attrs);
+    }
+
     private static List<BundleRequirementImpl> parseFragmentHost(
         Logger logger, BundleRevision owner, Map headerMap)
         throws BundleException
@@ -1861,4 +1922,4 @@
 
         return libList;
     }
-}
\ No newline at end of file
+}
diff --git a/framework/src/test/java/org/apache/felix/framework/util/manifestparser/ManifestParserTest.java b/framework/src/test/java/org/apache/felix/framework/util/manifestparser/ManifestParserTest.java
new file mode 100644
index 0000000..1ce5dc2
--- /dev/null
+++ b/framework/src/test/java/org/apache/felix/framework/util/manifestparser/ManifestParserTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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
+ *
+ *   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;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+
+public class ManifestParserTest extends TestCase {
+    public void testIdentityCapabilityMinimal() throws BundleException {
+        Map<String, String> headers = new HashMap<String, String>();
+        headers.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+        headers.put(Constants.BUNDLE_SYMBOLICNAME, "foo.bar");
+        ManifestParser mp = new ManifestParser(null, null, null, headers);
+
+        BundleCapability ic = findCapability(mp.getCapabilities(), IdentityNamespace.IDENTITY_NAMESPACE);
+        assertEquals("foo.bar", ic.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
+        assertEquals(IdentityNamespace.TYPE_BUNDLE, ic.getAttributes().get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE));
+        assertEquals(0, ic.getDirectives().size());
+    }
+
+    public void testIdentityCapabilityFull() throws BundleException {
+        Map<String, String> headers = new HashMap<String, String>();
+        headers.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+        headers.put(Constants.BUNDLE_SYMBOLICNAME, "abc;singleton:=true");
+        headers.put(Constants.BUNDLE_VERSION, "1.2.3.something");
+        String copyright = "(c) 2013 Apache Software Foundation";
+        headers.put(Constants.BUNDLE_COPYRIGHT, copyright);
+        String description = "A bundle description";
+        headers.put(Constants.BUNDLE_DESCRIPTION, description);
+        String docurl = "http://felix.apache.org/";
+        headers.put(Constants.BUNDLE_DOCURL, docurl);
+        String license = "http://www.apache.org/licenses/LICENSE-2.0";
+        headers.put("Bundle-License", license);
+        ManifestParser mp = new ManifestParser(null, null, null, headers);
+
+        BundleCapability ic = findCapability(mp.getCapabilities(), IdentityNamespace.IDENTITY_NAMESPACE);
+        assertEquals("abc", ic.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
+        assertEquals(new Version("1.2.3.something"), ic.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE));
+        assertEquals(IdentityNamespace.TYPE_BUNDLE, ic.getAttributes().get(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE));
+        assertEquals(copyright, ic.getAttributes().get(IdentityNamespace.CAPABILITY_COPYRIGHT_ATTRIBUTE));
+        assertEquals(description, ic.getAttributes().get(IdentityNamespace.CAPABILITY_DESCRIPTION_ATTRIBUTE));
+        assertEquals(docurl, ic.getAttributes().get(IdentityNamespace.CAPABILITY_DOCUMENTATION_ATTRIBUTE));
+        assertEquals(license, ic.getAttributes().get(IdentityNamespace.CAPABILITY_LICENSE_ATTRIBUTE));
+
+        assertEquals(1, ic.getDirectives().size());
+        assertEquals("true", ic.getDirectives().get(IdentityNamespace.CAPABILITY_SINGLETON_DIRECTIVE));
+    }
+
+    private BundleCapability findCapability(Collection<BundleCapability> capabilities, String namespace) {
+        for (BundleCapability capability : capabilities) {
+            if (namespace.equals(capability.getNamespace())) {
+                return capability;
+            }
+        }
+        return null;
+    }
+}