Moved manifest parsing out of Felix.java and into its own utility class.
Also strengthened the manifest parsing checks and verifications.
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@424343 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
index f371004..97e1f00 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -2666,97 +2666,15 @@
private IModule createModule(long targetId, int revision, Map headerMap)
throws Exception
{
- // Get the manifest version.
- String manifestVersion = (String) headerMap.get(FelixConstants.BUNDLE_MANIFESTVERSION);
- manifestVersion = (manifestVersion == null) ? "1" : manifestVersion;
- if (!manifestVersion.equals("1") && !manifestVersion.equals("2"))
+ ManifestParser mp = new ManifestParser(m_logger, headerMap);
+
+ // Verify that the bundle symbolic name and version is unique.
+ if (mp.getVersion().equals("2"))
{
- throw new BundleException("Unknown 'Bundle-ManifestVersion' value: " + manifestVersion);
- }
+ String bundleVersion = mp.get(FelixConstants.BUNDLE_VERSION);
+ bundleVersion = (bundleVersion == null) ? "0.0.0" : bundleVersion;
+ String symName = (String) mp.get(FelixConstants.BUNDLE_SYMBOLICNAME);
- // Create map to check for duplicate imports/exports.
- Map dupeMap = new HashMap();
-
- // Get export packages from bundle manifest.
- R4Package[] pkgs = R4Package.parseImportOrExportHeader(
- (String) headerMap.get(Constants.EXPORT_PACKAGE));
-
- // Create non-duplicated export array.
- dupeMap.clear();
- for (int i = 0; i < pkgs.length; i++)
- {
- if (dupeMap.get(pkgs[i].getName()) == null)
- {
- dupeMap.put(pkgs[i].getName(), new R4Export(pkgs[i]));
- }
- else
- {
- // TODO: FRAMEWORK - Exports can be duplicated, so fix this.
- m_logger.log(Logger.LOG_WARNING,
- "Duplicate export - " + pkgs[i].getName());
- }
- }
- R4Export[] exports =
- (R4Export[]) dupeMap.values().toArray(new R4Export[dupeMap.size()]);
-
- // Get import packages from bundle manifest.
- pkgs = R4Package.parseImportOrExportHeader(
- (String) headerMap.get(Constants.IMPORT_PACKAGE));
-
- // Create non-duplicated import array.
- dupeMap.clear();
- for (int i = 0; i < pkgs.length; i++)
- {
- if (dupeMap.get(pkgs[i].getName()) == null)
- {
- dupeMap.put(pkgs[i].getName(), new R4Import(pkgs[i]));
- }
- else
- {
- // TODO: FRAMEWORK - Determine if we should error here.
- m_logger.log(Logger.LOG_WARNING,
- "Duplicate import - " + pkgs[i].getName());
- }
- }
- R4Import[] imports =
- (R4Import[]) dupeMap.values().toArray(new R4Import[dupeMap.size()]);
-
- // Get dynamic import packages from bundle manifest.
- pkgs = R4Package.parseImportOrExportHeader(
- (String) headerMap.get(Constants.DYNAMICIMPORT_PACKAGE));
-
- // Create non-duplicated dynamic import array.
- dupeMap.clear();
- for (int i = 0; i < pkgs.length; i++)
- {
- if (dupeMap.get(pkgs[i].getName()) == null)
- {
- dupeMap.put(pkgs[i].getName(), new R4Import(pkgs[i]));
- }
- else
- {
- // TODO: FRAMEWORK - Determine if we should error here.
- m_logger.log(Logger.LOG_WARNING,
- "Duplicate import - " + pkgs[i].getName());
- }
- }
- R4Import[] dynamics =
- (R4Import[]) dupeMap.values().toArray(new R4Import[dupeMap.size()]);
-
- // Do some validity checking on bundles with R4 headers.
-// TODO: FRAMEWORK - Perhaps these verifications and conversions can be done more efficiently.
- if (manifestVersion.equals("2"))
- {
- // Verify that bundle symbolic name is specified.
- String targetSym = (String) headerMap.get(FelixConstants.BUNDLE_SYMBOLICNAME);
- if (targetSym == null)
- {
- throw new BundleException("R4 bundle manifests must include bundle symbolic name.");
- }
-
- // Verify that the bundle symbolic name and version is unique.
- String targetVer = (String) headerMap.get(FelixConstants.BUNDLE_VERSION);
- targetVer = (targetVer == null) ? "0.0.0" : targetVer;
Bundle[] bundles = getBundles();
for (int i = 0; (bundles != null) && (i < bundles.length); i++)
{
@@ -2766,144 +2684,11 @@
String ver = (String) ((BundleImpl) bundles[i])
.getInfo().getCurrentHeader().get(Constants.BUNDLE_VERSION);
ver = (ver == null) ? "0.0.0" : ver;
- if (targetSym.equals(sym) && targetVer.equals(ver) && (targetId != id))
+ if (symName.equals(sym) && bundleVersion.equals(ver) && (targetId != id))
{
throw new BundleException("Bundle symbolic name and version are not unique.");
}
}
-
- // Need to add symbolic name and bundle version to all R4 exports.
- for (int i = 0; (exports != null) && (i < exports.length); i++)
- {
- R4Attribute[] attrs = exports[i].getAttributes();
- R4Attribute[] newAttrs = new R4Attribute[attrs.length + 2];
- System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
- newAttrs[attrs.length] = new R4Attribute(
- Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, targetSym, false);
- newAttrs[attrs.length + 1] = new R4Attribute(
- Constants.BUNDLE_VERSION_ATTRIBUTE, targetVer, false);
- exports[i] = new R4Export(
- exports[i].getName(), exports[i].getDirectives(), newAttrs);
- }
- }
- // Do some validity checking and conversion on bundles with R3 headers.
- else if (manifestVersion.equals("1"))
- {
- // Check to make sure that R3 bundles have only specified
- // the 'specification-version' attribute and no directives
- // on their exports.
- for (int i = 0; (exports != null) && (i < exports.length); i++)
- {
- if (exports[i].getDirectives().length != 0)
- {
- throw new BundleException("R3 exports cannot contain directives.");
- }
- // 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 ((exports[i].getAttributes().length > 1) ||
- ((exports[i].getAttributes().length == 1) &&
- (!exports[i].getAttributes()[0].getName().equals(FelixConstants.VERSION_ATTRIBUTE))))
- {
- throw new BundleException(
- "Export does not conform to R3 syntax: " + exports[i]);
- }
- }
-
- // Check to make sure that R3 bundles have only specified
- // the 'specification-version' attribute and no directives
- // on their imports.
- for (int i = 0; (imports != null) && (i < imports.length); i++)
- {
- if (imports[i].getDirectives().length != 0)
- {
- throw new BundleException("R3 imports cannot contain directives.");
- }
- // 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 ((imports[i].getVersionHigh() != null) ||
- (imports[i].getAttributes().length > 1) ||
- ((imports[i].getAttributes().length == 1) &&
- (!imports[i].getAttributes()[0].getName().equals(FelixConstants.VERSION_ATTRIBUTE))))
- {
- throw new BundleException(
- "Import does not conform to R3 syntax: " + imports[i]);
- }
- }
-
- // Since all R3 exports imply an import, add a corresponding
- // import for each existing export. Create non-duplicated import array.
- dupeMap.clear();
- // Add existing imports.
- for (int i = 0; i < imports.length; i++)
- {
- dupeMap.put(imports[i].getName(), imports[i]);
- }
- // Add import for each export.
- for (int i = 0; i < exports.length; i++)
- {
- if (dupeMap.get(exports[i].getName()) == null)
- {
- dupeMap.put(exports[i].getName(), new R4Import(exports[i]));
- }
- }
- imports =
- (R4Import[]) dupeMap.values().toArray(new R4Import[dupeMap.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; (imports != null) && (i < imports.length); i++)
- {
- usesValue = usesValue
- + ((usesValue.length() > 0) ? "," : "")
- + imports[i].getName();
- }
- R4Directive uses = new R4Directive(
- FelixConstants.USES_DIRECTIVE, usesValue);
- for (int i = 0; (exports != null) && (i < exports.length); i++)
- {
- exports[i] = new R4Export(
- exports[i].getName(),
- new R4Directive[] { uses },
- exports[i].getAttributes());
- }
-
- // Check to make sure that R3 bundles have no attributes or
- // directives on their dynamic imports.
- for (int i = 0; (dynamics != null) && (i < dynamics.length); i++)
- {
- if (dynamics[i].getDirectives().length != 0)
- {
- throw new BundleException("R3 dynamic imports cannot contain directives.");
- }
- if (dynamics[i].getAttributes().length != 0)
- {
- throw new BundleException("R3 dynamic imports cannot contain attributes.");
- }
- }
- }
-
- // Get native library entry names for module library sources.
- R4LibraryHeader[] libraryHeaders =
- Util.parseLibraryStrings(
- m_logger,
- Util.parseDelimitedString(
- (String) headerMap.get(Constants.BUNDLE_NATIVECODE), ","));
- R4Library[] libraries = new R4Library[libraryHeaders.length];
- for (int i = 0; i < libraries.length; i++)
- {
- libraries[i] = new R4Library(
- m_logger, m_cache, targetId, revision,
- getProperty(Constants.FRAMEWORK_OS_NAME),
- getProperty(Constants.FRAMEWORK_PROCESSOR),
- libraryHeaders[i]);
}
// Now that we have all of the metadata associated with the
@@ -2916,11 +2701,18 @@
// First, create the module.
IModule module = m_factory.createModule(
Long.toString(targetId) + "." + Integer.toString(revision));
+
// Attach the R4 search policy metadata to the module.
- m_policyCore.setExports(module, exports);
- m_policyCore.setImports(module, imports);
- m_policyCore.setDynamicImports(module, dynamics);
- m_policyCore.setLibraries(module, libraries);
+ m_policyCore.setExports(module, mp.getExports());
+ m_policyCore.setImports(module, mp.getImports());
+ m_policyCore.setDynamicImports(module, mp.getDynamicImports());
+ m_policyCore.setLibraries(module,
+ mp.getLibraries(
+ m_cache,
+ targetId,
+ revision,
+ m_config.get(Constants.FRAMEWORK_OS_NAME),
+ m_config.get(Constants.FRAMEWORK_PROCESSOR)));
// Create the content loader associated with the module archive.
IContentLoader contentLoader = new ContentLoaderImpl(
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
index 827aae2..95e51b7 100755
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Package.java
@@ -16,11 +16,11 @@
*/
package org.apache.felix.framework.searchpolicy;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.framework.util.Util;
+import org.osgi.framework.Constants;
import org.osgi.framework.Version;
public class R4Package
@@ -129,9 +129,8 @@
}
// Parse the directives/attributes.
- R4Directive[] dirs = new R4Directive[pieces.length - pkgCount];
- R4Attribute[] attrs = new R4Attribute[pieces.length - pkgCount];
- int dirCount = 0, attrCount = 0;
+ Map dirsMap = new HashMap();
+ Map attrsMap = new HashMap();
int idx = -1;
String sep = null;
for (int pieceIdx = pkgCount; pieceIdx < pieces.length; pieceIdx++)
@@ -165,20 +164,49 @@
// Save the directive/attribute in the appropriate array.
if (sep.equals(FelixConstants.DIRECTIVE_SEPARATOR))
{
- dirs[dirCount++] = new R4Directive(key, value);
+ // Check for duplicates.
+ if (dirsMap.get(key) != null)
+ {
+ throw new IllegalArgumentException(
+ "Duplicate directive: " + key);
+ }
+ dirsMap.put(key, new R4Directive(key, value));
}
else
{
- attrs[attrCount++] = new R4Attribute(key, value, false);
+ // Check for duplicates.
+ if (attrsMap.get(key) != null)
+ {
+ throw new IllegalArgumentException(
+ "Duplicate attribute: " + key);
+ }
+ attrsMap.put(key, new R4Attribute(key, value, false));
}
}
- // Shrink directive array.
- R4Directive[] dirsFinal = new R4Directive[dirCount];
- System.arraycopy(dirs, 0, dirsFinal, 0, dirCount);
- // Shrink attribute array.
- R4Attribute[] attrsFinal = new R4Attribute[attrCount];
- System.arraycopy(attrs, 0, attrsFinal, 0, attrCount);
+ // Check for "version" and "specification-version" attributes
+ // and verify they are the same if both are specified.
+ R4Attribute v = (R4Attribute) attrsMap.get(Constants.VERSION_ATTRIBUTE);
+ R4Attribute sv = (R4Attribute) attrsMap.get(Constants.PACKAGE_SPECIFICATION_VERSION);
+ if ((v != null) && (sv != null))
+ {
+ // Verify they are equal.
+ if (!v.getValue().trim().equals(sv.getValue().trim()))
+ {
+ throw new IllegalArgumentException(
+ "Both version and specificat-version are specified, but they are not equal.");
+ }
+ // Remove spec-version since it isn't needed.
+ attrsMap.remove(Constants.PACKAGE_SPECIFICATION_VERSION);
+ }
+
+ // 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 package attributes for each package and
// set directives/attributes. Add each package to
@@ -186,7 +214,7 @@
R4Package[] pkgs = new R4Package[pkgCount];
for (int pkgIdx = 0; pkgIdx < pkgCount; pkgIdx++)
{
- pkgs[pkgIdx] = new R4Package(pieces[pkgIdx], dirsFinal, attrsFinal);
+ pkgs[pkgIdx] = new R4Package(pieces[pkgIdx], dirs, attrs);
completeList.add(pkgs[pkgIdx]);
}
}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java
new file mode 100644
index 0000000..d064c50
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.cache.BundleCache;
+import org.apache.felix.framework.searchpolicy.*;
+import org.osgi.framework.*;
+
+public class ManifestParser
+{
+ private Logger m_logger = null;
+ private Map m_headerMap = null;
+ private R4Export[] m_exports = null;
+ private R4Import[] m_imports = null;
+ private R4Import[] m_dynamics = null;
+ private R4LibraryHeader[] m_libraryHeaders = null;
+
+ public ManifestParser(Logger logger, Map headerMap) throws BundleException
+ {
+ m_logger = logger;
+ m_headerMap = headerMap;
+
+ // Verify that only manifest version 2 is specified.
+ String manifestVersion = get(Constants.BUNDLE_MANIFESTVERSION);
+ if ((manifestVersion != null) && !manifestVersion.equals("2"))
+ {
+ throw new BundleException(
+ "Unknown 'Bundle-ManifestVersion' value: " + manifestVersion);
+ }
+
+ // Verify bundle version syntax.
+ Version.parseVersion(get(Constants.BUNDLE_VERSION));
+
+ // Create map to check for duplicate imports/exports.
+ Map dupeMap = new HashMap();
+
+ //
+ // Parse Export-Package.
+ //
+
+ // Get export packages from bundle manifest.
+ R4Package[] pkgs = R4Package.parseImportOrExportHeader(
+ (String) headerMap.get(Constants.EXPORT_PACKAGE));
+
+ // Create non-duplicated export array.
+ dupeMap.clear();
+ for (int i = 0; i < pkgs.length; i++)
+ {
+ if (dupeMap.get(pkgs[i].getName()) == null)
+ {
+ // Verify that java.* packages are not exported.
+ if (pkgs[i].getName().startsWith("java."))
+ {
+ throw new BundleException(
+ "Exporting java.* packages not allowed: " + pkgs[i].getName());
+ }
+ dupeMap.put(pkgs[i].getName(), new R4Export(pkgs[i]));
+ }
+ else
+ {
+ // TODO: FRAMEWORK - Exports can be duplicated, so fix this.
+ m_logger.log(Logger.LOG_WARNING,
+ "Duplicate export - " + pkgs[i].getName());
+ }
+ }
+ m_exports = (R4Export[]) dupeMap.values().toArray(new R4Export[dupeMap.size()]);
+
+ //
+ // Parse Import-Package.
+ //
+
+ // Get import packages from bundle manifest.
+ pkgs = R4Package.parseImportOrExportHeader(
+ (String) headerMap.get(Constants.IMPORT_PACKAGE));
+
+ // Create non-duplicated import array.
+ dupeMap.clear();
+ for (int i = 0; i < pkgs.length; i++)
+ {
+ if (dupeMap.get(pkgs[i].getName()) == null)
+ {
+ // Verify that java.* packages are not imported.
+ if (pkgs[i].getName().startsWith("java."))
+ {
+ throw new BundleException(
+ "Importing java.* packages not allowed: " + pkgs[i].getName());
+ }
+ dupeMap.put(pkgs[i].getName(), new R4Import(pkgs[i]));
+ }
+ else
+ {
+ throw new BundleException(
+ "Duplicate import - " + pkgs[i].getName());
+ }
+ }
+ m_imports = (R4Import[]) dupeMap.values().toArray(new R4Import[dupeMap.size()]);
+
+ //
+ // Parse DynamicImport-Package.
+ //
+
+ // Get dynamic import packages from bundle manifest.
+ pkgs = R4Package.parseImportOrExportHeader(
+ (String) headerMap.get(Constants.DYNAMICIMPORT_PACKAGE));
+
+ // Dynamic imports can have duplicates, so just create an array.
+ m_dynamics = new R4Import[pkgs.length];
+ for (int i = 0; i < pkgs.length; i++)
+ {
+ m_dynamics[i] = new R4Import(pkgs[i]);
+ }
+
+ //
+ // Parse Bundle-NativeCode.
+ //
+
+ // Get native library entry names for module library sources.
+ m_libraryHeaders =
+ Util.parseLibraryStrings(
+ m_logger,
+ Util.parseDelimitedString(get(Constants.BUNDLE_NATIVECODE), ","));
+
+ // Do final checks and normalization of manifest.
+ if (getVersion().equals("2"))
+ {
+ checkAndNormalizeR4();
+ }
+ else
+ {
+ checkAndNormalizeR3();
+ }
+ }
+
+ public String get(String key)
+ {
+ return (String) m_headerMap.get(key);
+ }
+
+ public String getVersion()
+ {
+ String manifestVersion = get(Constants.BUNDLE_MANIFESTVERSION);
+ return (manifestVersion == null) ? "1" : manifestVersion;
+ }
+
+ public R4Export[] getExports()
+ {
+ return m_exports;
+ }
+
+ public R4Import[] getImports()
+ {
+ return m_imports;
+ }
+
+ public R4Import[] getDynamicImports()
+ {
+ return m_dynamics;
+ }
+
+ public R4LibraryHeader[] getLibraryHeaders()
+ {
+ return m_libraryHeaders;
+ }
+
+ public R4Library[] getLibraries(
+ BundleCache cache, long id, int revision, String osName, String processor)
+ {
+ R4Library[] libraries = new R4Library[m_libraryHeaders.length];
+ for (int i = 0; i < libraries.length; i++)
+ {
+ libraries[i] = new R4Library(
+ m_logger, cache, id, revision, osName, processor, m_libraryHeaders[i]);
+ }
+ return libraries;
+ }
+
+ 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.
+ for (int i = 0; (m_exports != null) && (i < m_exports.length); i++)
+ {
+ if (m_exports[i].getDirectives().length != 0)
+ {
+ throw new BundleException("R3 exports cannot contain directives.");
+ }
+ // 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 ((m_exports[i].getAttributes().length > 1) ||
+ ((m_exports[i].getAttributes().length == 1) &&
+ (!m_exports[i].getAttributes()[0].getName().equals(Constants.VERSION_ATTRIBUTE))))
+ {
+ throw new BundleException(
+ "Export does not conform to R3 syntax: " + m_exports[i]);
+ }
+ }
+
+ // Check to make sure that R3 bundles have only specified
+ // the 'specification-version' attribute and no directives
+ // on their imports.
+ for (int i = 0; (m_imports != null) && (i < m_imports.length); i++)
+ {
+ if (m_imports[i].getDirectives().length != 0)
+ {
+ throw new BundleException("R3 imports cannot contain directives.");
+ }
+ // 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 ((m_imports[i].getVersionHigh() != null) ||
+ (m_imports[i].getAttributes().length > 1) ||
+ ((m_imports[i].getAttributes().length == 1) &&
+ (!m_imports[i].getAttributes()[0].getName().equals(Constants.VERSION_ATTRIBUTE))))
+ {
+ throw new BundleException(
+ "Import does not conform to R3 syntax: " + m_imports[i]);
+ }
+ }
+
+ // Since all R3 exports imply an import, add a corresponding
+ // import for each existing export. Create non-duplicated import array.
+ Map map = new HashMap();
+ // Add existing imports.
+ for (int i = 0; i < m_imports.length; i++)
+ {
+ map.put(m_imports[i].getName(), m_imports[i]);
+ }
+ // Add import for each export.
+ for (int i = 0; i < m_exports.length; i++)
+ {
+ if (map.get(m_exports[i].getName()) == null)
+ {
+ map.put(m_exports[i].getName(), new R4Import(m_exports[i]));
+ }
+ }
+ m_imports =
+ (R4Import[]) map.values().toArray(new R4Import[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_imports != null) && (i < m_imports.length); i++)
+ {
+ usesValue = usesValue
+ + ((usesValue.length() > 0) ? "," : "")
+ + m_imports[i].getName();
+ }
+ R4Directive uses = new R4Directive(
+ Constants.USES_DIRECTIVE, usesValue);
+ for (int i = 0; (m_exports != null) && (i < m_exports.length); i++)
+ {
+ m_exports[i] = new R4Export(
+ m_exports[i].getName(),
+ new R4Directive[] { uses },
+ m_exports[i].getAttributes());
+ }
+
+ // Check to make sure that R3 bundles have no attributes or
+ // directives on their dynamic imports.
+ for (int i = 0; (m_dynamics != null) && (i < m_dynamics.length); i++)
+ {
+ if (m_dynamics[i].getDirectives().length != 0)
+ {
+ throw new BundleException("R3 dynamic imports cannot contain directives.");
+ }
+ if (m_dynamics[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 = get(Constants.BUNDLE_SYMBOLICNAME);
+ if (symName == null)
+ {
+ throw new BundleException("R4 bundle manifests must include bundle symbolic name.");
+ }
+
+ // Verify that there are no duplicate directives.
+ Map map = new HashMap();
+ for (int i = 0; (m_exports != null) && (i < m_exports.length); i++)
+ {
+ String targetVer = get(Constants.BUNDLE_VERSION);
+ targetVer = (targetVer == null) ? "0.0.0" : targetVer;
+
+ R4Attribute[] attrs = m_exports[i].getAttributes();
+ 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, targetVer, false);
+ m_exports[i] = new R4Export(
+ m_exports[i].getName(), m_exports[i].getDirectives(), newAttrs);
+ }
+
+ // Need to add symbolic name and bundle version to all R4 exports.
+ for (int i = 0; (m_exports != null) && (i < m_exports.length); i++)
+ {
+ String targetVer = get(Constants.BUNDLE_VERSION);
+ targetVer = (targetVer == null) ? "0.0.0" : targetVer;
+
+ R4Attribute[] attrs = m_exports[i].getAttributes();
+ 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, targetVer, false);
+ m_exports[i] = new R4Export(
+ m_exports[i].getName(), m_exports[i].getDirectives(), newAttrs);
+ }
+ }
+}
\ No newline at end of file