Minor reorganization of manifest parsing.


git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@486841 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/SystemBundle.java b/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
index bcde5cb..29cc2df 100644
--- a/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
+++ b/framework/src/main/java/org/apache/felix/framework/SystemBundle.java
@@ -62,15 +62,15 @@
 
         // Get system property that specifies which class path
         // packages should be exported by the system bundle.
-        R4Package[] classPathPkgs = null;
+        R4Export[] classPathPkgs = null;
         try
         {
-            classPathPkgs = ManifestParser.parseImportExportHeader(
-                getFelix().getConfig().get(Constants.FRAMEWORK_SYSTEMPACKAGES));
+            classPathPkgs = (R4Export[]) ManifestParser.parseImportExportHeader(
+                getFelix().getConfig().get(Constants.FRAMEWORK_SYSTEMPACKAGES), true);
         }
         catch (Exception ex)
         {
-            classPathPkgs = new R4Package[0];
+            classPathPkgs = new R4Export[0];
             getFelix().getLogger().log(
                 Logger.LOG_ERROR,
                 "Error parsing system bundle export statement: "
@@ -84,7 +84,7 @@
         // Copy the class path exported packages.
         for (int i = 0; i < classPathPkgs.length; i++)
         {
-            m_exports[i] = new R4Export(classPathPkgs[i]);
+            m_exports[i] = classPathPkgs[i];
         }
 
         m_contentLoader = new SystemBundleContentLoader(getFelix().getLogger());
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Export.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Export.java
index c04e896..ff4e77a 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Export.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Export.java
@@ -30,11 +30,6 @@
     private String[][] m_includeFilter = null;
     private String[][] m_excludeFilter = null;
 
-    public R4Export(R4Package pkg)
-    {
-        this(pkg.getName(), pkg.getDirectives(), pkg.getAttributes());
-    }
-
     public R4Export(String name, R4Directive[] directives, R4Attribute[] attrs)
     {
         super(name, directives, attrs);
@@ -107,23 +102,12 @@
             }
         }
 
-        // Find the version, if present, and convert to Version.
-        // The version attribute value may be a String or a Version,
-        // since the value may be coming from an R4Export that already
-        // converted it to Version.
-        m_version = Version.emptyVersion;
+        // Cache version, if present.
         for (int i = 0; i < m_attrs.length; i++)
         {
             if (m_attrs[i].getName().equals(Constants.VERSION_ATTRIBUTE))
             {
-                String versionStr = (m_attrs[i].getValue() instanceof Version)
-                    ? ((Version) m_attrs[i].getValue()).toString()
-                    : (String) m_attrs[i].getValue();
-                m_version = Version.parseVersion(versionStr);
-                m_attrs[i] = new R4Attribute(
-                    m_attrs[i].getName(),
-                    m_version,
-                    m_attrs[i].isMandatory());
+                m_version = (Version) m_attrs[i].getValue();
                 break;
             }
         }
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Import.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Import.java
index 3fbc61b..acf7166 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Import.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Import.java
@@ -26,11 +26,6 @@
     private VersionRange m_versionRange = null;
     private boolean m_isOptional = false;
 
-    public R4Import(R4Package pkg)
-    {
-        this(pkg.getName(), pkg.getDirectives(), pkg.getAttributes());
-    }
-
     public R4Import(String name, R4Directive[] directives, R4Attribute[] attrs)
     {
         super(name, directives, attrs);
@@ -44,35 +39,16 @@
             }
         }
 
-        // Convert version and bundle version attributes to VersionRange.
-        // The attribute value may be a String or a Version, since the
-        // value may be coming from an R4Export that already converted
-        // it to Version.
+        // Cache version and version range, if present.
         m_versionRange = VersionRange.parse(Version.emptyVersion.toString());
         m_version = m_versionRange.getLow();
         for (int i = 0; i < m_attrs.length; i++)
         {
             if (m_attrs[i].getName().equals(Constants.VERSION_ATTRIBUTE))
             {
-                String versionStr = (m_attrs[i].getValue() instanceof Version)
-                    ? ((Version) m_attrs[i].getValue()).toString()
-                    : (String) m_attrs[i].getValue();
-                m_versionRange = VersionRange.parse(versionStr);
+                m_versionRange = (VersionRange) m_attrs[i].getValue();
                 m_version = m_versionRange.getLow();
-                m_attrs[i] = new R4Attribute(
-                    m_attrs[i].getName(),
-                    m_versionRange,
-                    m_attrs[i].isMandatory());
-            }
-            else if (m_attrs[i].getName().equals(Constants.BUNDLE_VERSION_ATTRIBUTE))
-            {
-                String versionStr = (m_attrs[i].getValue() instanceof Version)
-                    ? ((Version) m_attrs[i].getValue()).toString()
-                    : (String) m_attrs[i].getValue();
-                m_attrs[i] = new R4Attribute(
-                    m_attrs[i].getName(),
-                    VersionRange.parse(versionStr),
-                    m_attrs[i].isMandatory());
+                break;
             }
         }
     }
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
index 5620e87..06dee44 100755
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -56,7 +56,6 @@
         return m_version;
     }
 
-
     public String toString()
     {
         String msg = getName();
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/VersionRange.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/VersionRange.java
index 86dc689..0dfd1cb 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/VersionRange.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/VersionRange.java
@@ -109,6 +109,7 @@
                 sb.append(',');
                 sb.append(m_high.toString());
                 sb.append(m_isHighInclusive ? ']' : ')');
+                m_toString = sb.toString();
             }
             else
             {
diff --git a/framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java b/framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java
index fdd2ec3..bdb2b0d 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java
@@ -110,30 +110,33 @@
         //
 
         // Get export packages from bundle manifest.
-        R4Package[] pkgs = parseImportExportHeader(
-            (String) headerMap.get(Constants.EXPORT_PACKAGE));
+        m_exports = (R4Export[]) parseImportExportHeader(
+            (String) headerMap.get(Constants.EXPORT_PACKAGE), true);
 
         // Create non-duplicated export array.
         dupeMap.clear();
-        for (int pkgIdx = 0; pkgIdx < pkgs.length; pkgIdx++)
+        for (int pkgIdx = 0; pkgIdx < m_exports.length; pkgIdx++)
         {
             // Verify that the named package has not already been declared.
-            if (dupeMap.get(pkgs[pkgIdx].getName()) == null)
+            if (dupeMap.get(m_exports[pkgIdx].getName()) == null)
             {
                 // Verify that java.* packages are not exported.
-                if (pkgs[pkgIdx].getName().startsWith("java."))
+                if (m_exports[pkgIdx].getName().startsWith("java."))
                 {
                     throw new BundleException(
-                        "Exporting java.* packages not allowed: " + pkgs[pkgIdx].getName());
+                        "Exporting java.* packages not allowed: "
+                        + m_exports[pkgIdx].getName());
                 }
-                dupeMap.put(pkgs[pkgIdx].getName(), new R4Export(pkgs[pkgIdx]));
+                dupeMap.put(m_exports[pkgIdx].getName(), m_exports[pkgIdx]);
             }
             else
             {
                 // TODO: FRAMEWORK - Exports can be duplicated, so fix this.
-                m_logger.log(Logger.LOG_WARNING, "Duplicate export - " + pkgs[pkgIdx].getName());
+                m_logger.log(Logger.LOG_WARNING, "Duplicate export - "
+                    + m_exports[pkgIdx].getName());
             }
         }
+        // This following line won't be necessary once duplicate exports are supported.
         m_exports = (R4Export[]) dupeMap.values().toArray(new R4Export[dupeMap.size()]);
 
         //
@@ -167,54 +170,53 @@
         //
 
         // Get import packages from bundle manifest.
-        pkgs = parseImportExportHeader(
-            (String) headerMap.get(Constants.IMPORT_PACKAGE));
+        m_imports = (R4Import[]) parseImportExportHeader(
+            (String) headerMap.get(Constants.IMPORT_PACKAGE), false);
 
         // Create non-duplicated import array.
         dupeMap.clear();
-        for (int pkgIdx = 0; pkgIdx < pkgs.length; pkgIdx++)
+        for (int pkgIdx = 0; pkgIdx < m_imports.length; pkgIdx++)
         {
             // Verify that the named package has not already been declared.
-            if (dupeMap.get(pkgs[pkgIdx].getName()) == null)
+            if (dupeMap.get(m_imports[pkgIdx].getName()) == null)
             {
                 // Verify that java.* packages are not imported.
-                if (pkgs[pkgIdx].getName().startsWith("java."))
+                if (m_imports[pkgIdx].getName().startsWith("java."))
                 {
                     throw new BundleException(
-                        "Importing java.* packages not allowed: " + pkgs[pkgIdx].getName());
+                        "Importing java.* packages not allowed: "
+                        + m_imports[pkgIdx].getName());
                 }
-                dupeMap.put(pkgs[pkgIdx].getName(), new R4Import(pkgs[pkgIdx]));
+                dupeMap.put(m_imports[pkgIdx].getName(), m_imports[pkgIdx]);
             }
             else
             {
                 throw new BundleException(
-                    "Duplicate import - " + pkgs[pkgIdx].getName());
+                    "Duplicate import - " + m_imports[pkgIdx].getName());
             }
         }
-        m_imports = (R4Import[]) dupeMap.values().toArray(new R4Import[dupeMap.size()]);
 
         //
         // Parse DynamicImport-Package.
         //
 
         // Get dynamic import packages from bundle manifest.
-        pkgs = parseImportExportHeader(
-            (String) headerMap.get(Constants.DYNAMICIMPORT_PACKAGE));
+        m_dynamics = (R4Import[]) parseImportExportHeader(
+            (String) headerMap.get(Constants.DYNAMICIMPORT_PACKAGE), false);
 
-        // Dynamic imports can have duplicates, so just create an array.
+        // Dynamic imports can have duplicates, so just check for import
+        // of java.*.
         List dynList = new ArrayList();
-        for (int pkgIdx = 0; pkgIdx < pkgs.length; pkgIdx++)
+        for (int pkgIdx = 0; pkgIdx < m_dynamics.length; pkgIdx++)
         {
             // Verify that java.* packages are not imported.
-            if (pkgs[pkgIdx].getName().startsWith("java."))
+            if (m_dynamics[pkgIdx].getName().startsWith("java."))
             {
                 throw new BundleException(
                     "Dynamically importing java.* packages not allowed: "
-                    + pkgs[pkgIdx].getName());
+                    + m_dynamics[pkgIdx].getName());
             }
-            dynList.add(new R4Import(pkgs[pkgIdx]));
         }
-        m_dynamics = (R4Import[]) dynList.toArray(new R4Import[dynList.size()]);
 
         //
         // Parse Bundle-NativeCode.
@@ -579,7 +581,23 @@
         {
             if (map.get(m_exports[i].getName()) == null)
             {
-                map.put(m_exports[i].getName(), new R4Import(m_exports[i]));
+                // Convert Version to VersionRange.
+                R4Attribute[] attrs = (R4Attribute[]) m_exports[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_exports[i].getName(),
+                    new R4Import(
+                        m_exports[i].getName(),
+                        m_exports[i].getDirectives(),
+                        attrs));
             }
         }
         m_imports =
@@ -663,7 +681,7 @@
         }
     }
 
-    public static R4Package[] parseImportExportHeader(String header)
+    public static R4Package[] parseImportExportHeader(String header, boolean export)
     {
         Object[][][] clauses = parseStandardHeader(header);
 
@@ -699,21 +717,45 @@
                 }
             }
     
-            // Ensure that only the "version" attribute is used
-            if (sv != null)
+            // Ensure that only the "version" attribute is used and convert
+            // it to the appropriate type.
+            if ((v != null) || (sv != null))
             {
                 attrMap.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
-                if (v == null)
+                v = (v == null) ? sv : v;
+                if (export)
                 {
                     attrMap.put(Constants.VERSION_ATTRIBUTE,
                         new R4Attribute(
                             Constants.VERSION_ATTRIBUTE,
-                            sv.getValue(),
-                            sv.isMandatory()));
-                    clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX] =
-                        attrMap.values().toArray(new R4Attribute[attrMap.size()]);
+                            Version.parseVersion(v.getValue().toString()),
+                            v.isMandatory()));
+                }
+                else
+                {
+                    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 Version.
+            // Only imports can specify this attribue.
+            v = (R4Attribute) attrMap.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+            if (!export && (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 packages.
@@ -724,14 +766,28 @@
                 pathIdx < clauses[clauseIdx][CLAUSE_PATHS_INDEX].length;
                 pathIdx++)
             {
-                pkgList.add(
-                    new R4Package(
-                        (String) clauses[clauseIdx][CLAUSE_PATHS_INDEX][pathIdx],
-                        (R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
-                        (R4Attribute[]) clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX]));
+                if (export)
+                {
+                    pkgList.add(
+                        new R4Export(
+                            (String) clauses[clauseIdx][CLAUSE_PATHS_INDEX][pathIdx],
+                            (R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
+                            (R4Attribute[]) clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX]));
+                }
+                else
+                {
+                    pkgList.add(
+                        new R4Import(
+                            (String) clauses[clauseIdx][CLAUSE_PATHS_INDEX][pathIdx],
+                            (R4Directive[]) clauses[clauseIdx][CLAUSE_DIRECTIVES_INDEX],
+                            (R4Attribute[]) clauses[clauseIdx][CLAUSE_ATTRIBUTES_INDEX]));
+                }
             }
         }
-        return (R4Package[]) pkgList.toArray(new R4Package[pkgList.size()]);
+
+        return (export)
+            ? (R4Package[]) pkgList.toArray(new R4Export[pkgList.size()])
+            : (R4Package[]) pkgList.toArray(new R4Import[pkgList.size()]);
     }
 
     public static final int CLAUSE_PATHS_INDEX = 0;