cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From serg...@apache.org
Subject svn commit: r690991 [15/20] - in /cxf/sandbox/dosgi: ./ discovery/ discovery/local/ discovery/local/src/ discovery/local/src/main/ discovery/local/src/main/java/ discovery/local/src/main/java/org/ discovery/local/src/main/java/org/apache/ discovery/loc...
Date Mon, 01 Sep 2008 15:08:10 GMT
Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java?rev=690991&view=auto
==============================================================================
--- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java (added)
+++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java Mon Sep  1 08:08:01 2008
@@ -0,0 +1,1248 @@
+/*
+ * 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.*;
+
+import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.cache.BundleRevision;
+import org.apache.felix.framework.util.*;
+import org.apache.felix.moduleloader.ICapability;
+import org.apache.felix.moduleloader.IRequirement;
+import org.osgi.framework.*;
+
+public class ManifestParser
+{
+    private Logger m_logger = null;
+    private Map m_configMap = null;
+    private Map m_headerMap = null;
+    private String m_bundleSymbolicName = null;
+    private Version m_bundleVersion = null;
+    private ICapability[] m_capabilities = null;
+    private IRequirement[] m_requirements = null;
+    private IRequirement[] m_dynamicRequirements = null;
+    private R4LibraryClause[] m_libraryHeaders = null;
+    private boolean m_libraryHeadersOptional = false;
+
+    public ManifestParser(Logger logger, Map configMap, Map headerMap)
+        throws BundleException
+    {
+        m_logger = logger;
+        m_configMap = configMap;
+        m_headerMap = headerMap;
+
+        // Verify that only manifest version 2 is specified.
+        String manifestVersion = (String) m_headerMap.get(Constants.BUNDLE_MANIFESTVERSION);
+        if ((manifestVersion != null) && !manifestVersion.equals("2"))
+        {
+            throw new BundleException(
+                "Unknown 'Bundle-ManifestVersion' value: " + manifestVersion);
+        }
+
+        // Create map to check for duplicate imports/exports
+        // and lists to hold capabilities and requirements.
+        List capList = new ArrayList();
+        List reqList = new ArrayList();
+        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)
+        {
+            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));
+            }
+            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));
+        }
+
+        //
+        // Parse Export-Package.
+        //
+
+        // Get exported packages from bundle manifest.
+        ICapability[] exportCaps = parseExportHeader(
+            (String) headerMap.get(Constants.EXPORT_PACKAGE));
+
+        // Verify that "java.*" packages are not exported.
+        for (int capIdx = 0; capIdx < exportCaps.length; capIdx++)
+        {
+            // Verify that the named package has not already been declared.
+            String pkgName = (String)
+                exportCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY);
+            // Verify that java.* packages are not exported.
+            if (pkgName.startsWith("java."))
+            {
+                throw new BundleException(
+                    "Exporting java.* packages not allowed: " + pkgName);
+            }
+            capList.add(exportCaps[capIdx]);
+        }
+
+        // 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));
+        for (int reqIdx = 0; reqIdx < bundleReq.length; reqIdx++)
+        {
+            reqList.add(bundleReq[reqIdx]);
+        }
+
+        //
+        // Parse Import-Package.
+        //
+
+        // Get import packages from bundle manifest.
+        IRequirement[] importReqs = parseImportHeader(
+            (String) headerMap.get(Constants.IMPORT_PACKAGE));
+
+        // Create non-duplicated import array.
+        dupeMap.clear();
+        for (int reqIdx = 0; reqIdx < importReqs.length; reqIdx++)
+        {
+            // Verify that the named package has not already been declared.
+            String pkgName = ((Requirement) importReqs[reqIdx]).getPackageName();
+
+            if (dupeMap.get(pkgName) == null)
+            {
+                // Verify that java.* packages are not imported.
+                if (pkgName.startsWith("java."))
+                {
+                    throw new BundleException(
+                        "Importing java.* packages not allowed: " + pkgName);
+                }
+                dupeMap.put(pkgName, importReqs[reqIdx]);
+            }
+            else
+            {
+                throw new BundleException(
+                    "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_dynamicRequirements = parseImportHeader(
+            (String) headerMap.get(Constants.DYNAMICIMPORT_PACKAGE));
+
+        // Dynamic imports can have duplicates, so just check for import
+        // of java.*.
+        for (int reqIdx = 0; reqIdx < m_dynamicRequirements.length; reqIdx++)
+        {
+            // Verify that java.* packages are not imported.
+            String pkgName = ((Requirement) m_dynamicRequirements[reqIdx]).getPackageName();
+            if (pkgName.startsWith("java."))
+            {
+                throw new BundleException(
+                    "Dynamically importing java.* packages not allowed: " + pkgName);
+            }
+        }
+
+        //
+        // Parse Bundle-NativeCode.
+        //
+
+        // Get native library entry names for module library sources.
+        m_libraryHeaders =
+            parseLibraryStrings(
+                m_logger,
+                parseDelimitedString((String) m_headerMap.get(Constants.BUNDLE_NATIVECODE), ","));
+
+        // Check to see if there was an optional native library clause, which is
+        // represented by a null library header; if so, record it and remove it.
+        if ((m_libraryHeaders.length > 0) &&
+            (m_libraryHeaders[m_libraryHeaders.length - 1].getLibraryEntries() == null))
+        {
+            m_libraryHeadersOptional = true;
+            R4LibraryClause[] tmp = new R4LibraryClause[m_libraryHeaders.length - 1];
+            System.arraycopy(m_libraryHeaders, 0, tmp, 0, m_libraryHeaders.length - 1);
+            m_libraryHeaders = tmp;
+        }
+
+        // Do final checks and normalization of manifest.
+        if (getManifestVersion().equals("2"))
+        {
+            checkAndNormalizeR4();
+        }
+        else
+        {
+            checkAndNormalizeR3();
+        }
+    }
+
+    public String getManifestVersion()
+    {
+        String manifestVersion = (String) m_headerMap.get(Constants.BUNDLE_MANIFESTVERSION);
+        return (manifestVersion == null) ? "1" : manifestVersion;
+    }
+
+    public String getSymbolicName()
+    {
+        return m_bundleSymbolicName;
+    }
+
+    public Version getBundleVersion()
+    {
+        return m_bundleVersion;
+    }
+
+    public ICapability[] getCapabilities()
+    {
+        return m_capabilities;
+    }
+
+    public IRequirement[] getRequirements()
+    {
+        return m_requirements;
+    }
+
+    public IRequirement[] getDynamicRequirements()
+    {
+        return m_dynamicRequirements;
+    }
+
+    public R4LibraryClause[] getLibraryClauses()
+    {
+        return m_libraryHeaders;
+    }
+
+    /**
+     * <p>
+     * This method returns the selected native library metadata from
+     * the manifest. The information is not the raw metadata from the
+     * manifest, but is native library metadata clause selected according
+     * to the OSGi native library clause selection policy. The metadata
+     * returned by this method will be attached directly to a module and
+     * used for finding its native libraries at run time. To inspect the
+     * raw native library metadata refer to <tt>getLibraryClauses()</tt>.
+     * </p>
+     * @return an array of selected library metadata objects from the manifest.
+     * @throws BundleException if any problems arise.
+    **/
+    public R4Library[] getLibraries() throws BundleException
+    {
+        R4LibraryClause clause = getSelectedLibraryClause();
+
+        if (clause != null)
+        {
+            String[] entries = clause.getLibraryEntries();
+            R4Library[] libraries = new R4Library[entries.length];
+            int current = 0;
+            try
+            {
+                for (int i = 0; i < libraries.length; i++)
+                {
+                    String name = getName(entries[i]);
+                    boolean found = false;
+                    for (int j = 0; !found && (j < current); j++)
+                    {
+                        found = getName(entries[j]).equals(name);
+                    }
+                    if (!found)
+                    {
+                        libraries[current++] = new R4Library(
+                            clause.getLibraryEntries()[i],
+                            clause.getOSNames(), clause.getProcessors(), clause.getOSVersions(),
+                            clause.getLanguages(), clause.getSelectionFilter());
+                    } 
+                }
+                if (current < libraries.length)
+                {
+                    R4Library[] tmp = new R4Library[current];
+                    System.arraycopy(libraries, 0, tmp, 0, current);
+                    libraries = tmp;
+                }
+                return libraries;
+            }
+            catch (Exception ex)
+            {
+                throw new BundleException("Unable to create library", ex);
+            }
+        }
+        return null;
+    }
+
+    private String getName(String path)
+    {
+        int idx = path.lastIndexOf('/');
+        if (idx > -1)
+        {
+            return path.substring(idx);
+        }
+        return path;
+    }
+
+    private R4LibraryClause getSelectedLibraryClause() throws BundleException
+    {
+        if ((m_libraryHeaders != null) && (m_libraryHeaders.length > 0))
+        {
+            List clauseList = new ArrayList();
+
+            // Search for matching native clauses.
+            for (int i = 0; i < m_libraryHeaders.length; i++)
+            {
+                if (m_libraryHeaders[i].match(m_configMap))
+                {
+                    clauseList.add(m_libraryHeaders[i]);
+                }
+            }
+
+            // Select the matching native clause.
+            int selected = 0;
+            if (clauseList.size() == 0)
+            {
+                // If optional clause exists, no error thrown.
+                if (m_libraryHeadersOptional)
+                {
+                    return null;
+                }
+                else
+                {
+                    throw new BundleException("Unable to select a native library clause.");
+                }
+            }
+            else if (clauseList.size() == 1)
+            {
+                selected = 0;
+            }
+            else if (clauseList.size() > 1)
+            {
+                selected = firstSortedClause(clauseList);
+            }
+            return ((R4LibraryClause) clauseList.get(selected));
+        }
+
+        return null;
+    }
+
+    private int firstSortedClause(List clauseList)
+    {
+        ArrayList indexList = new ArrayList();
+        ArrayList selection = new ArrayList();
+
+        // Init index list
+        for (int i = 0; i < clauseList.size(); i++)
+        {
+            indexList.add("" + i);
+        }
+
+        // Select clause with 'osversion' range declared
+        // and get back the max floor of 'osversion' ranges.
+        Version osVersionRangeMaxFloor = new Version(0, 0, 0);
+        for (int i = 0; i < indexList.size(); i++)
+        {
+            int index = Integer.parseInt(indexList.get(i).toString());
+            String[] osversions = ((R4LibraryClause) clauseList.get(index)).getOSVersions();
+            if (osversions != null)
+            {
+                selection.add("" + indexList.get(i));
+            }
+            for (int k = 0; (osversions != null) && (k < osversions.length); k++)
+            {
+                VersionRange range = VersionRange.parse(osversions[k]);
+                if ((range.getLow()).compareTo(osVersionRangeMaxFloor) >= 0)
+                {
+                    osVersionRangeMaxFloor = range.getLow();
+                }
+            }
+        }
+
+        if (selection.size() == 1)
+        {
+            return Integer.parseInt(selection.get(0).toString());
+        }
+        else if (selection.size() > 1)
+        {
+            // Keep only selected clauses with an 'osversion'
+            // equal to the max floor of 'osversion' ranges.
+            indexList = selection;
+            selection = new ArrayList();
+            for (int i = 0; i < indexList.size(); i++)
+            {
+                int index = Integer.parseInt(indexList.get(i).toString());
+                String[] osversions = ((R4LibraryClause) clauseList.get(index)).getOSVersions();
+                for (int k = 0; k < osversions.length; k++)
+                {
+                    VersionRange range = VersionRange.parse(osversions[k]);
+                    if ((range.getLow()).compareTo(osVersionRangeMaxFloor) >= 0)
+                    {
+                        selection.add("" + indexList.get(i));
+                    }
+                }
+            }
+        }
+
+        if (selection.size() == 0)
+        {
+            // Re-init index list.
+            selection.clear();
+            indexList.clear();
+            for (int i = 0; i < clauseList.size(); i++)
+            {
+                indexList.add("" + i);
+            }
+        }
+        else if (selection.size() == 1)
+        {
+            return Integer.parseInt(selection.get(0).toString());
+        }
+        else
+        {
+            indexList = selection;
+            selection.clear();
+        }
+
+        // Keep only clauses with 'language' declared.
+        for (int i = 0; i < indexList.size(); i++)
+        {
+            int index = Integer.parseInt(indexList.get(i).toString());
+            if (((R4LibraryClause) clauseList.get(index)).getLanguages() != null)
+            {
+                selection.add("" + indexList.get(i));
+            }
+        }
+
+        // Return the first sorted clause
+        if (selection.size() == 0)
+        {
+            return 0;
+        }
+        else
+        {
+            return Integer.parseInt(selection.get(0).toString());
+        }
+    }
+
+    private void checkAndNormalizeR3() throws BundleException
+    {
+        // 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 capIdx = 0;
+            (m_capabilities != null) && (capIdx < m_capabilities.length);
+            capIdx++)
+        {
+            if (m_capabilities[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            {
+                // R3 bundles cannot have directives on their exports.
+                if (((Capability) m_capabilities[capIdx]).getDirectives().length != 0)
+                {
+                    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 (((Capability) m_capabilities[capIdx]).getAttributes() != null)
+                {
+                    // 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];
+                        }
+                        else 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[] { pkgName, pkgVersion } );
+                }
+            }
+        }
+
+        // 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 reqIdx = 0; (m_requirements != null) && (reqIdx < m_requirements.length); reqIdx++)
+        {
+            if (m_requirements[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            {
+                // R3 bundles cannot have directives on their imports.
+                if (((Requirement) m_requirements[reqIdx]).getDirectives().length != 0)
+                {
+                    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 (((Requirement) m_requirements[reqIdx]).getAttributes() != 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
+        // requirement for each existing export capability. Do not
+        // duplicate imports.
+        Map map =  new HashMap();
+        // Add existing imports.
+        for (int i = 0; i < m_requirements.length; i++)
+        {
+            if (m_requirements[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            {
+                map.put(
+                    ((Requirement) m_requirements[i]).getPackageName(),
+                    m_requirements[i]);
+            }
+        }
+        // Add import requirement for each export capability.
+        for (int i = 0; i < m_capabilities.length; i++)
+        {
+            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[]) ((Capability) m_capabilities[i]).getAttributes().clone();
+                for (int attrIdx = 0; (attrs != null) && (attrIdx < attrs.length); attrIdx++)
+                {
+                    if (attrs[attrIdx].getName().equals(Constants.VERSION_ATTRIBUTE))
+                    {
+                        attrs[attrIdx] = new R4Attribute(
+                            attrs[attrIdx].getName(),
+                            VersionRange.parse(attrs[attrIdx].getValue().toString()),
+                            attrs[attrIdx].isMandatory());
+                    }
+                }
+
+                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_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
+        // exports, since export implies import); this is
+        // necessary since R3 bundles assumed a single class space,
+        // but R4 allows for multiple class spaces.
+        String usesValue = "";
+        for (int i = 0; (m_requirements != null) && (i < m_requirements.length); i++)
+        {
+            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_capabilities != null) && (i < m_capabilities.length); i++)
+        {
+            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_dynamicRequirements != null) && (i < m_dynamicRequirements.length);
+            i++)
+        {
+            if (((Requirement) m_dynamicRequirements[i]).getDirectives().length != 0)
+            {
+                throw new BundleException("R3 dynamic imports cannot contain directives.");
+            }
+            if (((Requirement) m_dynamicRequirements[i]).getAttributes().length != 0)
+            {
+//                throw new BundleException("R3 dynamic imports cannot contain attributes.");
+            }
+        }
+    }
+
+    private void checkAndNormalizeR4() throws BundleException
+    {
+        // Verify that bundle symbolic name is specified.
+        String symName = (String) m_headerMap.get(Constants.BUNDLE_SYMBOLICNAME);
+        if (symName == null)
+        {
+            throw new BundleException("R4 bundle manifests must include bundle symbolic name.");
+        }
+
+        // Verify that the exports do not specify bundle symbolic name
+        // or bundle version.
+        for (int i = 0; (m_capabilities != null) && (i < m_capabilities.length); i++)
+        {
+            if (m_capabilities[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
+            {
+                R4Attribute[] attrs = ((Capability) m_capabilities[i]).getAttributes();
+                for (int attrIdx = 0; attrIdx < attrs.length; attrIdx++)
+                {
+                    // 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, getBundleVersion(), false);
+                m_capabilities[i] = new Capability(
+                    ICapability.PACKAGE_NAMESPACE,
+                    ((Capability) m_capabilities[i]).getDirectives(),
+                    newAttrs);
+            }
+        }
+        
+        if (parseExtensionBundleHeader((String) 
+            m_headerMap.get(Constants.FRAGMENT_HOST)) != null)
+        {
+            checkExtensionBundle();
+        }
+    }
+    
+    private void checkExtensionBundle() throws BundleException
+    {
+        if (m_headerMap.containsKey(Constants.IMPORT_PACKAGE) ||
+            m_headerMap.containsKey(Constants.REQUIRE_BUNDLE) ||
+            m_headerMap.containsKey(Constants.BUNDLE_NATIVECODE) ||
+            m_headerMap.containsKey(Constants.DYNAMICIMPORT_PACKAGE) ||
+            m_headerMap.containsKey(Constants.BUNDLE_ACTIVATOR))
+        {
+            throw new BundleException("Invalid Extension Bundle Manifest");
+        }
+    }
+
+    public static ICapability[] parseExportHeader(String header)
+    {
+        Object[][][] clauses = parseStandardHeader(header);
+
+// TODO: FRAMEWORK - Perhaps verification/normalization should be completely
+// separated from parsing, since verification/normalization may vary.
+
+        // If both version and specification-version attributes are specified,
+        // then verify that the values are equal.
+        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.");
+                }
+            }
+
+            // Always add the default version if not specified.
+            if ((v == null) && (sv == null))
+            {
+                v = new R4Attribute(
+                    Constants.VERSION_ATTRIBUTE, Version.emptyVersion, false);
+            }
+
+            // Ensure that only the "version" attribute is used and convert
+            // it to the appropriate type.
+            if ((v != null) || (sv != null))
+            {
+                // Convert version attribute to type Version.
+                attrMap.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
+                v = (v == null) ? sv : v;
+                attrMap.put(Constants.VERSION_ATTRIBUTE,
+                    new R4Attribute(
+                        Constants.VERSION_ATTRIBUTE,
+                        Version.parseVersion(v.getValue().toString()),
+                        v.isMandatory()));
+
+                // Re-copy the attribute array since it has changed.
+                clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX] =
+                    attrMap.values().toArray(new R4Attribute[attrMap.size()]);
+            }
+        }
+
+        // Now convert generic header clauses into capabilities.
+        List capList = new ArrayList();
+        for (int clauseIdx = 0; clauseIdx < clauses.length; clauseIdx++)
+        {
+            for (int pathIdx = 0;
+                pathIdx < clauses[clauseIdx][CLAUSE_PATHS_INDEX].length;
+                pathIdx++)
+            {
+                // Prepend the package name to the array of attributes.
+                R4Attribute[] attrs = (R4Attribute[]) clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX];
+                R4Attribute[] newAttrs = new R4Attribute[attrs.length + 1];
+                newAttrs[0] = new R4Attribute(
+                    ICapability.PACKAGE_PROPERTY,
+                    (String) clauses[clauseIdx][CLAUSE_PATHS_INDEX][pathIdx], false);
+                System.arraycopy(attrs, 0, newAttrs, 1, attrs.length);
+
+                // Create package capability and add to capability list.
+                capList.add(
+                    new Capability(
+                        ICapability.PACKAGE_NAMESPACE,
+                        (R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
+                        newAttrs));
+            }
+        }
+
+        return (ICapability[]) capList.toArray(new ICapability[capList.size()]);
+    }
+
+    public static IRequirement[] parseImportHeader(String header)
+    {
+        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 VersionRange type.
+            if ((v != null) || (sv != null))
+            {
+                attrMap.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
+                v = (v == null) ? sv : v;
+                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 VersionRange.
+            v = (R4Attribute) attrMap.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+            if (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 requirements.
+        List reqList = new ArrayList();
+        for (int clauseIdx = 0; clauseIdx < clauses.length; clauseIdx++)
+        {
+            for (int pathIdx = 0;
+                pathIdx < clauses[clauseIdx][CLAUSE_PATHS_INDEX].length;
+                pathIdx++)
+            {
+                // Prepend the package name to the array of attributes.
+                R4Attribute[] attrs = (R4Attribute[]) clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX];
+                R4Attribute[] newAttrs = new R4Attribute[attrs.length + 1];
+                newAttrs[0] = new R4Attribute(
+                    ICapability.PACKAGE_PROPERTY,
+                    (String) clauses[clauseIdx][CLAUSE_PATHS_INDEX][pathIdx], false);
+                System.arraycopy(attrs, 0, newAttrs, 1, attrs.length);
+
+                // Create package requirement and add to requirement list.
+                reqList.add(
+                    new Requirement(
+                        ICapability.PACKAGE_NAMESPACE,
+                        null,
+                        (R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
+                        newAttrs));
+            }
+        }
+
+        return (IRequirement[]) reqList.toArray(new IRequirement[reqList.size()]);
+    }
+
+    public static IRequirement[] parseRequireBundleHeader(String header)
+    {
+        Object[][][] clauses = parseStandardHeader(header);
+
+// TODO: FRAMEWORK - Perhaps verification/normalization should be completely
+// separated from parsing, since verification/normalization may vary.
+
+        // Convert bundle version attribute to VersionRange type.
+        for (int clauseIdx = 0; clauseIdx < clauses.length; clauseIdx++)
+        {
+            for (int attrIdx = 0;
+                attrIdx < clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX].length;
+                attrIdx++)
+            {
+                R4Attribute attr = (R4Attribute) clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX][attrIdx];
+                if (attr.getName().equals(Constants.BUNDLE_VERSION_ATTRIBUTE))
+                {
+                    clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX][attrIdx] =
+                        new R4Attribute(
+                            Constants.BUNDLE_VERSION_ATTRIBUTE,
+                            VersionRange.parse(attr.getValue().toString()),
+                            attr.isMandatory());
+                }
+            }
+        }
+
+        // Now convert generic header clauses into requirements.
+        List reqList = new ArrayList();
+        for (int clauseIdx = 0; clauseIdx < clauses.length; clauseIdx++)
+        {
+            for (int pathIdx = 0;
+                pathIdx < clauses[clauseIdx][CLAUSE_PATHS_INDEX].length;
+                pathIdx++)
+            {
+                // Prepend the symbolic name to the array of attributes.
+                R4Attribute[] attrs = (R4Attribute[]) clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX];
+                R4Attribute[] newAttrs = new R4Attribute[attrs.length + 1];
+                newAttrs[0] = new R4Attribute(
+                    Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE,
+                    (String) clauses[clauseIdx][CLAUSE_PATHS_INDEX][pathIdx], false);
+                System.arraycopy(attrs, 0, newAttrs, 1, attrs.length);
+
+                // Create package requirement and add to requirement list.
+                reqList.add(
+                    new Requirement(
+                        ICapability.MODULE_NAMESPACE,
+                        null,
+                        (R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
+                        newAttrs));
+            }
+        }
+
+        return (IRequirement[]) reqList.toArray(new IRequirement[reqList.size()]);
+    }
+
+    public static R4Directive parseExtensionBundleHeader(String header)
+    {
+        Object[][][] clauses = parseStandardHeader(header);
+
+        R4Directive result = null;
+
+        if (clauses.length == 1)
+        {
+            if (FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(clauses[0][CLAUSE_PATHS_INDEX][0]) ||
+                Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(clauses[0][CLAUSE_PATHS_INDEX][0]))
+            {
+                if (clauses[0][CLAUSE_DIRECTIVES_INDEX].length == 1)
+                {
+                    if (Constants.EXTENSION_DIRECTIVE.equals(((R4Directive)
+                        clauses[0][CLAUSE_DIRECTIVES_INDEX][0]).getName()))
+                    {
+                        result = (R4Directive) clauses[0][CLAUSE_DIRECTIVES_INDEX][0];
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
+
+    public static final int CLAUSE_PATHS_INDEX = 0;
+    public static final int CLAUSE_DIRECTIVES_INDEX = 1;
+    public static final int CLAUSE_ATTRIBUTES_INDEX = 2;
+
+    // Like this: path; path; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2,
+    //            path; path; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2
+    public static Object[][][] parseStandardHeader(String header)
+    {
+        Object[][][] clauses = null;
+
+        if (header != null)
+        {
+            if (header.length() == 0)
+            {
+                throw new IllegalArgumentException(
+                    "A header cannot be an empty string.");
+            }
+
+            String[] clauseStrings = parseDelimitedString(
+                header, FelixConstants.CLASS_PATH_SEPARATOR);
+
+            List completeList = new ArrayList();
+            for (int i = 0; (clauseStrings != null) && (i < clauseStrings.length); i++)
+            {
+                completeList.add(parseStandardHeaderClause(clauseStrings[i]));
+            }
+            clauses = (Object[][][]) completeList.toArray(new Object[completeList.size()][][]);
+        }
+
+        return (clauses == null) ? new Object[0][][] : clauses;
+    }
+
+    // Like this: path; path; dir1:=dirval1; dir2:=dirval2; attr1=attrval1; attr2=attrval2
+    public static Object[][] parseStandardHeaderClause(String clauseString)
+        throws IllegalArgumentException
+    {
+        // Break string into semi-colon delimited pieces.
+        String[] pieces = parseDelimitedString(
+            clauseString, FelixConstants.PACKAGE_SEPARATOR);
+
+        // Count the number of different paths; paths
+        // will not have an '=' in their string. This assumes
+        // that paths come first, before directives and
+        // attributes.
+        int pathCount = 0;
+        for (int pieceIdx = 0; pieceIdx < pieces.length; pieceIdx++)
+        {
+            if (pieces[pieceIdx].indexOf('=') >= 0)
+            {
+                break;
+            }
+            pathCount++;
+        }
+
+        // Error if no paths were specified.
+        if (pathCount == 0)
+        {
+            throw new IllegalArgumentException(
+                "No paths specified in header: " + clauseString);
+        }
+
+        // Create an array of paths.
+        String[] paths = new String[pathCount];
+        System.arraycopy(pieces, 0, paths, 0, pathCount);
+
+        // Parse the directives/attributes.
+        Map dirsMap = new HashMap();
+        Map attrsMap = new HashMap();
+        int idx = -1;
+        String sep = null;
+        for (int pieceIdx = pathCount; pieceIdx < pieces.length; pieceIdx++)
+        {
+            // Check if it is a directive.
+            if ((idx = pieces[pieceIdx].indexOf(FelixConstants.DIRECTIVE_SEPARATOR)) >= 0)
+            {
+                sep = FelixConstants.DIRECTIVE_SEPARATOR;
+            }
+            // Check if it is an attribute.
+            else if ((idx = pieces[pieceIdx].indexOf(FelixConstants.ATTRIBUTE_SEPARATOR)) >= 0)
+            {
+                sep = FelixConstants.ATTRIBUTE_SEPARATOR;
+            }
+            // It is an error.
+            else
+            {
+                throw new IllegalArgumentException("Not a directive/attribute: " + clauseString);
+            }
+
+            String key = pieces[pieceIdx].substring(0, idx).trim();
+            String value = pieces[pieceIdx].substring(idx + sep.length()).trim();
+
+            // Remove quotes, if value is quoted.
+            if (value.startsWith("\"") && value.endsWith("\""))
+            {
+                value = value.substring(1, value.length() - 1);
+            }
+
+            // Save the directive/attribute in the appropriate array.
+            if (sep.equals(FelixConstants.DIRECTIVE_SEPARATOR))
+            {
+                // Check for duplicates.
+                if (dirsMap.get(key) != null)
+                {
+                    throw new IllegalArgumentException(
+                        "Duplicate directive: " + key);
+                }
+                dirsMap.put(key, new R4Directive(key, value));
+            }
+            else
+            {
+                // Check for duplicates.
+                if (attrsMap.get(key) != null)
+                {
+                    throw new IllegalArgumentException(
+                        "Duplicate attribute: " + key);
+                }
+                attrsMap.put(key, new R4Attribute(key, value, false));
+            }
+        }
+
+        // Create directive array.
+        R4Directive[] dirs = (R4Directive[])
+            dirsMap.values().toArray(new R4Directive[dirsMap.size()]);
+
+        // Create attribute array.
+        R4Attribute[] attrs = (R4Attribute[])
+            attrsMap.values().toArray(new R4Attribute[attrsMap.size()]);
+
+        // Create an array to hold the parsed paths, directives, and attributes.
+        Object[][] clause = new Object[3][];
+        clause[CLAUSE_PATHS_INDEX] = paths;
+        clause[CLAUSE_DIRECTIVES_INDEX] = dirs;
+        clause[CLAUSE_ATTRIBUTES_INDEX] = attrs;
+
+        return clause;
+    }
+
+    /**
+     * Parses delimited string and returns an array containing the tokens. This
+     * parser obeys quotes, so the delimiter character will be ignored if it is
+     * inside of a quote. This method assumes that the quote character is not
+     * included in the set of delimiter characters.
+     * @param value the delimited string to parse.
+     * @param delim the characters delimiting the tokens.
+     * @return an array of string tokens or null if there were no tokens.
+    **/
+    public static String[] parseDelimitedString(String value, String delim)
+    {
+        if (value == null)
+        {
+           value = "";
+        }
+
+        List list = new ArrayList();
+
+        int CHAR = 1;
+        int DELIMITER = 2;
+        int STARTQUOTE = 4;
+        int ENDQUOTE = 8;
+
+        StringBuffer sb = new StringBuffer();
+
+        int expecting = (CHAR | DELIMITER | STARTQUOTE);
+
+        for (int i = 0; i < value.length(); i++)
+        {
+            char c = value.charAt(i);
+
+            boolean isDelimiter = (delim.indexOf(c) >= 0);
+            boolean isQuote = (c == '"');
+
+            if (isDelimiter && ((expecting & DELIMITER) > 0))
+            {
+                list.add(sb.toString().trim());
+                sb.delete(0, sb.length());
+                expecting = (CHAR | DELIMITER | STARTQUOTE);
+            }
+            else if (isQuote && ((expecting & STARTQUOTE) > 0))
+            {
+                sb.append(c);
+                expecting = CHAR | ENDQUOTE;
+            }
+            else if (isQuote && ((expecting & ENDQUOTE) > 0))
+            {
+                sb.append(c);
+                expecting = (CHAR | STARTQUOTE | DELIMITER);
+            }
+            else if ((expecting & CHAR) > 0)
+            {
+                sb.append(c);
+            }
+            else
+            {
+                throw new IllegalArgumentException("Invalid delimited string: " + value);
+            }
+        }
+
+        if (sb.length() > 0)
+        {
+            list.add(sb.toString().trim());
+        }
+
+        return (String[]) list.toArray(new String[list.size()]);
+    }
+
+    /**
+     * Parses native code manifest headers.
+     * @param libStrs an array of native library manifest header
+     *        strings from the bundle manifest.
+     * @return an array of <tt>LibraryInfo</tt> objects for the
+     *         passed in strings.
+    **/
+    public static R4LibraryClause[] parseLibraryStrings(Logger logger, String[] libStrs)
+        throws IllegalArgumentException
+    {
+        if (libStrs == null)
+        {
+            return new R4LibraryClause[0];
+        }
+
+        List libList = new ArrayList();
+
+        for (int i = 0; i < libStrs.length; i++)
+        {
+            R4LibraryClause clause = R4LibraryClause.parse(logger, libStrs[i]);
+            libList.add(clause);
+        }
+
+        return (R4LibraryClause[]) libList.toArray(new R4LibraryClause[libList.size()]);
+    }
+}

Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Attribute.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Attribute.java?rev=690991&view=auto
==============================================================================
--- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Attribute.java (added)
+++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Attribute.java Mon Sep  1 08:08:01 2008
@@ -0,0 +1,48 @@
+/* 
+ * 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;
+
+public class R4Attribute
+{
+    private String m_name = "";
+    private Object m_value = null;
+    private boolean m_isMandatory = false;
+    
+    public R4Attribute(String name, Object value, boolean isMandatory)
+    {
+        m_name = name;
+        m_value = value;
+        m_isMandatory = isMandatory;
+    }
+
+    public String getName()
+    {
+        return m_name;
+    }
+
+    public Object getValue()
+    {
+        return m_value;
+    }
+
+    public boolean isMandatory()
+    {
+        return m_isMandatory;
+    }
+}
\ No newline at end of file

Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Attribute.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Attribute.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Directive.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Directive.java?rev=690991&view=auto
==============================================================================
--- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Directive.java (added)
+++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Directive.java Mon Sep  1 08:08:01 2008
@@ -0,0 +1,41 @@
+/* 
+ * 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;
+
+public class R4Directive
+{
+    private String m_name = "";
+    private String m_value = "";
+    
+    public R4Directive(String name, String value)
+    {
+        m_name = name;
+        m_value = value;
+    }
+
+    public String getName()
+    {
+        return m_name;
+    }
+
+    public String getValue()
+    {
+        return m_value;
+    }
+}
\ No newline at end of file

Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Directive.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Directive.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Library.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Library.java?rev=690991&view=auto
==============================================================================
--- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Library.java (added)
+++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Library.java Mon Sep  1 08:08:01 2008
@@ -0,0 +1,148 @@
+/*
+ * 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 org.osgi.framework.Constants;
+
+public class R4Library
+{
+    private String m_libraryFile = null;
+    private String[] m_osnames = null;
+    private String[] m_processors = null;
+    private String[] m_osversions = null;
+    private String[] m_languages = null;
+    private String m_selectionFilter = null;
+
+    public R4Library(
+        String libraryFile, String[] osnames, String[] processors, String[] osversions,
+        String[] languages, String selectionFilter) throws Exception
+    {
+        m_libraryFile = libraryFile;
+        m_osnames = osnames;
+        m_processors = processors;
+        m_osversions = osversions;
+        m_languages = languages;
+        m_selectionFilter = selectionFilter;
+    }
+
+    public String getEntryName()
+    {
+        return m_libraryFile;
+    }
+
+    public String[] getOSNames()
+    {
+        return m_osnames;
+    }
+
+    public String[] getProcessors()
+    {
+        return m_processors;
+    }
+
+    public String[] getOSVersions()
+    {
+        return m_osversions;
+    }
+
+    public String[] getLanguages()
+    {
+        return m_languages;
+    }
+
+    public String getSelectionFilter()
+    {
+        return m_selectionFilter;
+    }
+
+    /**
+     * <p>
+     * Determines if the specified native library name matches this native
+     * library definition.
+     * </p>
+     * @param name the native library name to try to match.
+     * @return <tt>true</tt> if this native library name matches this native
+     *         library definition; <tt>false</tt> otherwise.
+    **/
+    public boolean match(String name)
+    {
+        String libname = System.mapLibraryName(name);
+        if (m_libraryFile.equals(libname) || m_libraryFile.endsWith("/" + libname))
+        {
+            return true;
+        }
+        else if (libname.endsWith(".jnilib") &&
+            m_libraryFile.endsWith(".dylib"))
+        {
+            libname = libname.substring(0, libname.length() - 6) + "dylib";
+            if (m_libraryFile.equals(libname) || m_libraryFile.endsWith("/" + libname))
+            {
+                return true;
+            }
+        }
+        else if (m_libraryFile.equals(name) || m_libraryFile.endsWith("/" + name))
+        {
+            return true;
+        }
+        return false;
+    }
+
+    public String toString()
+    {
+        if (m_libraryFile != null)
+        {
+            StringBuffer sb = new StringBuffer();
+            sb.append(m_libraryFile);
+            sb.append(';');
+            for (int i = 0; (m_osnames != null) && (i < m_osnames.length); i++)
+            {
+                sb.append(Constants.BUNDLE_NATIVECODE_OSNAME);
+                sb.append('=');
+                sb.append(m_osnames[i]);
+                sb.append(';');
+            }
+            for (int i = 0; (m_processors != null) && (i < m_processors.length); i++)
+            {
+                sb.append(Constants.BUNDLE_NATIVECODE_PROCESSOR);
+                sb.append(m_processors[i]);
+                sb.append(';');
+            }
+            for (int i = 0; (m_osversions != null) && (i < m_osversions.length); i++)
+            {
+                sb.append(Constants.BUNDLE_NATIVECODE_OSVERSION);
+                sb.append(m_osversions[i]);
+                sb.append(';');
+            }
+            for (int i = 0; (m_languages != null) && (i < m_languages.length); i++)
+            {
+                sb.append(Constants.BUNDLE_NATIVECODE_LANGUAGE);
+                sb.append(m_languages[i]);
+                sb.append(';');
+            }
+            sb.append(Constants.SELECTION_FILTER_ATTRIBUTE);
+            sb.append('=');
+            sb.append('\'');
+            sb.append(m_selectionFilter);
+            sb.append('\'');
+
+            return sb.toString();
+        }
+        return "*";
+    }
+}
\ No newline at end of file

Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Library.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4Library.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4LibraryClause.java
URL: http://svn.apache.org/viewvc/cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4LibraryClause.java?rev=690991&view=auto
==============================================================================
--- cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4LibraryClause.java (added)
+++ cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4LibraryClause.java Mon Sep  1 08:08:01 2008
@@ -0,0 +1,540 @@
+/* 
+ * 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.*;
+
+import org.apache.felix.framework.FilterImpl;
+import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.util.*;
+import org.osgi.framework.*;
+
+public class R4LibraryClause
+{
+    private String[] m_libraryEntries = null;
+    private String[] m_osnames = null;
+    private String[] m_processors = null;
+    private String[] m_osversions = null;
+    private String[] m_languages = null;
+    private String m_selectionFilter = null;
+
+    public R4LibraryClause(String[] libraryEntries, String[] osnames,
+        String[] processors, String[] osversions, String[] languages,
+        String selectionFilter)
+    {
+        m_libraryEntries = libraryEntries;
+        m_osnames = osnames;
+        m_processors = processors;
+        m_osversions = osversions;
+        m_languages = languages;
+        m_selectionFilter = selectionFilter;
+    }
+
+    public R4LibraryClause(R4LibraryClause library)
+    {
+        m_libraryEntries = library.m_libraryEntries;
+        m_osnames = library.m_osnames;
+        m_osversions = library.m_osversions;
+        m_processors = library.m_processors;
+        m_languages = library.m_languages;
+        m_selectionFilter = library.m_selectionFilter;
+    }
+
+    public String[] getLibraryEntries()
+    {
+        return m_libraryEntries;
+    }
+
+    public String[] getOSNames()
+    {
+        return m_osnames;
+    }
+
+    public String[] getProcessors()
+    {
+        return m_processors;
+    }
+
+    public String[] getOSVersions()
+    {
+        return m_osversions;
+    }
+
+    public String[] getLanguages()
+    {
+        return m_languages;
+    }
+
+    public String getSelectionFilter()
+    {
+        return m_selectionFilter;
+    }
+
+    public boolean match(Map configMap) throws BundleException
+    {
+        String normal_osname = normalizeOSName((String) configMap.get(Constants.FRAMEWORK_OS_NAME));
+        String normal_processor = normalizeProcessor((String) configMap.get(Constants.FRAMEWORK_PROCESSOR));
+        String normal_osversion = normalizeOSVersion((String) configMap.get(Constants.FRAMEWORK_OS_VERSION));
+        String normal_language = (String) configMap.get(Constants.FRAMEWORK_LANGUAGE);
+
+        // Check library's osname.
+        if (!checkOSNames(normal_osname, getOSNames()))
+        {
+            return false;
+        }
+
+        // Check library's processor.
+        if (!checkProcessors(normal_processor, getProcessors()))
+        {
+            return false;
+        }
+
+        // Check library's osversion if specified.
+        if ((getOSVersions() != null) &&
+            (getOSVersions().length > 0) &&
+            !checkOSVersions(normal_osversion, getOSVersions()))
+        {
+            return false;
+        }
+
+        // Check library's language if specified.
+        if ((getLanguages() != null) &&
+            (getLanguages().length > 0) &&
+            !checkLanguages(normal_language, getLanguages()))
+        {
+            return false;
+        }
+
+        // Check library's selection-filter if specified.
+        if ((getSelectionFilter() != null) &&
+            (getSelectionFilter().length() >= 0) &&
+            !checkSelectionFilter(configMap, getSelectionFilter()))
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    private boolean checkOSNames(String currentOSName, String[] osnames)
+    {
+        boolean win32 = currentOSName.startsWith("win") && 
+            (currentOSName.equals("windows95") ||
+            currentOSName.equals("windows98") ||
+            currentOSName.equals("windowsnt") ||
+            currentOSName.equals("windows2000") ||
+            currentOSName.equals("windowsxp") ||
+            currentOSName.equals("windowsce") ||
+            currentOSName.equals("windowsvista"));
+
+        for (int i = 0; (osnames != null) && (i < osnames.length); i++)
+        {
+            if (osnames[i].equals(currentOSName) || 
+                ("win32".equals(osnames[i]) && win32))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean checkProcessors(String currentProcessor, String[] processors)
+    {
+        for (int i = 0; (processors != null) && (i < processors.length); i++)
+        {
+            if (processors[i].equals(currentProcessor))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean checkOSVersions(String currentOSVersion, String[] osversions)
+        throws BundleException
+    {
+        for (int i = 0; (osversions != null) && (i < osversions.length); i++)
+        {
+            try
+            {
+                VersionRange range = VersionRange.parse(osversions[i]);
+                if (range.isInRange(new Version(currentOSVersion)))
+                {
+                    return true;
+                }
+            }
+            catch (Exception ex)
+            {
+                throw new BundleException(
+                    "Error evaluating osversion: " + osversions[i], ex);
+            }
+        }
+        return false;
+    }
+
+    private boolean checkLanguages(String currentLanguage, String[] languages)
+    {
+        for (int i = 0; (languages != null) && (i < languages.length); i++)
+        {
+            if (languages[i].equals(currentLanguage))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean checkSelectionFilter(Map configMap, String expr)
+        throws BundleException
+    {
+        // Get all framework properties
+        Dictionary dict = new Hashtable();
+        for (Iterator i = configMap.keySet().iterator(); i.hasNext(); )
+        {
+            Object key = i.next();
+            dict.put(key, configMap.get(key));
+        }
+        // Compute expression
+        try
+        {
+            FilterImpl filter = new FilterImpl(expr);
+            return filter.match(dict);
+        }
+        catch (Exception ex)
+        {
+            throw new BundleException(
+                "Error evaluating filter expression: " + expr, ex);
+        }
+    }
+
+    public static R4LibraryClause parse(Logger logger, String s)
+    {
+        try
+        {
+            if ((s == null) || (s.length() == 0))
+            {
+                return null;
+            }
+
+            if (s.equals(FelixConstants.BUNDLE_NATIVECODE_OPTIONAL))
+            {
+                return new R4LibraryClause(null, null, null, null, null, null);
+            }
+
+            // The tokens are separated by semicolons and may include
+            // any number of libraries along with one set of associated
+            // properties.
+            StringTokenizer st = new StringTokenizer(s, ";");
+            String[] libEntries = new String[st.countTokens()];
+            List osNameList = new ArrayList();
+            List osVersionList = new ArrayList();
+            List processorList = new ArrayList();
+            List languageList = new ArrayList();
+            String selectionFilter = null;
+            int libCount = 0;
+            while (st.hasMoreTokens())
+            {
+                String token = st.nextToken().trim();
+                if (token.indexOf('=') < 0)
+                {
+                    // Remove the slash, if necessary.
+                    libEntries[libCount] = (token.charAt(0) == '/')
+                        ? token.substring(1)
+                        : token;
+                    libCount++;
+                }
+                else
+                {
+                    // Check for valid native library properties; defined as
+                    // a property name, an equal sign, and a value.
+                    // NOTE: StringTokenizer can not be used here because
+                    // a value can contain one or more "=" too, e.g.,
+                    // selection-filter="(org.osgi.framework.windowing.system=gtk)"
+                    String property = null;
+                    String value = null;
+                    if (!(token.indexOf("=") > 1))
+                    {
+                        throw new IllegalArgumentException(
+                            "Bundle manifest native library entry malformed: " + token);
+                    }
+                    else
+                    {
+                        property = (token.substring(0, token.indexOf("=")))
+                            .trim().toLowerCase();
+                        value = (token.substring(token.indexOf("=") + 1, token
+                            .length())).trim();
+                    }
+
+                    // Values may be quoted, so remove quotes if present.
+                    if (value.charAt(0) == '"')
+                    {
+                        // This should always be true, otherwise the
+                        // value wouldn't be properly quoted, but we
+                        // will check for safety.
+                        if (value.charAt(value.length() - 1) == '"')
+                        {
+                            value = value.substring(1, value.length() - 1);
+                        }
+                        else
+                        {
+                            value = value.substring(1);
+                        }
+                    }
+                    // Add the value to its corresponding property list.
+                    if (property.equals(Constants.BUNDLE_NATIVECODE_OSNAME))
+                    {
+                        osNameList.add(normalizeOSName(value));
+                    }
+                    else if (property.equals(Constants.BUNDLE_NATIVECODE_OSVERSION))
+                    {
+                        osVersionList.add(normalizeOSVersion(value));
+                    }
+                    else if (property.equals(Constants.BUNDLE_NATIVECODE_PROCESSOR))
+                    {
+                        processorList.add(normalizeProcessor(value));
+                    }
+                    else if (property.equals(Constants.BUNDLE_NATIVECODE_LANGUAGE))
+                    {
+                        languageList.add(value);
+                    }
+                    else if (property.equals(Constants.SELECTION_FILTER_ATTRIBUTE))
+                    {
+// TODO: NATIVE - I believe we can have multiple selection filters too.
+                        selectionFilter = value;
+                    }
+                }
+            }
+
+            if (libCount == 0)
+            {
+                return null;
+            }
+
+            // Shrink lib file array.
+            String[] actualLibEntries = new String[libCount];
+            System.arraycopy(libEntries, 0, actualLibEntries, 0, libCount);
+            return new R4LibraryClause(
+                actualLibEntries,
+                (String[]) osNameList.toArray(new String[osNameList.size()]),
+                (String[]) processorList.toArray(new String[processorList.size()]),
+                (String[]) osVersionList.toArray(new String[osVersionList.size()]),
+                (String[]) languageList.toArray(new String[languageList.size()]),
+                selectionFilter);
+        }
+        catch (RuntimeException ex)
+        {
+            logger.log(Logger.LOG_ERROR,
+                "Error parsing native library header.", ex);
+            throw ex;
+        }
+    }
+
+    public static String normalizeOSName(String value)
+    {
+        value = value.toLowerCase();
+
+        if (value.startsWith("win"))
+        {
+            String os = "win";
+            if (value.indexOf("32") >= 0 || value.indexOf("*") >= 0)
+            {
+                os = "win32";
+            }
+            else if (value.indexOf("95") >= 0)
+            {
+                os = "windows95";
+            }
+            else if (value.indexOf("98") >= 0)
+            {
+                os = "windows98";
+            }
+            else if (value.indexOf("nt") >= 0)
+            {
+                os = "windowsnt";
+            }
+            else if (value.indexOf("2000") >= 0)
+            {
+                os = "windows2000";
+            }
+            else if (value.indexOf("xp") >= 0)
+            {
+                os = "windowsxp";
+            }
+            else if (value.indexOf("ce") >= 0)
+            {
+                os = "windowsce";
+            }
+            else if (value.indexOf("vista") >= 0)
+            {
+                os = "windowsvista";
+            }
+            return os;
+        }
+        else if (value.startsWith("linux"))
+        {
+            return "linux";
+        }
+        else if (value.startsWith("aix"))
+        {
+            return "aix";
+        }
+        else if (value.startsWith("digitalunix"))
+        {
+            return "digitalunix";
+        }
+        else if (value.startsWith("hpux"))
+        {
+            return "hpux";
+        }
+        else if (value.startsWith("irix"))
+        {
+            return "irix";
+        }
+        else if (value.startsWith("macos") || value.startsWith("mac os"))
+        {
+            return "macos";
+        }
+        else if (value.startsWith("netware"))
+        {
+            return "netware";
+        }
+        else if (value.startsWith("openbsd"))
+        {
+            return "openbsd";
+        }
+        else if (value.startsWith("netbsd"))
+        {
+            return "netbsd";
+        }
+        else if (value.startsWith("os2") || value.startsWith("os/2"))
+        {
+            return "os2";
+        }
+        else if (value.startsWith("qnx") || value.startsWith("procnto"))
+        {
+            return "qnx";
+        }
+        else if (value.startsWith("solaris"))
+        {
+            return "solaris";
+        }
+        else if (value.startsWith("sunos"))
+        {
+            return "sunos";
+        }
+        else if (value.startsWith("vxworks"))
+        {
+            return "vxworks";
+        }
+        return value;
+    }
+
+    public static String normalizeProcessor(String value)
+    {
+        value = value.toLowerCase();
+
+        if (value.startsWith("x86-64") || value.startsWith("amd64"))
+        {
+            return "x86-64";
+        }
+        else if (value.startsWith("x86") || value.startsWith("pentium")
+            || value.startsWith("i386") || value.startsWith("i486")
+            || value.startsWith("i586") || value.startsWith("i686"))
+        {
+            return "x86";
+        }
+        else if (value.startsWith("68k"))
+        {
+            return "68k";
+        }
+        else if (value.startsWith("arm"))
+        {
+            return "arm";
+        }
+        else if (value.startsWith("alpha"))
+        {
+            return "alpha";
+        }
+        else if (value.startsWith("ignite") || value.startsWith("psc1k"))
+        {
+            return "ignite";
+        }
+        else if (value.startsWith("mips"))
+        {
+            return "mips";
+        }
+        else if (value.startsWith("parisc"))
+        {
+            return "parisc";
+        }
+        else if (value.startsWith("powerpc") || value.startsWith("power")
+            || value.startsWith("ppc"))
+        {
+            return "powerpc";
+        }
+        else if (value.startsWith("sparc"))
+        {
+            return "sparc";
+        }
+        return value;
+    }
+
+    public static String normalizeOSVersion(String value)
+    {
+        // Header: 'Bundle-NativeCode', Parameter: 'osversion'
+        // Standardized 'osversion': major.minor.micro, only digits
+        String VERSION_DELIM = ".";
+        String QUALIFIER_DELIM = "-";
+        int major = 0;
+        int minor = 0;
+        int micro = 0;
+        try
+        {
+            StringTokenizer st = new StringTokenizer(value, VERSION_DELIM, true);
+            major = Integer.parseInt(st.nextToken());
+
+            if (st.hasMoreTokens())
+            {
+                st.nextToken(); // consume delimiter
+                minor = Integer.parseInt(st.nextToken());
+
+                if (st.hasMoreTokens())
+                {
+                    st.nextToken(); // consume delimiter
+                    String microStr = st.nextToken();
+                    if (microStr.indexOf(QUALIFIER_DELIM) < 0)
+                    {
+                        micro = Integer.parseInt(microStr);
+                    }
+                    else
+                    {
+                        micro = Integer.parseInt(microStr.substring(0, microStr
+                            .indexOf(QUALIFIER_DELIM)));
+                    }
+                }
+            }
+        }
+        catch (Exception ex)
+        {
+            return Version.emptyVersion.toString();
+        }
+
+        return major + "." + minor + "." + micro;
+    }
+}
\ No newline at end of file

Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4LibraryClause.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/sandbox/dosgi/felix/framework/src/main/java/org/apache/felix/framework/util/manifestparser/R4LibraryClause.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date



Mime
View raw message