Merge
authorksrini
Mon Aug 04 14:55:36 2008 -0700 (15 months ago)
changeset 454b407b90b3793
parent 453519e2024e997
parent 4490c79f440d0ae
child 457e92973a92c3b
Merge
src/share/classes/sun/module/repository/MetadataXMLWriter.java
src/share/classes/sun/module/repository/URLModuleInfo.java
--- a/make/java/module/Makefile Fri Aug 01 08:19:12 2008 -0700
+++ b/make/java/module/Makefile Mon Aug 04 14:55:36 2008 -0700
@@ -58,14 +58,14 @@ SYSTEM_EXTENSION_DIR = $(LIBDIR)/module/
#
# Resources
#
-REPOSITORY_METADATA_XML = $(PKGDIR)/RepositoryMetadata.xml
+REPOSITORY_METADATA_XML = $(PKGDIR)/repository-metadata-schema.xml
#
# Rules
#
include $(BUILDDIR)/common/Rules.gmk
-all: classes repository_metadata_xml
+all: classes repository_metadata_schema_xml
build: properties visibilitypolicy importoverridepolicy repositoryprops systemextensiondir
@@ -99,9 +99,9 @@ clean clobber:: .delete.classlist
$(RM) -r $(CLASSBINDIR)/java/module
$(RM) $(PROPS_BUILD) $(VISIBILITY_POLICY_BUILD) $(IMPORT_OVERRIDE_POLICY_BUILD) $(REPOSITORY_PROPS_BUILD)
-repository_metadata_xml: $(CLASSBINDIR)/$(REPOSITORY_METADATA_XML)
+repository_metadata_schema_xml: $(CLASSBINDIR)/$(REPOSITORY_METADATA_XML)
$(CLASSBINDIR)/%.xml: $(SHARE_SRC)/classes/%.xml
$(install-file)
-.PHONY: repository_metadata_xml
+.PHONY: repository_metadata_schema_xml
--- a/src/share/classes/java/module/ModuleDefinition.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/java/module/ModuleDefinition.java Mon Aug 04 14:55:36 2008 -0700
@@ -111,10 +111,22 @@ public abstract class ModuleDefinition {
public abstract class ModuleDefinition {
/**
- * Constructor used by subclasses.
+ * Creates a {@code ModuleDefinition} instance.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's {@code checkPermission} method with
+ * {@code ModuleSystemPermission("createModuleDefinition")} permission to
+ * ensure it's ok to create a module definition.
+ *
+ * @throws SecurityException if a security manager exists and its
+ * {@code checkPermission} method denies access to create a new
+ * module definition.
*/
protected ModuleDefinition() {
- // empty
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new ModuleSystemPermission("createModuleDefinition"));
+ }
}
/**
@@ -187,6 +199,23 @@ public abstract class ModuleDefinition {
* @return the {@code ModuleSystem} object.
*/
public abstract ModuleSystem getModuleSystem();
+
+ /**
+ * Returns the module archive information that is associated with this
+ * {@code ModuleDefinition}.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's {@code checkPermission} method with a
+ * {@code ModuleSystemPermission("getModuleArchiveInfo")}
+ * permission to ensure it's ok to access the module archive
+ * info of this {@code ModuleDefinition}.
+ *
+ * @return the {@code ModuleArchiveInfo} object.
+ * @throws SecurityException if a security manager exists and
+ * its {@code checkPermission} method denies access
+ * to the module archive info of this {@code ModuleDefinition}.
+ */
+ public abstract ModuleArchiveInfo getModuleArchiveInfo();
/**
* Returns the name of the main class in this {@code ModuleDefinition}.
@@ -380,7 +409,7 @@ public abstract class ModuleDefinition {
* <p>
* If a security manager is present, this method calls the security
* manager's {@code checkPermission} method with a
- * {@code ModuleSystemPermission("accessModuleContent")}
+ * {@code ModuleSystemPermission("getModuleContent")}
* permission to ensure it's ok to access the content of this
* {@code ModuleDefinition}.
*
--- a/src/share/classes/java/module/ModuleSystemPermission.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/java/module/ModuleSystemPermission.java Mon Aug 04 14:55:36 2008 -0700
@@ -52,6 +52,32 @@ at the permission allows, and associated
* load their rogue modules and classes into the system.</td>
* </tr>
* <tr>
+ * <td>createModuleDefinition</td>
+ * <td>Creation of a module definition.</td>
+ * <td>This is an extremely dangerous permission to grant. Malicious
+ * applications that can instantiate their own module definitions could
+ * then load their rogue modules and classes into the system through an
+ * existing module system.</td>
+ * </tr>
+ * <tr>
+ * <td>createRepository</td>
+ * <td>Creation of a repository.</td>
+ * <td>This is an extremely dangerous permission to grant. Malicious
+ * applications that can instantiate their own repositories could then
+ * load their rogue modules and classes into the system.</td>
+ * </tr>
+ * <tr>
+ * <td>disableModuleDefinition</td>
+ * <td>Disables a module definition in a module system via calls to
+ * the {@code ModuleSystem}'s
+ * {@link ModuleSystem#disableModuleDefinition(ModuleDefinition)
+ * <tt>disableModuleDefinition</tt>} method.</td>
+ * <td>This is an extremely dangerous permission to grant. Malicious
+ * applications could allow an attacker to perform denial-of-service
+ * attacks by disabling a module definition, and the module system will
+ * not create any new module instances from the module definition.</td>
+ * </tr>
+ * <tr>
* <td>releaseModule</td>
* <td>Releases an existing module instance from a module system via calls to
* the {@code ModuleSystem}'s
@@ -59,20 +85,8 @@ at the permission allows, and associated
* <tt>releaseModule</tt>} method.</td>
* <td>This is a dangerous permission to grant. Malicious applications could
* allow an attacker to release an existing module instance, so the
- * runtime characteristics of the Java virtual machine is changed
- * unexpectedly and it could cause the system to misbehave.</td>
- * </tr>
- * <tr>
- * <td>disableModuleDefinition</td>
- * <td>Disables a module definition in a module system via calls to
- * the {@code ModuleSystem}'s
- * {@link ModuleSystem#disableModuleDefinition(ModuleDefinition)
- * <tt>disableModuleDefinition</tt>} method.</td>
- * <td>This is an extremely dangerous permission to grant. Malicious
- * applications could allow an attacker to perform denial-of-service
- * attack by disabling a module definition, and the module system will be
- * disallowed from creating any new module instance from that disabled
- * module definition.</td>
+ * runtime characteristics of the Java virtual machine are changed
+ * unexpectedly and could cause the system to misbehave.</td>
* </tr>
* <tr>
* <td>installModuleArchive</td>
@@ -98,13 +112,6 @@ at the permission allows, and associated
* repository.</td>
* </tr>
* <tr>
- * <td>createRepository</td>
- * <td>Creation of a repository.</td>
- * <td>This is an extremely dangerous permission to grant. Malicious
- * applications that can instantiate their own repositories could then
- * load their rogue modules and classes into the system.</td>
- * </tr>
- * <tr>
* <td>shutdownRepository</td>
* <td>Shutdown a repository via calls
* to the {@code Repository}'s {@link Repository#shutdown()
@@ -117,27 +124,59 @@ at the permission allows, and associated
* <td>Reloads module definitions in a repository via calls
* to the {@code Repository}'s {@link Repository#reload()
* <tt>reload</tt>} method.</td>
- * <td>This allows an attacker to invalidate the lifetime of the outstanding
- * module instances instantiated from the module definitions in the
- * repository.</td>
- * </tr>
- * <tr>
- * <td>accessModuleContent</td>
- * <td>Accesses the content of the module definition via calls
- * to the {@code ModuleDefinition}'s {@link ModuleDefinition#getModuleContent()
+ * <td>This allows an attacker to reload the module definitions
+ * in the repository, so the runtime characteristics of the
+ * Java virtual machine are changed unexpectedly and could
+ * cause the system to misbehave.</td>
+ * </tr>
+ * <tr>
+ * <td>getModuleArchiveInfo</td>
+ * <td>Gets the module archive info of the module definition via calls
+ * to the {@code ModuleDefinition}'s
+ * {@link ModuleDefinition#getModuleArchiveInfo()
+ * <tt>getModuleArchiveInfo</tt>} method.</td>
+ * <td>This allows an attacker to access the module archive info of
+ * the module definition, which may has sensitive information.</td>
+ * </tr>
+ * <tr>
+ * <td>getModuleContent</td>
+ * <td>Gets the content of the module definition via calls
+ * to the {@code ModuleDefinition}'s
+ * {@link ModuleDefinition#getModuleContent()
* <tt>getModuleContent</tt>} method.</td>
- * <td>This allows an attacker to have access to the actual content of the
- * module definition, which may contain sensitive information internally.</td>
+ * <td>This allows an attacker to access the content of the
+ * module definition, which may contain sensitive information.</td>
+ * </tr>
+ * <tr>
+ * <td>getVisibilityPolicy</td>
+ * <td>Gets the system's visibility policy
+ * via calls to the {@code Modules}'s
+ * {@link Modules#getVisibilityPolicy()
+ * <tt>getVisibilityPolicy</tt>} method.</td>
+ * .</td>
+ * <td>This allows an attacker to determine which module definitions
+ * are visible.</td>
* </tr>
* <tr>
* <td>setImportOverridePolicy</td>
- * <td>Changes the default import override policy in the JAM module system via calls
- * to the {@code Modules}'s
+ * <td>Changes the system's import override policy in the JAM module system
+ * via calls to the {@code Modules}'s
* {@link Modules#setImportOverridePolicy(ImportOverridePolicy)
* <tt>setImportOverridePolicy</tt>} method.</td>
* .</td>
- * <td>This allows an attacker to choose specific versions of imported
- * modules when a module instance is initialized.</td>
+ * <td>This allows an attacker to install a malicious import override
+ * policy to control the resolution of module instances in the JAM
+ * module system.</td>
+ * </tr>
+ * <tr>
+ * <td>getImportOverridePolicy</td>
+ * <td>Gets the system's import override policy in the JAM module system
+ * via calls to the {@code Modules}'s
+ * {@link Modules#getImportOverridePolicy()
+ * <tt>getImportOverridePolicy</tt>} method.</td>
+ * .</td>
+ * <td>This allows an attacker to determine the resolution result of module
+ * instances in the JAM module system.</td>
* </tr>
* <tr>
* <td>addModuleSystemListener</td>
@@ -145,8 +184,7 @@ at the permission allows, and associated
* calls to the {@code ModuleSystem}'s
* {@link ModuleSystem#addModuleSystemListener(ModuleSystemListener)
* <tt>addModuleSystemListener</tt>} method.</td>
- * <td>This allows an attacker to monitor the module system events in the
- * module systems.</td>
+ * <td>This allows an attacker to monitor the events in the module systems.</td>
* </tr>
* <tr>
* <td>removeModuleSystemListener</td>
@@ -154,8 +192,8 @@ at the permission allows, and associated
* via calls to the {@code ModuleSystem}'s
* {@link ModuleSystem#removeModuleSystemListener(ModuleSystemListener)
* <tt>removeModuleSystemListener</tt>} method.</td>
- * <td>This allows an attacker to remove a system-provided module system
- * listener from the module systems.</td>
+ * <td>This allows an attacker to remove a system-provided event listener from
+ * the module systems.</td>
* </tr>
* <tr>
* <td>addRepositoryListener</td>
@@ -163,8 +201,7 @@ at the permission allows, and associated
* via calls to the {@code Repository}'s
* {@link Repository#addRepositoryListener(RepositoryListener)
* <tt>addRepositoryListener</tt>} method.</td>
- * <td>This allows an attacker to monitor the repository events in the
- * repositories.</td>
+ * <td>This allows an attacker to monitor the events in the repositories.</td>
* </tr>
* <tr>
* <td>removeRepositoryListener</td>
@@ -172,7 +209,7 @@ at the permission allows, and associated
* via calls to the {@code Repository}'s
* {@link Repository#removeRepositoryListener(RepositoryListener)
* <tt>removeRepositoryListener</tt>} method.</td>
- * <td>This allows an attacker to remove a system-provided repository
+ * <td>This allows an attacker to remove a system-provided event
* listener from the repositories.</td>
* </tr>
* </table>
--- a/src/share/classes/java/module/Modules.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/java/module/Modules.java Mon Aug 04 14:55:36 2008 -0700
@@ -61,96 +61,41 @@ import sun.module.repository.URLReposito
* <h3> ModuleDefinition</h3>
* The JAM module system provides a concrete {@link ModuleDefinition}
* implementation for JAM modules. Applications can obtain the
- * {@code ModuleDefinition} objects by calling the
+ * {@code ModuleDefinition} objects by calling one of the
* {@link #newModuleDefinition(java.nio.ByteBuffer,ModuleContent,Repository,boolean)
* <tt>newModuleDefinition</tt>} factory methods.
* <p>
* <h3> Repository</h3>
* The JAM module system provides two concrete repository implementations:
- * <i>Local repository</i> and <i>URL repository</i>. Both repository
- * implementations must support the JAM file format as described in the JAM
- * Module System Specification. Both repository implementations must also
- * validate the integrity of a JAM file when the file is installed.
- * <p>
- * <A NAME="SelectionPolicy"></A><h5>Selection policy for JAM modules</h5>
- *
- * Local repository and URL repository have both platform-neutral and
- * <a href="package-summary.html#PlatformSpecificModules">platform-specific modules</a>
- * installed. Implementations of these repositories must use the following
- * policy to select the set of JAM modules appropriate for the platform and
- * architecture of the system:
- * <ul>
- * <li><p>JAM module with platform binding which does not match
- * the platform and architecture of the system is ignored.
- * </p></li>
- *
- * <li><p>JAM module with platform binding which matches
- * the system's platform and architecture is preferred
- * over the JAM module of the same name and version with no
- * platform binding.</p></li>
- * </ul>
- *
- * <h4>Local Repository</h4>
+ * <i>Local repository</i> and <i>URL repository</i>. Both repositories
+ * support the JAM file format as described in the JAM Module System
+ * Specification.
+ *
+ * <h4>Local repository</h4>
* <i>Local repository</i> supports loading JAM modules from a directory on
* a file system. Different repository instances in the same or different
- * Java virtual machines can process the
- * JAM modules from the same directory for sharing purposes. Hence, the
- * directory is also called <i>repository interchange directory</i>.
- * <p>
- * A local repository must follow the policy below to
- * process JAM modules in the repository interchange directory, when the
+ * Java virtual machines can process the JAM modules from the same directory
+ * for sharing purposes. Hence, the directory is called
+ * <i>repository interchange directory</i>.
+ * <p>
+ * Each local repository processes JAM modules in the repository interchange
+ * directory as follows, when the
* {@link Repository#initialize() <tt>initialize</tt>} or
* {@link Repository#reload() <tt>reload</tt>} method is called:
* <ul>
- * <li><p>A local repository must process JAM file which
- * has {@code .jam} extension and follows the naming convention
- * defined in Section 3.1 of the JAM Module System Specification.
- * A local repository must ignore JAM file which
- * has {@code .jam} extension but does not follow the naming
- * convention.
- * A local repository must ignore JAM file which
- * has {@code .jam.pack.gz}, {@code .jar}, {@code .zip} or other
- * filename extensions.
- *
- * <li><p>A local repository must support a
- * "hidden" (in the UNIX sense) repository interchange directory.
- * </p></li>
- *
- * <li><p>A local repository must ignore subdirectories
- * under the repository interchange directory.
- * </p></li>
- *
- * <li><p>Local repository implementations may enumerate the JAM files in
- * any order.</p></li>
- *
- * <li><p>Local repository implementations must ignore the duplicates
- * if there is more than one JAM file containing the same JAM module.
+ * <li><p>Only JAM files in the directory which have {@code .jam} extension
+ * and follow the naming convention
+ * defined in Section 3.1 of the JAM Module System Specification
+ * are recognized. Other files in the directory are ignored.
+ *
+ * <li><p>Subdirectories are ignored.</p></li>
+ *
+ * <li><p>JAM files in the directory may be enumerated in any order.</p></li>
+ *
+ * <li><p>Duplicates are ignored if there is more than one JAM
+ * file containing the same JAM module.
* </p></li>
* </ul>
- * <p>
- * A local repository must follow the
- * <a href="#SelectionPolicy">selection policy</a> to determine a
- * selected set of JAM modules, from the set of JAM modules available
- * in the repository interchange directory. Local repository
- * implementations must only create {@code ModuleDefinition}s for the
- * selected set of JAM modules.
- * <p>
- * Local repository implementations must support the
- * {@link Repository#reload() <tt>reload</tt>} operation. During reload,
- * a local repository must compare the set of JAM
- * modules in the repository interchange directory against
- * the set of JAM modules which was last recognized by the local
- * repository.
- * See
- * {@link Repository#reload()} for more details.
- * <p>
- * Local repository implementations must become
- * {@linkplain Repository#isReadOnly() read-only}
- * if the repository interchange directory is read-only as determined
- * when the repository is initialized and reloaded.
- * Local repository implementations must support the
- * {@link Repository#install(URI) <tt>install</tt>} and
- * {@link Repository#uninstall(ModuleArchiveInfo) <tt>uninstall</tt>} operations.
* <p>
* Instances of this {@code Repository} can be constructed using one of the
* {@link #newLocalRepository(String, File, Map, Repository)
@@ -171,32 +116,30 @@ import sun.module.repository.URLReposito
* // Search org.foo.xml version 1.0.0 from the repository instance.
* ModuleDefinition moduleDef = repo.find("org.foo.xml", VersionConstraint.valueOf("1.0.0"));</pre>
*
- * <h4>URL Repository</h4>
- * <i>URL repository</i> supports loading JAM modules
- * from a codebase URL. URL repository is typically used to
- * download JAM modules from server, but it can also be used with a
- * file-based URL.
- * <p>
- * URL repository must have a <i>repository metadata file</i>
- * (i.e. repository-metadata.xml) which describes the JAM modules in
+ * <h4>URL repository</h4>
+ * <i>URL repository</i> supports loading JAM modules from a codebase URL.
+ * URL repository is typically used to load JAM modules from a server, but
+ * it can also be used to load JAM modules from a file URL.
+ * <p>
+ * Each URL repository has a <i>repository metadata file</i>
+ * (i.e. {@code repository-metadata.xml}) which describes the JAM modules in
* the repository. The <i>repository metadata file</i> must exist
* directly under the codebase URL, and it must conform to the
- * <a href="RepositoryMetadata.xml">repository metadata schema</a>.
+ * <a href="repository-metadata-schema.xml">repository metadata schema</a>.
* <pre>
* {codebase}/repository-metadata.xml</pre>
*
* A JAM module in the URL repository is identified by placing an entry
- * in the <i>repository metadata file</i>. Each entry has a
- * module name, module version, path (relative path to a location
- * where the module is stored under the codebase URL), and platform
- * binding. URL repository implementations must ignore the duplicates
- * if there is more than one entry for the JAM module with the
+ * in the <i>repository metadata file</i>. Each entry has a module name,
+ * module version, path (relative path to a location where the module is
+ * stored under the codebase URL), and platform binding. Duplicates must
+ * be ignored if there is more than one entry for the JAM module with the
* same name, version, and platform binding.
* For a given JAM module in the URL repository, its module
* metadata file {@code MODULE.METADATA} must exist under the path, and
* its module archive (i.e. either {@code .jam} file,
* {@code .jam.pack.gz} file, or both} must also exist under the path.
- * <h5>Platform-neutral JAM module</h5>
+ * <h5>Portable JAM module</h5>
* <pre>
* {codebase}/{path}/MODULE.METADATA
* {codebase}/{path}/&lt;module-name&gt;-&lt;module-version&gt;.jam
@@ -208,59 +151,18 @@ import sun.module.repository.URLReposito
* {codebase}/{path}/&lt;module-name&gt;-&lt;module-version&gt;[&lt;platform&gt;-&lt;arch&gt;].jam
* {codebase}/{path}/&lt;module-name&gt;-&lt;module-version&gt;[&lt;platform&gt;-&lt;arch&gt;].jam.pack.gz</pre>
*
- * URL repository implementations must follow the
- * <a href="#SelectionPolicy">selection policy</a> to determine a
- * selected set of JAM modules, from the set of JAM modules available
- * in the repository as described in the repository metadata file.
- * URL repository implementations must only create
- * {@code ModuleDefinition}s for the selected set of JAM modules.
- * <p>
- * For each JAM module in the selected set,
- * <ul>
- * <li><p>URL repository implementations must either download the
- * {@code .jam} file or {@code .jam.pack.gz} file for the given
- * JAM module. URL repository implementations must prefer
- * the {@code .jam.pack.gz} file over the {@code .jam} file
- * if the codebase URL is not file-based.</p></li>
- *
- * <li><p>URL repository implementations must ignore the JAM module
- * if the module's name, version, and platform binding specified
- * in the repository metadata file do not match the information
- * in the module metadata file
- * (i.e. {@code MODULE.METADATA file}).</p></li>
- *
- * <li><p>A URL repository implementation must throw exception in
- * methods of {@link ModuleContent} in the
- * {@link ModuleDefinition}s the URL repository creates, if
- * the module metadata file (i.e. {@code MODULE.METADATA
- * file}) is not bit-wise equal to the module metadata file
- * inside the {@code .jam} file or {@code .jam.pack.gz} file
- * which the URL repository has downloaded.
- * </p></li>
- * </ul>
- * URL repository is {@linkplain Repository#isReadOnly() read-only}
- * if the codebase is a non-file-based URL or it is a file-based URL
- * which represents a read-only directory on the file system.
- * URL repository implementations must support the
- * {@link Repository#install(java.net.URI) <tt>install</tt>} and
- * {@link Repository#uninstall(ModuleArchiveInfo) <tt>uninstall</tt>}
- * operations for JAM files.
- * <p>
- * A URL repository must support the
- * {@linkplain Repository#reload() reload}
- * operation; it must compare the timestamp of the
- * <i>repository metadata file</i> against the timestamp of the same file
- * which was last downloaded. If the timestamps are different, a URL
- * repository must do the following:
- * <ol>
- * <li><p>Download the repository metadata file and determine
- * the set of JAM modules based on the selection policy.</p></li>
- * <li><p>Remove all existing module archives and module definitions
- * from the repository.</p></li>
- * <li><p>Add new module archives and module definitions to the
- * repository.</p></li>
- * </ol>
- * See {@link Repository#reload()} for more details.
+ * URL repository must ignore a JAM module if the name, version, and
+ * platform binding in its module metadata file
+ * (i.e. {@code MODULE.METADATA} file) does not match the information
+ * in its entry in the repository metadata file.
+ * URL repository must block instantiation of module instance from
+ * a module definition if its module metadata file
+ * is not bit-wise equal to the content of
+ * {@code META-INF/MODULE.METADATA} in the {@code .jam} file or
+ * {@code .jam.pack.gz} file.
+ * URL repository must prefer {@code .jam.pack.gz} file over {@code .jam}
+ * file for remote URL; it must prefer {@code .jam} file
+ * over {@code .jam.pack.gz} for file URL.
* <p>
* Instance of this {@code Repository} can be constructed using one of the
* {@link #newURLRepository(String, URL, Map, Repository)
@@ -283,6 +185,66 @@ import sun.module.repository.URLReposito
* // Search org.foo.xml version 1.3.0 from the repository instance.
* ModuleDefinition moduleDef = repo.find("org.foo.xml", VersionConstraint.valueOf("1.3.0"));</pre>
*
+ *
+ * <h4>Creating module definitions from JAM modules</h4>
+ *
+ * <i>Local repository</i> and <i>URL repository</i> may have portable and
+ * <a href="package-summary.html#PlatformSpecificModules">platform specific</a>
+ * modules installed for a given module's name and version. When a repository
+ * creates a module definition for a given module name and
+ * version during {@code initialize} or {@code reload},
+ * it must ignore all JAM modules that are
+ * incompatible with the system's platform and architecture. It must prefer
+ * a platform specific JAM module compatibile with the system rather than a
+ * portable JAM module for a given module's name and version.
+ * </ul>
+ *
+ * <h4>List</h4>
+ * <i>Local repository</i> supports the
+ * {@link Repository#list() <tt>list</tt>} operation by listing all JAM modules
+ * in the repository interchange directory.
+ * <i>URL repository</i> supports the operation by listing all JAM modules
+ * described in the repository metadata file.
+ *
+ * <h4>Install</h4><i>Local repository</i> and <i>URL repository</i> support the
+ * {@link Repository#install(URI) <tt>install</tt>} operation with JAM file.
+ * Both repositories must block the installation if the JAM file is invalid. If the
+ * repository has no existing module definition for a given module name and
+ * version when the JAM module is installed, the repository must create one
+ * from the newly installed JAM mdoule.
+ *
+ * <h4>Uninstall</h4><i>Local repository</i> and <i>URL repository</i> support the
+ * {@link Repository#uninstall(ModuleArchiveInfo) <tt>uninstall</tt>}
+ * operation for a given JAM module. If the repository has an
+ * existing module definition created from the JAM module, it removes
+ * the module definition if the uninstallation succeeds.
+ *
+ * <h4>Reload</h4><i>Local repository</i> supports the
+ * {@link Repository#reload() <tt>reload</tt>} operation by comparing
+ * the set of JAM modules in the repository interchange directory against
+ * the set of JAM modules last known to the repository. The repository
+ * removes an existing JAM module if the corresponding JAM file is
+ * missing from the directory. The repository replaces an existing JAM
+ * module if the corresponding JAM file in the directory has a different
+ * timestamp than the last known value. The repository adds a new JAM module
+ * if the corresponding JAM file is new in the directory.
+ * <p>
+ * <i>URL repository</i> supports the reload operation by comparing the
+ * timestamp of the <i>repository metadata file</i> against the timestamp
+ * last known to the repository. If the timestamps are different,
+ * the repository removes all existing JAM modules, and loads all new
+ * JAM modules from the codebase based on the repository metadata file.
+ * <p>
+ * See
+ * {@link Repository#reload()} for more details.
+ *
+ * <h4>Read only</h4>
+ * <i>Local repository</i> is {@linkplain Repository#isReadOnly() read-only}
+ * if the repository interchange directory is read-only.
+ * <i>URL repository</i> is read-only if the codebase is a non-file
+ * URL, or the codebase is a file URL that represents a read-only
+ * directory on the file system.
+ *
* <h3> Module dependency and package dependency</h3>
* The JAM module system provides a concrete implementation for
* {@link ModuleDependency} and another concrete implementation for
@@ -319,10 +281,10 @@ public class Modules {
private static WeakHashMap<ThreadGroup, ModuleSystem> moduleSystemMap = new WeakHashMap<ThreadGroup, ModuleSystem>();
- // Default import override policy
+ // System's import override policy
private static ImportOverridePolicy importOverridePolicy;
- // Default visibility policy
+ // System's visibility policy
private static VisibilityPolicy visibilityPolicy;
@@ -579,14 +541,43 @@ public class Modules {
/**
* Returns the system's import override policy for module definitions.
- * <p>
- * The default class of the override policy can be changed using the
- * {@code java.module.import.override.policy.classname} system property.
- *
- * @return the system's default import override policy for module definitions.
+ * This value should not be cached, as it may be changed by a call to
+ * {@code setImportOverridePolicy}.
+ * <p>
+ * If the system has no import override policy installed, this method returns
+ * an instance of the default {@code ImportOverridePolicy} implementation.
+ * <p>
+ * The default {@code ImportOverridePolicy} implementation can be changed
+ * by setting the value of the "import.override.policy.classname" property
+ * (in the Java module properties file) to the fully qualified name of
+ * the desired {@code ImportOverridePolicy} implementation. The Java module
+ * properties file is located in the file named
+ * {@code <JAVA_HOME>/lib/module/module.properties}. {@code <JAVA_HOME>}
+ * refers to the value of the {@code java.home} system property, and
+ * specifies the directory where the JRE is installed.
+ * <p>
+ * The default {@code ImportOverridePolicy} implementation can also be
+ * changed by setting the value of the
+ * {@code java.module.import.override.policy.classname} system property to the
+ * fully qualified name of the desired {@code ImportOverridePolicy}
+ * implementation.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's {@code checkPermission} method with a
+ * {@code ModuleSystemPermission("getImportOverridePolicy")}
+ * permission to ensure it's ok to get the system's import
+ * override policy.
+ *
+ * @return the system's import override policy for module definitions.
+ * @throws SecurityException if a security manager exists and its
+ * {@code checkPermission} method denies access to get the
+ * system's import override policy.
*/
public synchronized static ImportOverridePolicy getImportOverridePolicy() {
-
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new ModuleSystemPermission("getImportOverridePolicy"));
+ }
if (importOverridePolicy == null) {
try {
String clazzName = java.security.AccessController.doPrivileged(
@@ -635,13 +626,13 @@ public class Modules {
* If a security manager is present, this method calls the security
* manager's {@code checkPermission} method with a
* {@code ModuleSystemPermission("setImportOverridePolicy")}
- * permission to ensure it's ok to set the system's default import
+ * permission to ensure it's ok to set the system's import
* override policy.
*
* @param policy the import override policy for module definitions.
* @throws SecurityException if a security manager exists and its
* {@code checkPermission} method denies access to set the
- * system's default import override policy.
+ * system's import override policy.
*/
public synchronized static void setImportOverridePolicy(ImportOverridePolicy policy) {
if (policy == null)
@@ -655,16 +646,42 @@ public class Modules {
}
/**
- * Returns the system's default visibility policy for module definitions
- * in the repositories.
- * <p>
- * The default class of the visibility policy can be overridden using the
- * {@code java.module.visibility.policy.classname} system property.
- *
- * @return the system's default visibility policy for module definitions.
+ * Returns the system's visibility policy for module definitions in the
+ * repositories.
+ * <p>
+ * If the system has no visibility policy installed, this method returns
+ * an instance of the default {@code VisibilityPolicy} implementation.
+ * <p>
+ * The default {@code VisibilityPolicy} implementation can be changed
+ * by setting the value of the "visibility.policy.classname" property
+ * (in the Java module properties file) to the fully qualified name of
+ * the desired {@code VisibilityPolicy} implementation. The Java module
+ * properties file is located in the file named
+ * {@code <JAVA_HOME>/lib/module/module.properties}. {@code <JAVA_HOME>}
+ * refers to the value of the {@code java.home} system property, and
+ * specifies the directory where the JRE is installed.
+ * <p>
+ * The default {@code VisibilityPolicy} implementation can also be
+ * changed by setting the value of the
+ * {@code java.module.visibility.policy.classname} system property to the
+ * fully qualified name of the desired {@code VisibilityPolicy}
+ * implementation.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's {@code checkPermission} method with a
+ * {@code ModuleSystemPermission("getVisibilityPolicy")}
+ * permission to ensure it's ok to get the system's visibility policy.
+ *
+ * @return the system's visibility policy for module definitions.
+ * @throws SecurityException if a security manager exists and its
+ * {@code checkPermission} method denies access to get the
+ * system's visibility policy.
*/
synchronized static VisibilityPolicy getVisibilityPolicy() {
-
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new ModuleSystemPermission("getVisibilityPolicy"));
+ }
if (visibilityPolicy == null) {
try {
String clazzName = java.security.AccessController.doPrivileged(
@@ -711,29 +728,40 @@ public class Modules {
* Returns a new {@code ModuleDefinition} instance for a JAM module.
* Equivalent to:
* <pre>
- * newModuleDefinition(metadata, content, repository, moduleReleasable, getModuleSystem());</pre>
+ * newModuleDefinition(metadata, content, moduleArchiveInfo, repository, moduleReleasable, getModuleSystem());</pre>
*
* The content of the byte buffer is copied.
* This method will typically be called by repository implementations
* and not by applications.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's {@code checkPermission} method with
+ * {@code ModuleSystemPermission("createModuleDefinition")} permission to
+ * ensure it's ok to create a module definition.
*
* @param metadata a byte buffer which contains the content of the
* module metadata file
* @param content the {@code ModuleContent} to be used to access the
* contents of the module definition
- * @param repository the {@code Repository} in which the module definition
- * is associated with
+ * @param mai the module archive information with which the
+ * mdoule definition is associated
+ * @param repository the {@code Repository} with which the module definition
+ * is associated
* @param moduleReleasable true if the module instance instantiated from
* this {@code ModuleDefinition} is releasable from its module
* system
+ * @throws SecurityException if a security manager exists and its
+ * {@code checkPermission} method denies access to create a new
+ * module definition.
* @throws ModuleFormatException if the content of module metadata file
* is not recognized or is not well formed.
* @return a new {@code ModuleDefinition}.
*/
public static ModuleDefinition newModuleDefinition(ByteBuffer metadata,
- ModuleContent content, Repository repository, boolean moduleReleasable)
+ ModuleContent content, ModuleArchiveInfo mai,
+ Repository repository, boolean moduleReleasable)
throws ModuleFormatException {
- return newModuleDefinition(metadata, content, repository, moduleReleasable, getModuleSystem());
+ return newModuleDefinition(metadata, content, mai, repository, moduleReleasable, getModuleSystem());
}
/**
@@ -742,32 +770,46 @@ public class Modules {
* The content of the byte buffer is copied.
* This method will typically be called by repository implementations
* and not by applications.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's {@code checkPermission} method with
+ * {@code ModuleSystemPermission("createModuleDefinition")} permission to
+ * ensure it's ok to create a module definition.
*
* @param metadata a byte buffer which contains the content of the
* module metadata file
* @param content the {@code ModuleContent} to be used to access the
* contents of the module definition
- * @param repository the {@code Repository} in which the module definition
- * is associated with
+ * @param mai the module archive information with which the
+ * mdoule definition is associated
+ * @param repository the {@code Repository} with which the module definition
+ * is associated
* @param moduleReleasable true if the module instance instantiated from
* this {@code ModuleDefinition} is releasable from its module
* system
* @param moduleSystem the {@code ModuleSystem} instance to be associated with
* the module definition.
+ * @throws SecurityException if a security manager exists and its
+ * {@code checkPermission} method denies access to create a new
+ * module definition.
* @throws ModuleFormatException if the content of module metadata file
* is not recognized or is not well formed.
* @return a new {@code ModuleDefinition}.
*/
public static ModuleDefinition newModuleDefinition(ByteBuffer metadata,
- ModuleContent content, Repository repository, boolean moduleReleasable,
+ ModuleContent content, ModuleArchiveInfo mai,
+ Repository repository, boolean moduleReleasable,
ModuleSystem moduleSystem)
throws ModuleFormatException {
if (metadata == null) {
- throw new NullPointerException("metadata must not be null.");
+ throw new NullPointerException("metadataByteBuffer must not be null.");
}
if (content == null) {
throw new NullPointerException("content must not be null.");
}
+ if (mai == null) {
+ throw new NullPointerException("mai must not be null.");
+ }
if (repository == null) {
throw new NullPointerException("repository must not be null.");
}
@@ -777,7 +819,8 @@ public class Modules {
byte[] metadataBytes = new byte[metadata.remaining()];
metadata.get(metadataBytes); // get bytes out of byte buffer.
+
return new JamModuleDefinition(moduleSystem,
- null, null, metadataBytes, null, content, repository, moduleReleasable);
+ null, null, metadataBytes, content, mai, repository, moduleReleasable);
}
}
--- a/src/share/classes/java/module/Repository.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/java/module/Repository.java Mon Aug 04 14:55:36 2008 -0700
@@ -242,13 +242,36 @@ public abstract class Repository {
}
/**
- * Returns the system's default visibility policy for module definitions
- * in the repositories.
- * <p>
- * The default class of the visibility policy can be overridden using the
- * {@code java.module.visibility.policy.classname} system property.
- *
- * @return the system's default visibility policy for module definitions.
+ * Returns the system's visibility policy for module definitions in the
+ * repositories.
+ * <p>
+ * If the system has no visibility policy installed, this method returns
+ * an instance of the default {@code VisibilityPolicy} implementation.
+ * <p>
+ * The default {@code VisibilityPolicy} implementation can be changed
+ * by setting the value of the "visibility.policy.classname" property
+ * (in the Java module properties file) to the fully qualified name of
+ * the desired {@code VisibilityPolicy} implementation. The Java module
+ * properties file is located in the file named
+ * {@code <JAVA_HOME>/lib/module/module.properties}. {@code <JAVA_HOME>}
+ * refers to the value of the {@code java.home} system property, and
+ * specifies the directory where the JRE is installed.
+ * <p>
+ * The default {@code VisibilityPolicy} implementation can also be
+ * changed by setting the value of the
+ * {@code java.module.visibility.policy.classname} system property to the
+ * fully qualified name of the desired {@code VisibilityPolicy}
+ * implementation.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's {@code checkPermission} method with a
+ * {@code ModuleSystemPermission("getVisibilityPolicy")}
+ * permission to ensure it's ok to get the system's visibility policy.
+ *
+ * @return the system's visibility policy for module definitions.
+ * @throws SecurityException if a security manager exists and its
+ * {@code checkPermission} method denies access to get the
+ * system's visibility policy.
*/
public static VisibilityPolicy getVisibilityPolicy() {
return Modules.getVisibilityPolicy();
--- a/src/share/classes/java/module/package-info.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/java/module/package-info.java Mon Aug 04 14:55:36 2008 -0700
@@ -191,16 +191,17 @@
* implementation and the default module system within the Java Module System.
* <p>
* <h3> JAM modules</h3>
- * Modules in the JAM module system are called JAM modules. The distribution
+ * Modules in the JAM module system are called JAM modules. JAM modules are
+ * <i>portable</i> by default and can run under any platform. The distribution
* format of a JAM module is also called JAM. Each JAM file
* is self-contained by definition, and it does not reference any resource
* externally. See the JAM Module System Specification for more details.
* <p>
* <A NAME="PlatformSpecificModules"></A><h4> Platform-specific modules</h4>
- * JAM modules are <i>platform-neutral</i> by default. A JAM module is
- * <i>platform-specific</i> if it has
+ * JAM modules with
* {@link java.module.annotation.PlatformBinding platform binding}
- * for a specific platform and architecture.
+ * are <i>platform specific</i>. They can only run under the specific
+ * platform and architecture.
* <p>
* <h4> Resource modules</h4>
* Resources of different locales can be placed in different
--- a/src/share/classes/sun/module/bootstrap/BootstrapRepository.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/bootstrap/BootstrapRepository.java Mon Aug 04 14:55:36 2008 -0700
@@ -77,7 +77,7 @@ public final class BootstrapRepository e
for (ModuleDefinition md : moduleDefs) {
moduleArchiveInfos.add(new JamModuleArchiveInfo(this,
md.getName(), md.getVersion(),
- null, null, null, 0));
+ null, null, null));
}
}
--- a/src/share/classes/sun/module/bootstrap/VirtualModule.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/bootstrap/VirtualModule.java Mon Aug 04 14:55:36 2008 -0700
@@ -89,8 +89,10 @@ final class VirtualModule extends Module
@Override
public void deepValidate() {
if (supportsDeepValidation() == false) {
- throw new UnsupportedOperationException(moduleDef.getName()
- + " module cannot be deep validated.");
+ throw new UnsupportedOperationException(
+ "Module" + moduleDef.getName()
+ + " v" + moduleDef.getVersion()
+ + " cannot be deep validated.");
}
}
--- a/src/share/classes/sun/module/bootstrap/VirtualModuleDefinitions.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/bootstrap/VirtualModuleDefinitions.java Mon Aug 04 14:55:36 2008 -0700
@@ -417,7 +417,7 @@ public final class VirtualModuleDefiniti
try {
moduleDefs.add(new JamModuleDefinition(moduleSystem,
null, null, metadata,
- null, new DummyModuleContent(),
+ new DummyModuleContent(), null,
BootstrapRepository.getInstance(),
false));
} catch (Exception e) {
--- a/src/share/classes/sun/module/core/JamModuleDefinition.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/core/JamModuleDefinition.java Mon Aug 04 14:55:36 2008 -0700
@@ -37,13 +37,13 @@ import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.module.ImportDependency;
import java.module.Module;
import java.module.Modules;
+import java.module.ModuleArchiveInfo;
import java.module.ModuleContent;
import java.module.ModuleDefinition;
import java.module.ModuleDependency;
@@ -77,7 +77,7 @@ public final class JamModuleDefinition e
private final String name;
private final Version version;
private byte[] metadata;
- private final Callable<byte[]> metadataHandle;
+ private final ModuleArchiveInfo mai;
private final ModuleContent content;
private final Repository repository;
private final boolean moduleReleasable;
@@ -93,43 +93,17 @@ public final class JamModuleDefinition e
public JamModuleDefinition(ModuleSystem moduleSystem,
String name, Version version, byte[] metadata,
- Callable<byte[]> metadataHandle, ModuleContent content,
+ ModuleContent content,
+ ModuleArchiveInfo mai,
Repository repository, boolean moduleReleasable) {
this.moduleSystem = moduleSystem;
this.name = name;
this.version = version;
this.metadata = metadata;
- this.metadataHandle = metadataHandle;
+ this.mai = mai;
this.content = content;
this.repository = repository;
this.moduleReleasable = moduleReleasable;
- }
-
- //
- // The module metadata arrangement below is temporary until the
- // full JSR 294 reflective APIs are in place
- //
-
- /**
- * Returns the contents of the MODULE-INF/MODULE.METADATA file.
- *
- * @return the contents of the MODULE-INF/MODULE.METADATA file.
- */
- synchronized byte[] getMetadata() {
- if (metadata != null) {
- if (metadata.length == 0) {
- throw new RuntimeException("metadata is not available.");
- }
- return metadata;
- }
- try {
- metadata = metadataHandle.call();
- return metadata;
- } catch (Exception e) {
- // XXX
- metadata = new byte[0];
- throw new RuntimeException(e);
- }
}
private volatile ModuleInfo moduleInfo;
@@ -139,7 +113,7 @@ public final class JamModuleDefinition e
synchronized (this) {
if (moduleInfo == null) {
// XXX check name and version against metadata
- moduleInfo = ModuleInfo.getModuleInfo(getMetadata());
+ moduleInfo = ModuleInfo.getModuleInfo(metadata);
}
}
}
@@ -517,10 +491,19 @@ public final class JamModuleDefinition e
}
@Override
+ public ModuleArchiveInfo getModuleArchiveInfo() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new ModuleSystemPermission("getModuleArchiveInfo"));
+ }
+ return mai;
+ }
+
+ @Override
public ModuleContent getModuleContent() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- sm.checkPermission(new ModuleSystemPermission("accessModuleContent"));
+ sm.checkPermission(new ModuleSystemPermission("getModuleContent"));
}
return content;
}
--- a/src/share/classes/sun/module/core/ModuleImpl.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/core/ModuleImpl.java Mon Aug 04 14:55:36 2008 -0700
@@ -229,9 +229,25 @@ final class ModuleImpl extends Module {
@Override
public boolean supportsDeepValidation() {
try {
- // In order to support deep validation, member classes
- // must be known.
- moduleDef.getMemberClasses();
+ // Find the transitive closure of this module through imported dependency
+ Set<Module> closure = ModuleUtils.findImportedModulesClosure(this);
+
+ // Deep validation is supported only if the member classes in all
+ // modules in the transitive closure are known.
+ for (Module m : closure) {
+ ModuleDefinition md = m.getModuleDefinition();
+
+ // XXX: Workaround for virtual module for now ... until JSR 294
+ // support arrives
+ if (md.getName().equals("java.classpath")) {
+ throw new UnsupportedOperationException();
+ } else if (md.getRepository() == Repository.getBootstrapRepository()) {
+ continue;
+ }
+
+ md.getMemberClasses();
+ }
+
return true;
} catch (UnsupportedOperationException uoe) {
return false;
@@ -240,46 +256,39 @@ final class ModuleImpl extends Module {
@Override
public void deepValidate() throws ModuleInitializationException {
- if (supportsDeepValidation() == false) {
- throw new UnsupportedOperationException(moduleDef.getName()
- + " module cannot be deep validated.");
- }
-
- // Find the transitive closure of this module through imported dependency
- Set<Module> importedModulesClosure = ModuleUtils.findImportedModulesClosure(this);
-
- // Continue with deep validation only if all modules in the
- // transitive closure support deep validation.
- for (Module m : importedModulesClosure) {
- if (m.supportsDeepValidation() == false) {
- ModuleDefinition md = m.getModuleDefinition();
- throw new ModuleInitializationException("module " + toString(md)
- + " in the dependency transitive closure does not support deep validation.");
- }
- }
-
Set<String> classNamespace = new HashSet<String>();
Set<String> questionableClasses = new HashSet<String>();
- for (Module m : importedModulesClosure) {
- ModuleDefinition md = m.getModuleDefinition();
-
- // XXX: Workaround for virtual module for now ... until JSR 294
- // support arrives
- if (md.getRepository() == Repository.getBootstrapRepository()) {
- continue;
- }
-
- Set<String> memberClasses = md.getMemberClasses();
- for (String clazz : memberClasses) {
- if (classNamespace.contains(clazz)) {
- // The member class already exists in the namespace. There is
- // a potential conflict.
- questionableClasses.add(clazz);
- } else {
- // Add the class to the namespace
- classNamespace.add(clazz);
- }
+ for (Module m : ModuleUtils.findImportedModulesClosure(this)) {
+ try {
+ ModuleDefinition md = m.getModuleDefinition();
+
+ // XXX: Workaround for virtual module for now ... until JSR 294
+ // support arrives
+ if (md.getName().equals("java.classpath")) {
+ throw new UnsupportedOperationException();
+ } else if (md.getRepository() == Repository.getBootstrapRepository()) {
+ continue;
+ }
+
+ Set<String> memberClasses = md.getMemberClasses();
+
+ for (String clazz : memberClasses) {
+ if (classNamespace.contains(clazz)) {
+ // The member class already exists in the namespace.
+ // There is a potential type consistency conflict.
+ questionableClasses.add(clazz);
+ }
+ }
+
+ // Add the member classes to the namespace
+ classNamespace.addAll(memberClasses);
+
+ } catch (UnsupportedOperationException uoe) {
+ throw new ModuleInitializationException("Module " + moduleString
+ + " cannot be deep validated because member classes in "
+ + m.getModuleDefinition().toString()
+ + "in the dependency transitive closure are unknown.");
}
}
@@ -287,8 +296,8 @@ final class ModuleImpl extends Module {
// type conflict information could be reported more precisely through
// exception.
if (questionableClasses.size() > 0)
- throw new ModuleInitializationException("The class namespace of module "
- + moduleString + " has potential type conflict.");
+ throw new ModuleInitializationException("Module "
+ + moduleString + " has potential type consistency conflict.");
}
/**
--- a/src/share/classes/sun/module/osgi/OSGiModuleDefinition.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/osgi/OSGiModuleDefinition.java Mon Aug 04 14:55:36 2008 -0700
@@ -27,6 +27,7 @@ package sun.module.osgi;
import java.lang.annotation.Annotation;
import java.module.ImportDependency;
+import java.module.ModuleArchiveInfo;
import java.module.ModuleContent;
import java.module.ModuleDefinition;
import java.module.ModuleSystem;
@@ -102,6 +103,13 @@ public class OSGiModuleDefinition extend
@Override
public ModuleSystem getModuleSystem() {
return OSGiModuleSystem.getModuleSystem();
+ }
+
+
+ @Override
+ public ModuleArchiveInfo getModuleArchiveInfo() {
+ // XXX: TODO
+ return null;
}
@Override
--- a/src/share/classes/sun/module/osgi/OSGiRepository.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/osgi/OSGiRepository.java Mon Aug 04 14:55:36 2008 -0700
@@ -45,7 +45,6 @@ import java.util.Map;
import java.util.Map;
import java.util.Set;
-import sun.module.repository.JamModuleArchiveInfo;
import org.osgi.framework.Bundle;
/**
@@ -112,11 +111,9 @@ public class OSGiRepository extends Repo
}
private ModuleArchiveInfo newModuleArchiveInfo(Bundle bundle) {
- return new JamModuleArchiveInfo(this,
+ return new OSGiModuleArchiveInfo(this,
bundle.getSymbolicName(),
BundleManifestMapper.getVersion(bundle),
- null, /* XXX: platform neutral for now */
- null,
bundle.getLocation(), /* XXX: is it a valid filename? */
bundle.getLastModified());
}
@@ -196,16 +193,16 @@ public class OSGiRepository extends Repo
} else {
// A module definition already exists for a given name and version
- // (e.g. platform neutral vs platform specific module).
+ // (e.g. portable module vs platform specific module).
// XXX: do we replace the existing module definition with a new one
// if the newly installed module archive provides better
// platform binding?
//
- // e.g. a platform neutral module is already installed and in use
+ // e.g. a portable module is already installed and in use
// but now we just install a windows-x86 specific module (assuming
// we're running on Windows as well), should we swap the module
- // definition of the platform neutral module with that of a newly
+ // definition of the portable module with that of a newly
// installed one?
//
// For simplicity, the answer is no. Otherwise, the behavior could
@@ -286,7 +283,7 @@ public class OSGiRepository extends Repo
// archive info
OSGiModuleDefinition md = value.get(mai);
if (md == null) {
- // Module definition could be null if a platform neutral or
+ // Module definition could be null if a portable or
// platform-specific module with the same name and version
// already exists, but it's not the module archive that is
// being removed. In this case, there is no module definition
@@ -319,7 +316,7 @@ public class OSGiRepository extends Repo
// module archive for the same module name/version. e.g. a platform
// specific module is uninstalled but there exists a platform
// neutral module in the repository. In this case, do we recreate
- // the module definition for the platform neutral module and use
+ // the module definition for the portable module and use
// it in the repository?
//
// For simplicity, the answer is no. If the user uninstalls a
@@ -327,7 +324,7 @@ public class OSGiRepository extends Repo
// expect that no module definition for the given module
// name/version would be returned from the repository if it is
// searched through find(). If the repository returns a
- // module definition of the platform neutral module instead,
+ // module definition of the portable module instead,
// the behavior could be very confusing and problematic.
}
--- a/src/share/classes/sun/module/repository/AbstractRepository.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/repository/AbstractRepository.java Mon Aug 04 14:55:36 2008 -0700
@@ -63,8 +63,9 @@ import sun.module.repository.cache.Modul
import sun.module.repository.cache.ModuleDefInfo;
/**
- * A common base class for LocalRepository and URLRepository.
- * <p>
+ * A common base class for LocalRepository and URLRepository in the JAM module
+ * system. See the {@link java.module.Modules} class for more details.
+ *
* @see java.module.ModuleArchiveInfo
* @see java.module.ModuleDefinition
* @see java.module.Query
@@ -73,12 +74,6 @@ import sun.module.repository.cache.Modul
*/
abstract class AbstractRepository extends Repository {
- /**
- * Internal data structures for the repository.
- */
- protected final Map<String, Map<ModuleArchiveInfo, ModuleDefinition> > contentMapping =
- new HashMap<String, Map<ModuleArchiveInfo, ModuleDefinition> >();
-
/** Repository cache. */
protected Cache repositoryCache = null;
@@ -92,8 +87,7 @@ abstract class AbstractRepository extend
private ModuleSystem moduleSystem;
/**
- * Creates a new <code>AbstractRepository</code> instance, and initializes it
- * using information from the given {@code config}.
+ * Creates a new <code>AbstractRepository</code> instance.
* <p>
* If a security manager is present, this method calls the security
* manager's <code>checkPermission</code> method with a
@@ -115,11 +109,9 @@ abstract class AbstractRepository extend
super(name, parent);
this.config = config;
this.source = source;
-
- // All module definitions in the repository are associated with
+ // All module definitions in this repository are associated with
// the same JAM module system instance.
this.moduleSystem = Modules.getModuleSystem();
- initialize();
}
/**
@@ -127,7 +119,7 @@ abstract class AbstractRepository extend
*
* @return the source location.
*/
- public final URI getSourceLocation() {
+ final URI getSourceLocation() {
return source;
}
@@ -241,13 +233,20 @@ abstract class AbstractRepository extend
assertActive();
assertNotReadOnly();
+ assertValidDirs();
if ((mai instanceof JamModuleArchiveInfo) == false) {
throw new UnsupportedOperationException("type of module archive is not supported: "
+ mai.getClass().getName());
}
-
- assertValidDirs();
+ if (mai.getRepository() != this) {
+ throw new UnsupportedOperationException
+ ("module archive is associated with a different repository.");
+ }
+ if (!getModuleArchiveInfos().contains(mai)) {
+ // Returns false if the module archive no longer exists.
+ return false;
+ }
try {
// Uninstall the module archive under doPrivileged()
@@ -270,8 +269,8 @@ abstract class AbstractRepository extend
}
/**
- * Put the module archive into the repository cache, cook it, and update
- * the internal data structure to reflect the change.
+ * Put the module archive into the repository cache, cook it, and reflect
+ * the change in the repository.
*
* @param file module archive to be installed.
* @return module archive information
@@ -283,98 +282,89 @@ abstract class AbstractRepository extend
ModuleDefInfo mdInfo = repositoryCache.getModuleDefInfo(getSourceLocation().toURL(), file);
// Constructs a module archive info
- ModuleArchiveInfo mai = new JamModuleArchiveInfo(
+ JamModuleArchiveInfo jmai = new JamModuleArchiveInfo(
this, mdInfo.getName(), mdInfo.getVersion(),
mdInfo.getPlatform(), mdInfo.getArch(),
- file.getAbsolutePath(), file.lastModified());
-
- // Checks if a module definition already exists for a given module
- // name and version (e.g. platform neutral vs platform specific module).
- String key = mai.getName() + mai.getVersion();
- Map<ModuleArchiveInfo, ModuleDefinition> value = contentMapping.get(key);
- if (value == null) {
- // No module definition exists, and we should create one if the
- // module archive supports the running platform and architecture.
+ file.getAbsolutePath(), file.lastModified(),
+ mdInfo.getMetadataByteBuffer(),
+ mdInfo.getModuleContent());
+
+ // Adds the module archive into the internal data structure
+ addModuleArchiveInfo(jmai);
+
+ // A module definition MAY already exist for a given module name and
+ // version (e.g. portable module vs platform specific module).
+ Query query = Query.module(jmai.getName(), jmai.getVersion().toVersionConstraint());
+ List<ModuleDefinition> queryResult = findModuleDefinitions(query);
+
+ if (queryResult.size() == 0) {
+ // No module definition exists. Create a new module definition if
+ // the module archive supports the running platform and
+ // architecture.
if (mdInfo.supportsRunningPlatformArch()) {
// Constructs a module definition
ModuleDefinition md = Modules.newModuleDefinition(
- ByteBuffer.wrap(mdInfo.getMetadataBytes()),
- mdInfo.getModuleContent(),
+ jmai.getMetadataByteBuffer(),
+ jmai.getModuleContent(), jmai,
this, true, moduleSystem);
// Add the module definition into the internal data structure
addModuleDefinition(md);
-
- value = new HashMap<ModuleArchiveInfo, ModuleDefinition>();
- value.put(mai, md);
- contentMapping.put(key, value);
}
} else {
// A module definition already exists for a given name and version
- // (e.g. platform neutral vs platform specific module).
-
- // XXX: do we replace the existing module definition with a new one
- // if the newly installed module archive provides better
- // platform binding?
+ // (e.g. portable vs platform specific module).
+
+ // XXX: Should we replace an existing module definition if the
+ // newly installed module archive provides better platform binding?
//
- // e.g. a platform neutral module is already installed and in use
- // but now we just install a windows-x86 specific module (assuming
- // we're running on Windows as well), should we swap the module
- // definition of the platform neutral module with that of a newly
- // installed one?
- //
- // For simplicity, the answer is no. Otherwise, the behavior could
- // be very confusing and problematic.
- }
-
- // Adds the module archive into the internal data structure
- addModuleArchiveInfo(mai);
-
- return mai;
- }
-
- /**
- * Remove the module archive and the corresponding module definition
- * from the internal data structures so this repository won't
- * recognize it anymore.
+ // For simplicity, the answer is no. Otherwise, the runtime
+ // characteristics could be very confusing.
+ }
+
+ return jmai;
+ }
+
+ /**
+ * Remove the module archive and the corresponding module definition from
+ * this repository.
*
* @param mai module archive information that represents the module archive
* to be removed.
*/
protected final void removeModuleArchiveInternal(ModuleArchiveInfo mai) {
- String key = mai.getName() + mai.getVersion();
- Map<ModuleArchiveInfo, ModuleDefinition> value = contentMapping.get(key);
- if (value != null) {
- // Check if a module definition has been created for the module
- // archive info
- ModuleDefinition md = value.get(mai);
-
- if (md == null) {
- // Module definition could be null if a platform neutral or
- // platform-specific module with the same name and version
- // already exists, but it's not the module archive that is
- // being removed. In this case, there is no module definition
- // to be removed from the internal data structure.
- } else {
- // Removes the module archive and module definition mapping
- // from internal data structure.
+
+ // Find existing module definition created from the module archive
+ Query query = Query.module(mai.getName(), mai.getVersion().toVersionConstraint());
+ List<ModuleDefinition> result = findModuleDefinitions(query);
+
+ if (result.size() > 0) {
+ if (result.size() > 1) {
+ throw new AssertionError("internal repository error: more than"
+ + " one module definitions with the same name and version.");
+ }
+
+ ModuleDefinition md = result.get(0);
+ if (md.getModuleArchiveInfo() == mai) {
+ // A module definition was created from the removed module
+ // archive. Remove the module definition.
removeModuleDefinition(md);
- contentMapping.remove(key);
-
- // It is certainly possible that the repository may have another
- // module archive for the same module name/version. e.g. a platform
- // specific module is uninstalled but there exists a platform
- // neutral module in the repository. In this case, do we recreate
- // the module definition for the platform neutral module and use
- // it in the repository?
+
+ // The repository may have another module archive for the same
+ // module name/version. e.g. a platform specific module is
+ // uninstalled but there exists a portable module in the
+ // repository.
+ //
+ // XXX: Should we create a module definition from the
+ // portable module?
//
// For simplicity, the answer is no. If the user uninstalls a
// platform specific module from the repository, he/she would
// expect that no module definition for the given module
- // name/version would be returned from the repository if it is
- // searched through find(). If the repository returns a
- // module definition of the platform neutral module instead,
- // the behavior could be very confusing and problematic.
+ // name/version would be returned from the repository
+ // subsequently. If the repository returns a module
+ // definition created from the portable module instead,
+ // the runtime characteristics could be very confusing.
}
}
@@ -384,69 +374,51 @@ abstract class AbstractRepository extend
/**
* Constructs the module definition from the module archives based on the
- * current platform and architecture, and updates the internal data
- * structure.
+ * current platform and architecture.
*/
final Set<ModuleDefinition> constructModuleDefinitions(
- Map<ModuleArchiveInfo,
- ModuleDefInfo> mdInfoMap)
+ List<ModuleArchiveInfo> mais)
throws IOException {
- return constructModuleDefinitions(mdInfoMap,
+ return constructModuleDefinitions(mais,
RepositoryUtils.getPlatform(),
RepositoryUtils.getArch());
}
/**
* Constructs the module definition from the module archives based on the
- * specified platform and architecture, and updates the internal data
- * structure.
+ * specified platform and architecture.
*/
final Set<ModuleDefinition> constructModuleDefinitions(
- Map<ModuleArchiveInfo,
- ModuleDefInfo> mdInfoMap,
+ List<ModuleArchiveInfo> mais,
String platform, String arch)
throws IOException {
- //
- // It is certainly possible that the source directory may contain more
- // than one module with the same name and same version in some
- // repository implementations, e.g. in the case of LocalRepository,
- // duplicate module with different JAM filename, or platform neutral
+ // The source directory may contain more than one module with the
+ // same name and same version, e.g. in the case of LocalRepository,
+ // duplicate module with different JAM filename, or portable
// module vs platform specific module.
//
- // The list() method would return all the module archives. However, for
- // the find() method, it is important to filter out the unappropriate
- // module archives when constructing module definitions, so for a given
+ // The list() method returns all the module archives. However, for
+ // the find() method, it must filter out the unappropriate module
+ // archives when constructing module definitions, so for a given
// name and version, there is at most one module definition in the
// repository.
//
Collection<ModuleArchiveInfo> appropriateModuleArchiveInfos =
- getAppropriateModuleArchiveInfos(mdInfoMap.keySet(), platform, arch);
+ getAppropriateModuleArchiveInfos(mais, platform, arch);
Set<ModuleDefinition> result = new HashSet<ModuleDefinition>();
- //
// Iterate the list of appropriate module archive, and creates
- // module definition and updates the internal data struture.
+ // module definitions.
//
for (ModuleArchiveInfo mai : appropriateModuleArchiveInfos) {
- String key = mai.getName() + mai.getVersion();
-
- // Looks up the module definition info related to the preferred module archive.
- ModuleDefInfo mdInfo = mdInfoMap.get(mai);
+ JamModuleArchiveInfo jmai = (JamModuleArchiveInfo) mai;
// Constructs a module definition from the module archive.
ModuleDefinition md = Modules.newModuleDefinition(
- ByteBuffer.wrap(mdInfo.getMetadataBytes()),
- mdInfo.getModuleContent(),
+ jmai.getMetadataByteBuffer(),
+ jmai.getModuleContent(), jmai,
this, true, moduleSystem);
-
- // Updates the internal data structures so the repository would
- // recognize this module archive info and the module definition.
- HashMap<ModuleArchiveInfo, ModuleDefinition> value =
- new HashMap<ModuleArchiveInfo, ModuleDefinition>();
- value.put(mai, md);
- contentMapping.put(key, value);
-
result.add(md);
}
@@ -455,8 +427,7 @@ abstract class AbstractRepository extend
/**
* Reconstructs the module definition from the module archives if necessary
- * based on the current platform and architecture, and updates the internal
- * data structure.
+ * based on the current platform and architecture.
*/
protected final void reconstructModuleDefinitionsIfNecessary()
throws IOException {
@@ -466,38 +437,32 @@ abstract class AbstractRepository extend
/**
* Reconstructs the module definition from the module archives if necessary
- * based on the specified platform and architecture, and updates the internal
- * data structure.
+ * based on the specified platform and architecture.
*/
protected final void reconstructModuleDefinitionsIfNecessary(String platform, String arch)
throws IOException {
Collection<ModuleArchiveInfo> appropriateModuleArchiveInfos =
- getAppropriateModuleArchiveInfos(list(), platform, arch);
+ getAppropriateModuleArchiveInfos(getModuleArchiveInfos(), platform, arch);
for (ModuleArchiveInfo mai : appropriateModuleArchiveInfos) {
- String key = mai.getName() + mai.getVersion();
-
- // If there is no module definition for the appropriate module
- // archive.
- if (contentMapping.get(key) == null) {
- // Put the jam file into the repository cache and cook it
- ModuleDefInfo mdInfo = repositoryCache.getModuleDefInfo(
- getSourceLocation().toURL(),
- new File(mai.getFileName()));
+
+ // Find existing module definition created from the module archive.
+ Query query = Query.module(mai.getName(), mai.getVersion().toVersionConstraint());
+ List<ModuleDefinition> queryResult = findModuleDefinitions(query);
+
+ // If no module definition exists for the module archive,
+ // create a new one.
+ if (queryResult.size() == 0) {
+ JamModuleArchiveInfo jmai = (JamModuleArchiveInfo) mai;
// Constructs a module definition
ModuleDefinition md = Modules.newModuleDefinition(
- ByteBuffer.wrap(mdInfo.getMetadataBytes()),
- mdInfo.getModuleContent(),
+ jmai.getMetadataByteBuffer(),
+ jmai.getModuleContent(), jmai,
this, true, moduleSystem);
// Add the module definition into the internal data structure
addModuleDefinition(md);
-
- HashMap<ModuleArchiveInfo, ModuleDefinition> value =
- new HashMap<ModuleArchiveInfo, ModuleDefinition>();
- value.put(mai, md);
- contentMapping.put(key, value);
}
}
}
@@ -508,7 +473,7 @@ abstract class AbstractRepository extend
* duplicate modules (i.e. same name, version, and platform binding), the
* duplicate is removed in the result.
*
- * @param moduleArchiveInfos a list of module archive info
+ * @param moduleArchiveInfos a collection of module archive info
* @param p platform
* @param a architecture
*/
@@ -520,35 +485,32 @@ abstract class AbstractRepository extend
for (ModuleArchiveInfo ma : moduleArchiveInfos) {
JamModuleArchiveInfo mai = (JamModuleArchiveInfo) ma;
String key = mai.getName() + mai.getVersion();
- if (mai.isPlatformArchNeutral()) {
- // The module archive is platform neutral
+ if (mai.isPortable()) {
+ // The module archive is portable
// If no platform specific module exists in the preferred map,
- // use the platform neutral module.
+ // use the portable module.
if (preferredMap.get(key) == null) {
preferredMap.put(key, mai);
}
} else if (p.equals(mai.getPlatform())
&& a.equals(mai.getArch())) {
- // The module archive is platform specific to the specified
- // platform/arch.
+ // The module archive is specific to the specified platform/arch.
JamModuleArchiveInfo mai2 = (JamModuleArchiveInfo) preferredMap.get(key);
- // If no module archive exists in the prefered map for the given
- // module name/version, use this module archive. Or if module
- // archive exists in the preferred map but it is platform
- // neutral, replace it with this module archive.
- if (mai2 == null || mai2.isPlatformArchNeutral()) {
+ if (mai2 == null || mai2.isPortable()) {
+ // If no module archive exists in the prefered map for the given
+ // module name/version, use this module archive. Or if module
+ // archive exists in the preferred map but it is portable,
+ // replace it with this module archive.
preferredMap.put(key, mai);
} else {
// A module archive already exists in the preferred map but
- // it is also platform specific to the specified
- // platform/arch. In this case, this is a duplicate -
- // do nothing.
+ // it is also specific to the specified platform/arch. In
+ // this case, this is a duplicate. No-op.
}
} else {
- // The module archive is platform specified to other platform/
- // arch. No-op
+ // The module archive is specific to other platform/arch. No-op
}
}
@@ -593,7 +555,6 @@ abstract class AbstractRepository extend
AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
public Boolean run() throws Exception {
doShutdown2();
-
return Boolean.TRUE;
}
});
@@ -607,8 +568,6 @@ abstract class AbstractRepository extend
}
}
- contentMapping.clear();
-
// Shutdown repository cache
if (repositoryCache != null) {
repositoryCache.shutdown();
--- a/src/share/classes/sun/module/repository/JamModuleArchiveInfo.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/repository/JamModuleArchiveInfo.java Mon Aug 04 14:55:36 2008 -0700
@@ -25,14 +25,16 @@
package sun.module.repository;
+import java.lang.ModuleInfo;
import java.module.ModuleArchiveInfo;
+import java.module.ModuleContent;
import java.module.Repository;
import java.module.Version;
-
+import java.nio.ByteBuffer;
/**
* This class represents the information of an installed module archive
- * in a repository for the JAM (JAva Module) module system.
+ * in a repository for the JAM module system.
*
* @see java.module.Repository
* @see java.module.Version
@@ -40,21 +42,71 @@ import java.module.Version;
* @since 1.7
*/
public final class JamModuleArchiveInfo implements ModuleArchiveInfo {
- private Repository repository;
+ private final Repository repository;
+ private ByteBuffer metadataByteBuffer;
+ private ModuleContent moduleContent;
+ private final String path;
// These fields are a reflection of the information in the module archive.
- private String name;
- private Version version;
- private String platform;
- private String arch;
- private String fileName;
- private long lastModified;
+ private final String name;
+ private final Version version;
+ private final String platform;
+ private final String arch;
+ private final String fileName;
+ private final long lastModified;
/**
* Constructs a new {@code JamModuleArchiveInfo} instance.
* <p>
- * If the module archive is platform and architecture neutral,
- * both {@code platform} and {@code arch} must be null.
+ * If the module archive is portable, both {@code platform} and
+ * {@code arch} must be null.
+ *
+ * @param repository the repository
+ * @param name the name of the module definition in the module archive.
+ * @param version the version of the module definition in the module archive.
+ * @param platform the platform which the module archive targets.
+ * @param arch the architecture which the module archive targets.
+ * @param path relative path to the source location (for URLRepository)
+ * @throws NullPointerException if repository is null, name is null, or
+ * version is null. It is also thrown if platform is null but
+ * arch is not null, or platform is not null but arch is null.
+ */
+ public JamModuleArchiveInfo(Repository repository,
+ String name, Version version,
+ String platform, String arch,
+ String path) {
+ if (repository == null) {
+ throw new IllegalArgumentException("repository must not be null.");
+ }
+ if (name == null) {
+ throw new IllegalArgumentException("name must not be null.");
+ }
+ if (version == null) {
+ throw new IllegalArgumentException(
+ "version must not be null.");
+ }
+ if ((platform == null ^ arch == null)) {
+ throw new IllegalArgumentException(
+ "platform and arch must be either both provided, or neither provided.");
+ }
+
+ this.repository = repository;
+ this.metadataByteBuffer = null;
+ this.moduleContent = null;
+ this.name = name;
+ this.version = version;
+ this.platform = platform;
+ this.arch = arch;
+ this.path = path;
+ this.fileName = null;
+ this.lastModified = 0;
+ }
+
+ /**
+ * Constructs a new {@code JamModuleArchiveInfo} instance.
+ * <p>
+ * If the module archive is portable, both {@code platform} and
+ * {@code arch} must be null.
*
* @param repository the repository
* @param name the name of the module definition in the module archive.
@@ -63,14 +115,19 @@ public final class JamModuleArchiveInfo
* @param arch the architecture which the module archive targets.
* @param fileName the filename of the module archive.
* @param lastModified the last modified time of the module archive.
+ * @param metadataByteBuffer the metadata byte buffer
+ * @param moduleContent the ModuleContent object
* @throws NullPointerException if repository is null, name is null,
- * version is null, or the last modified time is less than 0. It
+ * version is null, last modified time is less than 0,
+ * metadataByteBuffer is null or moduleContent is null. It
* is also thrown if platform is null but arch is not null, or
* platform is not null but arch is null.
*/
public JamModuleArchiveInfo(Repository repository, String name,
Version version, String platform, String arch,
- String fileName, long lastModified) {
+ String fileName, long lastModified,
+ ByteBuffer metadataByteBuffer,
+ ModuleContent moduleContent) {
if (repository == null) {
throw new IllegalArgumentException("repository must not be null.");
}
@@ -85,113 +142,169 @@ public final class JamModuleArchiveInfo
throw new IllegalArgumentException(
"platform and arch must be either both provided, or neither provided.");
}
-
- if (lastModified <0) {
+ if (lastModified < 0) {
throw new IllegalArgumentException(
"lastModified must be greater than or equal to 0.");
}
+ if (metadataByteBuffer == null) {
+ throw new IllegalArgumentException(
+ "metadataByteBuffer must not be null.");
+ }
+ if (moduleContent == null) {
+ throw new IllegalArgumentException(
+ "moduleContent must not be null.");
+ }
this.repository = repository;
+ this.metadataByteBuffer = metadataByteBuffer;
+ this.moduleContent = moduleContent;
this.name = name;
this.version = version;
this.platform = platform;
this.arch = arch;
this.fileName = fileName;
this.lastModified = lastModified;
- }
-
- /**
- * Returns the repository where the module archive is stored.
- *
- * @return the repository.
- */
+ this.path = null;
+ }
+
@Override
public Repository getRepository() {
return repository;
}
- /**
- * Returns the name of the module definition in the module archive.
- *
- * @return the name of the module definition in the module archive.
- */
@Override
public String getName() {
return name;
}
- /**
- * Returns the version of the module definition in the module archive.
- *
- * @return the version of the module definition in the module archive.
- */
@Override
public Version getVersion() {
return version;
}
- /**
- * Returns the name of the platform which the module archive targets.
- * The value should be one of the possible values
- * of the system property {@code "os.platform"}.
- *
- * @return the name of the platform. If the module archive has no
- * platform binding, returns null.
- */
@Override
public String getPlatform() {
return platform;
}
- /**
- * Returns the name of the architecture of the module archive targets.
- * The value should be one of the possible values of the system property {@code "os.arch"}.
- *
- * @return the name of the architecture. If the module archive has no
- * platform binding, returns null.
- */
@Override
public String getArch() {
return arch;
}
- /**
- * Determines if the module archive is platform and architecture neutral.
- *
- * @return true if the module archive is platform
- * and architecture neutral; otherwise return false.
- */
- public boolean isPlatformArchNeutral() {
- return (platform == null && arch == null);
- }
-
- /**
- * Returns the filename of the module archive.
- *
- * @return the filename of the module archive. If the module archive does not
- * have a filename, return null.
- */
@Override
public String getFileName() {
return fileName;
}
- /**
- * Returns the last modified time of the module archive in the repository. The
- * result is the number of milliseconds since January 1, 1970 GMT.
- *
- * @return the time the module archive was last modified, or 0 if not known.
- */
@Override
public long getLastModified() {
return lastModified;
}
+ public String getPath() {
+ return path;
+ }
+
+ String getCanonicalizedPath() {
+ return getCanonicalizedPath('/');
+ }
+
+ String getCanonicalizedPath(char separatorChar) {
+ if (path != null) {
+ return path;
+ }
+
+ if (isPortable()) {
+ return getName() + separatorChar + getVersion();
+ } else {
+ return getName() + separatorChar
+ + getVersion() + separatorChar
+ + getPlatform() + "-" + getArch();
+ }
+ }
+
+ /**
+ * Determines if the module archive is portable.
+ *
+ * @return true if the module archive is portable; otherwise return false.
+ */
+ boolean isPortable() {
+ return (platform == null && arch == null);
+ }
+
+ /**
+ * Returns the metadata byte buffer.
+ *
+ * @return the metadata byte buffer, or null if not known.
+ */
+ ByteBuffer getMetadataByteBuffer() {
+ return metadataByteBuffer;
+ }
+
+ /**
+ * Set the metadata byte buffer.
+ *
+ * @param bf a byte buffer which contains the metadata
+ */
+ void setMetadataByteBuffer(ByteBuffer bf) {
+ metadataByteBuffer = bf;
+ }
+
+ /**
+ * Returns the module content.
+ *
+ * @return the module content, or null if not known.
+ */
+ ModuleContent getModuleContent() {
+ return moduleContent;
+ }
+
+ /**
+ * Set the module content
+ *
+ * @param content the module content
+ */
+ void setModuleContent(ModuleContent content) {
+ moduleContent = content;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null || !(other instanceof JamModuleArchiveInfo)) {
+ return false;
+ }
+
+ JamModuleArchiveInfo jmai = (JamModuleArchiveInfo) other;
+ if (!name.equals(jmai.name) || !version.equals(jmai.version)) {
+ return false;
+ }
+
+ if (isPortable() && jmai.isPortable()) {
+ return true;
+ } else if (isPortable() || jmai.isPortable()) {
+ return false;
+ } else {
+ return (platform.equals(jmai.platform)
+ && arch.equals(jmai.arch));
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ // Hash code is based on name, version, platform, and arch
+ int rc = name.hashCode();
+ rc = 31 * rc + version.hashCode();
+ rc = 31 * rc + (platform == null ? 0 : platform.hashCode());
+ rc = 31 * rc + (arch == null ? 0 : arch.hashCode());
+ return rc;
+ }
+
/**
* Returns a {@code String} object representing this
- * {@code ModuleArchiveInfo}.
- *
- * @return a string representation of the {@code ModuleArchiveInfo} object.
+ * {@code JamModuleArchiveInfo}.
+ *
+ * @return a string representation of the {@code JamModuleArchiveInfo} object.
*/
@Override
public String toString() {
@@ -203,7 +316,7 @@ public final class JamModuleArchiveInfo
builder.append(name);
builder.append(" v");
builder.append(version);
- if (!isPlatformArchNeutral()) {
+ if (!isPortable()) {
builder.append(",platform-arch=");
builder.append(platform);
builder.append("-");
--- a/src/share/classes/sun/module/repository/LocalRepository.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/repository/LocalRepository.java Mon Aug 04 14:55:36 2008 -0700
@@ -36,6 +36,7 @@ import java.module.Query;
import java.module.Query;
import java.module.Repository;
import java.module.Version;
+import java.nio.ByteBuffer;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
@@ -50,12 +51,8 @@ import sun.module.repository.cache.Modul
import sun.module.repository.cache.ModuleDefInfo;
/**
- * A repository for module definitions stored in the repository interchange
- * directory on the file system.
- * <p>
- * When the repository is initialized, the source location is interpreted by
- * the <code>LocalRepository</code> instance as a directory where the module
- * definitions are stored in the repository interchange directory.
+ * This class represents the Local repository in the JAM module system.
+ * See the {@link java.module.Modules} class for more details.
*
* @see java.module.ModuleArchiveInfo
* @see java.module.ModuleDefinition
@@ -66,12 +63,6 @@ public final class LocalRepository exten
public final class LocalRepository extends AbstractRepository {
/** Prefix of all properties use to configure this repository. */
private static final String PROPERTY_PREFIX = "sun.module.repository.LocalRepository.";
-
- /**
- * True iff the sourceDirectory is writable. Note that this can change upon
- * {@link #reload()}.
- */
- private boolean readOnly;
/**
* Directory in which JAM files are installed, derived from the source
@@ -147,6 +138,8 @@ public final class LocalRepository exten
Map<String, String> config,
Repository parent) throws IOException {
super(name, source, (config == null ? DEFAULT_CONFIG : config), parent);
+
+ initialize();
}
//
@@ -176,6 +169,7 @@ public final class LocalRepository exten
* @param config Map of configuration names to their values
* @throws IOException if the repository cannot be initialized
*/
+ @Override
protected List<ModuleArchiveInfo> doInitialize2() throws IOException {
if (config == null) {
throw new NullPointerException("config must not be null");
@@ -195,7 +189,6 @@ public final class LocalRepository exten
}
sourceDirectory = JamUtils.getFile(getSourceLocation().toURL());
- readOnly = (sourceDirectory.canWrite() == false);
if (sourceDirectory.isDirectory() == false) {
if (sourceLocMustExist) {
missingDir("source", sourceDirectory);
@@ -213,53 +206,45 @@ public final class LocalRepository exten
List<ModuleArchiveInfo> result = new ArrayList<ModuleArchiveInfo>();
+ File[] jamFiles = sourceDirectory.listFiles(JamUtils.JAM_JAR_FILTER);
+ if (jamFiles == null) {
+ return result;
+ }
+
// Iterates the JAM files in the source directory, and cook them
// one-by-one.
- File[] jamFiles = sourceDirectory.listFiles(JamUtils.JAM_JAR_FILTER);
-
- if (jamFiles != null) {
- Map<ModuleArchiveInfo, ModuleDefInfo> mdInfoMap =
- new HashMap<ModuleArchiveInfo, ModuleDefInfo>();
-
- for (File file : jamFiles) {
- try {
- // XXX Log this action
-
- // Put the jam file into the repository cache and cook it
- ModuleDefInfo mdInfo = repositoryCache.getModuleDefInfo(getSourceLocation().toURL(), file);
-
- // Constructs a module archive info
- JamModuleArchiveInfo mai = new JamModuleArchiveInfo(
- this, mdInfo.getName(), mdInfo.getVersion(),
- mdInfo.getPlatform(), mdInfo.getArch(),
- file.getAbsolutePath(), file.lastModified());
-
- mdInfoMap.put(mai, mdInfo);
-
- // Adds the module archive info into the data structure.
- result.add(mai);
- } catch (Exception ex) {
- // XXX log warning but otherwise ignore
- System.err.println("Failed to load module from " + file + ": " + ex);
- }
- }
-
- // It is certainly possible that the source directory may contain more
- // than one module with the same name and same version, e.g.
- // duplicate module with different JAM filename, or platform neutral
- // module vs platform specific module.
- //
- // Constructs the module definitions from the module archives
- // based on the current platform and architecture.
- addModuleDefinitions(constructModuleDefinitions(mdInfoMap));
- }
+ for (File file : jamFiles) {
+ try {
+ // Put the jam file into the repository cache and cook it
+ ModuleDefInfo mdInfo = repositoryCache.getModuleDefInfo(getSourceLocation().toURL(), file);
+
+ // Constructs a module archive info
+ JamModuleArchiveInfo mai = new JamModuleArchiveInfo(
+ this, mdInfo.getName(), mdInfo.getVersion(),
+ mdInfo.getPlatform(), mdInfo.getArch(),
+ file.getAbsolutePath(), file.lastModified(),
+ mdInfo.getMetadataByteBuffer(),
+ mdInfo.getModuleContent());
+
+ result.add(mai);
+ } catch (Exception ex) {
+ // XXX log warning but otherwise ignore
+ System.err.println("Failed to load module from " + file + ": " + ex);
+ }
+ }
+
+ // The source directory may contain more than one module with the
+ // same name and same version, e.g. duplicate module with different
+ // JAM filename, or portable module vs platform specific module.
+
+ // Constructs the module definitions from the module archives
+ // based on the current platform and architecture.
+ addModuleDefinitions(constructModuleDefinitions(result));
return result;
}
- /**
- * Install a module archive from a URL.
- */
+ @Override
protected ModuleArchiveInfo doInstall(URL url) throws IOException {
InputStream is = null;
File tmpFile = null;
@@ -288,13 +273,13 @@ public final class LocalRepository exten
// Check to see if there exists a module archive that has
// the same name, version, and platform binding.
- for (ModuleArchiveInfo a : list()) {
+ for (ModuleArchiveInfo a : getModuleArchiveInfos()) {
JamModuleArchiveInfo mai = (JamModuleArchiveInfo) a;
if (mai.getName().equals(mdInfo.getName())
&& mai.getVersion().equals(mdInfo.getVersion())) {
- if (mai.isPlatformArchNeutral()) {
- if (mdInfo.isPlatformArchNeutral()) {
+ if (mai.isPortable()) {
+ if (mdInfo.isPortable()) {
throw new IllegalStateException("A module definition with the same name,"
+ " version, and platform binding is already installed");
}
@@ -334,7 +319,7 @@ public final class LocalRepository exten
JamUtils.copyFile(tmpFile, jamFile);
// Put the JAM file into the repository cache, cook it, and
- // update the internal data structure to reflect the change.
+ // reflect the change.
return addModuleArchiveInternal(jamFile);
} catch(IOException ioe) {
// Something went wrong, remove the jam file in the source
@@ -351,15 +336,8 @@ public final class LocalRepository exten
}
}
- /**
- * Uninstall a module archive.
- */
+ @Override
protected boolean doUninstall(ModuleArchiveInfo mai) throws IOException {
- // Checks if the module archive still exists.
- if (!list().contains(mai)) {
- return false;
- }
-
// Remove the module archive if it is the same one that was installed,
// as determined by timestamp. Don't remove if the timestamp is
// different, as that could mean a file has been copied over the
@@ -376,40 +354,34 @@ public final class LocalRepository exten
}
// Remove the module archive and the corresponding module definition
- // (if it has been created) from the internal data structures so this
- // repository wont'recognize it anymore.
+ // (if it has been created) so this repository wont'recognize them
+ // anymore.
removeModuleArchiveInternal(mai);
return true;
}
- /**
- * Reload all module archives.
- */
+ @Override
protected void doReload() throws IOException {
- readOnly = (sourceDirectory.canWrite() == false);
-
- // Build a list of modules to uninstall, and of modules currently
- // installed that won't be uninstalled by this reload.
- List<ModuleArchiveInfo> uninstallCandidates = new ArrayList<ModuleArchiveInfo>();
+ Set<ModuleArchiveInfo> uninstalledJams = new HashSet<ModuleArchiveInfo>();
Set<File> existingJams = new HashSet<File>();
- for (ModuleArchiveInfo mai : list()) {
+
+ for (ModuleArchiveInfo mai : getModuleArchiveInfos()) {
File f = new File(mai.getFileName());
long modTime = mai.getLastModified();
- // Uninstall if source file is missing, or if it has been updated on disk.
+
+ // A module archive is considered "uninstalled" if source file is
+ // missing, or if it has been updated on disk.
if (!f.isFile() || (modTime != 0 && f.lastModified() != modTime)) {
- uninstallCandidates.add(mai);
+ uninstalledJams.add(mai);
} else {
existingJams.add(f);
}
}
- // Remove modules from the internal data structures for which there
- // is no corresponding JAM file in the source directory.
- for (ModuleArchiveInfo mai : uninstallCandidates) {
- // Removes the module archive and the corresponding module
- // definition from the internal data structure so this
- // repository won't recognize it anymore.
+ // Removes the module archive and the corresponding module
+ // definition from the repository.
+ for (ModuleArchiveInfo mai : uninstalledJams) {
removeModuleArchiveInternal(mai);
}
@@ -419,36 +391,33 @@ public final class LocalRepository exten
if (!existingJams.contains(file)) {
try {
// Put the JAM file into the repository cache, cook it,
- // and update the internal data structure of this
- // repository to reflect the change.
+ // and reflect the change.
addModuleArchiveInternal(file);
} catch(IOException ioe) {
// XXX: if reload() throws exception, there is no gurantee
- // that the internal data structure of the repository
- // remains the same as before reload() is called.
+ // that the set of module archives and module definitions
+ // in the repository remains the same as before reload()
+ // is called.
throw ioe;
}
}
}
- // It is possible that a platform specific module (that matches the
- // running platform/arch) have been uninstalled, but there is a
- // platform neutral module with the same name and version already
- // installed previously (i.e. not newly installed) in the repository.
- // In this case, the repository does not have any module definition for
- // this module name/version, and we'll need to construct a new module
- // definition and sync up the internal data structure again.
+ // A repository may have both portable module and platform specific
+ // modules with the same name and version installed, and it has
+ // constructed a module definition from one of the platform specific
+ // module. If this platform specific module is uninstalled, the
+ // repository will need to construct a new module definition from
+ // the portable module.
reconstructModuleDefinitionsIfNecessary();
}
- /**
- * Shutdown the repository.
- */
+ @Override
protected void doShutdown2() throws IOException {
// XXX This is a hook for testing shutdownOnExit.
if (uninstallOnShutdown) {
// Only remove what was installed
- for (ModuleArchiveInfo mai : list()) {
+ for (ModuleArchiveInfo mai : getModuleArchiveInfos()) {
try {
uninstall(mai);
} catch(Exception e) {
@@ -458,17 +427,11 @@ public final class LocalRepository exten
}
}
- /**
- * @return true if this repository is read-only; false otherwise
- */
@Override
public boolean isReadOnly() {
- return readOnly;
- }
-
- /**
- * @return true
- */
+ return (sourceDirectory.canWrite() == false);
+ }
+
@Override
public boolean supportsReload() {
return true;
--- a/src/share/classes/sun/module/repository/MetadataXMLReader.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/repository/MetadataXMLReader.java Mon Aug 04 14:55:36 2008 -0700
@@ -29,6 +29,7 @@ import java.io.BufferedInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.module.Repository;
import java.module.Version;
import java.net.URL;
import java.net.URLConnection;
@@ -52,21 +53,28 @@ import sun.module.JamUtils;
/**
* Reads from data from a {@code URL} which conforms to the
* <tt>RepositoryMetadata.xml</tt> schema, providing a set of
- * {@code URLModuleInfo} instances.
+ * {@code JamModuleArchiveInfo} instances.
* @since 1.7
*/
public class MetadataXMLReader extends DefaultHandler implements ErrorHandler {
- /** URLModuleInfo corresponding to data read from repository-metadata.xml. */
- private final Set<URLModuleInfo> urlModuleInfos = new HashSet<URLModuleInfo>();
+
+ private Repository repository;
+
+ /** JamModuleArchiveInfo corresponding to data read from repository-metadata.xml. */
+ private final Set<JamModuleArchiveInfo> result = new HashSet<JamModuleArchiveInfo>();
/** For handling errors. */
private Locator locator;
- /** Repository's source location. */
- private final String sourceLocation;
-
- /** Builds up information used to create elements of {@codeurlModuleInfos}. */
- private MutableURLModuleInfo urlModuleInfo;
+ /** URL connection to the repository metadata file. */
+ private final URLConnection conn;
+
+ /** Builds up information during parsing. */
+ private String moduleName;
+ private String moduleVersion;
+ private String platform;
+ private String arch;
+ private String path;
/**
* The setting of @{code expect} determines how the next invocation of
@@ -81,20 +89,21 @@ public class MetadataXMLReader extends D
private Kind expect = Kind.NONE;
/**
- * Returns information from given URL as a set
- * of URLModuleInfo instances. Validates the data aginst the
- * schema in {@code java/module/RepositoryMetadata.xml}.
+ * Returns information from given URL as a set of
+ * JamModuleArchiveInfo instances. Validates the data aginst the
+ * schema in {@code java/module/repository-metadata-schema.xml}.
*
- * @param source {@code URL} to a file which conforms to
- * the <tt>RepositoryMetadata.xml</tt> schema.
- * @return a {@code Set<URLModuleInfo>}, with one {@code URLModuleInfo} for each
- * <tt>module</tt> entry in the <tt>repository-metadata.xml</tt>.
+ * @param conn {@code URLConnection} to read the repository metadata file.
+ * @return a {@code Set<JamModuleArchiveInfo>}, with one
+ * {@code JamModuleArchiveInfo} for each
+ * <tt>module</tt> entry in the repository metadata file.
* @throws NullPointerException if any argument is null.
- * @throws IllegalArgumentException if the {@code source} has duplicate entries
- * (note that the <tt>path</tt> element is not considered when checking for
- * duplicates, though other elements are).
- */
- public static Set<URLModuleInfo> read(URL source) throws SAXException, IOException {
+ * @throws IllegalArgumentException if the repository metadata file has
+ * duplicate entries (note that the <tt>path</tt> element is not
+ * considered when checking for duplicates, though other elements
+ * are).
+ */
+ public static Set<JamModuleArchiveInfo> read(Repository repository, URLConnection conn) throws SAXException, IOException {
InputStream schemaStream = null;
InputStream repoStream = null;
@@ -124,13 +133,13 @@ public class MetadataXMLReader extends D
// Read the soruce into a byte array so it does not need to be downloaded
// more than once.
- repoStream = source.openStream();
+ repoStream = conn.getInputStream();
byte[] byteBuffer = JamUtils.getInputStreamAsBytes(repoStream);
// Validate schema
schemaStream = new BufferedInputStream(
ClassLoader.getSystemResourceAsStream(
- "java/module/RepositoryMetadata.xml"));
+ "java/module/repository-metadata-schema.xml"));
StreamSource ss = new StreamSource(schemaStream);
Schema s = f.newSchema(ss);
@@ -141,13 +150,13 @@ public class MetadataXMLReader extends D
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
MetadataXMLReader moduleTypeReader =
- new MetadataXMLReader(source.toString());
+ new MetadataXMLReader(repository, conn);
xmlReader.setErrorHandler(moduleTypeReader);
xmlReader.setContentHandler(moduleTypeReader);
is = new ByteArrayInputStream(byteBuffer);
xmlReader.parse(new InputSource(is));;
- return moduleTypeReader.urlModuleInfos;
+ return moduleTypeReader.result;
} finally {
// Restore context class loader
t.setContextClassLoader(cl);
@@ -157,8 +166,9 @@ public class MetadataXMLReader extends D
}
}
- private MetadataXMLReader(String sourceLocation) {
- this.sourceLocation = sourceLocation;
+ private MetadataXMLReader(Repository repository, URLConnection conn) {
+ this.repository = repository;
+ this.conn = conn;
}
//
@@ -196,7 +206,11 @@ public class MetadataXMLReader extends D
public void startElement(String ns, String name, String qname, Attributes attrs)
throws SAXException {
if ("module".equals(name)) {
- urlModuleInfo = new MutableURLModuleInfo();
+ moduleName = null;
+ moduleVersion = null;
+ platform = null;
+ arch = null;
+ path = null;
} else if ("name".equals(name)) {
expect = Kind.NAME;
} else if ("version".equals(name)) {
@@ -214,12 +228,23 @@ public class MetadataXMLReader extends D
public void endElement(String ns, String name, String qname)
throws SAXException, IllegalArgumentException {
if ("module".equals(name)) {
- URLModuleInfo mi = new URLModuleInfo(urlModuleInfo);
- if (urlModuleInfos.contains(mi)) {
+ Version version = Version.valueOf(moduleVersion);
+
+ if (path != null) {
+ if (path.startsWith("/") || path.endsWith("/")) {
+ throw new IllegalArgumentException(
+ "The path must not have leading or trailing \"'\".");
+ }
+ }
+
+ JamModuleArchiveInfo jmai = new JamModuleArchiveInfo(repository,
+ moduleName, version,
+ platform, arch, path);
+ if (result.contains(jmai)) {
throw new IllegalArgumentException(
- "duplicate URLModuleInfo is not allowed in " + sourceLocation);
+ "The repository metadata file has duplicate module entry.");
} else {
- urlModuleInfos.add(mi);
+ result.add(jmai);
}
expect = Kind.NONE;
}
@@ -232,35 +257,23 @@ public class MetadataXMLReader extends D
if (!tmp.trim().equals("")) {
switch (expect) {
case NAME:
- urlModuleInfo.setName(tmp);
+ moduleName = tmp;
break;
case VERSION:
- urlModuleInfo.setVersion(Version.valueOf(tmp));
+ moduleVersion = tmp;
break;
case PLATFORM:
- urlModuleInfo.setPlatform(tmp);
+ platform = tmp;
break;
case ARCH:
- urlModuleInfo.setArch(tmp);
+ arch = tmp;
break;
case PATH:
- urlModuleInfo.setPath(tmp);
+ path = tmp;
break;
case NONE:
break;
}
}
}
-
- //
- // Local implementation support
- //
-
- private static class MutableURLModuleInfo extends URLModuleInfo {
- void setName(String name) { this.name = name; }
- void setVersion(Version version) { this.version = version; }
- void setPlatform(String platform) { this.platform = platform; }
- void setArch(String arch) { this.arch = arch; }
- void setPath(String path) { this.path = path; }
- }
}
--- a/src/share/classes/sun/module/repository/URLRepository.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/repository/URLRepository.java Mon Aug 04 14:55:36 2008 -0700
@@ -44,6 +44,8 @@ import java.module.Repository;
import java.module.Repository;
import java.module.RepositoryEvent;
import java.module.Version;
+import java.nio.ByteBuffer;
+import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
@@ -63,57 +65,8 @@ import sun.module.repository.cache.Modul
import sun.module.repository.cache.ModuleDefInfo;
/**
- * This class represents a repository that loads module definitions from a
- * codebase URL.
- * <p>
- * Information about the module definitions available from the codebase URL
- * must be published in a repository metadata file. The contents of the file
- * must follow the schema of the URL Repository metadata for the Java Module
- * System.
- * <p><i>
- * {codebase}/repository-metadata.xml
- * <p></i>
- * When the repository is initialized, the repository metadata file (i.e.
- * repository-metadata.xml) would be downloaded from the codebase URL.
- * <p>
- * In the repository metadata file, each module definition is described with
- * a name, a version, a platform binding, and a path (relative to the codebase
- * URL where the module file, the module archive, and/or the packed module
- * archive are located). If no path and no platform binding is specified, the
- * default path is "{name}/{version}". If the path is not specified and the
- * module definition has platform binding, the default path is
- * "{name}/{version}/{platform}-{arch}".
- * <p>
- * After the URL repository instance successfully downloads the repository
- * metadata file, the module metadata file of each module definition
- * (i.e. MODULE.METADATA file) in the repository is downloaded based on the
- * information in the repository metadata file:
- * <p><i>
- * {codebase}/{path}/MODULE.METADATA
- * <p></i>
- * If a module definition is platform-specific, its module metadata file is
- * downloaded if and only if the platform binding described in the
- * repository metadata file matches the platform and the architecture of the
- * system.
- * <p>
- * Module definitions are available for searches after the URL repository
- * instance is initialized. If a module instance is instantiated from a module
- * definition that has no platform binding, the module archive is downloaded
- * by probing in the following order:
- * <p><i>
- * {codebase}/{path}/{name}-{version}.jam.pack.gz<p>
- * {codebase}/{path}/{name}-{version}.jam
- * <p></i>
- * On the other hand, if a module instance is instantiated from a
- * platform-specific module definition, the module archive is downloaded by
- * probing in the following order:
- * <p><i>
- * {codebase}/{path}/{name}-{version}-{platform}-{arch}.jam.pack.gz<p>
- * {codebase}/{path}/{name}-{version}-{platform}-{arch}.jam
- * <p></i>
- * To ensure the integrity of the separately-hosted module file is in sync
- * with that in the module archive of the same module definition, they are
- * compared bit-wise against each other after the module archive is downloaded.
+ * This class represents the URL repository in the JAM module system.
+ * See the {@link java.module.Modules} class for more details.
*
* @see java.module.ModuleArchiveInfo
* @see java.module.ModuleDefinition
@@ -124,6 +77,8 @@ import sun.module.repository.cache.Modul
*/
public final class URLRepository extends AbstractRepository {
+ private static final String REPOSITORY_METADATA_XML = "repository-metadata.xml";
+
/** Prefix of all properties use to configure this repository. */
private static final String PROPERTY_PREFIX = "sun.module.repository.URLRepository.";
@@ -177,7 +132,10 @@ public final class URLRepository extends
/** The architecture on which this URLRepository is running. */
// Non-final to assist in testing.
- private static String arch = RepositoryUtils.getArch();;
+ private static String arch = RepositoryUtils.getArch();
+
+ // Last modified date of the repository metadata file.
+ private long lastModified = 0;
/**
* Creates a new <code>URLRepository</code> instance, and initializes it
@@ -201,6 +159,8 @@ public final class URLRepository extends
Map<String, String> config,
Repository parent) throws IOException {
super(name, codebase, (config == null ? DEFAULT_CONFIG : config), parent);
+
+ initialize();
}
//
@@ -227,6 +187,7 @@ public final class URLRepository extends
* @param config Map of configuration names to their values
* @throws IOException if the repository cannot be initialized.
*/
+ @Override
protected final List<ModuleArchiveInfo> doInitialize2() throws IOException {
String tmp = getSourceLocation().toURL().toExternalForm();
if (tmp.endsWith("/")) {
@@ -262,79 +223,70 @@ public final class URLRepository extends
arch = v;
}
- Set<URLModuleInfo> urlModuleInfoSet = null;
try {
- URL repoMD = new URL(canonicalizedCodebase + "repository-metadata.xml");
- urlModuleInfoSet = MetadataXMLReader.read(repoMD);
-
- // Initializes the internal data structures based on the module
- // info set.
- return doInitialize2(urlModuleInfoSet);
+ URL repositoryMetadataURL = new URL(canonicalizedCodebase + REPOSITORY_METADATA_XML);
+ URLConnection conn = repositoryMetadataURL.openConnection();
+ lastModified = conn.getLastModified();
+ Set<JamModuleArchiveInfo> jmais = MetadataXMLReader.read(this, conn);
+
+ // Initializes based on the module archive info set.
+ return doInitialize2(jmais);
} catch (IOException ex) {
// ignore IOException
return new ArrayList<ModuleArchiveInfo>();
} catch (Exception ex) {
throw new IOException(
- "Error processing repository-metadata.xml: " + ex.getMessage(), ex);
- }
- }
-
- /**
- * Initialize the internal data structures of the repository based on the
- * modules information in the module info set. Creates the appropriate
- * module definitions if necessary.
- */
- private List<ModuleArchiveInfo> doInitialize2(Set<URLModuleInfo> urlModuleInfoSet)
+ "Error processing " + REPOSITORY_METADATA_XML + ": " + ex.getMessage(), ex);
+ }
+ }
+
+ /**
+ * Initialize the repository based on the modules information in the
+ * module archive info set. Creates the appropriate module definitions
+ * if necessary.
+ */
+ private List<ModuleArchiveInfo> doInitialize2(Set<JamModuleArchiveInfo> jmais)
throws IOException {
List<ModuleArchiveInfo> result = new ArrayList<ModuleArchiveInfo>();
- if (urlModuleInfoSet != null) {
- Map<ModuleArchiveInfo, ModuleDefInfo> mdInfoMap =
- new HashMap<ModuleArchiveInfo, ModuleDefInfo>();
- for (URLModuleInfo mi : urlModuleInfoSet) {
- try {
- // Retrieves the module metadata
- ModuleDefInfo mdInfo = repositoryCache.getModuleDefInfo(
- canonicalizedCodebase,
- mi.getName(), mi.getVersion(),
- mi.getPlatform(), mi.getArch(),
- mi.getCanonicalizedPath());
-
- // Constructs a module archive info
- JamModuleArchiveInfo mai = new JamModuleArchiveInfo(
- this, mdInfo.getName(), mdInfo.getVersion(),
- mdInfo.getPlatform(), mdInfo.getArch(), null, 0);
-
- mdInfoMap.put(mai, mdInfo);
-
- // Adds the module archive info into the internal data structure.
- result.add(mai);
- } catch (Exception ex) {
- // XXX log warning but otherwise ignore
- if (mi.getPlatform() == null && mi.getArch() == null) {
- System.err.println("Failed to load module " + mi.getName()
- + " v" + mi.getVersion() + " from "
- + getSourceLocation() + ": " + ex);
- } else {
- System.err.println("Failed to load module " + mi.getName()
- + " v" + mi.getVersion() + " "
- + mi.getPlatform() + "-" + mi.getArch()
- + " from " + getSourceLocation() + ": " + ex);
- }
+ for (JamModuleArchiveInfo mai : jmais) {
+ try {
+ // Retrieves the module metadata
+ ModuleDefInfo mdInfo = repositoryCache.getModuleDefInfo(
+ canonicalizedCodebase,
+ mai.getName(), mai.getVersion(),
+ mai.getPlatform(), mai.getArch(),
+ mai.getCanonicalizedPath());
+
+ // Set up the module archive info properly
+ mai.setMetadataByteBuffer(mdInfo.getMetadataByteBuffer());
+ mai.setModuleContent(mdInfo.getModuleContent());
+
+ // Adds the module archive info to the result
+ result.add(mai);
+ } catch (Exception ex) {
+ // XXX log warning but otherwise ignore
+ if (mai.isPortable()) {
+ System.err.println("Failed to load module " + mai.getName()
+ + " v" + mai.getVersion() + " from "
+ + getSourceLocation() + ": " + ex);
+ } else {
+ System.err.println("Failed to load module " + mai.getName()
+ + " v" + mai.getVersion() + " "
+ + mai.getPlatform() + "-" + mai.getArch()
+ + " from " + getSourceLocation() + ": " + ex);
}
}
-
- // Constructs the module definitions from the module archives
- // based on the specified platform and architecture.
- addModuleDefinitions(constructModuleDefinitions(mdInfoMap, platform, arch));
- }
+ }
+
+ // Constructs the module definitions from the module archives
+ // based on the specified platform and architecture.
+ addModuleDefinitions(constructModuleDefinitions(result, platform, arch));
return result;
}
- /**
- * Install a module archive from a URL.
- */
+ @Override
protected ModuleArchiveInfo doInstall(URL url) throws IOException {
InputStream is = null;
File sourceFile = null;
@@ -368,13 +320,13 @@ public final class URLRepository extends
// Check to see if there exists a module archive that has
// the same name, version, and platform binding.
- for (ModuleArchiveInfo ma : list()) {
+ for (ModuleArchiveInfo ma : getModuleArchiveInfos()) {
JamModuleArchiveInfo mai = (JamModuleArchiveInfo) ma;
if (mai.getName().equals(mdInfo.getName())
&& mai.getVersion().equals(mdInfo.getVersion())) {
- if (mai.isPlatformArchNeutral()) {
- if (mdInfo.isPlatformArchNeutral()) {
+ if (mai.isPortable()) {
+ if (mdInfo.isPortable()) {
throw new IllegalStateException("A module definition with the same name,"
+ " version, and platform binding is already installed");
}
@@ -386,6 +338,10 @@ public final class URLRepository extends
}
}
+ JamModuleArchiveInfo mai = new JamModuleArchiveInfo(this, mdInfo.getName(),
+ mdInfo.getVersion(), mdInfo.getPlatform(),
+ mdInfo.getArch(), null);
+
/*
* Installing the module requires these steps:
* (1) Creating MODULE.METADATA
@@ -404,15 +360,21 @@ public final class URLRepository extends
// <source location>/<module-name>/<module-version>
// or
// <source location>/<module-name>/<module-version>/<platform>-<arch>
- File moduleDestDir= new File(sourceDir, getFilePath(mdInfo.getName(), mdInfo.getVersion(),
- mdInfo.getPlatform(), mdInfo.getArch()));
+ File moduleDestDir= new File(sourceDir,
+ mai.getCanonicalizedPath(File.separatorChar));
+ // getFilePath(mdInfo.getName(), mdInfo.getVersion(),
+ // mdInfo.getPlatform(), mdInfo.getArch()));
moduleDestDir.mkdirs();
// Copy MODULE.METADATA file
destMDFile = new File(moduleDestDir, JamUtils.MODULE_METADATA);
BufferedOutputStream bos =
new BufferedOutputStream(new FileOutputStream(destMDFile));
- byte[] metadataBytes = mdInfo.getMetadataBytes();
+
+ ByteBuffer metadataByteBuffer = mdInfo.getMetadataByteBuffer();
+ byte[] metadataBytes = new byte[metadataByteBuffer.remaining()];
+ metadataByteBuffer.get(metadataBytes); // get bytes out of byte buffer.
+
bos.write(metadataBytes, 0, metadataBytes.length);
bos.flush();
bos.close();
@@ -439,9 +401,7 @@ public final class URLRepository extends
// Note that we create a temp ModuleArchiveInfo so we
// could update the repository metadata before we
// have a real ModuleArchiveInfo in step 4.
- writeRepositoryMetadata(new JamModuleArchiveInfo(this, mdInfo.getName(),
- mdInfo.getVersion(), mdInfo.getPlatform(),
- mdInfo.getArch(), null, 0), true);
+ updateRepositoryMetadata(mai, true);
// (4) Update internal data structures.
return addModuleArchiveInternal(destJamFile);
@@ -464,50 +424,37 @@ public final class URLRepository extends
}
}
- /**
- * Uninstall a module archive.
- */
+ @Override
protected boolean doUninstall(ModuleArchiveInfo mai) throws IOException {
- // Checks if the module archive still exists.
- if (!list().contains(mai)) {
- return false;
- }
-
// Source location
File sourceDir = new File(getSourceLocation().toURL().getFile());
- // Delete file/filesystem resources related to md, and then
- // remove it from contents.
- String moduleName = mai.getName();
- Version moduleVersion = mai.getVersion();
- String modulePlatform = mai.getPlatform();
- String moduleArch = mai.getArch();
-
- // This is the directory which contains MODULE.METADATA and JAM file.
+ // Delete files related to the module definition (e.g. MODULE.METADATA,
+ // .jam, .jam.pack.gz files), then remove the module's entry from
+ // the repository metadata file.
//
- // XXX moduleDir may not be right if the deployers have configured
- // a custom path in the repository-metadata.xml before. Will fix.
- File moduleDir = new File(sourceDir, getFilePath(moduleName,
- moduleVersion, modulePlatform,
- moduleArch));
+
+ // Directory which contains MODULE.METADATA and JAM file.
+ //
+ File moduleDir = new File(sourceDir, ((JamModuleArchiveInfo) mai).getCanonicalizedPath());
verifyExistence(moduleDir);
//
- // A module archive could be platform neutral or platform specific,
+ // A module archive could be portable or platform specific,
// and it resides under the same top directory for a given module
// name and version:
//
// <source location>/<module-name>/<module-version>/
// <source location>/<module-name>/<module-version>/<platform>-<arch>/
//
- // Thus, we cannot just blow away the directory because there
- // could be a platform specific subdirectory for other platform
- // specific module archives.
+ // We cannot just blow away the directory because there may
+ // exist some subdirectories for other platform specific
+ // module archives.
// jam name has no file extension
- String jamName = JamUtils.getJamFilename(moduleName, moduleVersion,
- modulePlatform, moduleArch);
+ String jamName = JamUtils.getJamFilename(mai.getName(), mai.getVersion(),
+ mai.getPlatform(), mai.getArch());
File packGzJamFile = new File(moduleDir, jamName + ".jam.pack.gz");
File jamFile = new File(moduleDir, jamName + ".jam");
@@ -535,7 +482,7 @@ public final class URLRepository extends
// Updated the repository metadata without the specified
// module archive.
- writeRepositoryMetadata(mai, false);
+ updateRepositoryMetadata((JamModuleArchiveInfo) mai, false);
if (metadataFileToRemove != null) {
metadataFileToRemove.delete();
@@ -566,52 +513,57 @@ public final class URLRepository extends
rename(packGzJamFileToRemove, packGzJamFile);
}
- writeRepositoryMetadata(mai, true);
+ updateRepositoryMetadata((JamModuleArchiveInfo) mai, true);
+
throw ex;
}
- // Remove the module archive and its corresponding module definition
- // from the internal data structures
+ // Remove the module archive and its corresponding module definition.
removeModuleArchiveInternal(mai);
return true;
}
- /**
- * Reload all module archives.
- */
+ @Override
protected void doReload() throws IOException {
try {
/**
- * Since the repository-metadata.xml does not contain any
+ * Since the repository metadata file does not contain any
* modification date information about the module metadata
* and the .jam/.jam.pack.gz file, it is rather complicated
* to detect actual change in individual module. For
* simplicity, this implementation would simply drop all the
* existing modules, and reload all module archives from the
* codebase again.
- *
- * XXX: We should check the timestamp of the repository
- * metadata and only reload if it has been modified. Also, for
- * each MODULE.METADATA which is downloaded via a
- * URLConnection, one can getLastModified(), and we could use
- * the information to determine if a module has been updated.
*/
- URL repoMD = new URL(canonicalizedCodebase + "repository-metadata.xml");
- Set<URLModuleInfo> urlModuleInfoSet = MetadataXMLReader.read(repoMD);
+ URL repositoryMetadataURL = new URL(canonicalizedCodebase + REPOSITORY_METADATA_XML);
+ URLConnection conn = repositoryMetadataURL.openConnection();
+
+ long oldLastModified = lastModified;
+ lastModified = conn.getLastModified();
+
+ // Compare timestamp of repository metadata file to last known value
+ if (oldLastModified != 0 && oldLastModified == lastModified) {
+ // Repository metadata file has not been changed.
+ // Close the connection and return.
+ if (conn instanceof HttpURLConnection) {
+ ((HttpURLConnection) conn).disconnect();
+ }
+ conn.getInputStream().close();
+ return;
+ }
+
+ Set<JamModuleArchiveInfo> jmais = MetadataXMLReader.read(this, conn);
// Uninstall all existing module archives and module definitions
- for (ModuleArchiveInfo mai : list()) {
+ for (ModuleArchiveInfo mai : getModuleArchiveInfos()) {
removeModuleArchiveInternal(mai);
}
- // Clear internal module archive/module definition mapping
- contentMapping.clear();
-
// Initializes the data structures based on the module info set again.
- List<ModuleArchiveInfo> moduleArchiveInfos = doInitialize2(urlModuleInfoSet);
-
- // Adds the module archives into the internal data structure
+ List<ModuleArchiveInfo> moduleArchiveInfos = doInitialize2(jmais);
+
+ // Adds the module archives into the repository
for (ModuleArchiveInfo mai : moduleArchiveInfos) {
addModuleArchiveInfo(mai);
}
@@ -634,10 +586,6 @@ public final class URLRepository extends
// Nothing specific to do during shutdown. No-op.
}
- /**
- * @return true if this repository is read-only, which is the case if it
- * was created with any other than a file: URL.
- */
@Override
public boolean isReadOnly() {
try {
@@ -647,31 +595,28 @@ public final class URLRepository extends
}
}
- /**
- * @return true if this repository supports reload.
- */
@Override
public boolean supportsReload() {
return true;
}
/**
- * Writes the repository's repository-metadata.xml file based on {@code
- * contents}.
- * @param mai {@code ModuleArchiveInfo} on behalf of which the metadata is
- * written.
- * @param writeMAI if true, then write the given {@code mai} in addition
- * to the repository's other contents.
- */
- private void writeRepositoryMetadata(
- ModuleArchiveInfo mai,
+ * Updates the repository metadata file.
+ *
+ * @param mai {@code JamModuleArchiveInfo} on behalf of which the metadata
+ * is written.
+ * @param writeMAI true if the given {@code mai} should be written in
+ * addition to the other module archive infos in the repository
+ */
+ private void updateRepositoryMetadata(
+ JamModuleArchiveInfo mai,
boolean writeMAI) throws IOException {
URL repoMD = new URL(
getSourceLocation().toURL().toExternalForm()
- + "/repository-metadata.xml");
+ + "/" + REPOSITORY_METADATA_XML);
File repoMDFile = new File(repoMD.getFile());
File repoMDDir = repoMDFile.getParentFile();
- File tmpRepoMDFile = new File(repoMDDir, "repository-metadata.xml.tmp");
+ File tmpRepoMDFile = new File(repoMDDir, REPOSITORY_METADATA_XML + ".tmp");
if (tmpRepoMDFile.exists()) {
if (!tmpRepoMDFile.delete()) {
throw new IOException(
@@ -681,9 +626,9 @@ public final class URLRepository extends
+ tmpRepoMDFile);
}
}
- RepoMDWriter writer = new RepoMDWriter(tmpRepoMDFile);
+ RepositoryMetadataWriter writer = new RepositoryMetadataWriter(tmpRepoMDFile);
writer.begin();
- for (ModuleArchiveInfo m : list()) {
+ for (ModuleArchiveInfo m : getModuleArchiveInfos()) {
if (!writeMAI && m.equals(mai)) {
// Don't write this ModuleArchiveInfo if it matches that given
} else {
@@ -691,7 +636,7 @@ public final class URLRepository extends
}
}
if (writeMAI) {
- writer.writeModule((JamModuleArchiveInfo) mai);
+ writer.writeModule(mai);
}
if (!writer.end()) {
@@ -727,14 +672,14 @@ public final class URLRepository extends
}
}
- /** Writes XML for a repository-metadata.xml file. */
- static class RepoMDWriter {
+ /** Writes XML for the repository metadata file. */
+ static class RepositoryMetadataWriter {
private final PrintWriter pw;
private int indent = 0;
private static final int WIDTH = 4;
private static final String spaces = " ";
- RepoMDWriter(File out) throws IOException {
+ RepositoryMetadataWriter(File out) throws IOException {
pw = new PrintWriter(
new BufferedOutputStream(
new FileOutputStream(out)), false);
@@ -759,7 +704,7 @@ public final class URLRepository extends
indent++;
output("<name>" + mai.getName() + "</name>");
output("<version>" + mai.getVersion().toString() + "</version>");
- if (!mai.isPlatformArchNeutral()) {
+ if (!mai.isPortable()) {
output("<platform-binding>");
indent++;
output("<platform>" + mai.getPlatform() + "</platform>");
@@ -767,10 +712,9 @@ public final class URLRepository extends
indent--;
output("</platform-binding>");
}
-
- // Note that we don't support <path>, since there's no way to
- // specify that via Repository.install().
-
+ if (mai.getPath() != null) {
+ output("<path>" + mai.getPath() + "</path>");
+ }
indent--;
output("</module>");
}
@@ -812,23 +756,6 @@ public final class URLRepository extends
if (prev != null) {
prev.renameTo(next);
}
- }
-
- /**
- * Returns file path for a module under codebase, based on module name,
- * version, platform and architecture.
- *
- * @param name module name
- * @param version module version
- * @param platform target platform
- * @param arch target architecture
- * @return file path
- */
- private static String getFilePath(String name, Version version,
- String platform, String arch) {
- return name + File.separator + version
- + ((platform == null) ? "" :
- File.separator + platform + "-" + arch);
}
protected void assertValidDirs() throws IOException {
--- a/src/share/classes/sun/module/repository/cache/Cache.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/repository/cache/Cache.java Mon Aug 04 14:55:36 2008 -0700
@@ -181,7 +181,7 @@ import sun.module.repository.RepositoryU
String platform, String arch) throws IOException {
String path;
if (platform == null || arch == null) {
- // platform neutral module
+ // portable module
path = name + "/" + version;
} else {
// platform specific module
--- a/src/share/classes/sun/module/repository/cache/CacheModuleContent.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/repository/cache/CacheModuleContent.java Mon Aug 04 14:55:36 2008 -0700
@@ -81,10 +81,11 @@ abstract class CacheModuleContent implem
/**
* Constructs a new cache module content.
*/
- CacheModuleContent(File entryDirectory, byte[] metadataBytes, ModuleInfo moduleInfo) {
+ CacheModuleContent(File entryDirectory, ByteBuffer metadataByteBuffer, ModuleInfo moduleInfo) {
this.entryDirectory = entryDirectory;
- this.metadataBytes = metadataBytes;
this.moduleInfo = moduleInfo;
+ this.metadataBytes = new byte[metadataByteBuffer.remaining()];
+ metadataByteBuffer.asReadOnlyBuffer().get(this.metadataBytes);
}
/**
@@ -204,10 +205,6 @@ abstract class CacheModuleContent implem
* does not match what the module metadata we obtained earlier.
*/
private void compareMetadataBytes(byte[] moduleMetadataBytes) throws IOException {
-
- System.out.println(" " + metadataBytes.length);
- System.out.println(" " + moduleMetadataBytes.length);
-
if ((metadataBytes.length != moduleMetadataBytes.length)
|| Arrays.equals(metadataBytes, moduleMetadataBytes) == false) {
throw new IOException("Mismatch between MODULE.METADATA file and the one in the JAM file");
--- a/src/share/classes/sun/module/repository/cache/LocalModuleContent.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/repository/cache/LocalModuleContent.java Mon Aug 04 14:55:36 2008 -0700
@@ -45,7 +45,7 @@ final class LocalModuleContent extends C
* Constructs a new local cache module content.
*/
LocalModuleContent(LocalModuleDefInfo mdInfo) {
- super(mdInfo.getEntryDirectory(), mdInfo.getMetadataBytes(), mdInfo.getModuleInfo());
+ super(mdInfo.getEntryDirectory(), mdInfo.getMetadataByteBuffer(), mdInfo.getModuleInfo());
this.mdInfo = mdInfo;
}
--- a/src/share/classes/sun/module/repository/cache/ModuleDefInfo.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/repository/cache/ModuleDefInfo.java Mon Aug 04 14:55:36 2008 -0700
@@ -30,6 +30,7 @@ import java.module.ModuleContent;
import java.module.ModuleContent;
import java.module.Version;
import java.module.annotation.PlatformBinding;
+import java.nio.ByteBuffer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import sun.module.JamUtils;
@@ -43,8 +44,8 @@ import sun.module.repository.RepositoryU
// Directory where this object lives.
private final File entryDirectory;
- // Byte array that represents the module metadata
- private final byte[] metadataBytes;
+ // Byte buffer that contains the module metadata
+ private final ByteBuffer metadataByteBuffer;
// ModuleInfo rectified from the module metadata
private final ModuleInfo moduleInfo;
@@ -73,7 +74,7 @@ import sun.module.repository.RepositoryU
*/
ModuleDefInfo(File entryDirectory, byte[] metadataBytes, ModuleInfo moduleInfo) {
this.entryDirectory = entryDirectory;
- this.metadataBytes = metadataBytes;
+ this.metadataByteBuffer = ByteBuffer.wrap(metadataBytes);
this.moduleInfo = moduleInfo;
// Module name
@@ -100,11 +101,10 @@ import sun.module.repository.RepositoryU
}
/**
- * Returns the byte array of the module metadata.
+ * Returns a read-only byte buffer of the module metadata.
*/
- public byte[] getMetadataBytes() {
- // XXX make a copy
- return metadataBytes;
+ public ByteBuffer getMetadataByteBuffer() {
+ return metadataByteBuffer.asReadOnlyBuffer();
}
/**
@@ -136,12 +136,12 @@ import sun.module.repository.RepositoryU
}
/**
- * Determines if the module definition is platform and architecture neutral.
+ * Determines if the module definition is portable.
*
- * @return true if the module archive is platform and architecture neutral;
- * return false otherwise.
+ * @return true if the module definition is portable; otherwise,
+ * return false.
*/
- public boolean isPlatformArchNeutral() {
+ public boolean isPortable() {
return (getPlatform() == null && getArch() == null);
}
@@ -150,7 +150,7 @@ import sun.module.repository.RepositoryU
* architecture.
*/
public boolean supportsRunningPlatformArch() {
- if (isPlatformArchNeutral()) {
+ if (isPortable()) {
return true;
}
--- a/src/share/classes/sun/module/repository/cache/URLModuleContent.java Fri Aug 01 08:19:12 2008 -0700
+++ b/src/share/classes/sun/module/repository/cache/URLModuleContent.java Mon Aug 04 14:55:36 2008 -0700
@@ -61,7 +61,7 @@ final class URLModuleContent extends Cac
* Constructs a new URL module content.
*/
URLModuleContent(URLModuleDefInfo mdInfo) {
- super(mdInfo.getEntryDirectory(), mdInfo.getMetadataBytes(), mdInfo.getModuleInfo());
+ super(mdInfo.getEntryDirectory(), mdInfo.getMetadataByteBuffer(), mdInfo.getModuleInfo());
this.mdInfo = mdInfo;
}
--- a/test/java/module/config/DefaultImportOverridePolicy/DefaultImportOverridePolicyTest.java Fri Aug 01 08:19:12 2008 -0700
+++ b/test/java/module/config/DefaultImportOverridePolicy/DefaultImportOverridePolicyTest.java Mon Aug 04 14:55:36 2008 -0700
@@ -27,6 +27,7 @@ import java.module.ImportDependency;
import java.module.ImportDependency;
import java.module.ImportOverridePolicy;
import java.module.Modules;
+import java.module.ModuleArchiveInfo;
import java.module.ModuleDefinition;
import java.module.ModuleDependency;
import java.module.ModuleContent;
@@ -139,6 +140,11 @@ public class DefaultImportOverridePolicy
}
@Override
+ public ModuleArchiveInfo getModuleArchiveInfo() {
+ return null;
+ }
+
+ @Override
public ModuleContent getModuleContent() {
return null;
}
--- a/test/java/module/config/DefaultVisibilityPolicy/DefaultVisibilityPolicyTest.java Fri Aug 01 08:19:12 2008 -0700
+++ b/test/java/module/config/DefaultVisibilityPolicy/DefaultVisibilityPolicyTest.java Mon Aug 04 14:55:36 2008 -0700
@@ -26,6 +26,7 @@ import java.io.FileNotFoundException;
import java.io.FileNotFoundException;
import java.module.ImportDependency;
import java.module.Modules;
+import java.module.ModuleArchiveInfo;
import java.module.ModuleDefinition;
import java.module.ModuleContent;
import java.module.ModuleSystem;
@@ -138,6 +139,11 @@ public class DefaultVisibilityPolicyTest
}
@Override
+ public ModuleArchiveInfo getModuleArchiveInfo() {
+ return null;
+ }
+
+ @Override
public ModuleContent getModuleContent() {
return null;
}
--- a/test/java/module/config/ImportOverridePolicyFile/ImportOverridePolicyFileTest.java Fri Aug 01 08:19:12 2008 -0700
+++ b/test/java/module/config/ImportOverridePolicyFile/ImportOverridePolicyFileTest.java Mon Aug 04 14:55:36 2008 -0700
@@ -27,6 +27,7 @@ import java.module.ImportDependency;
import java.module.ImportDependency;
import java.module.ImportOverridePolicy;
import java.module.Modules;
+import java.module.ModuleArchiveInfo;
import java.module.ModuleDefinition;
import java.module.ModuleDependency;
import java.module.ModuleContent;
@@ -138,6 +139,11 @@ public class ImportOverridePolicyFileTes
}
@Override
+ public ModuleArchiveInfo getModuleArchiveInfo() {
+ return null;
+ }
+
+ @Override
public ModuleContent getModuleContent() {
return null;
}
--- a/test/java/module/config/VisibilityPolicyFile/VisibilityPolicyFileTest.java Fri Aug 01 08:19:12 2008 -0700
+++ b/test/java/module/config/VisibilityPolicyFile/VisibilityPolicyFileTest.java Mon Aug 04 14:55:36 2008 -0700
@@ -25,6 +25,7 @@ import java.io.File;
import java.io.File;
import java.io.FileNotFoundException;
import java.module.ImportDependency;
+import java.module.ModuleArchiveInfo;
import java.module.ModuleDefinition;
import java.module.ModuleContent;
import java.module.ModuleSystem;
@@ -136,6 +137,11 @@ public class VisibilityPolicyFileTest {
}
@Override
+ public ModuleArchiveInfo getModuleArchiveInfo() {
+ return null;
+ }
+
+ @Override
public ModuleContent getModuleContent() {
return null;
}
--- a/test/java/module/modinit/mtest/deepvalidate/deepvalidate.mtest Fri Aug 01 08:19:12 2008 -0700
+++ b/test/java/module/modinit/mtest/deepvalidate/deepvalidate.mtest Mon Aug 04 14:55:36 2008 -0700
@@ -3,7 +3,8 @@
# - m2 imports m3; no overlapped member class
# - m4 imports m5 imports m6; overlapped member class in m4 and m6
# - m7 imports m4, m6; overlapped member class in m4 and m6
-# - m8 imports java.classpath; deep validation should fail
+# - m8 imports m9 imports java.classpath; deep validation is not supported
+# - m10 imports m11 imports m11 imports m9 again; overlapped member class in m10 and m11
#
>>> begin module m1
> annotations
@@ -70,6 +71,9 @@ m1.MainA
m4.deepValidate();
throw new Exception("m4's deep validation does not fail as expected.");
}
+ catch (UnsupportedOperationException u) {
+ throw new Exception("m4's deep validation fails but unexpected exception is thrown: " + u);
+ }
catch (ModuleInitializationException e) {
}
m5.deepValidate();
@@ -93,12 +97,20 @@ m1.MainA
}
+ // m8 and m9 should NOT support deep validation.
ModuleDefinition md8 = r.find("m8");
+ ModuleDefinition md9 = r.find("m9");
Module m8 = md8.getModuleInstance();
+ Module m9 = md9.getModuleInstance();
// m8 should NOT support deep validation
- if (m8.supportsDeepValidation() == false) {
- throw new Exception("m8 does not support deep validation as expected.");
+ if (m8.supportsDeepValidation() == true) {
+ throw new Exception("m8 unexpectedly supports deep validation.");
+ }
+
+ // m9 should NOT support deep validation
+ if (m9.supportsDeepValidation() == true) {
+ throw new Exception("m9 unexpectedly supports deep validation.");
}
// deep validation should fail for m8
@@ -111,6 +123,69 @@ m1.MainA
}
catch (ModuleInitializationException e) {
}
+
+ // deep validation should fail for m9
+ try {
+ m9.deepValidate();
+ throw new Exception("m9's deep validation does not fail as expected.");
+ }
+ catch (UnsupportedOperationException u) {
+ throw new Exception("m9's deep validation fails but unexpected exception is thrown: " + u);
+ }
+ catch (ModuleInitializationException e) {
+ }
+
+ // m10, m11 and m12 should NOT support deep validation
+ ModuleDefinition md10 = r.find("m10");
+ ModuleDefinition md11 = r.find("m11");
+ ModuleDefinition md12 = r.find("m12");
+ Module m10 = md10.getModuleInstance();
+ Module m11 = md11.getModuleInstance();
+ Module m12 = md12.getModuleInstance();
+
+ // m10, m11 and m12 should support deep validation
+ if (m10.supportsDeepValidation() == false) {
+ throw new Exception("m10 does not support deep validation as expected.");
+ }
+ if (m11.supportsDeepValidation() == false) {
+ throw new Exception("m11 does not support deep validation as expected.");
+ }
+ if (m12.supportsDeepValidation() == false) {
+ throw new Exception("m12 does not support deep validation as expected.");
+ }
+
+ // deep validation should fail for m10
+ try {
+ m10.deepValidate();
+ throw new Exception("m10's deep validation does not fail as expected.");
+ }
+ catch (UnsupportedOperationException u) {
+ throw new Exception("m10's deep validation fails but unexpected exception is thrown: " + u);
+ }
+ catch (ModuleInitializationException e) {
+ }
+
+ // deep validation should fail for m11
+ try {
+ m11.deepValidate();
+ throw new Exception("m11's deep validation does not fail as expected.");
+ }
+ catch (UnsupportedOperationException u) {
+ throw new Exception("m11's deep validation fails but unexpected exception is thrown: " + u);
+ }
+ catch (ModuleInitializationException e) {
+ }
+
+ // deep validation should fail for m12
+ try {
+ m12.deepValidate();
+ throw new Exception("m12's deep validation does not fail as expected.");
+ }
+ catch (UnsupportedOperationException u) {
+ throw new Exception("m12's deep validation fails but unexpected exception is thrown: " + u);
+ }
+ catch (ModuleInitializationException e) {
+ }
>> end class
>>> end module
>>> begin module m2
@@ -194,13 +269,66 @@ m1.MainA
@Version("1.0")
@ImportModules({
@ImportModule(name="java.se"),
+ @ImportModule(name="m9")
+})
+@sun.module.annotation.LegacyClasses({ // Use it as a workaround to populate the membership list
+ "m8.MainH"
+})
+>> begin class m8.MainH
+>> end class
+>>> end module
+>>> begin module m9
+> annotations
+@Version("1.0")
+@ImportModules({
+ @ImportModule(name="java.se"),
@ImportModule(name="java.classpath")
})
@sun.module.annotation.LegacyClasses({ // Use it as a workaround to populate the membership list
- "conflictTypeXYZ",
- "m8.MainH"
-})
->> begin class m8.MainH
+ "m9.MainH"
+})
+>> begin class m9.MainH
+>> end class
+>>> end module
+>>> begin module m10
+> annotations
+@Version("1.0")
+@ImportModules({
+ @ImportModule(name="java.se"),
+ @ImportModule(name="m11")
+})
+@sun.module.annotation.LegacyClasses({ // Use it as a workaround to populate the membership list
+ "m10.MainH"
+})
+>> begin class m10.MainH
+>> end class
+>>> end module
+>>> begin module m11
+> annotations
+@Version("1.0")
+@ImportModules({
+ @ImportModule(name="java.se"),
+ @ImportModule(name="m12")
+})
+@sun.module.annotation.LegacyClasses({ // Use it as a workaround to populate the membership list
+ "m11.MainH",
+ "conflictTypeXYZ"
+})
+>> begin class m11.MainH
+>> end class
+>>> end module
+>>> begin module m12
+> annotations
+@Version("1.0")
+@ImportModules({
+ @ImportModule(name="java.se"),
+ @ImportModule(name="m10")
+})
+@sun.module.annotation.LegacyClasses({ // Use it as a workaround to populate the membership list
+ "m12.MainH",
+ "conflictTypeXYZ"
+})
+>> begin class m12.MainH
>> end class
>>> end module
>>> begin test m1
--- a/test/java/module/query/QueryTest.java Fri Aug 01 08:19:12 2008 -0700
+++ b/test/java/module/query/QueryTest.java Mon Aug 04 14:55:36 2008 -0700
@@ -26,6 +26,7 @@ import java.module.VersionConstraint;
import java.module.VersionConstraint;
import java.module.Query;
import java.module.ImportDependency;
+import java.module.ModuleArchiveInfo;
import java.module.ModuleDefinition;
import java.module.ModuleContent;
import java.module.ModuleSystem;
@@ -150,6 +151,11 @@ public class QueryTest {
}
@Override
+ public ModuleArchiveInfo getModuleArchiveInfo() {
+ return null;
+ }
+
+ @Override
public boolean isModuleReleasable() {
return true;
}
--- a/test/java/module/repository/URLRepositoryReloadTest.java Fri Aug 01 08:19:12 2008 -0700
+++ b/test/java/module/repository/URLRepositoryReloadTest.java Mon Aug 04 14:55:36 2008 -0700
@@ -35,7 +35,6 @@ import java.util.jar.JarFile;
import java.util.jar.JarFile;
import sun.module.JamUtils;
import sun.module.repository.RepositoryConfig;
-import sun.module.repository.MetadataXMLWriter;
import sun.module.repository.URLRepository;
/**
@@ -101,6 +100,11 @@ public class URLRepositoryReloadTest ext
check(!ec.installEventExists(repoTest, null));
check(!ec.uninstallEventExists(repoTest, null));
+ // Sleep for 1 second to make sure the timestamp of
+ // a modified repository metadata file is at last one
+ // second apart from its previous's last modified date
+ Thread.sleep(1000);
+
/*
* Check three cases of reload() [spec 6.2.6]
* (1) New module definition added in source location
@@ -131,13 +135,24 @@ public class URLRepositoryReloadTest ext
// Since repoTest and repoWork share the same filesytem structures, this
// works:
repoTest.reload();
- check(repoTest.find("ModuleJamNew") != null);
+ ModuleDefinition md = repoTest.find("ModuleJamNew");
+ check(md != null);
// Only MODULE_ARCHIVE_INSTALLED event should be fired.
check(!ec.initializeEventExists(repoTest));
check(!ec.shutdownEventExists(repoTest));
check(ec.installEventExists(repoTest, null));
check(!ec.uninstallEventExists(repoTest, null));
+
+ // Reload the repository should have no effect since
+ // there has been no new change
+ repoTest.reload();
+ check(repoTest.find("ModuleJamNew") == md);
+
+ // Sleep for 1 second to make sure the timestamp of
+ // a modified repository metadata file is at last one
+ // second apart from its previous's last modified date
+ Thread.sleep(1000);
// (2) Existing module definition removed from source location
// Uninstall from repoWork...
@@ -161,6 +176,11 @@ public class URLRepositoryReloadTest ext
check(!ec.shutdownEventExists(repoTest));
check(!ec.installEventExists(repoTest, null));
check(ec.uninstallEventExists(repoTest, null));
+
+ // Sleep for 1 second to make sure the timestamp of
+ // a modified repository metadata file is at last one
+ // second apart from its previous's last modified date
+ Thread.sleep(1000);
// (3) Existing module definition replaced in source location
// Create a module in repoTest, make sure it operates as expected
@@ -182,7 +202,8 @@ public class URLRepositoryReloadTest ext
// Now reload repoTest: as with (1), the module should be available
repoTest.reload();
- check(repoTest.find("ModuleJamReplace") != null);
+ md = repoTest.find("ModuleJamReplace");
+ check(md != null);
runModule(repoTest, "ModuleJamReplace", "foo");
// Only MODULE_ARCHIVE_INSTALLED event should be fired.
@@ -190,6 +211,16 @@ public class URLRepositoryReloadTest ext
check(!ec.shutdownEventExists(repoTest));
check(ec.installEventExists(repoTest, null));
check(!ec.uninstallEventExists(repoTest, null));
+
+ // Reload the repository should have no effect since
+ // there has been no new change
+ repoTest.reload();
+ check(repoTest.find("ModuleJamReplace") == md);
+
+ // Sleep for 1 second to make sure the timestamp of
+ // a modified repository metadata file is at last one
+ // second apart from its previous's last modified date
+ Thread.sleep(1000);
// Now remove ModuleJamReplace from repoWork, create a new JAM for a
// module of the same name, and install it in repoWork
@@ -227,6 +258,11 @@ public class URLRepositoryReloadTest ext
check(!ec.shutdownEventExists(repoTest));
check(ec.installEventExists(repoTest, null));
check(ec.uninstallEventExists(repoTest, null));
+
+ // Sleep for 1 second to make sure the timestamp of
+ // a modified repository metadata file is at last one
+ // second apart from its previous's last modified date
+ Thread.sleep(1000);
ModuleArchiveInfo mai = repoWork.list().get(0);
check(repoWork.uninstall(mai));
--- a/test/java/module/repository/URLRepositoryTest.java Fri Aug 01 08:19:12 2008 -0700
+++ b/test/java/module/repository/URLRepositoryTest.java Mon Aug 04 14:55:36 2008 -0700
@@ -36,7 +36,6 @@ import java.util.Map;
import java.util.Map;
import java.util.jar.JarFile;
import sun.module.JamUtils;
-import sun.module.repository.MetadataXMLWriter;
import sun.module.repository.RepositoryConfig;
import sun.module.repository.RepositoryUtils;
import sun.module.repository.URLRepository;
--- a/test/java/module/repository/xmlreader/MetadataXMLReaderTest.java Fri Aug 01 08:19:12 2008 -0700
+++ b/test/java/module/repository/xmlreader/MetadataXMLReaderTest.java Mon Aug 04 14:55:36 2008 -0700
@@ -23,11 +23,12 @@
import java.io.File;
import java.io.IOException;
+import java.module.Repository;
import java.module.Version;
import java.net.URL;
import java.util.Set;
import org.xml.sax.SAXException;
-import sun.module.repository.URLModuleInfo;
+import sun.module.repository.JamModuleArchiveInfo;
import sun.module.repository.MetadataXMLReader;
/**
@@ -39,6 +40,11 @@ public class MetadataXMLReaderTest {
public class MetadataXMLReaderTest {
private static String platform = "solaris";
private static String arch = "sparc";
+ private static class DummyRepository extends Repository {
+ DummyRepository() {
+ super("dummy");
+ };
+ };
public static void realMain(String[] args) throws Throwable {
testRead01();
@@ -57,10 +63,11 @@ public class MetadataXMLReaderTest {
/** Checks basics of construction, optional platform-arch. No errors. */
static public void testRead01() throws Exception {
- Set<URLModuleInfo> result = MetadataXMLReader.read(
- getURL("repository-metadata-01.xml"));
+ Set<JamModuleArchiveInfo> result = MetadataXMLReader.read(
+ new DummyRepository(),
+ getURL("repository-metadata-01.xml").openConnection());
check(result.size() == 3);
- for (URLModuleInfo mt : result) {
+ for (JamModuleArchiveInfo mt : result) {
if (mt.getName().equals("org.foo.xml")) {
check(mt.getVersion().equals(Version.valueOf("1.3")));
check(mt.getPlatform() == null);
@@ -87,10 +94,11 @@ public class MetadataXMLReaderTest {
/** Checks that all optional elements can really be optional. */
static public void testRead02() throws Exception {
- Set<URLModuleInfo> result = MetadataXMLReader.read(
- getURL("repository-metadata-02.xml"));
+ Set<JamModuleArchiveInfo> result = MetadataXMLReader.read(
+ new DummyRepository(),
+ getURL("repository-metadata-02.xml").openConnection());
check(result.size() == 1);
- URLModuleInfo mt = result.iterator().next();
+ JamModuleArchiveInfo mt = result.iterator().next();
check(mt.getName().equals("org.foo.xml"));
check(mt.getVersion().equals(Version.valueOf("1.3")));
check(mt.getPlatform() == null);
@@ -100,10 +108,11 @@ public class MetadataXMLReaderTest {
/** Checks error: platform but no arch. */
static public void testRead03() throws Exception {
- Set<URLModuleInfo> result = null;
- try {
- result = MetadataXMLReader.read(
- getURL("repository-metadata-03.xml"));
+ Set<JamModuleArchiveInfo> result = null;
+ try {
+ result = MetadataXMLReader.read(
+ new DummyRepository(),
+ getURL("repository-metadata-03.xml").openConnection());
fail();
} catch (SAXException ex) {
if (ex.toString().indexOf("'{arch}' is expected") < 0) {
@@ -116,10 +125,11 @@ public class MetadataXMLReaderTest {
/** Checks error: arch but no platform. */
static public void testRead04() throws Exception {
- Set<URLModuleInfo> result = null;
- try {
- result = MetadataXMLReader.read(
- getURL("repository-metadata-04.xml"));
+ Set<JamModuleArchiveInfo> result = null;
+ try {
+ result = MetadataXMLReader.read(
+ new DummyRepository(),
+ getURL("repository-metadata-04.xml").openConnection());
fail();
} catch (SAXException ex) {
if (ex.toString().indexOf("'{platform}' is expected") < 0) {
@@ -132,10 +142,11 @@ public class MetadataXMLReaderTest {
/** Checks error: empty <platform-binding> element. */
static public void testRead05() throws Exception {
- Set<URLModuleInfo> result = null;
- try {
- result = MetadataXMLReader.read(
- getURL("repository-metadata-05.xml"));
+ Set<JamModuleArchiveInfo> result = null;
+ try {
+ result = MetadataXMLReader.read(
+ new DummyRepository(),
+ getURL("repository-metadata-05.xml").openConnection());
fail();
} catch (SAXException ex) {
if (ex.toString().indexOf("'platform-binding'") < 0) {
@@ -148,10 +159,11 @@ public class MetadataXMLReaderTest {
/** Checks that duplicates are not allowed. */
static public void testRead06() throws Exception {
- Set<URLModuleInfo> result = null;
- try {
- result = MetadataXMLReader.read(
- getURL("repository-metadata-06.xml"));
+ Set<JamModuleArchiveInfo> result = null;
+ try {
+ result = MetadataXMLReader.read(
+ new DummyRepository(),
+ getURL("repository-metadata-06.xml").openConnection());
fail();
} catch (IllegalArgumentException ex) {
pass();
@@ -160,10 +172,11 @@ public class MetadataXMLReaderTest {
/** Checks that XML-specified path, platform & arch work. */
static public void testRead07() throws Exception {
- Set<URLModuleInfo> result = MetadataXMLReader.read(
- getURL("repository-metadata-07.xml"));
+ Set<JamModuleArchiveInfo> result = MetadataXMLReader.read(
+ new DummyRepository(),
+ getURL("repository-metadata-07.xml").openConnection());
check(result.size() == 1);
- URLModuleInfo mt = result.iterator().next();
+ JamModuleArchiveInfo mt = result.iterator().next();
check(mt.getName().equals("org.foo.xml"));
check(mt.getVersion().equals(Version.valueOf("1.3")));
check(mt.getPlatform().equals(platform));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deleted_files/src/share/classes/sun/module/repository/MetadataXMLWriter.java Mon Aug 04 14:55:36 2008 -0700
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.module.repository;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.module.ModuleArchiveInfo;
+import java.net.URL;
+import java.util.List;
+
+/**
+ * Writes XML for a repository-metadata.xml file.
+ * @since 1.7
+ */
+public class MetadataXMLWriter {
+ private final PrintWriter pw;
+ private int indent = 0;
+
+ // Amount of indentation
+ private static final int WIDTH = 4;
+
+ // Used for indentation
+ private static final String spaces32 = " ";
+
+ /**
+ * Writes the repository's repository-metadata.xml file based on {@code
+ * contents}.
+ * @param mai {@code ModuleArchiveInfo} on behalf of which the metadata is
+ * written.
+ * @param writeMAI if true, then write the given {@code mai} in addition
+ * to the repository's other contents.
+ */
+ public static void write(
+ URLRepository repo,
+ List<JamModuleArchiveInfo> maiList,
+ JamModuleArchiveInfo mai,
+ boolean writeMAI) throws IOException {
+ URL repoMD = new URL(
+ repo.getSourceLocation().toURL().toExternalForm()
+ + "/repository-metadata.xml");
+ File repoMDFile = new File(repoMD.getFile());
+ File repoMDDir = repoMDFile.getParentFile();
+ File tmpRepoMDFile = new File(repoMDDir, "repository-metadata.xml.tmp");
+ if (tmpRepoMDFile.exists()) {
+ if (!tmpRepoMDFile.delete()) {
+ throw new IOException(
+ "Cannot update repository metadata file for "
+ + mai.getName()
+ + ": cannot create temporary repository metadata file "
+ + tmpRepoMDFile);
+ }
+ }
+ MetadataXMLWriter writer = new MetadataXMLWriter(tmpRepoMDFile);
+ writer.begin();
+ for (JamModuleArchiveInfo m : maiList) {
+ if (!writeMAI && m.equals(mai)) {
+ // Don't write this ModuleArchiveInfo if it matches that given
+ } else {
+ writer.writeModule(m);
+ }
+ }
+ if (writeMAI) {
+ writer.writeModule(mai);
+ }
+
+ if (!writer.end()) {
+ throw new IOException(
+ "Cannot update repository metadata file for "
+ + mai.getName()
+ + ": failure while writing temporary repository metadata file "
+ + tmpRepoMDFile);
+ }
+
+ File prev = new File(repoMDFile.getCanonicalPath() + ".prev");
+ prev.delete();
+ if (!repoMDFile.renameTo(prev)) {
+ throw new IOException(
+ "Cannot update repository metadata file for "
+ + mai.getName()
+ + ": cannot rename " + repoMDFile + " to " + prev);
+ }
+ prev.deleteOnExit();
+
+ if (!tmpRepoMDFile.renameTo(repoMDFile)) {
+ throw new IOException(
+ "Cannot update repository metadata file for "
+ + mai.getName()
+ + ": cannot create updated repository-metadata.xml file"
+ + " by renaming " + tmpRepoMDFile + " to " + repoMDFile);
+ }
+ }
+
+ private MetadataXMLWriter(File out) throws IOException {
+ pw = new PrintWriter(
+ new BufferedOutputStream(
+ new FileOutputStream(out)), false);
+ }
+
+ void begin() {
+ pw.println("<modules>");
+ indent++;
+ }
+
+ boolean end() {
+ boolean rc = false;
+ indent--;
+ pw.println("</modules>");
+ rc = pw.checkError();
+ pw.close();
+ return !rc; // Return false if error
+ }
+
+ void writeModule(JamModuleArchiveInfo mai) {
+ output("<module>");
+ indent++;
+ output("<name>" + mai.getName() + "</name>");
+ output("<version>" + mai.getVersion().toString() + "</version>");
+ if (!mai.isPlatformArchNeutral()) {
+ output("<platform-binding>");
+ indent++;
+ output("<platform>" + mai.getPlatform() + "</platform>");
+ output("<arch>" + mai.getArch() + "</arch>");
+ indent--;
+ output("</platform-binding>");
+ }
+
+ // Entries with <path> are not created, since there's no way to
+ // specify that via Repository.install().
+
+ indent--;
+ output("</module>");
+ }
+
+ void output(String s) {
+ pw.print(spaces32.substring(0, indent * WIDTH));
+ pw.println(s);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deleted_files/src/share/classes/sun/module/repository/URLModuleInfo.java Mon Aug 04 14:55:36 2008 -0700
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.module.repository;
+
+import java.module.ModuleArchiveInfo;
+import java.module.Version;
+
+/**
+ * Represents the information about a single module as described by the schema
+ * <tt>java.module.RepositoryMetada.xml</tt>.
+ * @since 1.7
+ */
+public class URLModuleInfo {
+ // These fields are a reflection of the information in a
+ // repository-metadata.xml file. They're not private so they can
+ // be accessed by subclasses e.g. {@code MetadataXMLReader.MutableURLModuleInfo}.
+ String name;
+ Version version;
+ String platform;
+ String arch;
+ String path;
+
+ /**
+ * Having this constructor restricts its use to subclasses in this package,
+ * specifically to {@code MetadataXMLReader.MutableURLModuleInfo}.
+ **/
+ URLModuleInfo() { }
+
+ URLModuleInfo(URLModuleInfo other) {
+ this.name = other.name;
+ this.version = other.version;
+ this.platform = other.platform;
+ this.arch = other.arch;
+ this.path = other.path;
+ }
+
+ URLModuleInfo(String name, Version version, String platform, String arch, String path) {
+ if ((platform == null ^ arch == null)) {
+ throw new IllegalArgumentException(
+ "module platform and arch must be either both provided, or neither provided");
+ }
+
+ if (name == null) {
+ throw new IllegalArgumentException(
+ "name must not be null");
+ }
+
+ if (version == null) {
+ throw new IllegalArgumentException(
+ "version must not be null");
+ }
+
+ this.name = name;
+ this.version = version;
+ this.platform = platform;
+ this.arch = arch;
+ this.path = path;
+ }
+
+ URLModuleInfo(ModuleArchiveInfo mai) {
+ name = mai.getName();
+ version = mai.getVersion();
+ platform = mai.getPlatform();
+ arch = mai.getArch();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Version getVersion() {
+ return version;
+ }
+
+ public String getPlatform() {
+ return platform;
+ }
+
+ public String getArch() {
+ return arch;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String getCanonicalizedPath() {
+ if (path != null) {
+ return path;
+ } else {
+ if (getPlatform() != null && getArch() != null) {
+ return getName() + "/" + getVersion() + "/"
+ + getPlatform() + "-" + getArch();
+ } else {
+ return getName() + "/" + getVersion();
+ }
+ }
+ }
+
+ /** Two URLModuleInfo's are equal iff all fields are equal. */
+ public boolean equals(Object other) {
+ if (other == null || !(other instanceof URLModuleInfo)) {
+ return false;
+ }
+
+ URLModuleInfo mi = (URLModuleInfo) other;
+ if (!name.equals(mi.name) || !version.equals(mi.version)) {
+ return false;
+ }
+
+ if (platform == null) {
+ if (mi.platform != null) {
+ return false;
+ }
+ } else if (!platform.equals(mi.platform)) {
+ return false;
+ }
+
+ if (arch == null) {
+ if (mi.arch != null) {
+ return false;
+ }
+ } else if (!arch.equals(mi.arch)) {
+ return false;
+ }
+
+ // Note that path is not compared on purpose, because it is
+ // a property of where the module lives, not a property of
+ // the module itself.
+
+ return true;
+ }
+
+ /** A URLModuleInfo's hash code is based on all fields except {@code path}. */
+ public int hashCode() {
+ int rc = name.hashCode();
+ rc = 31 * rc + version.hashCode();
+ rc = 31 * rc + (platform == null ? 0 : platform.hashCode());
+ rc = 31 * rc + (arch == null ? 0 : arch.hashCode());
+
+ // Note that path is not used on purpose, because it is
+ // a property of where the module lives, not a property of
+ // the module itself.
+
+ return rc;
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("URLModuleInfo[name=");
+ builder.append(name);
+ builder.append(",version=");
+ builder.append(version);
+ if (platform != null) {
+ builder.append(",platform=");
+ builder.append(platform);
+ }
+ if (arch != null) {
+ builder.append(",arch=");
+ builder.append(arch);
+ }
+ if (path != null) {
+ builder.append(",path=");
+ builder.append(path);
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/module/repository-metadata-schema.xml Mon Aug 04 14:55:36 2008 -0700
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
+DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+This code is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 only, as
+published by the Free Software Foundation. Sun designates this
+particular file as subject to the "Classpath" exception as provided
+by Sun in the LICENSE file that accompanied this code.
+
+This code is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+version 2 for more details (a copy is included in the LICENSE file that
+accompanied this code).
+
+You should have received a copy of the GNU General Public License version
+2 along with this work; if not, write to the Free Software Foundation,
+Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+CA 95054 USA or visit www.sun.com if you need additional information or
+have any questions.
+-->
+
+<!--
+ This schema defines the structure of data downloaded by a URLRepository
+ when it is is initialized. Data using this schema describes the modules
+ available in a URL Repository.
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ URL Repository Metadata Schema for Java Module System.
+ Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:element name="modules" type="ModulesType"/>
+ <xs:complexType name="ModulesType">
+ <xs:sequence>
+ <xs:element name="module" type="ModuleType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="ModuleType">
+ <xs:sequence>
+ <!-- Name of the JAM module. -->
+ <xs:element name="name" type="xs:string"/>
+ <!--
+ Version of the JAM module. It must conform to the version
+ format in the versioning scheme in the Java Module System.
+ -->
+ <xs:element name="version" type="xs:string"/>
+ <!--
+ Platform binding of the JAM module.
+ -->
+ <xs:element name="platform-binding"
+ type="PlatformBindingType" minOccurs="0" maxOccurs="1"/>
+ <!--
+ Relative path to the files which belong to the specified
+ JAM module, including the module file (i.e.
+ MODULE.METADATA), the module archive (i.e. .jam file)
+ and/or the packed module archive (i.e. .jam.pack.gz
+ file). The path must be specified using '/' as the path
+ separator; it must have no leading and trailing '/'.
+
+ URL repository implementations must treat the path as
+
+ <name>/<version>[/<platform>-<arch>]
+
+ if this element is missing.
+ -->
+ <xs:element name="path" type="xs:string" minOccurs="0" maxOccurs="1"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="PlatformBindingType">
+ <xs:sequence>
+ <!--
+ Name of the platform. It is one of the possible values
+ of the system property "os.platform".
+ -->
+ <xs:element name="platform" type="xs:string"/>
+ <!--
+ Architecture of the platform. It is one of the possible values
+ of the system property "os.arch".
+ -->
+ <xs:element name="arch" type="xs:string"/>
+ </xs:sequence>
+ </xs:complexType>
+</xs:schema>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/module/osgi/OSGiModuleArchiveInfo.java Mon Aug 04 14:55:36 2008 -0700
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.module.osgi;
+
+import java.module.ModuleArchiveInfo;
+import java.module.Repository;
+import java.module.Version;
+
+/**
+ * This class represents the information of an installed module archive
+ * in a repository for the OSGi module system.
+ *
+ * @see java.module.Repository
+ * @see java.module.Version
+ *
+ * @since 1.7
+ */
+final class OSGiModuleArchiveInfo implements ModuleArchiveInfo {
+ private Repository repository;
+
+ // These fields are a reflection of the information in the module archive.
+ private String name;
+ private Version version;
+ private String fileName;
+ private long lastModified;
+
+ /**
+ * Constructs a new {@code OSGiModuleArchiveInfo} instance.
+ * <p>
+ *
+ * @param repository the repository
+ * @param name the name of the module definition in the module archive.
+ * @param version the version of the module definition in the module archive.
+ * @param fileName the filename of the module archive.
+ * @param lastModified the last modified time of the module archive.
+ * @throws NullPointerException if repository is null, name is null,
+ * version is null, or the last modified time is less than 0.
+ */
+ public OSGiModuleArchiveInfo(Repository repository, String name,
+ Version version, String fileName, long lastModified) {
+ if (repository == null) {
+ throw new IllegalArgumentException("repository must not be null.");
+ }
+ if (name == null) {
+ throw new IllegalArgumentException("name must not be null.");
+ }
+ if (version == null) {
+ throw new IllegalArgumentException(
+ "version must not be null.");
+ }
+ if (lastModified <0) {
+ throw new IllegalArgumentException(
+ "lastModified must be greater than or equal to 0.");
+ }
+
+ this.repository = repository;
+ this.name = name;
+ this.version = version;
+ this.fileName = fileName;
+ this.lastModified = lastModified;
+ }
+
+ @Override
+ public Repository getRepository() {
+ return repository;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public Version getVersion() {
+ return version;
+ }
+
+ @Override
+ public String getPlatform() {
+ return null;
+ }
+
+ @Override
+ public String getArch() {
+ return null;
+ }
+
+ @Override
+ public String getFileName() {
+ return fileName;
+ }
+
+ /**
+ * Returns the last modified time of the module archive in the repository. The
+ * result is the number of milliseconds since January 1, 1970 GMT.
+ *
+ * @return the time the module archive was last modified, or 0 if not known.
+ */
+ @Override
+ public long getLastModified() {
+ return lastModified;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("OSGiModuleArchiveInfo[repository=");
+ builder.append(repository.getName());
+ builder.append(",module=");
+ builder.append(name);
+ builder.append(" v");
+ builder.append(version);
+ if (fileName != null) {
+ builder.append(",fileName=");
+ builder.append(fileName);
+ }
+ if (lastModified >= 0) {
+ builder.append(",lastModified=");
+ builder.append(new java.util.Date(lastModified));
+ }
+ builder.append("]");
+
+ return builder.toString();
+ }
+}
--- a/src/share/classes/sun/module/repository/MetadataXMLWriter.java Fri Aug 01 08:19:12 2008 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.module.repository;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.module.ModuleArchiveInfo;
-import java.net.URL;
-import java.util.List;
-
-/**
- * Writes XML for a repository-metadata.xml file.
- * @since 1.7
- */
-public class MetadataXMLWriter {
- private final PrintWriter pw;
- private int indent = 0;
-
- // Amount of indentation
- private static final int WIDTH = 4;
-
- // Used for indentation
- private static final String spaces32 = " ";
-
- /**
- * Writes the repository's repository-metadata.xml file based on {@code
- * contents}.
- * @param mai {@code ModuleArchiveInfo} on behalf of which the metadata is
- * written.
- * @param writeMAI if true, then write the given {@code mai} in addition
- * to the repository's other contents.
- */
- public static void write(
- URLRepository repo,
- List<JamModuleArchiveInfo> maiList,
- JamModuleArchiveInfo mai,
- boolean writeMAI) throws IOException {
- URL repoMD = new URL(
- repo.getSourceLocation().toURL().toExternalForm()
- + "/repository-metadata.xml");
- File repoMDFile = new File(repoMD.getFile());
- File repoMDDir = repoMDFile.getParentFile();
- File tmpRepoMDFile = new File(repoMDDir, "repository-metadata.xml.tmp");
- if (tmpRepoMDFile.exists()) {
- if (!tmpRepoMDFile.delete()) {
- throw new IOException(
- "Cannot update repository metadata file for "
- + mai.getName()
- + ": cannot create temporary repository metadata file "
- + tmpRepoMDFile);
- }
- }
- MetadataXMLWriter writer = new MetadataXMLWriter(tmpRepoMDFile);
- writer.begin();
- for (JamModuleArchiveInfo m : maiList) {
- if (!writeMAI && m.equals(mai)) {
- // Don't write this ModuleArchiveInfo if it matches that given
- } else {
- writer.writeModule(m);
- }
- }
- if (writeMAI) {
- writer.writeModule(mai);
- }
-
- if (!writer.end()) {
- throw new IOException(
- "Cannot update repository metadata file for "
- + mai.getName()
- + ": failure while writing temporary repository metadata file "
- + tmpRepoMDFile);
- }
-
- File prev = new File(repoMDFile.getCanonicalPath() + ".prev");
- prev.delete();
- if (!repoMDFile.renameTo(prev)) {
- throw new IOException(
- "Cannot update repository metadata file for "
- + mai.getName()
- + ": cannot rename " + repoMDFile + " to " + prev);
- }
- prev.deleteOnExit();
-
- if (!tmpRepoMDFile.renameTo(repoMDFile)) {
- throw new IOException(
- "Cannot update repository metadata file for "
- + mai.getName()
- + ": cannot create updated repository-metadata.xml file"
- + " by renaming " + tmpRepoMDFile + " to " + repoMDFile);
- }
- }
-
- private MetadataXMLWriter(File out) throws IOException {
- pw = new PrintWriter(
- new BufferedOutputStream(
- new FileOutputStream(out)), false);
- }
-
- void begin() {
- pw.println("<modules>");
- indent++;
- }
-
- boolean end() {
- boolean rc = false;
- indent--;
- pw.println("</modules>");
- rc = pw.checkError();
- pw.close();
- return !rc; // Return false if error
- }
-
- void writeModule(JamModuleArchiveInfo mai) {
- output("<module>");
- indent++;
- output("<name>" + mai.getName() + "</name>");
- output("<version>" + mai.getVersion().toString() + "</version>");
- if (!mai.isPlatformArchNeutral()) {
- output("<platform-binding>");
- indent++;
- output("<platform>" + mai.getPlatform() + "</platform>");
- output("<arch>" + mai.getArch() + "</arch>");
- indent--;
- output("</platform-binding>");
- }
-
- // Entries with <path> are not created, since there's no way to
- // specify that via Repository.install().
-
- indent--;
- output("</module>");
- }
-
- void output(String s) {
- pw.print(spaces32.substring(0, indent * WIDTH));
- pw.println(s);
- }
-}
--- a/src/share/classes/sun/module/repository/URLModuleInfo.java Fri Aug 01 08:19:12 2008 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,193 +0,0 @@
-/*
- * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.module.repository;
-
-import java.module.ModuleArchiveInfo;
-import java.module.Version;
-
-/**
- * Represents the information about a single module as described by the schema
- * <tt>java.module.RepositoryMetada.xml</tt>.
- * @since 1.7
- */
-public class URLModuleInfo {
- // These fields are a reflection of the information in a
- // repository-metadata.xml file. They're not private so they can
- // be accessed by subclasses e.g. {@code MetadataXMLReader.MutableURLModuleInfo}.
- String name;
- Version version;
- String platform;
- String arch;
- String path;
-
- /**
- * Having this constructor restricts its use to subclasses in this package,
- * specifically to {@code MetadataXMLReader.MutableURLModuleInfo}.
- **/
- URLModuleInfo() { }
-
- URLModuleInfo(URLModuleInfo other) {
- this.name = other.name;
- this.version = other.version;
- this.platform = other.platform;
- this.arch = other.arch;
- this.path = other.path;
- }
-
- URLModuleInfo(String name, Version version, String platform, String arch, String path) {
- if ((platform == null ^ arch == null)) {
- throw new IllegalArgumentException(
- "module platform and arch must be either both provided, or neither provided");
- }
-
- if (name == null) {
- throw new IllegalArgumentException(
- "name must not be null");
- }
-
- if (version == null) {
- throw new IllegalArgumentException(
- "version must not be null");
- }
-
- this.name = name;
- this.version = version;
- this.platform = platform;
- this.arch = arch;
- this.path = path;
- }
-
- URLModuleInfo(ModuleArchiveInfo mai) {
- name = mai.getName();
- version = mai.getVersion();
- platform = mai.getPlatform();
- arch = mai.getArch();
- }
-
- public String getName() {
- return name;
- }
-
- public Version getVersion() {
- return version;
- }
-
- public String getPlatform() {
- return platform;
- }
-
- public String getArch() {
- return arch;
- }
-
- public String getPath() {
- return path;
- }
-
- public String getCanonicalizedPath() {
- if (path != null) {
- return path;
- } else {
- if (getPlatform() != null && getArch() != null) {
- return getName() + "/" + getVersion() + "/"
- + getPlatform() + "-" + getArch();
- } else {
- return getName() + "/" + getVersion();
- }
- }
- }
-
- /** Two URLModuleInfo's are equal iff all fields are equal. */
- public boolean equals(Object other) {
- if (other == null || !(other instanceof URLModuleInfo)) {
- return false;
- }
-
- URLModuleInfo mi = (URLModuleInfo) other;
- if (!name.equals(mi.name) || !version.equals(mi.version)) {
- return false;
- }
-
- if (platform == null) {
- if (mi.platform != null) {
- return false;
- }
- } else if (!platform.equals(mi.platform)) {
- return false;
- }
-
- if (arch == null) {
- if (mi.arch != null) {
- return false;
- }
- } else if (!arch.equals(mi.arch)) {
- return false;
- }
-
- // Note that path is not compared on purpose, because it is
- // a property of where the module lives, not a property of
- // the module itself.
-
- return true;
- }
-
- /** A URLModuleInfo's hash code is based on all fields except {@code path}. */
- public int hashCode() {
- int rc = name.hashCode();
- rc = 31 * rc + version.hashCode();
- rc = 31 * rc + (platform == null ? 0 : platform.hashCode());
- rc = 31 * rc + (arch == null ? 0 : arch.hashCode());
-
- // Note that path is not used on purpose, because it is
- // a property of where the module lives, not a property of
- // the module itself.
-
- return rc;
- }
-
- public String toString() {
- StringBuilder builder = new StringBuilder();
-
- builder.append("URLModuleInfo[name=");
- builder.append(name);
- builder.append(",version=");
- builder.append(version);
- if (platform != null) {
- builder.append(",platform=");
- builder.append(platform);
- }
- if (arch != null) {
- builder.append(",arch=");
- builder.append(arch);
- }
- if (path != null) {
- builder.append(",path=");
- builder.append(path);
- }
- builder.append("]");
- return builder.toString();
- }
-}