6683470: Refactor local and URL repository implementations
authorstanleyh
Wed Apr 02 17:59:05 2008 -0700 (19 months ago)
changeset 11681f712211a0b
parent 1155930ee9dd9a8
child 12505b0bf6af29d
6683470: Refactor local and URL repository implementations
Summary: Also updated JSR 277 APIs, and fixed 6604984, 6672434, 6566022, and 6558953.
Reviewed-by: bristor, ksrini
deleted_files/src/share/classes/sun/module/repository/LocalJamDefinitionContent.java
deleted_files/src/share/classes/sun/module/repository/RepositoryContents.java
deleted_files/src/share/classes/sun/module/repository/URLModuleDefinitionContent.java
src/share/classes/java/module/ImportDependency.java
src/share/classes/java/module/Module.java
src/share/classes/java/module/ModuleArchiveInfo.java
src/share/classes/java/module/ModuleDefinition.java
src/share/classes/java/module/ModuleDefinitionContent.java
src/share/classes/java/module/ModuleSystem.java
src/share/classes/java/module/ModuleSystemEvent.java
src/share/classes/java/module/Modules.java
src/share/classes/java/module/Query.java
src/share/classes/java/module/Repository.java
src/share/classes/java/module/RepositoryEvent.java
src/share/classes/sun/module/JamUtils.java
src/share/classes/sun/module/ModuleLauncher.java
src/share/classes/sun/module/bootstrap/BootstrapModuleSystem.java
src/share/classes/sun/module/bootstrap/BootstrapRepository.java
src/share/classes/sun/module/core/ModuleImpl.java
src/share/classes/sun/module/core/ModuleLoader.java
src/share/classes/sun/module/core/ModuleSystemImpl.java
src/share/classes/sun/module/core/ModuleUtils.java
src/share/classes/sun/module/repository/AbstractRepository.java
src/share/classes/sun/module/repository/LocalJamDefinitionContent.java
src/share/classes/sun/module/repository/LocalRepository.java
src/share/classes/sun/module/repository/MetadataXMLReader.java
src/share/classes/sun/module/repository/MetadataXMLWriter.java
src/share/classes/sun/module/repository/ModuleInfo.java
src/share/classes/sun/module/repository/RepositoryContents.java
src/share/classes/sun/module/repository/RepositoryUtils.java
src/share/classes/sun/module/repository/URLModuleDefinitionContent.java
src/share/classes/sun/module/repository/URLRepository.java
src/share/classes/sun/module/repository/cache/Cache.java
src/share/classes/sun/module/repository/cache/CacheModuleDefinitionContent.java
src/share/classes/sun/module/repository/cache/LocalModuleDefInfo.java
src/share/classes/sun/module/repository/cache/LocalModuleDefinitionContent.java
src/share/classes/sun/module/repository/cache/ModuleDefInfo.java
src/share/classes/sun/module/repository/cache/URLModuleDefInfo.java
src/share/classes/sun/module/repository/cache/URLModuleDefinitionContent.java
src/share/classes/sun/module/tools/JRepo.java
test/java/module/basic/BasicLauncherTests.java
test/java/module/modinit/RunMTest.java
test/java/module/modinit/mtest/moduleevent/moduleDefinitionDisabled.mtest
test/java/module/modinit/mtest/moduleevent/moduleInitialized.mtest
test/java/module/modinit/mtest/moduleevent/moduleReleased.mtest
test/java/module/repository/LegacyJarTest.java
test/java/module/repository/LocalRepositoryTest.java
test/java/module/repository/MetadataCompareTest.java
test/java/module/repository/NativeLibraryTest.java
test/java/module/repository/RepositoryTest.java
test/java/module/repository/URLRepoInstallTest.java
test/java/module/repository/URLRepositoryReloadTest.java
test/java/module/repository/URLRepositoryServer.java
test/java/module/repository/URLRepositoryTest.java
test/java/module/tools/jrepo/JRepoTest.java
--- a/src/share/classes/java/module/ImportDependency.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/java/module/ImportDependency.java Wed Apr 02 17:59:05 2008 -0700
@@ -88,7 +88,7 @@ public class ImportDependency implements
*
* @return the name of the imported module definition.
*/
- public String getModuleName() {
+ public String getName() {
return name;
}
@@ -143,7 +143,7 @@ public class ImportDependency implements
ImportDependency importDep = (ImportDependency) obj;
- return (name.equals(importDep.getModuleName())
+ return (name.equals(importDep.getName())
&& constraint.equals(importDep.getVersionConstraint())
&& reexport == importDep.isReexported()
&& optional == importDep.isOptional());
@@ -174,17 +174,15 @@ public class ImportDependency implements
public String toString() {
StringBuilder builder = new StringBuilder();
- builder.append("ImportDependency[imported-module=");
+ builder.append("ImportDependency[module ");
builder.append(name);
- builder.append(",version-constraint=");
+ builder.append(" ");
builder.append(constraint.toString());
if (reexport) {
- builder.append(",re-export=");
- builder.append(reexport);
+ builder.append(",re-export");
}
if (optional) {
- builder.append(",optional=");
- builder.append(optional);
+ builder.append(",optional");
}
builder.append("]");
--- a/src/share/classes/java/module/Module.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/java/module/Module.java Wed Apr 02 17:59:05 2008 -0700
@@ -147,15 +147,7 @@ public abstract class Module
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
-
- /*
- builder.append("Module[name=");
- builder.append(getModuleDefinition().getName());
- builder.append(",version=");
- builder.append(getModuleDefinition().getVersion());
- builder.append("]");
- */
- builder.append("Module ");
+ builder.append("module ");
builder.append(getModuleDefinition().getName());
builder.append(" v");
builder.append(getModuleDefinition().getVersion());
--- a/src/share/classes/java/module/ModuleArchiveInfo.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/java/module/ModuleArchiveInfo.java Wed Apr 02 17:59:05 2008 -0700
@@ -47,23 +47,28 @@ public class ModuleArchiveInfo {
/**
* Constructs a new <code>ModuleArchiveInfo</code> instance.
+ * <p>
+ * If the module definition in the module archive is platform and
+ * architecture neutral, both platform and 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 of the module definition in the module
- * archive.
- * @param arch the architecture of the module definition in the module
- * archive.
+ * @param platform the platform which the module definition in the module
+ * archive targets.
+ * @param arch the architecture which the module definition in the module
+ * archive targets.
* @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, or
- * version is null. It is also thrown if platform or archive is
- * provided, they are not provided together, or if the last
- * modified time is less than 0.
- */
- public ModuleArchiveInfo(Repository repository, String name, Version version, String platform, String arch, String fileName, long lastModified) {
+ * @throws NullPointerException if repository is null, name is null,
+ * version is null, or the last modified time is less than 0. It
+ * is also thrown if platform is null but arch is not null, or
+ * platform is not null but arch is null.
+ */
+ public ModuleArchiveInfo(Repository repository, String name,
+ Version version, String platform, String arch,
+ String fileName, long lastModified) {
if (repository == null) {
throw new IllegalArgumentException("repository must not be null.");
}
@@ -76,7 +81,7 @@ public class ModuleArchiveInfo {
}
if ((platform == null ^ arch == null)) {
throw new IllegalArgumentException(
- "platform and architecture must be either both provided, or neither provided.");
+ "platform and arch must be either both provided, or neither provided.");
}
if (lastModified <0) {
@@ -140,8 +145,19 @@ public class ModuleArchiveInfo {
* @return the name of the architecture. If the module definition has no
* platform binding, returns null.
*/
- public String getArchitecture() {
+ public String getArch() {
return arch;
+ }
+
+ /**
+ * Determines if the module definition in the module archive is
+ * platform and architecture neutral.
+ *
+ * @return true if the module definition in the module archive is platform
+ * and architecture neutral; otherwise return false.
+ */
+ public boolean isPlatformArchNeutral() {
+ return (platform == null && arch == null);
}
/**
@@ -162,31 +178,6 @@ public class ModuleArchiveInfo {
*/
public long getLastModified() {
return lastModified;
- }
-
- /**
- * Compare two <code>ModuleArchiveInfo</code> objects for
- * equality. The result is <code>true</code> if and only if
- * the argument is not <code>null</code> and is a
- * <code>ModuleArchiveInfo</code> object that is the same
- * instance as this <code>ModuleArchiveInfo</code>.
- *
- * @param other the object to compare with.
- * @return whether or not the two objects are equal.
- */
- @Override
- public boolean equals(Object other) {
- return (this == other);
- }
-
- @Override
- public int hashCode() {
- int rc = repository.hashCode();
- rc = 31 * 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;
}
/**
@@ -201,16 +192,14 @@ public class ModuleArchiveInfo {
builder.append("ModuleArchiveInfo[repository=");
builder.append(repository.getName());
- builder.append(",name=");
+ builder.append(",module=");
builder.append(name);
- builder.append(",version=");
+ builder.append(" v");
builder.append(version);
- if (platform != null) {
- builder.append(",platform=");
+ if (!isPlatformArchNeutral()) {
+ builder.append(",platform-arch=");
builder.append(platform);
- }
- if (arch != null) {
- builder.append(",arch=");
+ builder.append("-");
builder.append(arch);
}
if (fileName != null) {
@@ -219,7 +208,7 @@ public class ModuleArchiveInfo {
}
if (lastModified >= 0) {
builder.append(",lastModified=");
- builder.append(lastModified);
+ builder.append(new java.util.Date(lastModified));
}
builder.append("]");
--- a/src/share/classes/java/module/ModuleDefinition.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/java/module/ModuleDefinition.java Wed Apr 02 17:59:05 2008 -0700
@@ -283,23 +283,13 @@ public abstract class ModuleDefinition {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
-/*
- builder.append("ModuleDefinition[name=");
- builder.append(getName());
- builder.append(",version=");
- builder.append(getVersion());
- builder.append(",repository=");
- builder.append(getRepository().getName());
- builder.append("]");
-*/
- builder.append("ModuleDefinition ");
+ builder.append("module definition ");
builder.append(getName());
builder.append(" v");
builder.append(getVersion());
builder.append(" (");
builder.append(getRepository().getName());
builder.append(" repository)");
-
return builder.toString();
}
}
--- a/src/share/classes/java/module/ModuleDefinitionContent.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/java/module/ModuleDefinitionContent.java Wed Apr 02 17:59:05 2008 -0700
@@ -35,8 +35,12 @@ import java.security.CodeSigner;
/**
* This class represents the content of the module definition.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method in this class will cause a {@link NullPointerException} to be thrown.
* <p>
* @see java.module.ModuleDefinition
+ * @see java.security.CodeSigner
*
* @since 1.7
*/
@@ -50,14 +54,14 @@ public abstract class ModuleDefinitionCo
}
/**
- * Checks if an entry exists in the module definition.
+ * Determines if an entry exists in the module definition.
* <p>
* The entry's name is specified as '/' separated paths, with no
* leading '/'.
*
* @param name entry's name.
- * @return true if entry exists in the module definition;
- * otherwise, false is returned.
+ * @return true if entry exists in the module definition; otherwise,
+ * returns false.
*/
public abstract boolean hasEntry(String name);
@@ -68,8 +72,7 @@ public abstract class ModuleDefinitionCo
* leading '/'.
*
* @param name entry's name.
- * @return if entry exists, return input stream; otherwise,
- * return null.
+ * @return if entry exists, return input stream; otherwise, return null.
* @throws IOException if an I/O error occurs.
*/
public abstract InputStream getEntryAsStream(String name) throws IOException;
@@ -81,8 +84,7 @@ public abstract class ModuleDefinitionCo
* leading '/'.
*
* @param name entry's name.
- * @return if entry exists, return byte array; otherwise,
- * return null.
+ * @return if an entry exists, return byte array; otherwise, returns null.
* @throws IOException if an I/O error occurs.
*/
public byte[] getEntryAsByteArray(String name) throws IOException {
@@ -118,7 +120,7 @@ public abstract class ModuleDefinitionCo
* definition.
*
* @param libraryName the library name.
- * @return native library if found; otherwise, null is returned.
+ * @return native library if it is found; otherwise, returns null.
*/
public abstract File getNativeLibrary(String libraryName);
@@ -126,8 +128,9 @@ public abstract class ModuleDefinitionCo
* Returns the code signers associated with the module definition.
*
* @return code signers of the module definition.
+ * @throws IOException if an I/O error occurs.
*/
- public abstract CodeSigner[] getCodeSigners();
+ public abstract CodeSigner[] getCodeSigners() throws IOException;
/**
--- a/src/share/classes/java/module/ModuleSystem.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/java/module/ModuleSystem.java Wed Apr 02 17:59:05 2008 -0700
@@ -167,24 +167,25 @@ public abstract class ModuleSystem {
}
// Module system listener(s)
- private ModuleSystemListener moduleSystemListener = null;
+ private static ModuleSystemListener moduleSystemListener = null;
+ private static Object listenerSyncObject = new Object();
/**
* Adds the specified module system listener to receive module system
- * events from this module system.
+ * events from the module systems.
* <p>
* If a security manager is present, this method calls the security
* manager's checkPermission method with a <code>
* ModuleSystemPermission("addModuleSystemListener")</code> permission to
- * ensure it's ok to add a module system listener to the module system.
+ * ensure it's ok to add a module system listener to the module systems.
*
* @param listener the module system listener
* @throws SecurityException if a security manager exists and its
* checkPermission method denies access to add a module system
- * listener to the module system.
+ * listener to the module systems.
* @throws NullPointerException if listener is null.
*/
- public final void addModuleSystemListener(ModuleSystemListener listener) {
+ public static final void addModuleSystemListener(ModuleSystemListener listener) {
if (listener == null) {
throw new NullPointerException("Module system listener must not be null.");
}
@@ -194,27 +195,28 @@ public abstract class ModuleSystem {
sm.checkPermission(new ModuleSystemPermission("addModuleSystemListener"));
}
- synchronized (this) {
+ synchronized(listenerSyncObject) {
moduleSystemListener = EventMulticaster.add(moduleSystemListener, listener);
}
}
/**
* Removes the specified module system listener so that it no longer
- * receives module system events from this module system.
- * <p>
- * If a security manager is present, this method calls the security
- * manager's checkPermission method with a <code>
- * ModuleSystemPermission("removeModuleSystemListener")</code> permission to
- * ensure it's ok to remove a module system listener from the module system.
+ * receives module system events from the module systems.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's checkPermission method with a <code>
+ * ModuleSystemPermission("removeModuleSystemListener")</code> permission
+ * to ensure it's ok to remove a module system listener from the module
+ * systems.
*
* @param listener the module system listener
* @throws SecurityException if a security manager exists and its
* checkPermission method denies access to remove a module system
- * listener from the module system.
+ * listener from the module systems.
* @throws NullPointerException if listener is null.
*/
- public final void removeModuleSystemListener(ModuleSystemListener listener) {
+ public static final void removeModuleSystemListener(ModuleSystemListener listener) {
if (listener == null) {
throw new NullPointerException("Module system listener must not be null.");
}
@@ -224,7 +226,7 @@ public abstract class ModuleSystem {
sm.checkPermission(new ModuleSystemPermission("removeModuleSystemListener"));
}
- synchronized (this) {
+ synchronized(listenerSyncObject) {
moduleSystemListener = EventMulticaster.remove(moduleSystemListener, listener);
}
}
@@ -252,6 +254,7 @@ public abstract class ModuleSystem {
case MODULE_INITIALIZED:
case MODULE_RELEASED:
case MODULE_INITIALIZATION_EXCEPTION:
+ case MODULE_DEFINITION_DISABLED:
listener.handleEvent(event);
break;
default:
@@ -261,7 +264,7 @@ public abstract class ModuleSystem {
}
}
- private ExecutorService executorService = null;
+ private static ExecutorService executorService = null;
/**
* Processes module system event occuring in this module system by
@@ -276,7 +279,7 @@ public abstract class ModuleSystem {
if (listener == null)
return;
- synchronized(this) {
+ synchronized(listenerSyncObject) {
if (executorService == null) {
// Creates a single thread executor that creates thread in the main
// thread group.
--- a/src/share/classes/java/module/ModuleSystemEvent.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/java/module/ModuleSystemEvent.java Wed Apr 02 17:59:05 2008 -0700
@@ -25,8 +25,6 @@
package java.module;
-import java.util.EventObject;
-
/**
* This class represents a module system event that occurs in the module
* system.
@@ -38,9 +36,7 @@ import java.util.EventObject;
*
* @since 1.7
*/
-public class ModuleSystemEvent extends EventObject {
-
- private static final long serialVersionUID = -2113392048839692418L;
+public class ModuleSystemEvent {
/**
* Types of module system events.
@@ -59,44 +55,81 @@ public class ModuleSystemEvent extends E
/**
* The initialization of a module instance has failed.
*/
- MODULE_INITIALIZATION_EXCEPTION
+ MODULE_INITIALIZATION_EXCEPTION,
+
+ /**
+ * A module definition has been disabled successfully.
+ */
+ MODULE_DEFINITION_DISABLED
};
private Type type;
- private transient Module module;
- private transient ModuleDefinition moduleDef;
- private transient ModuleInitializationException exception;
-
- /**
- * Constructs a ModuleSystemEvent object with the specified module system,
- * event type, and module instance.
+ private ModuleSystem source;
+ private Module module;
+ private ModuleDefinition moduleDef;
+ private ModuleInitializationException exception;
+
+ /**
+ * Constructs a ModuleSystemEvent object with event type MODULE_INITIALIZED,
+ * or MODULE_RELEASED, using the specified module system, event type, and
+ * module instance.
*
* @param source the module system where the event occurs
* @param type the event type
* @param module the module instance that the event applies to
- * @throws NullPointerException if source is null, type is null, or
- * module is null.
+ * @throws IllegalArgumentException if type is
+ * MODULE_INITIALIZATION_EXCEPTION or MODULE_DEFINITION_DISABLED
+ * @throws NullPointerException if source is null, type is null,
+ * or module is null.
+ *
*/
public ModuleSystemEvent(ModuleSystem source, Type type, Module module) {
- super(source);
-
- if (source == null)
- throw new NullPointerException("source must not be null.");
+ if (source == null)
+ throw new NullPointerException("source must not be null");
if (type == null)
- throw new NullPointerException("type must not be null.");
+ throw new NullPointerException("type must not be null");
if (module == null)
- throw new NullPointerException("module must not be null.");
+ throw new NullPointerException("module must not be null");
+
+ if (!(type.equals(Type.MODULE_INITIALIZED) || type.equals(Type.MODULE_RELEASED)))
+ throw new IllegalArgumentException("type must not be " + type);
this.type = type;
+ this.source = source;
this.module = module;
this.moduleDef = module.getModuleDefinition();
this.exception = null;
}
/**
- * Constructs a ModuleSystemEvent object with the specified module system,
+ * Constructs a ModuleSystemEvent object with event type
+ * MODULE_DEFINITION_DISABLED, using the specified module system
+ * and module definition.
+ *
+ * @param source the module system where the event occurs
+ * @param moduleDef the module definition that the event applies to
+ * @throws NullPointerException if source is null, or moduleDef is null.
+ *
+ */
+ public ModuleSystemEvent(ModuleSystem source, ModuleDefinition moduleDef) {
+ if (source == null)
+ throw new NullPointerException("source must not be null");
+
+ if (moduleDef == null)
+ throw new NullPointerException("moduleDef must not be null");
+
+ this.type = ModuleSystemEvent.Type.MODULE_DEFINITION_DISABLED;
+ this.source = source;
+ this.module = null;
+ this.moduleDef = moduleDef;
+ this.exception = null;
+ }
+
+ /**
+ * Constructs a ModuleSystemEvent object with event type
+ * MODULE_INITIALIZATION_EXCEPTION, using the specified module system,
* module definition, and module initialization exception.
*
* @param source the module system where the event occurs
@@ -106,18 +139,17 @@ public class ModuleSystemEvent extends E
* exception is null.
*/
public ModuleSystemEvent(ModuleSystem source, ModuleDefinition moduleDef, ModuleInitializationException exception) {
- super(source);
-
- if (source == null)
- throw new NullPointerException("source must not be null.");
+ if (source == null)
+ throw new NullPointerException("source must not be null");
if (moduleDef == null)
- throw new NullPointerException("moduleDef must not be null.");
+ throw new NullPointerException("moduleDef must not be null");
if (exception == null)
- throw new NullPointerException("exception must not be null.");
+ throw new NullPointerException("exception must not be null");
this.type = ModuleSystemEvent.Type.MODULE_INITIALIZATION_EXCEPTION;
+ this.source = source;
this.module = null;
this.moduleDef = moduleDef;
this.exception = exception;
@@ -130,6 +162,12 @@ public class ModuleSystemEvent extends E
return type;
}
+ /**
+ * Returns the module system associated with the event.
+ */
+ public ModuleSystem getSource() {
+ return source;
+ }
/**
* Returns the module.
@@ -164,17 +202,12 @@ public class ModuleSystemEvent extends E
builder.append("ModuleSystemEvent[type=");
builder.append(type.toString());
-
- ModuleDefinition md = moduleDef;
- if (type.equals(ModuleSystemEvent.Type.MODULE_INITIALIZATION_EXCEPTION) == false) {
- // MODULE_INITIALIZED or MODULE_RELEASED
- md = module.getModuleDefinition();
- }
-
- builder.append(",module-name=");
- builder.append(md.getName());
- builder.append(",module-version=");
- builder.append(md.getVersion());
+ builder.append(",module-system=");
+ builder.append(getSource().toString());
+ builder.append(",module=");
+ builder.append(moduleDef.getName());
+ builder.append(" v");
+ builder.append(moduleDef.getVersion());
builder.append("]");
return builder.toString();
--- a/src/share/classes/java/module/Modules.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/java/module/Modules.java Wed Apr 02 17:59:05 2008 -0700
@@ -45,6 +45,9 @@ import sun.module.repository.URLReposito
* addition, it contains methods for setting or getting the system's visibility
* policy and import override policy.
*
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method in this class will cause a {@link NullPointerException} to be thrown.
+ * <p>
* @see java.module.ImportOverridePolicy
* @see java.module.Module
* @see java.module.ModuleDefinition
@@ -94,8 +97,6 @@ public class Modules {
* @throws SecurityException if a security manager exists and
* its <tt>checkPermission</tt> method denies access
* to create a new instance of repository.
- * @throws NullPointerException if <code>parent</code> is null,
- * <code>name</code> is null, or <code>source</code> is null.
* @throws IOException if the repository cannot be constructed and
* initialized.
* @throws IllegalArgumentException if a circularity is detected.
@@ -120,8 +121,6 @@ public class Modules {
* @throws SecurityException if a security manager exists and
* its <tt>checkPermission</tt> method denies access
* to create a new instance of repository.
- * @throws NullPointerException if <code>name</code> is null,
- * or <code>source</code> is null.
* @throws IOException if the repository cannot be constructed and
* initialized.
*/
@@ -148,9 +147,6 @@ public class Modules {
* @throws SecurityException if a security manager exists and
* its <tt>checkPermission</tt> method denies access
* to create a new instance of repository.
- * @throws NullPointerException if <code>parent</code> is null,
- * <code>name</code> is null, <code>source</code> is null,
- * or <code>config</code> is null.
* @throws IOException if the repository cannot be constructed and
* initialized.
* @throws IllegalArgumentException if a circularity is detected.
@@ -178,8 +174,6 @@ public class Modules {
* @throws SecurityException if a security manager exists and
* its <tt>checkPermission</tt> method denies access
* to create a new instance of repository.
- * @throws NullPointerException if <code>name</code> is null,
- * <code>source</code> is null, or <code>config</code> is null.
* @throws IOException if the repository cannot be constructed and
* initialized.
*/
@@ -256,8 +250,6 @@ public class Modules {
* @throws SecurityException if a security manager exists and
* its <tt>checkPermission</tt> method denies access
* to create a new instance of repository.
- * @throws NullPointerException if <code>parent</code> is null,
- * <code>name</code> is null, or <code>codebase</code> is null.
* @throws IOException if the repository cannot be constructed and
* initialized.
* @throws IllegalArgumentException if a circularity is detected.
@@ -282,8 +274,6 @@ public class Modules {
* @throws SecurityException if a security manager exists and its
* <tt>checkPermission</tt> method denies access to create a new
* instance of repository.
- * @throws NullPointerException if <code>name</code> is null, or
- * <code>codebase</code> is null.
* @throws IOException if the repository cannot be constructed and
* initialized.
*/
@@ -310,9 +300,6 @@ public class Modules {
* @throws SecurityException if a security manager exists and
* its <tt>checkPermission</tt> method denies access
* to create a new instance of repository.
- * @throws NullPointerException if <code>parent</code> is null,
- * <code>name</code> is null, <code>codebase</code> is null,
- * or <code>config</code> is null.
* @throws IOException if the repository cannot be constructed and
* initialized.
* @throws IllegalArgumentException if a circularity is detected.
@@ -340,8 +327,6 @@ public class Modules {
* @throws SecurityException if a security manager exists and
* its <tt>checkPermission</tt> method denies access
* to create a new instance of repository.
- * @throws NullPointerException if <code>name</code> is null,
- * <code>codebase</code> is null, or <code>config</code> is null.
* @throws IOException if the repository cannot be constructed and
* initialized.
*/
@@ -413,7 +398,6 @@ public class Modules {
* override policy..
*
* @param policy the import override policy for module definitions.
- * @throws NullPointerException if the policy is null.
* @throws SecurityException if a security manager exists and its
* <tt>checkPermission</tt> method denies access to set the
* system's default import override policy.
@@ -483,8 +467,8 @@ public class Modules {
}
/**
- * Returns a new ModuleDefinition for modules based on the
- * Java Module System format.
+ * Returns a new {@code ModuleDefinition} for modules based on the Java
+ * Module System format.
*
* <p>This method will typically called by repository implementations
* and not by applications.
@@ -496,13 +480,9 @@ public class Modules {
* @param repository the repository in which the module archive is stored
* @param moduleReleasable the module instance instantiated from this module
* definition is releasable from the module system
- *
- * @throws NullPointerException if one of metadata, content, or repository
- * are null
* @throws ModuleFormatException if the contents of {@code metadata}
* are not well formed.
- *
- * @return a new ModuleDefinition
+ * @return a new {@code ModuleDefinition}
*/
public static ModuleDefinition newJamModuleDefinition(byte[] metadata,
ModuleDefinitionContent content, Repository repository, boolean moduleReleasable)
@@ -525,24 +505,18 @@ public class Modules {
* Java Module System format.
*
* <p>This method will typically called by repository implementations
- * and not by applications.
- * It is useful in case the metadata has not yet been retrieved but
- * the module name and version are available.
+ * and not by applications. It is useful in case the metadata has not
+ * yet been retrieved but the module name and version are available.
*
* @param name the name of the module definition
* @param version the version of the module definition
* @param metadataHandle a Callable from which the contents of the
- * {@code MODULE-INF/METADATA.MODULE} file can be retrieved
+ * {@code MODULE-INF/METADATA.MODULE} file can be retrieved
* @param content the ModuleDefinitionContent to be used to access the
- * contents of the module archive
+ * contents of the module archive
* @param repository the repository in which the module archive is stored
* @param moduleReleasable the module instance instantiated from this module
- * definition is releasable from the module system
- *
- * @throws NullPointerException if one of
- * name, version, metadataHandle, content, or repository
- * are null
- *
+ * definition is releasable from the module system
* @return a new ModuleDefinition
*/
public static ModuleDefinition newJamModuleDefinition(String name, Version version,
--- a/src/share/classes/java/module/Query.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/java/module/Query.java Wed Apr 02 17:59:05 2008 -0700
@@ -45,6 +45,9 @@ import java.util.Set;
* Query.versionRange("2.0.0+"));
* </pre>
*
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method in this class will cause a {@link NullPointerException} to be thrown.
+ * <p>
* @see java.module.ModuleDefinition
* @see java.module.VersionConstraint
* @since 1.7
@@ -410,7 +413,6 @@ public abstract class Query implements S
*
* @param query the specified query.
* @return the <code>Query</code> object.
- * @throws NullPointerException if query is null.
*/
public static Query not(Query query) {
if (query == null)
@@ -428,7 +430,6 @@ public abstract class Query implements S
* @param query1 A query.
* @param query2 Another query.
* @return the <code>Query</code> object.
- * @throws NullPointerException if query1 is null or query2 is null.
*/
public static Query and(Query query1, Query query2) {
if (query1 == null)
@@ -457,7 +458,6 @@ public abstract class Query implements S
* @param query1 A query.
* @param query2 Another query.
* @return the <code>Query</code> object.
- * @throws NullPointerException if query1 is null or query2 is null.
*/
public static Query or(Query query1, Query query2) {
if (query1 == null)
@@ -490,7 +490,6 @@ public abstract class Query implements S
* @return the <code>Query</code> object.
* @throws IllegalArgumentException if the string does not follow
* the version constraint format.
- * @throws NullPointerException if source is null.
*/
public static Query version(String source) {
if (source == null)
@@ -506,7 +505,6 @@ public abstract class Query implements S
*
* @param versionConstraint the <code>VersionConstraint</code> object.
* @return the <code>Query</code> object.
- * @throws NullPointerException if versionConstraint is null.
*/
public static Query version(VersionConstraint versionConstraint) {
if (versionConstraint == null)
@@ -524,7 +522,6 @@ public abstract class Query implements S
*
* @param name the name of the module definition.
* @return the <code>Query</code> object.
- * @throws NullPointerException if name is null.
*/
public static Query name(String name) {
if (name == null)
@@ -539,7 +536,6 @@ public abstract class Query implements S
*
* @param name the name of the module attribute.
* @return the <code>Query</code> object.
- * @throws NullPointerException if name is null.
*/
public static Query attribute(String name) {
if (name == null)
@@ -555,7 +551,6 @@ public abstract class Query implements S
* @param name the name of the module attribute.
* @param value the value of the module attribute.
* @return the <code>Query</code> object.
- * @throws NullPointerException if name is null or value is null.
*/
public static Query attribute(String name, String value) {
if (name == null)
@@ -572,7 +567,6 @@ public abstract class Query implements S
*
* @param annotationClass the Class object corresponding to the annotation type.
* @return the <code>Query</code> object.
- * @throws NullPointerException if the annotationClass is null.
*/
public static Query annotation(Class annotationClass) {
if (annotationClass == null)
--- a/src/share/classes/java/module/Repository.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/java/module/Repository.java Wed Apr 02 17:59:05 2008 -0700
@@ -27,6 +27,8 @@ package java.module;
import java.io.IOException;
import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
@@ -38,6 +40,9 @@ import sun.module.repository.RepositoryC
/**
* This class represents the repository in the module system.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method in this class will cause a {@link NullPointerException} to be thrown.
* <p>
* @see java.module.ModuleDefinition
* @see java.module.ModuleSystemPermission
@@ -56,8 +61,9 @@ public abstract class Repository {
private final ModuleSystem system;
- /** Listens to RepositoryEvents. */
- private RepositoryListener repositoryListener = null;
+ /** Listeners of RepositoryEvents. */
+ private static RepositoryListener repositoryListener = null;
+ private static Object listenerSyncObject = new Object();
/**
* Obtains the default thread factory when Repository.class is loaded, so
@@ -67,7 +73,7 @@ public abstract class Repository {
private static final ThreadFactory threadFactory = Executors.defaultThreadFactory();
/** Used to run the RepositoryEventHandler. */
- private ExecutorService executorService = null;
+ private static ExecutorService executorService = null;
/** Shuts down the repository upon JVM exit; see {@link #shutdownOnExit}. */
private Thread shutdownThread;
@@ -92,9 +98,6 @@ public abstract class Repository {
* @throws SecurityException if a security manager exists and its
* <tt>checkPermission</tt> method denies access to create a new
* instance of repository.
- * @throws NullPointerException if <code>parent</code> is null,
- * <code>name</code> is null, <code>source</code> is null,
- * or <code>system</code> is null.
* @throws IllegalArgumentException if a circularity is detected.
*/
protected Repository(Repository parent, String name, URL source, ModuleSystem system) {
@@ -146,8 +149,6 @@ public abstract class Repository {
* @throws SecurityException if a security manager exists and its
* <tt>checkPermission</tt> method denies access to create a new
* instance of repository.
- * @throws NullPointerException if <code>name</code> is null,
- * <code>source</code> is null, or <code>system</code> is null.
* @throws IllegalArgumentException if a circularity is detected.
*/
protected Repository(String name, URL source, ModuleSystem system) {
@@ -247,28 +248,36 @@ public abstract class Repository {
public abstract void shutdown() throws IOException;
/**
- * Enable or disable that the repository is shutdown when the
- * module system terminates. Shutdown will be attempted only
- * during the normal termination of the virtual machine, as
- * defined by the Java Language Specification. By default,
- * shutdown on exit is disabled.
- *
- * If a security manager is present, this method calls the
- * security manager's <code>checkPermission</code> method with
- * a <code>ModuleSystemPermission("shutdownRepository")</code>
- * permission to ensure it's ok to shutdown a repository.
+ * Enable or disable that the repository is shutdown when the module
+ * system terminates. Shutdown will be attempted only during the normal
+ * termination of the virtual machine, as defined by the Java Language
+ * Specification. By default, shutdown on exit is disabled.
+ *
+ * If a security manager is present, this method calls the security
+ * manager's <code>checkPermission</code> method with a
+ * <code>ModuleSystemPermission("shutdownRepository")</code> permission
+ * to ensure it's ok to shutdown a repository.
*
* @param value indicating enabling or disabling of shutdown.
- * @throws SecurityException if a security manager exists and
- * its <tt>checkPermission</tt> method denies access
- * to shutdown the repository.
- */
- public synchronized void shutdownOnExit(boolean value) {
+ * @throws SecurityException if a security manager exists and its
+ * <tt>checkPermission</tt> method denies access to shutdown the
+ * repository.
+ */
+ public final synchronized void shutdownOnExit(final boolean value) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new ModuleSystemPermission("shutdownRepository"));
}
-
+ // shutdownOnExit under doPrivileged()
+ AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+ public Boolean run() {
+ doShutdownOnExit(value);
+ return Boolean.TRUE;
+ }
+ });
+ }
+
+ private void doShutdownOnExit(boolean value) {
// Create/destroy shutdownThread based on given value.
if (value) {
if (shutdownThread == null) {
@@ -315,9 +324,7 @@ public abstract class Repository {
* @return true if this repository supports reloading.
* @see #reload()
*/
- public boolean isReloadSupported() {
- return false;
- }
+ public abstract boolean supportsReload();
/**
* Find a module definition. Equivalent to:
@@ -325,14 +332,14 @@ public abstract class Repository {
* find(moduleName, VersionConstraint.DEFAULT);
* </pre>
*
- * If this repository instance has not been initialized when this
- * method is called, it will be initialized automatically by
- * calling the initialize method with no argument.
+ * If this repository instance has not been initialized when this method
+ * is called, it will be initialized automatically by calling the
+ * {@link #initialize} method with no argument.
*
* @param name the module definition's name.
- * @return the module definition or null if not found. If
- * more than one module definition matches the specified
- * name, the latest version is returned.
+ * @return the module definition or null if not found. If more than one
+ * module definition matches the specified name, the highest
+ * version is returned.
* @throws IllegalStateException if the repository instance has been
* shutdown.
*/
@@ -344,15 +351,15 @@ public abstract class Repository {
/**
* Find a module definition.
*
- * If this repository instance has not been initialized when this
- * method is called, it will be initialized automatically by
- * calling the initialize method with no argument.
+ * If this repository instance has not been initialized when this method
+ * is called, it will be initialized automatically by calling the
+ * {@link #initialize} method with no argument.
*
* @param name the module definition's name.
* @param versionConstraint the version constraint.
- * @return the module definition or null if not found. If
- * more than one module definition matches the specified
- * name and version constraint, the latest version is returned.
+ * @return the module definition or null if not found. If more than one
+ * module definition matches the specified name and version
+ * constraint, the highest version is returned.
* @throws IllegalStateException if the repository instance has been
* shutdown.
*/
@@ -386,7 +393,7 @@ public abstract class Repository {
*
* If this repository instance has not been initialized when this
* method is called, it will be initialized automatically by
- * calling the initialize method with no argument.
+ * calling the {@link #initialize} method with no argument.
*
* @return the result list.
* @throws IllegalStateException if the repository instance has been
@@ -398,12 +405,11 @@ public abstract class Repository {
}
/**
- * Find all matching module definitions that match the specified
- * constraint.
+ * Find all matching module definitions that match the specified constraint.
*
* If this repository instance has not been initialized when this
* method is called, it will be initialized automatically by
- * calling the initialize method with no argument.
+ * calling the {@link #initialize} method with no argument.
*
* @param constraint the constraint.
* @return the result list.
@@ -460,131 +466,130 @@ public abstract class Repository {
}
/**
- * Find all matching module definitions in the repository. This
- * method should be overridden by repository implementations for
- * finding matching module definitions, and will be invoked by
- * the find method after checking the parent repository for
- * the requested module definitions.
- * <p>
- * If this repository instance has not been initialized when this
- * method is called, it will be initialized automatically by
- * calling the initialize method with no argument.
+ * Find all matching module definitions in the repository. This method
+ * should be overridden by repository implementations for finding
+ * matching module definitions, and will be invoked by the
+ * {@link #find} method after checking the parent repository for the
+ * requested module definitions.
+ * <p>
+ * If this repository instance has not been initialized when this method
+ * is called, it will be initialized automatically by calling the
+ * {@link #initialize} method with no argument.
*
* @param constraint the constraint.
* @return the collection of matching module definitions.
- * @throws IllegalStateException if the repository instance has
- * not been initialized or has been shutdown.
+ * @throws IllegalStateException if the repository instance has not been
+ * initialized or has been shutdown.
*/
protected abstract List<ModuleDefinition> findModuleDefinitions(Query constraint);
/**
- * Returns an unmodifiable list of the installed module archives' information
- * in the repository. The list will contain a snapshot of the installed module
- * archives in the repository at the time of the given invocation of this method.
- * <p>
- * If a security manager is present, this method calls the
- * security manager's <code>checkPermission</code> method with
- * a <code>ModuleSystemPermission("listModuleArchive")
- * </code> permission to ensure it's ok to return the information of the
- * installed module archives in a repository.
- *
- * @return an unmodifiable list of the installed module archives' information.
+ * Returns an unmodifiable list of the installed module archives'
+ * information in the repository. The list will contain a snapshot of the
+ * installed module archives in the repository at the time of the given
+ * invocation of this method.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's <code>checkPermission</code> method with a
+ * <code>ModuleSystemPermission("listModuleArchive")</code> permission to
+ * ensure it's ok to return the information of the installed module
+ * archives in a repository.
+ *
+ * @return an unmodifiable list of the installed module archives'
+ * information.
* @throws SecurityException if a security manager exists and its
* <tt>checkPermission</tt> method denies access to return the
- * the information of the installed module archives.
- * @throws IllegalStateException if the repository instance has not
- * been initialized or it has been shutdown.
+ * information of the installed module archives.
+ * @throws IllegalStateException if the repository instance has not been
+ * initialized or it has been shutdown.
*/
public abstract List<ModuleArchiveInfo> list();
/**
* Install a module archive with the module definition into the repository.
* <p>
- * If a security manager is present, this method calls the
- * security manager's <code>checkPermission</code> method with
- * a <code>ModuleSystemPermission("installModuleArchive")
- * </code> permission to ensure it's ok to install a module
- * archive into a repository.
- *
- * @param u the URL to the module archive.
- * @return the <code>ModuleArchiveInfo</code> object that represents
- * the installed module archive.
+ * If a security manager is present, this method calls the security
+ * manager's <code>checkPermission</code> method with a
+ * <code>ModuleSystemPermission("installModuleArchive")</code> permission
+ * to ensure it's ok to install a module archive into a repository.
+ *
+ * @param url the URL to the module archive.
+ * @return the <code>ModuleArchiveInfo</code> object that represents the
+ * installed module archive.
* @throws SecurityException if a security manager exists and its
* <tt>checkPermission</tt> method denies access to install a
* module archive in the repository.
+ * @throws UnsupportedOperationException if the repository is read-only.
* @throws IOException if an error occurs while installing the module archive.
* @throws ModuleFormatException if the module archive format is not
* supported by this implementation.
- * @throws UnsupportedOperationException if the repositoryis read-only.
* @throws IllegalStateException if a module definition with the same name,
* version and platform binding is already installed, or if the
* repository instance has not been initialized or it has been
* shutdown.
*/
- public abstract ModuleArchiveInfo install(URL u) throws IOException;
+ public abstract ModuleArchiveInfo install(URL url) throws IOException;
/**
* Uninstall a module archive from the repository.
* <p>
- * If a security manager is present, this method calls the
- * security manager's <code>checkPermission</code> method with
- * a <code>ModuleSystemPermission("uninstallModuleArchive")
- * </code> permission to ensure it's ok to uninstall a module
- * archive from a repository.
+ * If a security manager is present, this method calls the security
+ * manager's <code>checkPermission</code> method with a
+ * <code>ModuleSystemPermission("uninstallModuleArchive")</code>
+ * permission to ensure it's ok to uninstall a module archive from a
+ * repository.
*
* @param m the module archive to be uninstalled.
- * @return true if the module archive is found and uninstalled,
- * returns false otherwise.
- * @throws SecurityException if a security manager exists and
- * its <tt>checkPermission</tt> method denies access
- * to uninstall the module archive in the repository.
+ * @return true if the module archive is found and uninstalled, returns
+ * false otherwise.
+ * @throws SecurityException if a security manager exists and its
+ * <tt>checkPermission</tt> method denies access to uninstall the
+ * module archive in the repository.
+ * @throws UnsupportedOperationException if the repository is read-only.
* @throws IllegalStateException if the module definition in the specified
- * specified module archive is in use, or
- * if the repository instance has not been
- * initialized or it has been shutdown.
- * @throws UnsupportedOperationException if the repository is read-only.
- * @throws IOException If an error occurs while uninstalling the module archive.
+ * specified module archive is in use, or if the repository
+ * instance has not been initialized or it has been shutdown.
+ * @throws IOException If an error occurs while uninstalling the module
+ * archive.
*/
public abstract boolean uninstall(ModuleArchiveInfo m) throws IOException;
/**
- * Reload the repository. The behavior of this method depends on
- * the implementation.
- * <p>
- * If a security manager is present, this method calls the
- * security manager's <code>checkPermission</code> method with
- * a <code>ModuleSystemPermission("reloadRepository")</code>
- * permission to ensure it's ok to reload module
- * definitions in a repository.
- *
- * @throws SecurityException if a security manager exists and
- * its <tt>checkPermission</tt> method denies access
- * to reload module definitions in the repository.
- * @throws UnsupportedOperationException if the repository
- * does not support reload.
- * @throws IllegalStateException if a module definition is in use
- * thus cannot be reloaded.
- * @throws IOException If an error occurs while reloading the
- * module definitions.
+ * Reload the repository. The behavior of this method depends on the
+ * implementation.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's <code>checkPermission</code> method with a
+ * <code>ModuleSystemPermission("reloadRepository")</code> permission
+ * to ensure it's ok to reload module definitions in a repository.
+ *
+ * @throws SecurityException if a security manager exists and its
+ * <tt>checkPermission</tt> method denies access to reload module
+ * definitions in the repository.
+ * @throws UnsupportedOperationException if the repository does not
+ * support reload.
+ * @throws IllegalStateException if a module definition is in use thus
+ * cannot be reloaded.
+ * @throws IOException If an error occurs while reloading the module
+ * definitions.
*/
public abstract void reload() throws IOException;
/**
- * Adds the specified repository listener to receive repository events
- * from this repository.
- * <p>
- * If a security manager is present, this method calls the security
- * manager's checkPermission method with a <code>
- * ModuleSystemPermission("addRepositoryListener")</code> permission to
- * ensure it's ok to add a repository listener to the repository.
+ * Adds the specified repository listener to receive repository events from
+ * the repositories.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's checkPermission method with a
+ * <code>ModuleSystemPermission("addRepositoryListener")</code> permission
+ * to ensure it's ok to add a repository listener to the repositories.
*
* @param listener the repository listener
* @throws SecurityException if a security manager exists and its
- * checkPermission method denies access to add a repository
- * listener to the repository.
- * @throws NullPointerException if listener is null.
- */
- public final void addRepositoryListener(RepositoryListener listener) {
+ * <tt>checkPermission</tt> method denies access to add a
+ * repository listener to the repositories.
+ */
+ public static final void addRepositoryListener(RepositoryListener listener) {
if (listener == null) {
throw new NullPointerException("Repository listener must not be null.");
}
@@ -594,27 +599,27 @@ public abstract class Repository {
sm.checkPermission(new ModuleSystemPermission("addRepositoryListener"));
}
- synchronized (this) {
+ synchronized(listenerSyncObject) {
repositoryListener = EventMulticaster.add(repositoryListener, listener);
}
}
/**
- * Removes the specified repository listener so that it no longer
- * receives repository events from this repository.
- * <p>
- * If a security manager is present, this method calls the security
- * manager's checkPermission method with a <code>
- * ModuleSystemPermission("removeModuleSystemListener")</code> permission to
- * ensure it's ok to remove a repository listener from the repository.
+ * Removes the specified repository listener so that it no longer receives
+ * repository events from the repositories.
+ * <p>
+ * If a security manager is present, this method calls the security
+ * manager's checkPermission method with a
+ * <code>ModuleSystemPermission("removeModuleSystemListener")</code>
+ * permission to ensure it's ok to remove a repository listener from the
+ * repositories.
*
* @param listener the repository listener
* @throws SecurityException if a security manager exists and its
- * checkPermission method denies access to remove a repository
- * listener from the repository.
- * @throws NullPointerException if listener is null.
- */
- public final void removeRepositoryListener(RepositoryListener listener) {
+ * <tt>checkPermission</tt> method denies access to remove a
+ * repository listener from the repositories.
+ */
+ public static final void removeRepositoryListener(RepositoryListener listener) {
if (listener == null) {
throw new NullPointerException("Repository listener must not be null.");
}
@@ -624,7 +629,7 @@ public abstract class Repository {
sm.checkPermission(new ModuleSystemPermission("removeRepositoryListener"));
}
- synchronized (this) {
+ synchronized(listenerSyncObject) {
repositoryListener = EventMulticaster.remove(repositoryListener, listener);
}
}
@@ -656,8 +661,8 @@ public abstract class Repository {
}
/**
- * Processes repository event occuring in this repository by
- * dispatching them to any registered RepositoryListener objects.
+ * Processes repository event occuring in this repository by dispatching
+ * them to any registered RepositoryListener objects.
*
* @param event the repository event
*/
@@ -668,7 +673,7 @@ public abstract class Repository {
if (listener == null)
return;
- synchronized(this) {
+ synchronized(listenerSyncObject) {
if (executorService == null) {
// Creates a single thread executor that creates thread in the main
// thread group.
@@ -721,15 +726,13 @@ public abstract class Repository {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
-
- builder.append("Repository[name=");
+ builder.append("repository ");
builder.append(getName());
if (getSourceLocation() != null) {
- builder.append(",source=");
+ builder.append(" (");
builder.append(getSourceLocation());
- }
- builder.append("]");
-
+ builder.append(")");
+ }
return builder.toString();
}
--- a/src/share/classes/java/module/RepositoryEvent.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/java/module/RepositoryEvent.java Wed Apr 02 17:59:05 2008 -0700
@@ -25,8 +25,6 @@
package java.module;
-import java.util.EventObject;
-
/**
* This class represents a repository event that occurs in the repository.
*
@@ -37,7 +35,7 @@ import java.util.EventObject;
*
* @since 1.7
*/
-public class RepositoryEvent extends EventObject {
+public class RepositoryEvent {
/**
* Types of repository events.
@@ -65,13 +63,9 @@ public class RepositoryEvent extends Eve
MODULE_UNINSTALLED
};
- /*
- * JDK 1.1 serialVersionUID
- */
- private static final long serialVersionUID = 5422851685952565936L;
-
private Type type;
- private transient ModuleArchiveInfo info;
+ private Repository source;
+ private ModuleArchiveInfo info;
/**
* Constructs a RepositoryEvent object with the specified repository,
@@ -82,8 +76,6 @@ public class RepositoryEvent extends Eve
* @throws NullPointerException if source is null or type is null.
*/
public RepositoryEvent(Repository source, Type type) {
- super(source);
-
if (source == null)
throw new NullPointerException("source must not be null.");
@@ -91,6 +83,7 @@ public class RepositoryEvent extends Eve
throw new NullPointerException("type must not be null.");
this.type = type;
+ this.source = source;
this.info = null;
}
@@ -105,8 +98,6 @@ public class RepositoryEvent extends Eve
* info is null.
*/
public RepositoryEvent(Repository source, Type type, ModuleArchiveInfo info) {
- super(source);
-
if (source == null)
throw new NullPointerException("source must not be null.");
@@ -117,6 +108,7 @@ public class RepositoryEvent extends Eve
throw new NullPointerException("info must not be null.");
this.type = type;
+ this.source = source;
this.info = info;
}
@@ -125,6 +117,13 @@ public class RepositoryEvent extends Eve
*/
public Type getType() {
return type;
+ }
+
+ /**
+ * Returns the repository associated with the event.
+ */
+ public Repository getSource() {
+ return source;
}
/**
@@ -147,11 +146,11 @@ public class RepositoryEvent extends Eve
builder.append("RepositoryEvent[type=");
builder.append(type.toString());
builder.append(",repository=");
-
- Repository repository = (Repository) getSource();
- builder.append(repository.getName());
- builder.append(",module-archive-info=");
- builder.append(info.toString());
+ builder.append(getSource().getName());
+ if (info != null) {
+ builder.append(",module-archive-info=");
+ builder.append(info.toString());
+ }
builder.append("]");
return builder.toString();
--- a/src/share/classes/sun/module/JamUtils.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/JamUtils.java Wed Apr 02 17:59:05 2008 -0700
@@ -30,6 +30,7 @@ import java.module.Version;
import java.module.Version;
import java.net.*;
import java.security.AccessController;
+import java.security.CodeSigner;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -62,6 +63,20 @@ public final class JamUtils {
public static final String MODULE_INF_METADATA = MODULE_INF + "/" + MODULE_METADATA;
+ private static File tempDirectory = null;
+
+ static {
+ // Determines the temp directory.
+ try {
+ File tempFile = File.createTempFile("temp-directory-test-", ".tmp");
+ tempDirectory = tempFile.getParentFile();
+ tempFile.deleteOnExit();
+ tempFile.delete();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
private JamUtils() {
}
@@ -111,50 +126,12 @@ public final class JamUtils {
public static File createTempDir() throws IOException {
File rc = File.createTempFile("jam-" + System.currentTimeMillis(), ".tmp");
rc.deleteOnExit();
+ rc.delete();
return rc.getParentFile();
}
- public static byte[] readFile(File file) throws IOException {
- if (file.isFile() == false) {
- throw new IOException("Not a regular file: " + file);
- }
- long llen = file.length();
- if (llen > 64 * 1024 * 1024) { // 64 MB
- throw new IOException("File too large: " + file);
- }
- InputStream in = new FileInputStream(file);
- int len = (int)llen;
- byte[] data = new byte[len];
- int ofs = 0;
- while (len > 0) {
- int n = in.read(data, ofs, len);
- if (n < 0) {
- break;
- }
- len -= n;
- ofs += n;
- }
- in.close();
- if (len != 0) {
- throw new IOException("Could not read file");
- }
- return data;
- }
-
- public static byte[] readStream(InputStream in) throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- byte[] buffer = new byte[BUFFER_SIZE];
-
- while (true) {
- int n = in.read(buffer, 0, buffer.length);
- if (n < 0) {
- break;
- }
- out.write(buffer, 0, n);
- }
-
- in.close();
- return out.toByteArray();
+ public static File getTempDir() {
+ return tempDirectory;
}
public static void close(Closeable c) {
@@ -253,6 +230,23 @@ public final class JamUtils {
unpacker.unpack(gis, jos);
jos.close();
gis.close();
+ }
+
+ /**
+ * Unpack the source file into the destination file.
+ *
+ * @param sourceJamPackGz .jam.pack.gz file to extract.
+ * @param destJam the unpacked jam file.
+ * @throws IOException if an I/O exception occurs.
+ */
+ public static void unpackJamPackGz(File sourceJamPackGz, File destJam) throws IOException {
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(sourceJamPackGz);
+ unpackStreamAsFile(fis, destJam);
+ } finally {
+ close(fis);
+ }
}
/**
@@ -318,15 +312,17 @@ public final class JamUtils {
}
/**
- * Gets module metadata from a JAM file.
+ * Returns the module metadata from a JAM file as byte array.
*
* @param jamFile JAM file
- * @return a byte[] of data from the MODULE.METADATA file within a JAM file.
- */
- public static byte[] getMetadata(JarFile jamFile) throws IOException {
+ * @return a byte array that represents the MODULE.METADATA file in a JAM
+ * file.
+ * @throws IOException if an I/O exception has occurred.
+ */
+ public static byte[] getMetadataBytes(JarFile jamFile) throws IOException {
JarEntry je = jamFile.getJarEntry("MODULE-INF/MODULE.METADATA");
if (je == null) {
- throw new IllegalArgumentException(
+ throw new IOException(
jamFile + " does not contain MODULE-INF/MODULE.METADATA");
}
InputStream is = jamFile.getInputStream(je);
@@ -341,6 +337,73 @@ public final class JamUtils {
}
/**
+ * Retrieves the bytes from the input stream.
+ *
+ * @param is input stream
+ * @return a byte array read from the input stream
+ * @throws IOException if an I/O exception occurs.
+ */
+ public static byte[] getInputStreamAsBytes(InputStream is) throws IOException {
+ BufferedInputStream bis = new BufferedInputStream(is);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int len = 0;
+ byte[] buf = new byte[BUFFER_SIZE];
+ while ((len = bis.read(buf, 0, buf.length)) >= 0) {
+ baos.write(buf, 0, len);
+ }
+ bis.close();
+ return baos.toByteArray();
+ }
+
+ /**
+ * Returns the code signers from the JAM file
+ *
+ * @param jamFile jam file
+ * @return an array of code signers that sign the JAM file.
+ * @throw IOException if the JAM file is not consistently signed by same
+ * set of signers.
+ */
+ public static CodeSigner[] getCodeSigners(JarFile jamFile) throws IOException {
+ List<CodeSigner> overallCodeSigners = null;
+
+ // Iterate each entry in the JAM file
+ for (JarEntry je : Collections.list(jamFile.entries())) {
+ String s = je.getName();
+
+ // Skip the entry if it is in META-INF directory.
+ if (s.startsWith("META-INF/")) {
+ continue;
+ }
+
+ // Convert entry's code signers into a list
+ CodeSigner[] cs = je.getCodeSigners();
+ List<CodeSigner> entryCodeSigners = null;
+ if (cs == null) {
+ entryCodeSigners = new ArrayList<CodeSigner>();
+ } else {
+ entryCodeSigners = Arrays.asList(cs);
+ }
+
+ // This is the first entry that matters, use it as the overall
+ // JAM code signers
+ if (overallCodeSigners == null) {
+ overallCodeSigners = entryCodeSigners;
+ continue;
+ }
+
+ // Check to see if the entry's signers and the overall JAM signers
+ // are identical.
+ if (!overallCodeSigners.containsAll(entryCodeSigners)
+ || !entryCodeSigners.containsAll(overallCodeSigners))
+ throw new IOException("Not all entries in the JAM file are "
+ + "signed consistently by the same set of signers: "
+ + jamFile.getName());
+ }
+
+ return overallCodeSigners.toArray(new CodeSigner[0]);
+ }
+
+ /**
* Returns jam filename with no file extension, based on module name,
* version, platform and architecture.
*
@@ -350,20 +413,7 @@ public final class JamUtils {
* @param arch target architecture
* @return jam filename with no file extension
*/
- public static String getJamFilenameNoExt(String name, Version version, String platform, String arch) {
+ public static String getJamFilename(String name, Version version, String platform, String arch) {
return name + "-" + version + ((platform == null) ? "" : "-" + platform + "-" + arch);
}
-
- /**
- * Returns jam filename 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 jam filename
- */
- public static String getJamFilename(String name, Version version, String platform, String arch) {
- return getJamFilenameNoExt(name, version, platform, arch) + ".jam";
- }
}
--- a/src/share/classes/sun/module/ModuleLauncher.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/ModuleLauncher.java Wed Apr 02 17:59:05 2008 -0700
@@ -99,8 +99,8 @@ public final class ModuleLauncher {
throw new Exception("No Main-Class attribute in the module definition");
}
}
- Module module = moddef.getModuleInstance();
- ClassLoader loader = module.getClassLoader();
+ Module m = moddef.getModuleInstance();
+ ClassLoader loader = m.getClassLoader();
ProxyModuleLoader.setPrimaryModuleLoader(loader);
Class<?> clazz = loader.loadClass(mainClassName);
return clazz;
--- a/src/share/classes/sun/module/bootstrap/BootstrapModuleSystem.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/bootstrap/BootstrapModuleSystem.java Wed Apr 02 17:59:05 2008 -0700
@@ -87,7 +87,7 @@ public final class BootstrapModuleSystem
for (ImportDependency imp : moduleDef.getImportDependencies()) {
// Find the imported module only through the bootstrap repository.
- ModuleDefinition md = Repository.getBootstrapRepository().find(imp.getModuleName(), imp.getVersionConstraint());
+ ModuleDefinition md = Repository.getBootstrapRepository().find(imp.getName(), imp.getVersionConstraint());
// Instantiate a new module instance of the imported module
Module importedModule = getModuleInternal(md);
@@ -104,21 +104,21 @@ public final class BootstrapModuleSystem
}
@Override
- public void releaseModule(ModuleDefinition definition) {
+ public void releaseModule(ModuleDefinition moduleDef) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new ModuleSystemPermission("releaseModule"));
}
- if (definition.getName().startsWith("java.")) {
+ if (moduleDef.getName().startsWith("java.")) {
throw new UnsupportedOperationException("Cannot release module instances with name begins with \"java.\".");
}
- if (definition.getRepository() == Repository.getBootstrapRepository()) {
+ if (moduleDef.getRepository() == Repository.getBootstrapRepository()) {
throw new UnsupportedOperationException("Cannot release module instances instantiated from module definitions in the bootstrap repository.");
}
- if (definition.getRepository().getModuleSystem() != this) {
+ if (moduleDef.getRepository().getModuleSystem() != this) {
throw new UnsupportedOperationException("Cannot release module instances instantiated from module definitions in a different module system.");
}
- if (definition.isModuleReleasable() == false) {
+ if (moduleDef.isModuleReleasable() == false) {
throw new UnsupportedOperationException("Cannot release module instances instantiated from a module definition which is not releasable.");
}
@@ -127,18 +127,18 @@ public final class BootstrapModuleSystem
}
@Override
- public void disableModuleDefinition(ModuleDefinition definition) {
+ public void disableModuleDefinition(ModuleDefinition moduleDef) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new ModuleSystemPermission("disableModuleDefinition"));
}
- if (definition.getName().startsWith("java.")) {
+ if (moduleDef.getName().startsWith("java.")) {
throw new UnsupportedOperationException("Cannot disable module definition with name begins with \"java.\".");
}
- if (definition.getRepository() == Repository.getBootstrapRepository()) {
+ if (moduleDef.getRepository() == Repository.getBootstrapRepository()) {
throw new UnsupportedOperationException("Cannot disable module definition in the bootstrap repository.");
}
- if (definition.getRepository().getModuleSystem() != this) {
+ if (moduleDef.getRepository().getModuleSystem() != this) {
throw new UnsupportedOperationException("Cannot disable module definition in a different module system..");
}
}
--- a/src/share/classes/sun/module/bootstrap/BootstrapRepository.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/bootstrap/BootstrapRepository.java Wed Apr 02 17:59:05 2008 -0700
@@ -111,6 +111,11 @@ public final class BootstrapRepository e
}
@Override
+ public boolean supportsReload() {
+ return false;
+ }
+
+ @Override
public void reload() throws IOException {
// empty
}
--- a/src/share/classes/sun/module/core/ModuleImpl.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/core/ModuleImpl.java Wed Apr 02 17:59:05 2008 -0700
@@ -454,9 +454,9 @@ final class ModuleImpl extends Module {
// Build version constraint map from the ImportDependencies
Map<String,VersionConstraint> versionConstraints = new HashMap<String,VersionConstraint>();
for (ImportDependency dep : importDependencies) {
- if (versionConstraints.put(dep.getModuleName(), dep.getVersionConstraint()) != null) {
+ if (versionConstraints.put(dep.getName(), dep.getVersionConstraint()) != null) {
fail(null, "Module " + moduleString + " imports module "
- + dep.getModuleName() + " more than once.");
+ + dep.getName() + " more than once.");
}
}
versionConstraints = Collections.unmodifiableMap(versionConstraints);
@@ -575,11 +575,11 @@ final class ModuleImpl extends Module {
if (dep.isOptional() == false) {
fail(null, "Import policy error in module " + moduleString
+ ": non-optional imported module definition is missing in the returned list: "
- + dep.getModuleName() + " " + dep.getVersionConstraint());
+ + dep.getName() + " " + dep.getVersionConstraint());
}
continue;
}
- String name = dep.getModuleName();
+ String name = dep.getName();
if (name.equals(md.getName()) == false) {
fail(null, "Import policy error in module " + moduleString
+ ": mismatch in the name of imported module definition in the returned list: "
@@ -613,7 +613,7 @@ final class ModuleImpl extends Module {
Repository rep = moduleDef.getRepository();
List<ImportDependency> importDependencies = moduleDef.getImportDependencies();
for (ImportDependency dep : importDependencies) {
- String name = dep.getModuleName();
+ String name = dep.getName();
VersionConstraint constraint = constraints.get(name);
if (constraint == null) {
throw new ModuleInitializationException
@@ -626,12 +626,12 @@ final class ModuleImpl extends Module {
if (dep.isOptional() == false) {
throw new ModuleInitializationException
("Default import policy error in module " + moduleString
- + ": imported module " + dep.getModuleName() + " "
+ + ": imported module " + dep.getName() + " "
+ dep.getVersionConstraint() + " is not found");
}
if (DEBUG) {
System.out.println("Optional import is not satisfied: "
- + dep.getModuleName() + " " + dep.getVersionConstraint());
+ + dep.getName() + " " + dep.getVersionConstraint());
}
continue;
}
--- a/src/share/classes/sun/module/core/ModuleLoader.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/core/ModuleLoader.java Wed Apr 02 17:59:05 2008 -0700
@@ -35,6 +35,7 @@ import java.net.URL;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
+import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.SecureClassLoader;
@@ -51,7 +52,7 @@ final class ModuleLoader extends SecureC
final static boolean DEBUG = ModuleImpl.DEBUG;
private final Module module;
- private final ModuleDefinition definition;
+ private final ModuleDefinition moduleDef;
private final ModuleDefinitionContent content;
private final ClassLoader parent;
@@ -61,21 +62,21 @@ final class ModuleLoader extends SecureC
private boolean manifestSet = false;
private String classesDirectoryPath = null;
- ModuleLoader(Module module, final ModuleDefinition definition)
+ ModuleLoader(Module module, final ModuleDefinition moduleDef)
throws ModuleInitializationException {
super();
this.parent = getParent();
this.module = module;
- this.definition = definition;
- Module coreModule = definition.getRepository().find("java.se.core").getModuleInstance();
+ this.moduleDef = moduleDef;
+ Module coreModule = moduleDef.getRepository().find("java.se.core").getModuleInstance();
importedModules = Collections.singletonList(coreModule);
content = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<ModuleDefinitionContent>() {
public ModuleDefinitionContent run() {
- return definition.getModuleDefinitionContent();
+ return moduleDef.getModuleDefinitionContent();
}
});
- ClassesDirectoryPath classesDirectoryPathAnnotation = definition.getAnnotation(ClassesDirectoryPath.class);
+ ClassesDirectoryPath classesDirectoryPathAnnotation = moduleDef.getAnnotation(ClassesDirectoryPath.class);
if (classesDirectoryPathAnnotation != null) {
classesDirectoryPath = classesDirectoryPathAnnotation.value();
if (classesDirectoryPath.startsWith("/")) {
@@ -92,19 +93,27 @@ final class ModuleLoader extends SecureC
// constructs module URL and module's code source
StringBuilder sb = new StringBuilder();
sb.append("module:");
- sb.append(definition.getRepository().getName());
- if (definition.getRepository().getSourceLocation() != null) {
+ sb.append(moduleDef.getRepository().getName());
+ if (moduleDef.getRepository().getSourceLocation() != null) {
sb.append("/");
- sb.append(definition.getRepository().getSourceLocation().toString());
+ sb.append(moduleDef.getRepository().getSourceLocation().toString());
}
sb.append("!/");
- sb.append(definition.getName());
+ sb.append(moduleDef.getName());
sb.append("/");
- sb.append(definition.getVersion());
+ sb.append(moduleDef.getVersion());
URL moduleURL = new URL(sb.toString());
- cs = new CodeSource(moduleURL, content.getCodeSigners());
- } catch (MalformedURLException e) {
+
+ // This is currently the very first call the module system would
+ // call into ModuleDefinitionContent in a module definition. In the
+ // case of URLRepository, this would trigger the JAM file to be
+ // downloaded and the module metadata is compared (and potentially
+ // throws exception if there is a mismatch between the
+ // MODULE.METADATA file and that in the JAM file.
+ CodeSigner[] codeSigners = content.getCodeSigners();
+ cs = new CodeSource(moduleURL, codeSigners);
+ } catch (IOException e) {
throw new ModuleInitializationException("cannot construct module's code source", e);
}
}
@@ -361,7 +370,7 @@ final class ModuleLoader extends SecureC
try {
ResourceHandler handler = new ResourceHandler(this, path);
URL url = new URL("x-module-internal",
- definition.getName() + "-" + definition.getVersion(),
+ moduleDef.getName() + "-" + moduleDef.getVersion(),
-1, "/" + path, handler);
handler.url = url;
return url;
@@ -463,18 +472,23 @@ final class ModuleLoader extends SecureC
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
-
- builder.append("ModuleClassLoader[module-name=");
- builder.append(definition.getName());
- builder.append(",module-version=");
- builder.append(definition.getVersion());
- builder.append(",imported modules=");
- for (Module m:importedModules) {
- builder.append(m);
- builder.append(",");
- }
- builder.append("]");
-
+ builder.append("ModuleClassLoader[module=");
+ builder.append(moduleDef.getName());
+ builder.append(" v");
+ builder.append(moduleDef.getVersion());
+ builder.append(", imported-modules=[");
+ boolean first = true;
+ for (Module m : importedModules) {
+ if (!first) {
+ builder.append(", ");
+ }
+ ModuleDefinition md = m.getModuleDefinition();
+ builder.append(md.getName());
+ builder.append(" v");
+ builder.append(md.getVersion());
+ first = false;
+ }
+ builder.append("]]");
return builder.toString();
}
}
--- a/src/share/classes/sun/module/core/ModuleSystemImpl.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/core/ModuleSystemImpl.java Wed Apr 02 17:59:05 2008 -0700
@@ -80,24 +80,24 @@ public final class ModuleSystemImpl exte
}
@Override
- public synchronized void releaseModule(ModuleDefinition definition) {
+ public synchronized void releaseModule(ModuleDefinition moduleDef) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new ModuleSystemPermission("releaseModule"));
}
- if (definition.getName().startsWith("java.")) {
+ if (moduleDef.getName().startsWith("java.")) {
throw new UnsupportedOperationException("Cannot release module instances with name begins with \"java.\".");
}
- if (definition.getRepository() == Repository.getBootstrapRepository()) {
+ if (moduleDef.getRepository() == Repository.getBootstrapRepository()) {
throw new UnsupportedOperationException("Cannot release module instances instantiated from module definitions in the bootstrap repository.");
}
- if (definition.getRepository().getModuleSystem() != this) {
+ if (moduleDef.getRepository().getModuleSystem() != this) {
throw new UnsupportedOperationException("Cannot release module instances instantiated from module definitions in a different module system.");
}
- if (definition.isModuleReleasable() == false) {
+ if (moduleDef.isModuleReleasable() == false) {
throw new UnsupportedOperationException("Cannot release module instances instantiated from a module definition which is not releasable.");
}
- Module moduleToRelease = modules.get(definition);
+ Module moduleToRelease = modules.get(moduleDef);
if (moduleToRelease == null) {
// There is no module instance that is fully initialized, partially
// initialized, or in error state, which corresponds to the module
@@ -110,7 +110,7 @@ public final class ModuleSystemImpl exte
// fully initialized module instance, or obtain an initialization
// exception.
try {
- getModule(definition);
+ getModuleInternal(moduleDef);
} catch(ModuleInitializationException mie) {
// No module instance is instantiated successfully, thus nothing
// to release.
@@ -168,40 +168,50 @@ public final class ModuleSystemImpl exte
}
@Override
- public void disableModuleDefinition(ModuleDefinition definition) {
+ public void disableModuleDefinition(ModuleDefinition moduleDef) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new ModuleSystemPermission("disableModuleDefinition"));
}
- if (definition.getName().startsWith("java.")) {
+ if (moduleDef.getName().startsWith("java.")) {
throw new UnsupportedOperationException("Cannot disable module definition with name begins with \"java.\".");
}
- if (definition.getRepository() == Repository.getBootstrapRepository()) {
+ if (moduleDef.getRepository() == Repository.getBootstrapRepository()) {
throw new UnsupportedOperationException("Cannot disable module definition in the bootstrap repository.");
}
- if (definition.getRepository().getModuleSystem() != this) {
+ if (moduleDef.getRepository().getModuleSystem() != this) {
throw new UnsupportedOperationException("Cannot disable module definition in a different module system..");
}
synchronized(disabledModuleDefinitionIds) {
- if (disabledModuleDefinitionIds.contains(new Long(definition.getId()))) {
+ if (disabledModuleDefinitionIds.contains(new Long(moduleDef.getId()))) {
throw new IllegalStateException("Cannot disable module definition which has already been disabled.");
}
- disabledModuleDefinitionIds.add(new Long(definition.getId()));
- }
- }
-
- @Override
- public Module getModule(ModuleDefinition definition) throws ModuleInitializationException {
+ disabledModuleDefinitionIds.add(new Long(moduleDef.getId()));
+ }
+
+ // Send MODULE_DEFINITION_DISABLED event
+ ModuleSystemEvent evt = new ModuleSystemEvent(this, moduleDef);
+ this.sendEvent(evt);
+ }
+
+ @Override
+ public Module getModule(ModuleDefinition moduleDef) throws ModuleInitializationException {
// Check if the module definition has been disabled.
//
synchronized(disabledModuleDefinitionIds) {
- if (disabledModuleDefinitionIds.contains(new Long(definition.getId()))) {
+ if (disabledModuleDefinitionIds.contains(new Long(moduleDef.getId()))) {
throw new IllegalStateException("Cannot instantiate new module instance from a disabled module definition.");
}
}
-
+ return getModuleInternal(moduleDef);
+ }
+
+ /**
+ * Internal method to get a module instance from a module definition.
+ */
+ private Module getModuleInternal(ModuleDefinition moduleDef) throws ModuleInitializationException {
try {
- ModuleImpl m = getModuleInstance(definition);
+ ModuleImpl m = getModuleInstance(moduleDef);
if (m.initializationComplete() || (Thread.currentThread() != initializerThread)) {
// Wait for the module initializer thread to ready the module
// or if initialization is already complete, check if there
@@ -232,15 +242,15 @@ public final class ModuleSystemImpl exte
}
}
- synchronized ModuleImpl getModuleInstance(ModuleDefinition definition) {
- if (definition.getRepository().getModuleSystem() != this) {
+ synchronized ModuleImpl getModuleInstance(ModuleDefinition moduleDef) {
+ if (moduleDef.getRepository().getModuleSystem() != this) {
throw new IllegalArgumentException
("Cannot instantiate new module instance from module definition in a different module system.");
}
- ModuleImpl module = modules.get(definition);
+ ModuleImpl module = modules.get(moduleDef);
if (module == null) {
- module = new ModuleImpl(this, definition);
- modules.put(definition, module);
+ module = new ModuleImpl(this, moduleDef);
+ modules.put(moduleDef, module);
newModules.add(module);
}
return module;
--- a/src/share/classes/sun/module/core/ModuleUtils.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/core/ModuleUtils.java Wed Apr 02 17:59:05 2008 -0700
@@ -44,12 +44,12 @@ public final class ModuleUtils {
/**
* Expand reexports of a specified module instance.
*
- * @param module module instance
+ * @param m module instance
* @param modules a list of expanded modules
* @param includeAll true if the expansion should include all imported modules
*/
- static void expandReexports(Module module, List<Module> modules, boolean includeAll) {
- for (ImportDependency dep : module.getModuleDefinition().getImportDependencies()) {
+ public static void expandReexports(Module m, List<Module> modules, boolean includeAll) {
+ for (ImportDependency dep : m.getModuleDefinition().getImportDependencies()) {
if ((includeAll == false) && (dep.isReexported() == false)) {
continue;
}
@@ -58,8 +58,8 @@ public final class ModuleUtils {
// name, just comparing names is fine.
// Note that due to optional imports, we cannot assume
// that module[i] corresponds to import[i]
- String name = dep.getModuleName();
- for (Module importedModule : module.getImportedModules()) {
+ String name = dep.getName();
+ for (Module importedModule : m.getImportedModules()) {
if (!importedModule.getModuleDefinition().getName().equals(name)) {
continue;
}
@@ -80,7 +80,7 @@ public final class ModuleUtils {
* @param module module instance
* @return a set of modules in the importing transitive closure
*/
- static Set<Module> findImportingModulesClosure(Module module) {
+ public static Set<Module> findImportingModulesClosure(Module module) {
// Determine the transitive closure of the importing modules using
// BFS (Breadth-First-Search)
Set<Module> visitedModules = new HashSet<Module>();
@@ -119,7 +119,7 @@ public final class ModuleUtils {
* @param module module instance
* @return a set of modules in the imported transitive closure
*/
- static Set<Module> findImportedModulesClosure(Module module) {
+ public static Set<Module> findImportedModulesClosure(Module module) {
// Determine the transitive closure of the imported modules using
// BFS (Breadth-First-Search)
Set<Module> visitedModules = new HashSet<Module>();
--- a/src/share/classes/sun/module/repository/LocalRepository.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/repository/LocalRepository.java Wed Apr 02 17:59:05 2008 -0700
@@ -25,54 +25,58 @@
package sun.module.repository;
-import java.io.BufferedInputStream;
import java.io.File;
-import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
import java.io.IOException;
import java.module.ModuleArchiveInfo;
import java.module.ModuleDefinition;
import java.module.ModuleSystem;
-import java.module.ModuleSystemPermission;
+import java.module.Modules;
import java.module.Query;
import java.module.Repository;
-import java.module.RepositoryEvent;
import java.module.Version;
-import java.module.annotation.PlatformBinding;
import java.net.URL;
+import java.net.URLConnection;
import java.util.ArrayList;
-import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import sun.module.JamUtils;
+import sun.module.repository.cache.Cache;
+import sun.module.repository.cache.ModuleDefInfo;
/**
- * A repository for module definitions stored on the file system.
+ * 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.
*
* @see java.module.ModuleArchiveInfo
+ * @see java.module.ModuleDefinition
+ * @see java.module.Query
* @see java.module.Repository
* @since 1.7
*/
-public final class LocalRepository extends Repository {
+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 sourceDir is writable. Note that this can change upon
+ * 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
- * location given in constructors.
- */
- private File sourceDir;
+ * location given in the constructors.
+ */
+ private File sourceDirectory;
/**
* True if the source location must exist during execution of {@code
@@ -88,8 +92,8 @@ public final class LocalRepository exten
PROPERTY_PREFIX + "sourceLocationMustExist";
/**
- * True if all modules must be uninstalled during execution of {@code
- * shutdown()}.
+ * True if all modules must be removed from the source location
+ * during execution of {@code shutdown()}.
*/
private boolean uninstallOnShutdown;
@@ -98,71 +102,27 @@ public final class LocalRepository exten
/**
* Directory containing directories for JAM expansion and creation of any
- * other artifacts for this repository, unless their locations are
- * specified by client via properties.
- */
- private File baseDir;
-
- /**
- * Directory into which embedded jars and native libraries in a JAM are
- * expanded. Not created in the filesystem unless actually needed.
- */
- private File expansionDir;
-
- /**
- * Name of expansion directory based on system property and config in
- * {@link #initialize(Map<String, String>)}.
- */
- private String expansionDirName;
-
- /**
- * Directory name corresponding to {@code EXPANSION_DIR_KEY} as obtained
+ * other artifacts for this repository.
+ */
+ private File cacheDirectory;
+
+ /**
+ * Directory name corresponding to {@code CACHE_DIR_KEY} as obtained
* from System properties.
*/
- private static final String sysPropExpansionDirName;
+ private static final String sysPropCacheDirName;
/**
* Property name to configure the directory into which native libraries
* and embedded JAR files are expanded from a JAM file.
*/
- private static final String EXPANSION_DIR_KEY =
- PROPERTY_PREFIX + "expansionDirectory";
+ private static final String CACHE_DIR_KEY =
+ PROPERTY_PREFIX + "cacheDirectory";
static {
sysPropSourceLocMustExist = RepositoryUtils.getProperty(SOURCE_LOC_MUST_EXIST_KEY);
- sysPropExpansionDirName = RepositoryUtils.getProperty(EXPANSION_DIR_KEY);
- }
-
- /** Describes the contents of this repository. */
- private RepositoryContents contents = new RepositoryContents();
-
- /**
- * A cache of ModuleDefinitions that have been installed and which also
- * match the current platform binding. Module definitions are added as
- * they are installed and removed as they are uninstalled. (Contrast with
- * {@code contents}, which describes all installed modules regardless of
- * platform binding.)
- */
- private final List<ModuleDefinition> modDefCache =
- new ArrayList<ModuleDefinition>();
-
- /** Marks the time this repository was created. */
- private final long timestamp;
-
- /** JAM files that have been installed. */
- private final List<File> jams = new ArrayList<File>();
-
- /** True if this repository has been initialized but not yet shutdown. */
- private boolean active;
-
- /** True if this repository has been shutdown. */
- private boolean shutdown;
-
- private static String platform = RepositoryUtils.getPlatform();
-
- private static String arch = RepositoryUtils.getArch();
-
- private static final Map<String, String> DEFAULT_CONFIG = Collections.emptyMap();
+ sysPropCacheDirName = RepositoryUtils.getProperty(CACHE_DIR_KEY);
+ }
/**
* Creates a new <code>LocalRepository</code> instance.
@@ -227,9 +187,7 @@ public final class LocalRepository exten
*/
public LocalRepository(Repository parent, String name,
URL source, Map<String, String> config) throws IOException {
- super(parent, name, source, ModuleSystem.getDefault());
- timestamp = System.currentTimeMillis();
- initialize(config);
+ super(parent, name, source, config);
}
/**
@@ -256,210 +214,7 @@ public final class LocalRepository exten
}
//
- // Extend Repository
- //
-
- @Override
- public void initialize() throws IOException {
- initialize(DEFAULT_CONFIG);
- }
-
- /**
- * @see Repository#install(URL u)
- * @return a {code ModuleArchiveInfo} corresponding to the newly-installed
- * module, or null if the module was already installed.
- * @throws IOException if given URL names a file that does not exist.
- * directory.
- */
- @Override
- public synchronized ModuleArchiveInfo install(URL u) throws IOException {
- assertActive();
- assertNotReadOnly();
- assertValidDirs();
-
- File f = JamUtils.getFile(u);
- File dest = new File(sourceDir + File.separator + f.getName());
- if (dest.exists()) {
- throw new IllegalStateException(
- msg("Cannot overwrite " + f.getName()
- + " in repository's source directory"));
- }
- JamUtils.saveStreamAsFile(new FileInputStream(f), dest);
-
- ModuleArchiveInfo rc = installInternal(dest);
- return rc;
- }
-
- @Override
- public synchronized boolean uninstall(ModuleArchiveInfo mai) throws IOException {
- assertActive();
- assertNotReadOnly();
- assertValidDirs();
-
- if (!contents.contains(mai)) {
- return false;
- }
-
- // Remove any legacy JAR files for this module
- File legacyJarDir = RepositoryUtils.getLegacyJarDir(expansionDir, mai.getName(), mai.getVersion(), mai.getPlatform(), mai.getArchitecture());
- if (legacyJarDir.isDirectory()) {
- // XXX Remove the Windows-specificity once disableModuleDefinition is implemented
- if (!platform.startsWith("windows")) {
- if (!JamUtils.recursiveDelete(legacyJarDir)) {
- throw new IOException(
- msg("Could not delete expansion directory " + legacyJarDir));
- }
- }
- } else if (legacyJarDir.exists()) {
- throw new IllegalStateException(
- msg("File " + legacyJarDir.getCanonicalPath()
- + " is expected to be a directory but is not"));
- }
-
- ModuleDefinition md = contents.get(mai);
- // XXX Uncomment below disableModuleDefinition is implemented
- //if (md != null) {
- // getModuleSystem().disableModuleDefinition(md);
- //}
-
- // Remove the module file if it is the same one that was installed,
- // as determined by timestamp. Don't remove if the timestamp is
- // different, as that could represent file copied over the installed
- // file.
- // XXX Remove the Windows-specificity once disableModuleDefinition is implemented
- if (!platform.startsWith("windows")) {
- File f = new File(mai.getFileName());
- if (f.lastModified() == mai.getLastModified() && f.isFile() && !f.delete()) {
- throw new IOException(
- msg("Could not delete module for " + mai.getName()
- + "from the repository"));
- }
- }
-
- // Remove from cache & contents
- modDefCache.remove(md);
- boolean rc = contents.remove(mai);
-
- if (rc) {
- // Send MODULE_UNINSTALLED event
- RepositoryEvent evt = new RepositoryEvent(this, RepositoryEvent.Type.MODULE_UNINSTALLED, mai);
- processEvent(evt);
- }
- return rc;
- }
-
- @Override
- public synchronized List<ModuleDefinition> findModuleDefinitions(Query constraint) {
- assertActive();
- return RepositoryUtils.findModuleDefinitions(constraint, modDefCache);
- }
-
- @Override
- public List<ModuleArchiveInfo> list() {
- return Collections.unmodifiableList(contents.getModuleArchiveInfos());
- }
-
- /**
- * Compares the cache with the contents of the source directory. Modules
- * that are in both places are not affected. Modules in the cache but not
- * source directory are uninstalled. Modules in the source directory but
- * not the cache are installed.
- */
- @Override
- public synchronized void reload() throws IOException {
- assertActive();
- readOnly = (sourceDir.canWrite() == false);
- initializeCache();
-
- // 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<File> currentModules = new HashSet<File>();
- for (ModuleArchiveInfo mai : contents.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.
- if (!f.isFile() || (modTime != 00 && f.lastModified() != modTime)) {
- uninstallCandidates.add(mai);
- } else {
- currentModules.add(f);
- }
- }
-
- // Uninstall modules for which there is no corresponding file in the
- // source directory
- for (ModuleArchiveInfo mai : uninstallCandidates) {
- uninstall(mai);
- }
-
- // Install modules that have a JAM in the source directory, but are
- // not in the cache.
- for (File f : sourceDir.listFiles(JamUtils.JAM_FILTER)) {
- if (!currentModules.contains(f)) {
- installInternal(f);
- }
- }
- }
-
- /**
- * Uninstalls all modules. Removes repository-specific directories.
- *
- * @throws java.io.IOException if there's an error removing directories.
- */
- @Override
- public synchronized void shutdown() throws IOException {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- sm.checkPermission(new ModuleSystemPermission("shutdownRepository"));
- }
- if (shutdown) {
- return; // shutdown only once
- }
- assertActive();
-
- if (uninstallOnShutdown) {
- // Only remove what was installed
- for (ModuleArchiveInfo mai : contents.getModuleArchiveInfos()) {
- File f = new File(mai.getFileName());
- if (f.isFile()) {
- f.delete();
- }
- }
- }
-
- removeCache();
-
- active = false;
- shutdown = true;
-
- // Send REPOSITORY_SHUTDOWN event
- RepositoryEvent evt = new RepositoryEvent(this, RepositoryEvent.Type.REPOSITORY_SHUTDOWN);
- processEvent(evt);
- }
-
- @Override
- public boolean isActive() {
- return active;
- }
-
- /**
- * @return true if this repository is read-only; false otherwise
- */
- @Override
- public boolean isReadOnly() {
- return readOnly;
- }
-
- /**
- * @return true
- */
- @Override
- public boolean isReloadSupported() {
- return true;
- }
-
- //
- // Implementation specific to LocalRepository
+ // Extend AbstractRepository
//
/**
@@ -485,17 +240,7 @@ public final class LocalRepository exten
* @param config Map of configuration names to their values
* @throws IOException if the repository cannot be initialized
*/
- private synchronized void initialize(Map<String, String> config) throws IOException {
- if (active) {
- return; // initialize only once
- }
- if (shutdown) {
- throw new IllegalStateException(msg("Repository is shut down."));
- }
- if (config == null) {
- throw new NullPointerException(msg("Parameter 'config' cannot be null."));
- }
-
+ protected void doInitialize(Map<String, String> config) throws IOException {
if ("true".equalsIgnoreCase(sysPropSourceLocMustExist)) {
sourceLocMustExist = true;
} else {
@@ -504,157 +249,300 @@ public final class LocalRepository exten
uninstallOnShutdown = "true".equalsIgnoreCase(config.get(UNINSTALL_ON_SHUTDOWN_KEY));
- expansionDirName = sysPropExpansionDirName != null
- ? sysPropExpansionDirName : config.get(EXPANSION_DIR_KEY);
-
- sourceDir = JamUtils.getFile(getSourceLocation());
- readOnly = (sourceDir.canWrite() == false);
- if (sourceDir.isDirectory()) {
- initializeCache();
- installJams();
+ String cacheDirName = sysPropCacheDirName != null
+ ? sysPropCacheDirName : config.get(CACHE_DIR_KEY);
+ if (cacheDirName != null) {
+ cacheDirectory = new File(cacheDirName);
+ }
+
+ sourceDirectory = JamUtils.getFile(getSourceLocation());
+ readOnly = (sourceDirectory.canWrite() == false);
+ if (sourceDirectory.isDirectory() == false) {
+ if (sourceLocMustExist) {
+ missingDir("source", sourceDirectory);
+ }
+ }
+
+ // Constructs a repository cache instance
+ if (cacheDirectory != null) {
+ repositoryCache = Cache.newInstance(cacheDirectory);
} else {
- if (sourceLocMustExist) {
- missingDir("source", sourceDir);
- }
- }
-
- active = true;
-
- // Send REPOSITORY_INITIALIZED event
- RepositoryEvent evt = new RepositoryEvent(this, RepositoryEvent.Type.REPOSITORY_INITIALIZED);
- processEvent(evt);
- }
-
- /**
- * Installs given JAM file into the repository.
- */
- private ModuleArchiveInfo installInternal(File file) throws IOException {
- if (file.isFile() == false) {
- throw new IOException(msg("File does not exist: " + file));
- }
-
- ModuleDefinition md = RepositoryUtils.createLocalModuleDefinition(
- this, file, expansionDir);
-
- ModuleArchiveInfo mai = new ModuleArchiveInfo(
- this, md.getName(), md.getVersion(),
- platform, arch,
- file.getAbsolutePath(), file.lastModified());
-
- // Determine if the module definition matches the current platform platform
- PlatformBinding platformBinding = md.getAnnotation(PlatformBinding.class);
-
- if (RepositoryUtils.bindingMatches(platformBinding, platform, arch)) {
- modDefCache.add(md);
- contents.put(mai, md);
- } else {
- contents.put(mai, null);
- }
-
- if (mai != null) {
- // Send MODULE_INSTALLED event
- RepositoryEvent evt = new RepositoryEvent(this, RepositoryEvent.Type.MODULE_INSTALLED, mai);
- processEvent(evt);
- }
-
- return mai;
- }
-
- /**
- * Ensure that the required directories exist.
- */
- private void initializeCache() throws IOException {
- if (expansionDirName != null) {
- expansionDir = new File(expansionDirName,
- getName() + "-" + timestamp + "-expand");
- } else {
- if (baseDir == null) {
- baseDir = new File(JamUtils.createTempDir(), "LocalRepository");
- baseDir = new File(baseDir, getName() + "-" + timestamp);
- }
- expansionDir = new File(baseDir, "expand");
- }
+ repositoryCache = Cache.newInstance();
+ }
+
assertValidDirs();
- }
-
- /**
- * Removes the contents of the repository's metadata and download
- * directories. Clears repository contents and list of loaded JAMs.
- */
- private void removeCache() throws IOException {
- if (baseDir != null) {
- JamUtils.recursiveDelete(baseDir);
- }
-
- if (expansionDir != null) {
- JamUtils.recursiveDelete(expansionDir);
- }
-
- baseDir = null;
- expansionDir = null;
- contents.clear();
- jams.clear();
- }
-
- /**
- * Install JAM files in the source dir that aren't already installed.
- */
- private void installJams() {
- File[] jamFiles = sourceDir.listFiles(JamUtils.JAM_JAR_FILTER);
- for (File jf : jamFiles) {
- if (!jams.contains(jf)) {
- // no need to retry if it does not work the first time
- jams.add(jf);
+
+ // 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
- installInternal(jf);
+
+ // Put the jam file into the repository cache and cook it
+ ModuleDefInfo mdInfo = repositoryCache.getModuleDefInfo(file);
+
+ // Constructs a module archive info
+ ModuleArchiveInfo mai = new ModuleArchiveInfo(
+ this, mdInfo.getName(), mdInfo.getVersion(),
+ mdInfo.getPlatform(), mdInfo.getArch(),
+ file.getAbsolutePath(), file.lastModified());
+
+ mdInfoMap.put(mai, mdInfo);
+
+ // Adds the module archive info into the internal data structure.
+ moduleArchiveInfos.add(mai);
} catch (Exception ex) {
// XXX log warning but otherwise ignore
+ System.err.println("Failed to load module from " + file + ": " + ex);
}
}
- }
- }
-
- private void assertActive() throws IllegalStateException {
- if (!isActive()) {
- throw new IllegalStateException(msg("Repository is not active."));
- }
- }
-
- private void assertNotActive() throws IllegalStateException {
- if (isActive()) {
- throw new IllegalStateException(msg("Repository is active."));
- }
- }
-
- private void assertNotReadOnly() throws IllegalStateException {
- if (isReadOnly()) {
- throw new UnsupportedOperationException(msg("Repository is read-only."));
- }
- }
-
- private void assertValidDirs() throws IOException {
+
+ // 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.
+ constructModuleDefinitions(mdInfoMap);
+ }
+ }
+
+ /**
+ * Install a module archive from a URL.
+ */
+ protected ModuleArchiveInfo doInstall(URL url) throws IOException {
+ InputStream is = null;
+ File tmpFile = null;
+ File jamFile = null;
+
+ try {
+ URLConnection uc = url.openConnection();
+ is = uc.getInputStream();
+
+ // Store the file in a temp directory first. Unpack the file if
+ // necessary.
+ tmpFile = File.createTempFile("local-repository-install-", "tmp");
+ tmpFile.deleteOnExit();
+
+ if (url.getFile().endsWith(".jam.pack.gz")) {
+ JamUtils.unpackStreamAsFile(is, tmpFile);
+ } else {
+ JamUtils.saveStreamAsFile(is, tmpFile);
+ }
+
+ // Retrieve the module metadata from the JAM file to find out
+ // the module information, e.g. name, version, etc.
+ //
+ // No need to shadow copy (if set) because this is a temp file.
+ ModuleDefInfo mdInfo = repositoryCache.getModuleDefInfo(tmpFile, false);
+
+ // Check to see if there exists a module archive that has
+ // the same name, version, and platform binding.
+ for (ModuleArchiveInfo mai : moduleArchiveInfos) {
+ if (mai.getName().equals(mdInfo.getName())
+ && mai.getVersion().equals(mdInfo.getVersion())) {
+ if (mai.isPlatformArchNeutral()) {
+ if (mdInfo.isPlatformArchNeutral()) {
+ throw new IllegalStateException("A module definition with the same name,"
+ + " version, and platform binding is already installed");
+ }
+ } else if (mai.getPlatform().equals(mdInfo.getPlatform())
+ && mai.getArch().equals(mdInfo.getArch())) {
+ throw new IllegalStateException("A module definition with the same name,"
+ + " version, and platform binding is already installed");
+ }
+ }
+ }
+
+ // Generate the destination jam file
+ String jamName = JamUtils.getJamFilename(mdInfo.getName(),
+ mdInfo.getVersion(), mdInfo.getPlatform(),
+ mdInfo.getArch());
+ jamFile = new File(sourceDirectory + File.separator + jamName + ".jam");
+
+ // Checks to see if the jam file already exists in the source directory.
+ //
+ // Typically, this check is a bit redundent because we have already
+ // checked above that there is no existing module archive that has
+ // the same name, version, and platform binding as the
+ // about-to-be-installed module archive. If such file exists, it could
+ // happen only if that file was installed into source location somehow
+ // but the local repository in this JVM session was not aware of it.
+ if (jamFile.exists() && !jamFile.canWrite()) {
+ throw new IOException(
+ "Cannot overwrite " + jamFile.getName()
+ + " in the source directory: " + sourceDirectory);
+ }
+
+ // Copy the jam file into the source directory.
+ //
+ // Note that we always copy the unpacked JAM file into the
+ // source directory. This is done to optimize the startup
+ // performance of the local repository in subsequence launch.
+ JamUtils.copyFile(tmpFile, jamFile);
+
+ // Put the JAM file into the repository cache, cook it, and
+ // update the internal data structure to reflect the change.
+ return addModuleArchiveInternal(jamFile);
+ } catch(IOException ioe) {
+ // Something went wrong, remove the jam file in the source
+ // directory.
+ if (jamFile != null) {
+ jamFile.delete();
+ }
+ throw ioe;
+ } finally {
+ JamUtils.close(is);
+ if (tmpFile != null) {
+ tmpFile.delete();
+ }
+ }
+ }
+
+ /**
+ * Uninstall a module archive.
+ */
+ protected boolean doUninstall(ModuleArchiveInfo mai) throws IOException {
+ // Checks if the module archive still exists.
+ if (!moduleArchiveInfos.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
+ // installed file.
+ File f = new File(mai.getFileName());
+ if (f.lastModified() != mai.getLastModified()) {
+ throw new IOException(
+ "Could not delete module archive because the modification "
+ + "date was different than expected: " + mai.getFileName());
+ }
+ if (f.isFile() && !f.delete()) {
+ throw new IOException(
+ "Could not delete module archive: " + mai.getFileName());
+ }
+
+ // 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.
+ removeModuleArchiveInternal(mai);
+
+ return true;
+ }
+
+ /**
+ * Reload all module archives.
+ */
+ 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<File> existingJams = new HashSet<File>();
+ for (ModuleArchiveInfo mai : moduleArchiveInfos) {
+ File f = new File(mai.getFileName());
+ long modTime = mai.getLastModified();
+ // Uninstall if source file is missing, or if it has been updated on disk.
+ if (!f.isFile() || (modTime != 0 && f.lastModified() != modTime)) {
+ uninstallCandidates.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.
+ removeModuleArchiveInternal(mai);
+ }
+
+ // Adds the new module archive from the source directory, but are
+ // not in the cache.
+ for (File file : sourceDirectory.listFiles(JamUtils.JAM_FILTER)) {
+ 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.
+ 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.
+ 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.
+ reconstructModuleDefinitionsIfNecessary();
+ }
+
+ /**
+ * Shutdown the repository.
+ */
+ protected void doShutdown() throws IOException {
+ // XXX This is a hook for testing shutdownOnExit.
+ if (uninstallOnShutdown) {
+ // Only remove what was installed
+ for (ModuleArchiveInfo mai : moduleArchiveInfos) {
+ try {
+ uninstall(mai);
+ } catch(Exception e) {
+ // ignore exception
+ }
+ }
+ }
+ }
+
+ /**
+ * @return true if this repository is read-only; false otherwise
+ */
+ @Override
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ /**
+ * @return true
+ */
+ @Override
+ public boolean supportsReload() {
+ return true;
+ }
+
+ protected void assertValidDirs() throws IOException {
if (sourceLocMustExist) {
- if (sourceDir == null || !sourceDir.isDirectory()) {
- missingDir("source", sourceDir);
- }
- }
- if (expansionDir != null
- && (expansionDir.exists() && !expansionDir.isDirectory())) {
+ if (sourceDirectory == null || !sourceDirectory.isDirectory()) {
+ missingDir("source", sourceDirectory);
+ }
+ }
+ if (cacheDirectory != null
+ && (cacheDirectory.exists() && !cacheDirectory.isDirectory())) {
throw new IOException(
- msg("Specified expansion directory "
- + expansionDir + " is not a directory"));
+ cacheDirectory + " is not a directory");
}
}
private void missingDir(String type, File dir) throws IOException {
- throw new IOException(
- msg("Specified " + type + " directory "
- + dir + " does not exist or is not a directory"));
- }
-
- private String msg(String s) {
- return "LocalRepository: " + getName() + " at "
- + getSourceLocation().toExternalForm() + ": " + s;
+ throw new FileNotFoundException(
+ dir + " does not exist or is not a directory");
}
}
--- a/src/share/classes/sun/module/repository/MetadataXMLReader.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/repository/MetadataXMLReader.java Wed Apr 02 17:59:05 2008 -0700
@@ -25,6 +25,7 @@
package sun.module.repository;
+import java.io.ByteArrayInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -94,10 +95,18 @@ public class MetadataXMLReader extends D
* duplicates, though other elements are).
*/
public static Set<ModuleInfo> read(URL source) throws SAXException, IOException {
- SchemaFactory f = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
InputStream schemaStream = null;
InputStream repoStream = null;
+
try {
+ SchemaFactory f = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
+
+ // Read the soruce into a byte array so it does not need to be downloaded
+ // more than once.
+ repoStream = source.openStream();
+ byte[] byteBuffer = JamUtils.getInputStreamAsBytes(repoStream);
+
+ // Validate schema
schemaStream = new BufferedInputStream(
ClassLoader.getSystemResourceAsStream(
"java/module/RepositoryMetadata.xml"));
@@ -105,26 +114,23 @@ public class MetadataXMLReader extends D
StreamSource ss = new StreamSource(schemaStream);
Schema s = f.newSchema(ss);
Validator v = s.newValidator();
- repoStream = new BufferedInputStream(source.openStream());
- v.validate(new StreamSource(repoStream));
- } finally {
- JamUtils.close(schemaStream);
- JamUtils.close(repoStream);
- }
-
- XMLReader xmlReader = XMLReaderFactory.createXMLReader();
-
- MetadataXMLReader moduleTypeReader =
- new MetadataXMLReader(source.toString());
- xmlReader.setErrorHandler(moduleTypeReader);
- xmlReader.setContentHandler(moduleTypeReader);
- repoStream = new BufferedInputStream(source.openStream());
- try {
- xmlReader.parse(new InputSource(repoStream));;
+ InputStream is = new ByteArrayInputStream(byteBuffer);
+ v.validate(new StreamSource(is));
+
+ XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+
+ MetadataXMLReader moduleTypeReader =
+ new MetadataXMLReader(source.toString());
+ xmlReader.setErrorHandler(moduleTypeReader);
+ xmlReader.setContentHandler(moduleTypeReader);
+ is = new ByteArrayInputStream(byteBuffer);
+ xmlReader.parse(new InputSource(is));;
+
+ return moduleTypeReader.moduleInfos;
} finally {
JamUtils.close(repoStream);
- }
- return moduleTypeReader.moduleInfos;
+ JamUtils.close(schemaStream);
+ }
}
private MetadataXMLReader(String sourceLocation) {
--- a/src/share/classes/sun/module/repository/MetadataXMLWriter.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/repository/MetadataXMLWriter.java Wed Apr 02 17:59:05 2008 -0700
@@ -70,10 +70,10 @@ public class MetadataXMLWriter {
if (tmpRepoMDFile.exists()) {
if (!tmpRepoMDFile.delete()) {
throw new IOException(
- repo.msg("Cannot update repository metadata file for "
+ "Cannot update repository metadata file for "
+ mai.getName()
+ ": cannot create temporary repository metadata file "
- + tmpRepoMDFile));
+ + tmpRepoMDFile);
}
}
MetadataXMLWriter writer = new MetadataXMLWriter(tmpRepoMDFile);
@@ -91,28 +91,28 @@ public class MetadataXMLWriter {
if (!writer.end()) {
throw new IOException(
- repo.msg("Cannot update repository metadata file for "
+ "Cannot update repository metadata file for "
+ mai.getName()
+ ": failure while writing temporary repository metadata file "
- + tmpRepoMDFile));
+ + tmpRepoMDFile);
}
File prev = new File(repoMDFile.getCanonicalPath() + ".prev");
prev.delete();
if (!repoMDFile.renameTo(prev)) {
throw new IOException(
- repo.msg("Cannot update repository metadata file for "
+ "Cannot update repository metadata file for "
+ mai.getName()
- + ": cannot rename " + repoMDFile + " to " + prev));
+ + ": cannot rename " + repoMDFile + " to " + prev);
}
prev.deleteOnExit();
if (!tmpRepoMDFile.renameTo(repoMDFile)) {
throw new IOException(
- repo.msg("Cannot update repository metadata file for "
+ "Cannot update repository metadata file for "
+ mai.getName()
+ ": cannot create updated repository-metadata.xml file"
- + " by renaming " + tmpRepoMDFile + " to " + repoMDFile));
+ + " by renaming " + tmpRepoMDFile + " to " + repoMDFile);
}
}
@@ -141,12 +141,11 @@ public class MetadataXMLWriter {
indent++;
output("<name>" + mai.getName() + "</name>");
output("<version>" + mai.getVersion().toString() + "</version>");
- String platform = mai.getPlatform();
- if (platform != null) {
+ if (!mai.isPlatformArchNeutral()) {
output("<platform-binding>");
indent++;
- output("<platform>" + platform + "</platform>");
- output("<arch>" + mai.getArchitecture() + "</arch>");
+ output("<platform>" + mai.getPlatform() + "</platform>");
+ output("<arch>" + mai.getArch() + "</arch>");
indent--;
output("</platform-binding>");
}
--- a/src/share/classes/sun/module/repository/ModuleInfo.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/repository/ModuleInfo.java Wed Apr 02 17:59:05 2008 -0700
@@ -84,7 +84,7 @@ public class ModuleInfo {
name = mai.getName();
version = mai.getVersion();
platform = mai.getPlatform();
- arch = mai.getArchitecture();
+ arch = mai.getArch();
}
public String getName() {
@@ -111,8 +111,12 @@ public class ModuleInfo {
if (path != null) {
return path;
} else {
- return getName() + "/" + getVersion() + "/"
- + (getPlatform() == null ? "" : getPlatform() + "-" + getArch());
+ if (getPlatform() != null && getArch() != null) {
+ return getName() + "/" + getVersion() + "/"
+ + getPlatform() + "-" + getArch();
+ } else {
+ return getName() + "/" + getVersion();
+ }
}
}
--- a/src/share/classes/sun/module/repository/RepositoryUtils.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/repository/RepositoryUtils.java Wed Apr 02 17:59:05 2008 -0700
@@ -38,8 +38,12 @@ import java.module.annotation.PlatformBi
import java.module.annotation.PlatformBinding;
import java.security.AccessController;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import sun.module.JamUtils;
@@ -104,238 +108,13 @@ public class RepositoryUtils {
return JamUtils.MODULE_INF + "/bin/" + getPlatform() + "/" + getArch();
}
- static File getLegacyJarDir(File dir, String name, Version version, String platform, String arch) {
- return new File(getModuleDir(dir, name, version, platform, arch), "lib");
- }
- static File getNativeLibraryDir(File dir, String name, Version version, String platform, String arch) {
- return new File(getModuleDir(dir, name, version, platform, arch), "bin");
- }
-
- /**
- * Creates a {@code ModuleDefinition} for a {@code LocalRepository}
- *
- * @param repository LocalRepository in which the module exists
- * @param file a JAM file
- * @param expansionDir directory into which JAR files & native libraries
- * file are expanded.
- * @return a {@code ModuleDefinition} corresponding to MODULE.METADATA
- * from the JAM
- * @throws IOException if {@code downloadDir} isn't a directory, or if
- * there's a problem downloading the module data, etc.
- */
- static ModuleDefinition createLocalModuleDefinition(
- LocalRepository repository,
- File file,
- File expansionDir) throws IOException {
-
- if ((repository == null)
- || (file == null)
- || (expansionDir == null)) {
- throw new NullPointerException();
- }
-
- JarFile jamFile = new JarFile(file, false);
-
- LocalJamDefinitionContent content = new LocalJamDefinitionContent(
- jamFile, repository);
-
- // Extracts module metadata from JAM file.
- byte[] metadata = JamUtils.getMetadata(jamFile);
-
- // Constructs a superpackage from module metadata, for extracting the
- // stock annotations. Note that it is very important to go through
- // superpackage instead of ModuleDefinition to extract annotations
- // at this point, as the latter might trigger loading of the JAM file
- // in some rare cases.
- java.lang.reflect.Superpackage superPackage = sun.module.JamUtils.getSuperpackage(metadata);
-
- // Module name
- String moduleName = superPackage.getName();
- if (moduleName.startsWith("java.")) {
- throw new IOException("Non-bootstrap repository could not create " + moduleName + " module definition.");
- }
-
- // Module version
- java.module.annotation.Version aversion = superPackage.getAnnotation
- (java.module.annotation.Version.class);
- Version moduleVersion = Version.DEFAULT;
- if (aversion != null) {
- try {
- moduleVersion = Version.valueOf(aversion.value());
- } catch (IllegalArgumentException e) {
- // ignore
- }
- }
-
- // Platform Binding
- java.module.annotation.PlatformBinding platformBinding = superPackage.getAnnotation
- (java.module.annotation.PlatformBinding.class);
- String platform = null;
- String arch = null;
- if (platformBinding != null) {
- platform = platformBinding.platform();
- arch = platformBinding.arch();
- }
-
- // JarLibraryPath
- JarLibraryPath jlp = superPackage.getAnnotation(JarLibraryPath.class);
- if (jlp != null) {
- content.setJarLibraryPath(jlp.value());
- }
- content.setLegacyJarDir(
- getLegacyJarDir(expansionDir, moduleName, moduleVersion, platform, arch));
-
- NativeLibraryPaths nlps = superPackage.getAnnotation(NativeLibraryPaths.class);
- if (nlps != null) {
- for (NativeLibraryPath nlp : nlps.value()) {
- content.setNativeLibraryPath(nlp.platform(), nlp.arch(), nlp.path());
- }
- }
- content.setNativeLibraryDir(
- getNativeLibraryDir(expansionDir, moduleName, moduleVersion, platform, arch));
-
- // TODO: moduleReleasable might be false in some cases
- return Modules.newJamModuleDefinition(metadata, content, repository, true);
- }
-
- /**
- * Creates a {@code ModuleDefinition} for a {@code URLRepository}
- *
- * @param repository URLRepository in which the module exists
- * @param downloadDir Directory into which JAM files are downloaded. This
- * is the parent of each JAM-specific {@code baseDir}.
- * @param moduleInfo {@code ModuleInfo} describing this module
- * @param metadataFile MODULE.METADATA file for the {@code ModuleDefinition} to
- * be returned
- * @return a {@code ModuleDefinition} corresponding to MODULE.METADATA
- * from the JAM
- * @throws IOException if {@code downloadDir} isn't a directory, or if
- * there's a problem downloading the module data, etc.
- */
- static ModuleDefinition createURLModuleDefinition(
- URLRepository repository,
- File downloadDir,
- ModuleInfo moduleInfo,
- File metadataFile) throws IOException {
-
- if ((repository == null)
- || (downloadDir == null)
- || (moduleInfo == null)
- || (metadataFile == null)) {
- throw new NullPointerException();
- }
-
- if (!downloadDir.isDirectory()) {
- throw new IOException(downloadDir.getName() + " is not a directory.");
- }
- File baseDir = getModuleDir(
- downloadDir, moduleInfo.getName(), moduleInfo.getVersion(),
- moduleInfo.getPlatform(), moduleInfo.getArch());
- if (!baseDir.isDirectory() && !baseDir.mkdirs()) {
- throw new IOException("Cannot create directory for module "
- + moduleInfo.getName() + " v" + moduleInfo.getVersion() + " at "
- + baseDir.getAbsolutePath());
- }
-
- URLModuleDefinitionContent content = new URLModuleDefinitionContent(
- baseDir, repository, moduleInfo, metadataFile);
-
- // Extracts module metadata from MODULE.METADATA file.
- byte[] metadata = JamUtils.readFile(metadataFile);
-
- // Constructs a superpackage from module metadata, for extracting the
- // stock annotations. Note that it is very important to go through
- // superpackage instead of ModuleDefinition to extract annotations
- // at this point, as the latter might trigger loading of the JAM file
- // in some rare cases.
- java.lang.reflect.Superpackage superPackage = sun.module.JamUtils.getSuperpackage(metadata);
-
- // Module name
- String moduleName = superPackage.getName();
- if (moduleName.startsWith("java.")) {
- throw new IOException("Non-bootstrap repository could not create " + moduleName + " module definition.");
- }
-
- // Module version
- java.module.annotation.Version aversion = superPackage.getAnnotation
- (java.module.annotation.Version.class);
- Version moduleVersion = Version.DEFAULT;
- if (aversion != null) {
- try {
- moduleVersion = Version.valueOf(aversion.value());
- } catch (IllegalArgumentException e) {
- // ignore
- }
- }
-
- // Platform Binding
- java.module.annotation.PlatformBinding platformBinding = superPackage.getAnnotation
- (java.module.annotation.PlatformBinding.class);
- String platform = null;
- String arch = null;
- if (platformBinding != null) {
- platform = platformBinding.platform();
- arch = platformBinding.arch();
- }
-
- // JarLibraryPath
- JarLibraryPath jlp = superPackage.getAnnotation(JarLibraryPath.class);
- if (jlp != null) {
- content.setJarLibraryPath(jlp.value());
- }
-
- NativeLibraryPaths nlps = superPackage.getAnnotation(NativeLibraryPaths.class);
- if (nlps != null) {
- for (NativeLibraryPath nlp : nlps.value()) {
- content.setNativeLibraryPath(nlp.platform(), nlp.arch(), nlp.path());
- }
- }
-
- // TODO: moduleReleasable might be false in some cases
- return Modules.newJamModuleDefinition(metadata, content, repository, true);
- }
-
- /**
- * Finds module definitions in a given cache.
- *
- * @param constraint Query to select module definitions
- * @param cache Cache in which to search
- * @return module definitions matching {@code constraint} in {@code cache}
- */
- static List<ModuleDefinition> findModuleDefinitions(
- Query constraint, List<ModuleDefinition> cache) {
- List<ModuleDefinition> rc = new ArrayList<ModuleDefinition>();
-
- if (constraint == Query.ANY) {
- rc = cache;
- } else {
- for (ModuleDefinition md : cache) {
- if (constraint.match(md)) {
- rc.add(md);
- }
- }
- }
- return Collections.unmodifiableList(rc);
- }
-
- /**
- * Indicates whether or not the {@code ModuleDefinition} is appropriate
- * for the given {@code platform} and {@arch}.
- *
- * @return true if the given module definition's platform binding is not
- * given or if it matches the {@code platform} and {@code platform} given
- * @param platformBinding Platform binding to check
- * @param platform name of current platform
- * @param arch name of current arch
- * @return true if the md's platform & arch match those given
- */
- static boolean bindingMatches(
- PlatformBinding platformBinding, String platform, String arch) {
- if (platformBinding == null) {
- return true;
- }
-
- return (platform.equals(platformBinding.platform()) && arch.equals(platformBinding.arch()));
+ // Determines if the original file should be shadow copied into the cache
+ // before opening it. This is to avoid locking the original file on certain
+ // operating systems, e.g. Windows.
+ public static boolean shouldShadowCopyFiles() {
+ Boolean shadowCopyFiles = java.security.AccessController.doPrivileged(
+ new sun.security.action.GetBooleanAction("java.module.repository.shadowcopyfiles"));
+ return shadowCopyFiles == Boolean.TRUE;
}
/**
@@ -383,7 +162,7 @@ public class RepositoryUtils {
* @throws IOException if there are errors accessing the JAM file or in
* writing jar/lib files.
*/
- static File[] extractJarsAndLibs(final JarFile jamFile,
+ public static File[] extractJarsAndLibs(final JarFile jamFile,
final String jarLibraryPath, final File legacyJarDir,
final String nativeLibraryPath, final File nativeLibraryDir) throws IOException {
@@ -399,6 +178,7 @@ public class RepositoryUtils {
// Save in nativeLibraryDir using only the last component of
// the JAM file's entry name.
rc = new File(nativeLibraryDir, new File(name).getName());
+ nativeLibraryDir.mkdirs();
JamUtils.saveStreamAsFile(jamFile.getInputStream(je), rc);
}
return rc;
@@ -416,10 +196,16 @@ public class RepositoryUtils {
name = name.substring(start + 1);
}
File f = new File(legacyJarDir, name);
+ legacyJarDir.mkdirs();
JamUtils.saveStreamAsFile(jamFile.getInputStream(je), f);
- JarFile jf = new JarFile(f);
- boolean ok = (jf.getEntry(JamUtils.MODULE_INF_METADATA) == null);
- JamUtils.close(jf);
+ JarFile jf = null;
+ boolean ok;
+ try {
+ jf = new JarFile(f, false);
+ ok = (jf.getEntry(JamUtils.MODULE_INF_METADATA) == null);
+ } finally {
+ JamUtils.close(jf);
+ }
if (ok) {
rc = f;
} else {
@@ -452,74 +238,4 @@ public class RepositoryUtils {
}
return rc.toArray(new File[0]);
}
-
- /**
- * Returns the directory where module-specific files are kept based on
- * information in a {@code ModuleArchiveInfo}.
- *
- * @param base directory where information for a repository is kept
- * @param mai {@code ModuleArchiveInfo} for a module
- * @return the location under {@code base} where legacy JAR files are kept
- * for a module with the given {@code ModuleArchiveInfo}
- */
- private static File getModuleDir(File base, ModuleArchiveInfo mai) {
- return getModuleDir(
- base,
- mai.getName(), mai.getVersion(),
- mai.getPlatform(), mai.getArchitecture());
- }
-
- /**
- * Returns the directory where module-specific files are kept based on the
- * information in a {@code ModuleDefinition}.
- *
- * @param base directory where information for a repository is kept
- * @param md {@code ModuleDefinition} for a module
- * @return the location under {@code base} where legacy JAR files are kept
- * for a module with the given {@code ModuleDefinition}
- */
- private static File getModuleDir(File base, ModuleDefinition md) {
- String platform = null;
- String arch = null;
- PlatformBinding pb = md.getAnnotation(PlatformBinding.class);
- if (pb != null) {
- platform = pb.platform();
- arch = pb.arch();
- }
- return getModuleDir(
- base,
- md.getName(), md.getVersion(),
- platform, arch);
- }
-
- /**
- * Returns the directory where module-specific files are kept.
- *
- * @param base directory where information for a repository is kept
- * @param name module name
- * @param version module version
- * @param platform module platform (may be null)
- * @param arch module arch (may be null if {@code platform} is null)
- * @return the location under {@code base} where repository-specific files
- * are kept for a module with the given {@code name} and {@code version}.
- */
- private static File getModuleDir(
- File base, String name, Version version,
- String platform, String arch) {
- return new File(
- base,
- name + "-" + version
- + ((platform == null) ? "" : "-" + platform + "-" + arch));
- }
-
- /**
- * @see #getModuleDir(File, ModuleArchiveInfo)
- * @see #getModuleDir(File, ModuleDefinition)
- */
- private static File getModuleDir(
- File base, String name, Version version,
- String platform, String arch, String dest) {
- return new File(
- getModuleDir(base, name, version, platform, arch), dest);
- }
}
--- a/src/share/classes/sun/module/repository/URLRepository.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/repository/URLRepository.java Wed Apr 02 17:59:05 2008 -0700
@@ -28,6 +28,7 @@ import java.io.BufferedInputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -36,6 +37,7 @@ import java.module.ModuleArchiveInfo;
import java.module.ModuleArchiveInfo;
import java.module.ModuleDefinition;
import java.module.ModuleDefinitionContent;
+import java.module.ModuleFormatException;
import java.module.ModuleSystem;
import java.module.ModuleSystemPermission;
import java.module.Modules;
@@ -43,10 +45,11 @@ import java.module.Repository;
import java.module.Repository;
import java.module.RepositoryEvent;
import java.module.Version;
-import java.module.annotation.PlatformBinding;
import java.net.URL;
import java.net.URLConnection;
-import java.security.CodeSigner;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -56,111 +59,98 @@ import java.util.Set;
import java.util.Set;
import java.util.jar.JarFile;
import sun.module.JamUtils;
+import sun.module.repository.cache.Cache;
+import sun.module.repository.cache.ModuleDefInfo;
/**
- * This class represents a repository that loads module definitions
- * from a codebase URL.
+ * 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.
+ * 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.
+ * 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}".
+ * 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 file of each module definition
- * (i.e. MODULE.METADATA file) in the repository is downloaded based on
- * the information in the repository metadata file:
+ * 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 file is
+ * 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.
+ * 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:
+ * 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:
+ * 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.
+ * 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.
*
+ * @see java.module.ModuleArchiveInfo
* @see java.module.ModuleDefinition
* @see java.module.ModuleSystemPermission
* @see java.module.Query
+ * @see java.module.Repository
* @since 1.7
*/
-public final class URLRepository extends Repository {
- /** Describes the contents of this repository. */
- private RepositoryContents contents = new RepositoryContents();
-
- /**
- * A cache of ModuleDefinitions that have been installed and which also
- * match the current platform binding. Module definitions are added as
- * they are installed and removed as they are uninstalled. (Contrast with
- * {@code contents}, which describes all installed modules regardless of
- * platform binding.)
- */
- private final List<ModuleDefinition> modDefCache =
- new ArrayList<ModuleDefinition>();
-
- /** Marks the time this repository was created. */
- private final long timestamp;
+public final class URLRepository extends AbstractRepository {
/** Prefix of all properties use to configure this repository. */
private static final String PROPERTY_PREFIX = "sun.module.repository.URLRepository.";
/**
- * Directory into which MODULE.METADATA file and JAM files are downloaded
+ * Directory into which MODULE.METADATA file and JAM files are cached
* and expanded.
*/
- private File downloadDir;
+ private File cacheDirectory;
/**
* Name of metadata directory based on system property and config in
* {@link #initialize(Map<String,String>)}.
*/
- private String downloadDirName;
-
- /**
- * Directory name corresponding to {@code DOWNLOAD_DIR_KEY} as obtained
+ private String cacheDirName;
+
+ /**
+ * Directory name corresponding to {@code CACHE_DIR_KEY} as obtained
* from system properties.
*/
- private static final String sysPropDownloadDirName;
+ private static final String sysPropCacheDirName;
/**
* Property name to configure the directory to which JAM files are
- * downloaded.
- */
- private static final String DOWNLOAD_DIR_KEY =
- PROPERTY_PREFIX + "downloadDirectory";
+ * cached.
+ */
+ private static final String CACHE_DIR_KEY =
+ PROPERTY_PREFIX + "cacheDirectory";
/**
* True if the source location must exist during execution of {@code
@@ -175,28 +165,12 @@ public final class URLRepository extends
PROPERTY_PREFIX + "sourceLocationMustExist";
static {
- sysPropDownloadDirName = RepositoryUtils.getProperty(DOWNLOAD_DIR_KEY);
+ sysPropCacheDirName = RepositoryUtils.getProperty(CACHE_DIR_KEY);
sysPropSourceLocMustExist = RepositoryUtils.getProperty(SOURCELOC_MUST_EXIST_KEY);
}
/** String form of codebase given in constructor but with a trailing '/'. */
- private final String sourcePath;
-
- /** True if this repository has been initialized and not yet shutdown;
- * false otherwise. */
- private boolean active;
-
- /** True if this repository has been shutdown. */
- private boolean shutdown;
-
- /** True is this repository is read-only. */
- private final boolean readOnly;
-
- /** True if this repository was created with a file: URL; false
- * otherwise. */
- private final boolean fileBased;
-
- private static final Map<String, String> DEFAULT_CONFIG = Collections.emptyMap();
+ private URL canonicalizedCodebase;
/** The platform on which this URLRepository is running. */
private static String platform = RepositoryUtils.getPlatform();
@@ -204,9 +178,6 @@ 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();;
-
- /** Name used to identify this class in exceptions. */
- private static final String IDENT = "URLRepository";
/**
* Creates a new <code>URLRepository</code> instance.
@@ -273,18 +244,7 @@ public final class URLRepository extends
*/
public URLRepository(Repository parent, String name, URL codebase,
Map<String, String> config) throws IOException {
- super(parent, name, codebase, ModuleSystem.getDefault());
-
- fileBased = codebase.getProtocol().equals("file");
- readOnly = !fileBased;
- String tmp = codebase.toExternalForm();
- if (tmp.endsWith("/")) {
- sourcePath = tmp;
- } else {
- sourcePath = tmp + "/";
- }
- timestamp = System.currentTimeMillis();
- initialize(config);
+ super(parent, name, codebase, config);
}
/**
@@ -312,479 +272,8 @@ public final class URLRepository extends
}
//
- // Extend Repository
+ // Extend AbstractRepository
//
-
- /** Initializes the repository using the default configuration. */
- @Override
- public void initialize() throws IOException {
- initialize(DEFAULT_CONFIG);
- }
-
- /**
- * If this URLRepository uses a file: - based source:
- * <ul>
- * <li>
- * Copy the JAM file designated by the URL into this repository.
- * </li>
- * <li>
- * Create a MODULE.METADATA file for the JAM to the right directory in
- * this repository.
- * </li>
- * <li>
- * Update the repository's repository-metadata.xml file with information
- * about the newly-installed module.
- *</li>
- * </ul>
- */
- @Override
- public synchronized ModuleArchiveInfo install(URL u) throws IOException {
- assertActive();
- assertNotReadOnly();
-
- if (!u.getProtocol().equals("file")) {
- throw new IllegalArgumentException(
- msg("Only installation via file: protocol is supported"));
- }
-
- String srcJamFileName = u.getFile();
- if (!new File(srcJamFileName).exists()) {
- throw new IllegalArgumentException(
- msg("Cannot install non-existent file: " + srcJamFileName));
- }
- if (!(srcJamFileName.endsWith(".jam")
- || srcJamFileName.endsWith(".jar")
- || srcJamFileName.endsWith(".jam.pack.gz"))) {
- throw new IllegalArgumentException(
- msg("Only installation of .jam, .jar, and .jam.pack.gz files are supported; cannot install "
- + srcJamFileName));
- }
-
- File srcJamFile = null;
- boolean packedJam = false;
- if (srcJamFileName.endsWith(".jam.pack.gz")) {
- packedJam = true;
- srcJamFile = File.createTempFile("jamgz-" + System.currentTimeMillis(), ".jar");
- JamUtils.unpackStreamAsFile(u.openStream(), srcJamFile);
- // Tag it for deletion, in case an exception is thrown between
- // here and when it is deleted below.
- srcJamFile.deleteOnExit();
- } else {
- srcJamFile = new File(srcJamFileName);
- }
-
- JarFile mdJamFile = new JarFile(srcJamFile);
-
- // Extracts module metadata from JAM file
- byte[] metadata = JamUtils.getMetadata(mdJamFile);
- mdJamFile.close();
-
- // Constructs a superpackage from module metadata, for extracting the
- // stock annotations.
- java.lang.reflect.Superpackage superPackage = sun.module.JamUtils.getSuperpackage(metadata);
-
- // Module name
- String moduleName = superPackage.getName();
-
- // Module version
- java.module.annotation.Version aversion = superPackage.getAnnotation
- (java.module.annotation.Version.class);
- Version moduleVersion = Version.DEFAULT;
- if (aversion != null) {
- try {
- moduleVersion = Version.valueOf(aversion.value());
- } catch (IllegalArgumentException e) {
- // ignore
- }
- }
-
- // Platform Binding
- java.module.annotation.PlatformBinding platformBinding = superPackage.getAnnotation
- (java.module.annotation.PlatformBinding.class);
- String modulePlatform = null;
- String moduleArch = null;
- String moduleBinding = null;
- if (platformBinding != null) {
- modulePlatform = platformBinding.platform();
- moduleArch = platformBinding.arch();
- moduleBinding = modulePlatform + "-" + moduleArch;
- }
-
- if (((modulePlatform == null) ^ (moduleArch == null))) {
- throw new IOException(
- msg(
- "Module " + moduleName
- + " v" + moduleVersion
- + " has mismatched platform and architecture:"
- + " platform=" + platform + ", arch=" + arch));
- }
-
- // Refuse to install if comparable module is already installed.
- for (ModuleArchiveInfo mai : contents.getModuleArchiveInfos()) {
- if (moduleName.equals(mai.getName())
- && moduleVersion.equals(mai.getVersion())) {
-
- // Platform binding matches only if both are null or both have
- // same platform and arch. The test for platform XOR arch was
- // done above so don't repeat that here, and never create a
- // ModuleArchiveInfo where there's a mismatch.
- if ((modulePlatform == null && mai.getPlatform() == null)
- || (modulePlatform.equals(mai.getPlatform())
- && moduleArch.equals(mai.getArchitecture()))) {
- throw new IllegalStateException(
- msg(
- "Module " + moduleName
- + " v" + moduleVersion
- + " already exists in the repository at "
- + getSourceLocation()));
- }
- }
- }
-
- initializeCache();
-
- /*
- * Installing the module requires these steps:
- * (1) Creating MODULE.METADATA
- * (2) Copying the JAM file
- * (3) Creating and caching the ModuleDefinition
- * (4) Updating repository-metadata.xml
- * (5) updating the contents field of this repository instance
- *
- * If any step fails, undo any of the other steps already done.
- */
-
- // (1) Create the new MODULE.METADATA file.
- //
- File sourceDir = new File(getSourceLocation().getFile());
-
- // The module destination directory in the URLRepository should be
- // <source location>/<module-name>/<module-version>
- // or
- // <source location>/<module-name>/<module-version>/<platform>-<arch>
- File moduleDestDir = new File(sourceDir,
- getFilePath(moduleName, moduleVersion, modulePlatform, moduleArch));
- moduleDestDir.mkdirs();
-
- // Copy MODULE.METADATA file
- File destMDFile = new File(moduleDestDir, JamUtils.MODULE_METADATA);
- BufferedOutputStream bos =
- new BufferedOutputStream(new FileOutputStream(destMDFile));
- bos.write(metadata, 0, metadata.length);
- bos.flush();
- bos.close();
-
- // Copy JAM file
- String destJamName = JamUtils.getJamFilename(moduleName, moduleVersion, modulePlatform, moduleArch);
- File destJamFile = new File(moduleDestDir, destJamName);
-
- ModuleArchiveInfo mai = null;
- try {
- // (2) Copy the JAM file
- JamUtils.copyFile(srcJamFile, destJamFile);
- if (packedJam) {
- srcJamFile.delete();
- }
-
- // (3) Create and cache the ModuleDefinition
- mai = new ModuleArchiveInfo(
- this, moduleName, moduleVersion,
- modulePlatform, moduleArch,
- destJamFile.getCanonicalPath(), destJamFile.lastModified());
-
- ModuleDefinition installedMD = null;
- if (RepositoryUtils.bindingMatches(platformBinding, platform, arch)) {
- installedMD = RepositoryUtils.createURLModuleDefinition(
- this,
- downloadDir,
- new ModuleInfo(
- moduleName,
- moduleVersion,
- modulePlatform,
- moduleArch,
- null),
- destMDFile);
- modDefCache.add(installedMD);
- }
-
- // (4) Create an updated repository-metadata.xml.tmp file
- writeRepositoryMetadata(mai, true);
-
- // (5) Update contents field
- contents.put(mai, installedMD);
-
- } catch (IOException ex) {
- destMDFile.delete();
- destJamFile.delete();
- throw ex;
- }
-
- // Send MODULE_INSTALLED event
- RepositoryEvent evt = new RepositoryEvent(this, RepositoryEvent.Type.MODULE_INSTALLED, mai);
- processEvent(evt);
-
- return mai;
- }
-
- @Override
- public synchronized boolean uninstall(ModuleArchiveInfo mai) throws IOException {
- assertActive();
- assertNotReadOnly();
- assertValidDirs();
- return uninstall0(mai);
- }
-
- /**
- * Uninstalls the specified module. In a http-based repository, this is
- * limited to removing downloaded temporary structures and in-memory cache
- * structures. In a file-based repository, this also removes the metadata
- * and associated JAM file.
- * @param mai Specifies module to uninstall
- * @throws IOException if an error occurs during uninstallation
- */
- private boolean uninstall0(ModuleArchiveInfo mai) throws IOException {
- if (!contents.contains(mai)) {
- return false;
- }
-
- File sourceDir = new File(getSourceLocation().getFile());
-
- // Delete file/filesystem resources related to md, and then
- // remove it from contents.
-
- // XXX ModuleArchiveInfo doesn't contain path information. Get from
- // XXX ModuleInfo? Defer until install() handles it?
-
- String moduleName = mai.getName();
- Version moduleVersion = mai.getVersion();
- String modulePlatform = mai.getPlatform();
- String moduleArch = mai.getArchitecture();
-
- // This is the directory which contains MODULE.METADATA and the JAM file
- File moduleDir = new File(sourceDir, getFilePath(moduleName, moduleVersion, modulePlatform, moduleArch));
- verifyExistence(moduleDir);
-
- String jamName = JamUtils.getJamFilenameNoExt(moduleName, moduleVersion, modulePlatform, moduleArch);
-
- // This is where any downloads for this module are
- File moduleDownloadDir = new File(downloadDir, jamName);
-
- /*
- * Presume that ability to rename implies ability to remove:
- * rename the files to be deleted; if that succeeds then
- * delete them. If any rename or deletion fails, undo
- * whatever can be undone.
- */
- File moduleDirToRemove = null;
- File moduleDownloadDirToRemove = null;
-
- try {
- moduleDirToRemove = rename(moduleDir);
- if (moduleDownloadDir.isDirectory()) {
- // XXX Remove the Windows-specificity once disableModuleDefinition is implemented
- if (!platform.startsWith("windows")) {
- moduleDownloadDirToRemove = rename(moduleDownloadDir);
- }
- }
-
- // Updated the repository metadata without the specified
- // module definition.
- writeRepositoryMetadata(mai, false);
-
- if (!JamUtils.recursiveDelete(moduleDirToRemove)) {
- throw new IOException(
- msg("Could not remove directory: " + moduleDirToRemove.getCanonicalPath()));
- }
- // XXX: should we really throw exception if we can't clean up the
- // internal cache only but everything else works?
- if (moduleDownloadDirToRemove != null
- && !JamUtils.recursiveDelete(moduleDownloadDirToRemove)) {
- throw new IOException(
- msg("Could not remove directory: " + moduleDownloadDirToRemove.getCanonicalPath()));
- }
- } catch (IOException ex) {
- // restore previus state as much as possible
- if (moduleDownloadDirToRemove != null) {
- rename(moduleDownloadDirToRemove, moduleDownloadDir);
- }
- if (moduleDirToRemove != null) {
- rename(moduleDirToRemove, moduleDir);
- }
- writeRepositoryMetadata(mai, true);
- throw ex;
- }
-
- return uninstall1(mai);
- }
-
- /**
- * Updates data structures for an uninstall, and sends MODULE_UNINSTALLED
- * event.
- */
- private boolean uninstall1(ModuleArchiveInfo mai) {
- ModuleDefinition md = contents.get(mai);
- // XXX Uncomment below disableModuleDefinition is implemented
- //if (md != null) {
- // getModuleSystem().disableModuleDefinition(md);
- //}
- modDefCache.remove(md);
- boolean rc = contents.remove(mai);
-
- if (rc) {
- // Send MODULE_UNINSTALLED event
- RepositoryEvent evt = new RepositoryEvent(this, RepositoryEvent.Type.MODULE_UNINSTALLED, mai);
- processEvent(evt);
- }
- return rc;
- }
-
- /**
- * Finds all matching module definitions in this repository.
- *
- * @param constraint the constraint.
- * @return the collection of matching module definitions.
- */
- @Override
- public synchronized List<ModuleDefinition> findModuleDefinitions(Query constraint) {
- assertActive();
- return RepositoryUtils.findModuleDefinitions(constraint, modDefCache);
- }
-
- @Override
- public List<ModuleArchiveInfo> list() {
- return Collections.unmodifiableList(contents.getModuleArchiveInfos());
- }
-
- /**
- * Compares the cache with a freshly-downloaded repository-metadata.xml.
- * Modules that are in both places are not affected. Modules in the cache
- * but not metadata are uninstalled. Modules in the metadata but not the
- * cache, for which a MODULE.METADATA is newer than that already
- * installed, have their metadata loaded.
- */
- @Override
- public synchronized void reload() throws IOException {
- assertActive();
-
- initializeCache();
-
- URL repoMD = new URL(sourcePath + "repository-metadata.xml");
- try {
- // Build a list of modules to uninstall, and of modules currently
- // installed that won't be uninstalled by this reload.
- Set<ModuleInfo> moduleInfoSet = MetadataXMLReader.read(repoMD);
- Set<ModuleArchiveInfo> uninstallCandidates = new HashSet<ModuleArchiveInfo>();
- Map<ModuleInfo, ModuleArchiveInfo> replaceCandidates =
- new HashMap<ModuleInfo, ModuleArchiveInfo>();
-
- for (ModuleArchiveInfo mai : contents.getModuleArchiveInfos()) {
- ModuleInfo mi = new ModuleInfo(mai);
- if (!moduleInfoSet.contains(mi)) {
- uninstallCandidates.add(mai);
- } else {
- replaceCandidates.put(mi, mai);
- }
-
- // Remove a ModuleInfo from this set if it has a corresponding
- // entry in contents; that is, if it is already installed in
- // this repository. After this loop, moduleInfoSet will list
- // entries newly-added to repository-metadata.xml
- moduleInfoSet.remove(mi);
- }
-
- // Uninstall modules for which there is no corresponding file in the
- // source directory
- for (ModuleArchiveInfo mai : uninstallCandidates) {
- uninstall1(mai);
- }
-
- // Reload already-installed modules.
- for (Map.Entry<ModuleInfo, ModuleArchiveInfo> entry : replaceCandidates.entrySet()) {
- ModuleArchiveInfo mai =
- loadMetadata(entry.getKey(), entry.getValue());
- RepositoryEvent evt = new RepositoryEvent(
- this, RepositoryEvent.Type.MODULE_INSTALLED, mai);
- processEvent(evt);
- }
-
- // Load new modules
- for (ModuleInfo mi : moduleInfoSet) {
- ModuleArchiveInfo mai = loadMetadata(mi, null);
- RepositoryEvent evt = new RepositoryEvent(
- this, RepositoryEvent.Type.MODULE_INSTALLED, mai);
- processEvent(evt);
-
- }
- } catch (IllegalArgumentException ex) {
- throw ex;
- } catch (IOException ex) {
- throw ex;
- } catch (Exception ex) {
- throw new IOException(
- msg("Error reloading repository at " + sourcePath
- + ": " + ex.getMessage()), ex);
- }
- }
-
- /**
- * Uninstalls all modules. Removes repository-specific directories.
- *
- * @throws java.io.IOException if there's an error removing directories.
- * */
- @Override
- public synchronized void shutdown() throws IOException {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- sm.checkPermission(new ModuleSystemPermission("shutdownRepository"));
- }
- if (shutdown) {
- return; // shutdown only once
- }
- assertActive();
-
- removeCache();
-
- active = false;
- shutdown = true;
-
- // Send REPOSITORY_SHUTDOWN event
- RepositoryEvent evt = new RepositoryEvent(this, RepositoryEvent.Type.REPOSITORY_SHUTDOWN);
- processEvent(evt);
- }
-
- @Override
- public boolean isActive() {
- return active;
- }
-
- /**
- * @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() {
- return readOnly;
- }
-
- /**
- * @return true if this repository's source location is a file-based URL.
- */
- @Override
- public boolean isReloadSupported() {
- return getSourceLocation().getProtocol().equals("file");
- }
-
- //
- // Implementation specific to URLRepository
- //
-
- /**
- * @return the path of the url given in the constructor but always with a
- * trailing '/'.
- */
- String getSourcePath() {
- return sourcePath;
- }
/**
* Initializes the repository instance using the supplied configuration.
@@ -795,10 +284,9 @@ public final class URLRepository extends
* These keys are checked for in {@code config} and in System properties;
* entries in System properties override entries in {@code config}:
* <ul>
- * <li>{@code sun.module.repository.URLRepository.downloadDirectory}:
- * Specifies the directory into which the contents of
- * JAM files are downloaded. Will be created if it
- * does not already exist.
+ * <li>{@code sun.module.repository.URLRepository.cacheDirectory}:
+ * Specifies the directory into which the contents of JAM files
+ * are cached. Will be created if it does not already exist.
* </li>
* </ul>
* <em>Note:</em> Values are read from System properties only once, when
@@ -807,15 +295,12 @@ public final class URLRepository extends
* @param config Map of configuration names to their values
* @throws IOException if the repository cannot be initialized.
*/
- private synchronized void initialize(Map<String, String> config) throws IOException {
- if (active) {
- return; // initialize only once
- }
- if (shutdown) {
- throw new IllegalStateException(msg("Repository has been shut down."));
- }
- if (config == null) {
- throw new NullPointerException(msg("Parameter 'config' cannot be null."));
+ protected final void doInitialize(Map<String, String> config) throws IOException {
+ String tmp = getSourceLocation().toExternalForm();
+ if (tmp.endsWith("/")) {
+ canonicalizedCodebase = new URL(tmp);
+ } else {
+ canonicalizedCodebase = new URL(tmp + "/");
}
if ("true".equalsIgnoreCase(sysPropSourceLocMustExist)) {
@@ -823,130 +308,410 @@ public final class URLRepository extends
} else {
sourceLocMustExist = "true".equalsIgnoreCase(config.get(SOURCELOC_MUST_EXIST_KEY));
}
- downloadDirName = sysPropDownloadDirName != null
- ? sysPropDownloadDirName : config.get(DOWNLOAD_DIR_KEY);
+
+ cacheDirName = sysPropCacheDirName != null
+ ? sysPropCacheDirName : config.get(CACHE_DIR_KEY);
+
+ // Constructs a repository cache instance
+ if (cacheDirName == null) {
+ repositoryCache = Cache.newInstance();
+ } else {
+ repositoryCache = Cache.newInstance(new File(cacheDirName));
+ }
+
+ assertValidDirs();
// The ability to configure platform and arch are for testing only!
- String value;
- if ((value = config.get(PROPERTY_PREFIX + "test.platform")) != null) {
- platform = value;
- }
- if ((value = config.get(PROPERTY_PREFIX + "test.arch")) != null) {
- arch = value;
- }
+ String v;
+ if ((v = config.get(PROPERTY_PREFIX + "test.platform")) != null) {
+ platform = v;
+ }
+ if ((v = config.get(PROPERTY_PREFIX + "test.arch")) != null) {
+ arch = v;
+ }
+
Set<ModuleInfo> moduleInfoSet = null;
try {
- URL repoMD = new URL(sourcePath + "repository-metadata.xml");
+ URL repoMD = new URL(canonicalizedCodebase + "repository-metadata.xml");
moduleInfoSet = MetadataXMLReader.read(repoMD);
+
+ // Initializes the internal data structures based on the module
+ // info set.
+ doInitialize(moduleInfoSet);
} catch (IOException ex) {
- if (sourceLocMustExist) {
- throw ex;
- }
+ // no-op
} catch (Exception ex) {
throw new IOException(
- msg("Error processing repository-metadata.xml: " + ex.getMessage()), ex);
- }
-
+ "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 void doInitialize(Set<ModuleInfo> moduleInfoSet) throws IOException {
if (moduleInfoSet != null) {
- initializeCache();
+ Map<ModuleArchiveInfo, ModuleDefInfo> mdInfoMap =
+ new HashMap<ModuleArchiveInfo, ModuleDefInfo>();
for (ModuleInfo mi : moduleInfoSet) {
- loadMetadata(mi, null);
- }
- }
-
- active = true;
-
- // Send REPOSITORY_INITIALIZED event
- RepositoryEvent evt = new RepositoryEvent(this, RepositoryEvent.Type.REPOSITORY_INITIALIZED);
- processEvent(evt);
- }
-
- /**
- * Loads MODULE.METADATA from {@code sourcePath} for the given
- * {code ModuleInfo}. After this, the module definition is available via
- * the find and list methods.
- * @param moduleInfo Describes the module whose metadata is to be loaded
- * @param mai Denotes an already-installed module. If not null, then the
- * module described by {@code moduleInfo} is loaded only if it is newer
- * than the module denoted by {@code mai}.
- * @return ModuleArchiveInfo for the newly-loaded module or for the
- * already-installed module as appropriate.
- */
- private ModuleArchiveInfo loadMetadata(
- ModuleInfo moduleInfo, ModuleArchiveInfo mai) throws IOException {
-
- URL moduleMD = new URL(sourcePath + moduleInfo.getCanonicalizedPath() + "/" + JamUtils.MODULE_METADATA);
- URLConnection uc = null;
+ 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
+ ModuleArchiveInfo mai = new ModuleArchiveInfo(
+ 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.
+ moduleArchiveInfos.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);
+ }
+ }
+ }
+
+ // Constructs the module definitions from the module archives
+ // based on the specified platform and architecture.
+ constructModuleDefinitions(mdInfoMap, platform, arch);
+ }
+ }
+
+ /**
+ * Install a module archive from a URL.
+ */
+ protected ModuleArchiveInfo doInstall(URL url) throws IOException {
+ InputStream is = null;
+ File sourceFile = null;
+ File tmpFile = null;
+ File destMDFile = null;
+ File destJamFile = null;
+
try {
- uc = moduleMD.openConnection();
+ URLConnection uc = url.openConnection();
+ is = uc.getInputStream();
+
+ // Store the file in a temp directory first. Unpack the file if
+ // necessary.
+ sourceFile = File.createTempFile("url-repository-install-", "tmp");
+ sourceFile.deleteOnExit();
+ JamUtils.saveStreamAsFile(is, sourceFile);
+
+ if (url.getFile().endsWith(".jam.pack.gz")) {
+ tmpFile = File.createTempFile("url-repository-install-", "tmp");
+ tmpFile.deleteOnExit();
+ JamUtils.unpackJamPackGz(sourceFile, tmpFile);
+ } else {
+ tmpFile = sourceFile;
+ }
+
+ // Retrieve the module metadata from the JAM file to find out
+ // the module information, e.g. name, version, etc.
+ //
+ // No need to shadow copy (if set) because this is a temp file.
+ ModuleDefInfo mdInfo = repositoryCache.getModuleDefInfo(tmpFile, false);
+
+ // Check to see if there exists a module archive that has
+ // the same name, version, and platform binding.
+ for (ModuleArchiveInfo mai : moduleArchiveInfos) {
+ if (mai.getName().equals(mdInfo.getName())
+ && mai.getVersion().equals(mdInfo.getVersion())) {
+ if (mai.isPlatformArchNeutral()) {
+ if (mdInfo.isPlatformArchNeutral()) {
+ throw new IllegalStateException("A module definition with the same name,"
+ + " version, and platform binding is already installed");
+ }
+ } else if (mai.getPlatform().equals(mdInfo.getPlatform())
+ && mai.getArch().equals(mdInfo.getArch())) {
+ throw new IllegalStateException("A module definition with the same name,"
+ + " version, and platform binding is already installed");
+ }
+ }
+ }
+
+ /*
+ * Installing the module requires these steps:
+ * (1) Creating MODULE.METADATA
+ * (2) Copying the JAM file
+ * (3) Updating repository-metadata.xml
+ * (4) updating the internal data structures of this repository instance
+ *
+ * If any step fails, undo any of the other steps already done.
+ */
+
+ // (1) Create the new MODULE.METADATA file.
+ //
+ File sourceDir = new File(getSourceLocation().getFile());
+
+ // The module destination directory in the URLRepository should be
+ // <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()));
+ moduleDestDir.mkdirs();
+
+ // Copy MODULE.METADATA file
+ destMDFile = new File(moduleDestDir, JamUtils.MODULE_METADATA);
+ BufferedOutputStream bos =
+ new BufferedOutputStream(new FileOutputStream(destMDFile));
+ byte[] metadataBytes = mdInfo.getMetadataBytes();
+ bos.write(metadataBytes, 0, metadataBytes.length);
+ bos.flush();
+ bos.close();
+
+ // Copy JAM file
+ String destFileName = JamUtils.getJamFilename(mdInfo.getName(),
+ mdInfo.getVersion(),
+ mdInfo.getPlatform(),
+ mdInfo.getArch());
+ if (sourceFile == tmpFile) {
+ // no unpack
+ destFileName +=".jam";
+ } else {
+ destFileName +=".jam.pack.gz";
+ }
+
+ destJamFile = new File(moduleDestDir, destFileName);
+
+ // (2) Copy the JAM file
+ JamUtils.copyFile(sourceFile, destJamFile);
+
+ // (3) Create an updated repository-metadata.xml file
+ //
+ // 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 ModuleArchiveInfo(this, mdInfo.getName(),
+ mdInfo.getVersion(), mdInfo.getPlatform(),
+ mdInfo.getArch(), null, 0), true);
+
+ // (4) Update internal data structures.
+ return addModuleArchiveInternal(destJamFile);
} catch (IOException ex) {
- throw new IOException(msg("Cannot open connection to " + moduleMD), ex);
- }
-
- File moduleDir = new File(
- downloadDir + File.separator + moduleInfo.getName()
- + (moduleInfo.getVersion() == null ? "" : "-" + moduleInfo.getVersion()));
- File mdFile = new File(moduleDir, JamUtils.MODULE_METADATA);
-
- // During reload, only download metadata if it is for a new or
- // replaced JAM.
- if (mai != null) {
- if (mdFile.exists()) {
- long fileMod = mdFile.lastModified();
- long urlMod = uc.getLastModified();
- if (fileMod != 0 && fileMod == urlMod) {
- return mai;
- } else {
- modDefCache.remove(contents.get(mai));
- contents.remove(mai);
- }
- }
- }
-
- InputStream is = null;
- OutputStream os = null;
+ if (destMDFile != null) {
+ destMDFile.delete();
+ }
+ if (destJamFile != null) {
+ destJamFile.delete();
+ }
+ throw ex;
+ } finally {
+ if (sourceFile != null) {
+ sourceFile.delete();
+ }
+ if (tmpFile != null) {
+ tmpFile.delete();
+ }
+ JamUtils.close(is);
+ }
+ }
+
+ /**
+ * Uninstall a module archive.
+ */
+ protected boolean doUninstall(ModuleArchiveInfo mai) throws IOException {
+ // Checks if the module archive still exists.
+ if (!moduleArchiveInfos.contains(mai)) {
+ return false;
+ }
+
+ // Source location
+ File sourceDir = new File(getSourceLocation().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.
+ //
+ // 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));
+ verifyExistence(moduleDir);
+
+
+ //
+ // A module archive could be platform neutral 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.
+
+ // jam name has no file extension
+ String jamName = JamUtils.getJamFilename(moduleName, moduleVersion,
+ modulePlatform, moduleArch);
+
+ File packGzJamFile = new File(moduleDir, jamName + ".jam.pack.gz");
+ File jamFile = new File(moduleDir, jamName + ".jam");
+ File metadataFile = new File(moduleDir, JamUtils.MODULE_METADATA);
+ File packGzJamFileToRemove = null;
+ File jamFileToRemove = null;
+ File metadataFileToRemove = null;
+
+ /*
+ * Presume that ability to rename implies ability to remove:
+ * rename the files to be deleted; if that succeeds then
+ * delete them. If any rename or deletion fails, undo
+ * whatever can be undone.
+ */
try {
- is = new BufferedInputStream(uc.getInputStream(),
- JamUtils.BUFFER_SIZE);
+ if (metadataFile.exists()) {
+ metadataFileToRemove = rename(metadataFile);
+ }
+ if (jamFile.exists()) {
+ jamFileToRemove = rename(jamFile);
+ }
+ if (packGzJamFile.exists()) {
+ packGzJamFileToRemove = rename(packGzJamFile);
+ }
+
+ // Updated the repository metadata without the specified
+ // module archive.
+ writeRepositoryMetadata(mai, false);
+
+ if (metadataFileToRemove != null) {
+ metadataFileToRemove.delete();
+ metadataFileToRemove = null;
+ }
+ if (jamFileToRemove != null) {
+ jamFileToRemove.delete();
+ jamFileToRemove = null;
+ }
+ if (packGzJamFileToRemove != null) {
+ packGzJamFileToRemove.delete();
+ packGzJamFileToRemove = null;
+ }
+
+ // Only when there is no other file in the directory, blow the directory away
+ File[] files = moduleDir.listFiles();
+ if (files == null || files.length == 0) {
+ JamUtils.recursiveDelete(moduleDir);
+ }
} catch (IOException ex) {
- throw new IOException(msg("Cannot load " + JamUtils.MODULE_METADATA
- + " for " + moduleMD), ex);
- }
-
+ if (metadataFileToRemove != null) {
+ rename(metadataFileToRemove, metadataFile);
+ }
+ if (jamFileToRemove != null) {
+ rename(jamFileToRemove, jamFile);
+ }
+ if (packGzJamFileToRemove != null) {
+ rename(packGzJamFileToRemove, packGzJamFile);
+ }
+
+ writeRepositoryMetadata(mai, true);
+ throw ex;
+ }
+
+ // Remove the module archive and its corresponding module definition
+ // from the internal data structures
+ removeModuleArchiveInternal(mai);
+
+ return true;
+ }
+
+ /**
+ * Reload all module archives.
+ */
+ protected void doReload() throws IOException {
try {
- // The repository-metadata.xml file might specify a path, but
- // ignore that when storing the metadata locally.
- if (!moduleDir.isDirectory() && !moduleDir.mkdirs()) {
- throw new IOException(msg("Cannot create directory for metadata: " + moduleDir));
- }
- os = new BufferedOutputStream(
- new FileOutputStream(mdFile));
-
- byte[] buf = new byte[JamUtils.BUFFER_SIZE];
- int len = 0;
- while ((len = is.read(buf, 0, buf.length)) > 0) {
- os.write(buf, 0, len);
- }
- os.close();
- ModuleDefinition md = RepositoryUtils.createURLModuleDefinition(
- this, downloadDir, moduleInfo, mdFile);
- mai = new ModuleArchiveInfo(
- this, md.getName(), md.getVersion(),
- moduleInfo.getPlatform(), moduleInfo.getArch(),
- null, 0);
-
- PlatformBinding platformBinding = md.getAnnotation(PlatformBinding.class);
- if (RepositoryUtils.bindingMatches(platformBinding, platform, arch)) {
- modDefCache.add(md);
- contents.put(mai, md);
- } else {
- contents.put(mai, null);
- }
- return mai;
- } finally {
- JamUtils.close(is);
- JamUtils.close(os);
- }
+ /**
+ * Since the repository-metadata.xml 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<ModuleInfo> moduleInfoSet = MetadataXMLReader.read(repoMD);
+
+ // Uninstall all existing module archives and module definitions
+ for (ModuleArchiveInfo mai : new ArrayList<ModuleArchiveInfo>(moduleArchiveInfos)) {
+ removeModuleArchiveInternal(mai);
+ }
+
+ moduleDefs.clear();
+ moduleArchiveInfos.clear();
+ contentMapping.clear();
+
+ // Initializes the internal data structures based on the module
+ // info set again.
+ doInitialize(moduleInfoSet);
+
+ for (ModuleArchiveInfo mai : moduleArchiveInfos) {
+ RepositoryEvent evt = new RepositoryEvent(
+ this, RepositoryEvent.Type.MODULE_INSTALLED, mai);
+ processEvent(evt);
+ }
+
+ // Reconstructs module definitions from the module archives if
+ // necessary.
+ reconstructModuleDefinitionsIfNecessary(platform, arch);
+ } catch (IllegalArgumentException ex) {
+ throw ex;
+ } catch (IOException ex) {
+ throw ex;
+ } catch (Exception ex) {
+ throw new IOException(
+ "Unable to reload the repository", ex);
+ }
+ }
+
+ @Override
+ protected void doShutdown() throws IOException {
+ // 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() {
+ return (getSourceLocation().getProtocol().equals("file") == false);
+ }
+
+ /**
+ * @return true if this repository supports reload.
+ */
+ @Override
+ public boolean supportsReload() {
+ return true;
}
/**
@@ -969,15 +734,15 @@ public final class URLRepository extends
if (tmpRepoMDFile.exists()) {
if (!tmpRepoMDFile.delete()) {
throw new IOException(
- msg("Cannot update repository metadata file for "
+ "Cannot update repository metadata file for "
+ mai.getName()
+ ": cannot create temporary repository metadata file "
- + tmpRepoMDFile));
+ + tmpRepoMDFile);
}
}
RepoMDWriter writer = new RepoMDWriter(tmpRepoMDFile);
writer.begin();
- for (ModuleArchiveInfo m : contents.getModuleArchiveInfos()) {
+ for (ModuleArchiveInfo m : moduleArchiveInfos) {
if (!writeMAI && m.equals(mai)) {
// Don't write this ModuleArchiveInfo if it matches that given
} else {
@@ -990,28 +755,34 @@ public final class URLRepository extends
if (!writer.end()) {
throw new IOException(
- msg("Cannot update repository metadata file for "
+ "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(
- msg("Cannot update repository metadata file for "
- + mai.getName()
- + ": cannot rename " + repoMDFile + " to " + prev));
- }
- prev.deleteOnExit();
+ + tmpRepoMDFile);
+ }
+
+ // Rename the repository-metadata.xml file to repository-metadata.xml.prev
+ // repository-metadata.xml may not exist if the URLRepository is new and
+ // no repository-metadata.xml has been created yet.
+ if (repoMDFile.exists()) {
+ 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(
- msg("Cannot update repository metadata file for "
+ "Cannot update repository metadata file for "
+ mai.getName()
+ ": cannot create updated repository-metadata.xml file"
- + " by renaming " + tmpRepoMDFile + " to " + repoMDFile));
+ + " by renaming " + tmpRepoMDFile + " to " + repoMDFile);
}
}
@@ -1047,12 +818,11 @@ public final class URLRepository extends
indent++;
output("<name>" + mai.getName() + "</name>");
output("<version>" + mai.getVersion().toString() + "</version>");
- String platform = mai.getPlatform();
- if (platform != null) {
+ if (!mai.isPlatformArchNeutral()) {
output("<platform-binding>");
indent++;
- output("<platform>" + platform + "</platform>");
- output("<arch>" + mai.getArchitecture() + "</arch>");
+ output("<platform>" + mai.getPlatform() + "</platform>");
+ output("<arch>" + mai.getArch() + "</arch>");
indent--;
output("</platform-binding>");
}
@@ -1071,73 +841,12 @@ public final class URLRepository extends
}
/**
- * Create a directory.
- * @param parentDirName Client-provided full pathname to a directory. May
- * be null.
- * @param dirName Name of directory to be created in {@code
- * parentDirName}. The actual directory created is suffixed with the
- * repository's {@code timestamp}. If the {@code parentDirName} is null,
- * then {@code dirName} is created in a repository-specific directory
- * under the system temporary directory.
- * @return a {@code File} representing the directory
- * @throws IOException if the directory cannot be created
- */
- private File createDir(String parentDirName, String dirName) throws IOException {
- File rc = new File(parentDirName,
- getName() + "-" + timestamp + "-" + dirName);
-
- if (!rc.isDirectory() && !rc.mkdirs()) {
- try {
- // Remove any intermediate directories created
- JamUtils.recursiveDelete(rc);
- } catch (IOException ex) {
- // Ignore if some cannot be removed
- }
- throw new IOException(msg("Cannot create directory at "
- + rc.getAbsolutePath()));
- }
- return rc;
- }
-
- /**
- * Ensure that the required directories exist.
- */
- private void initializeCache() throws IOException {
- if (fileBased) {
- File sourceDir = new File(getSourceLocation().getFile());
- File repoMDFile = new File(sourceDir, "repository-metadata.xml");
- if (!repoMDFile.exists()) {
- BufferedOutputStream bos =
- new BufferedOutputStream(new FileOutputStream(repoMDFile));
- bos.write("<modules></modules>".getBytes("ASCII"));
- bos.close();
- }
- }
- if (downloadDir == null) {
- downloadDir = createDir(downloadDirName, "download");
- }
- }
-
- /**
- * Removes the contents of the repository's metadata and download
- * directories.
- */
- private void removeCache() throws IOException {
- if (downloadDir != null) {
- JamUtils.recursiveDelete(downloadDir);
- }
-
- downloadDir = null;
- contents.clear();
- }
-
- /**
* @throws IOException if file {@code f} doesn't exist
*/
private void verifyExistence(File f) throws IOException {
if (!f.exists()) {
- throw new IOException(
- msg("Expected file is missing: " + f.getAbsolutePath()));
+ throw new FileNotFoundException(
+ "File not found: " + f.getAbsolutePath());
}
}
@@ -1145,11 +854,12 @@ public final class URLRepository extends
* @return file {@code prev} renamed by adding a time-based extension
*/
private File rename(File prev) throws IOException {
- File next = new File(prev.getCanonicalPath() + "." + System.currentTimeMillis());
+ File next = new File(prev.getCanonicalPath() + "."
+ + System.currentTimeMillis());
if (!prev.renameTo(next)) {
throw new IOException(
- msg("Could not rename file for deletion: "
- + prev.getCanonicalPath()));
+ "Could not rename file for deletion: "
+ + prev.getCanonicalPath());
}
return next;
}
@@ -1164,7 +874,8 @@ public final class URLRepository extends
}
/**
- * Returns file path based on module name, version, platform and architecture.
+ * Returns file path for a module under codebase, based on module name,
+ * version, platform and architecture.
*
* @param name module name
* @param version module version
@@ -1172,49 +883,27 @@ public final class URLRepository extends
* @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);
- }
-
- private void assertActive() throws IllegalStateException {
- if (!isActive()) {
- throw new IllegalStateException(msg("Repository is not active."));
- }
- }
-
- private void assertNotActive() throws IllegalStateException {
- if (isActive()) {
- throw new IllegalStateException(msg("Repository is active."));
- }
- }
-
- private void assertNotReadOnly() throws IllegalStateException {
- if (isReadOnly()) {
- throw new UnsupportedOperationException(msg("Repository is read-only."));
- }
- }
-
- private void assertValidDirs() throws IOException {
- if (fileBased) {
- File sourceDir = new File(getSourceLocation().getFile());
- if (sourceDir == null || !sourceDir.isDirectory()) {
- missingDir("source", sourceDir);
- }
- }
- if (downloadDir == null || !downloadDir.isDirectory()) {
- missingDir("download", downloadDir);
+ 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 {
+ if (getSourceLocation().getProtocol().equals("file")) {
+ File sourceDirectory = JamUtils.getFile(getSourceLocation());
+ if (sourceDirectory.exists() == false
+ || sourceDirectory.isDirectory() == false) {
+ if (sourceLocMustExist) {
+ missingDir("source", sourceDirectory);
+ }
+ }
}
}
private void missingDir(String type, File dir) throws IOException {
- throw new IOException(
- msg("specified " + type + " directory "
- + dir + " does not exist or is not a directory"));
- }
-
- String msg(String s) {
- return IDENT + " " + getName() + " at "
- + getSourceLocation().toExternalForm() + ": " + s;
- }
-
+ throw new FileNotFoundException(
+ dir + " does not exist or is not a directory");
+ }
}
--- a/src/share/classes/sun/module/tools/JRepo.java Thu Mar 27 15:49:52 2008 -0700
+++ b/src/share/classes/sun/module/tools/JRepo.java Wed Apr 02 17:59:05 2008 -0700
@@ -283,7 +283,7 @@ public class JRepo {
}
pw.printf(MAIFormatVerbose,
mai.getPlatform() == null ? "generic" : mai.getPlatform(),
- mai.getArchitecture() == null ? "generic" : mai.getArchitecture(),
+ mai.getArch() == null ? "generic" : mai.getArch(),
lastMod == null ? "n/a" : lastMod,
mai.getFileName() == null ? "n/a" : mai.getFileName()
);
@@ -737,7 +737,7 @@ public class JRepo {
if (platformBinding == null) {
rc = true;
} else {
- String pb = mai.getPlatform() + "-" + mai.getArchitecture();
+ String pb = mai.getPlatform() + "-" + mai.getArch();
if (platformBinding.equals(pb)) {
rc = true;
}
--- a/test/java/module/basic/BasicLauncherTests.java Thu Mar 27 15:49:52 2008 -0700
+++ b/test/java/module/basic/BasicLauncherTests.java Wed Apr 02 17:59:05 2008 -0700
@@ -199,6 +199,7 @@ public class BasicLauncherTests {
out = out.append("package " + pkg + ";\n");
out = out.append("import java.lang.reflect.Superpackage.*;\n");
out = out.append("import java.module.annotation.*;\n");
+ out = out.append("@Version(\"" + Version.valueOf(JAM_VERSION) +"\")\n");
out = out.append("@MainClass(\"" + pkg + "." + klass + "\")\n");
out = out.append("@ImportModules({\n");
out = out.append(" @ImportModule(name=\"java.se\"),\n");
@@ -630,8 +631,15 @@ class TestExec {
javaCmdArgs.add(javaCmd);
- javaCmdArgs.add("-Dsun.module.repository.URLRepository.downloadDirectory="
+ javaCmdArgs.add("-Dsun.module.repository.URLRepository.cacheDirectory="
+ downloadDirName);
+
+ // Enables shadow file copies in the repository if we're running
+ // on Windows. This is to prevent file locking in the
+ // source location.
+ if (System.getProperty("os.platform").equalsIgnoreCase("windows")) {
+ javaCmdArgs.add("-Djava.module.repository.shadowcopyfiles=true");
+ }
if (classpath != null) {
javaCmdArgs.add("-classpath");
--- a/test/java/module/modinit/RunMTest.java Thu Mar 27 15:49:52 2008 -0700
+++ b/test/java/module/modinit/RunMTest.java Wed Apr 02 17:59:05 2008 -0700
@@ -24,7 +24,7 @@
/**
* @test
* @compile -XDignore.symbol.file RunMTest.java classp/MainX.java
- * @run main/othervm/timeout=300 RunMTest
+ * @run main/othervm/timeout=600 RunMTest
*/
import java.util.*;
--- a/test/java/module/modinit/mtest/moduleevent/moduleInitialized.mtest Thu Mar 27 15:49:52 2008 -0700
+++ b/test/java/module/modinit/mtest/moduleevent/moduleInitialized.mtest Wed Apr 02 17:59:05 2008 -0700
@@ -32,7 +32,7 @@ m1.MainA
// Poll first MODULE_INITIALIZED event
//
- ModuleSystemEvent evt = eventQueue.poll(20L, java.util.concurrent.TimeUnit.SECONDS);
+ ModuleSystemEvent evt = eventQueue.poll(10L, java.util.concurrent.TimeUnit.SECONDS);
if (evt.getType() != ModuleSystemEvent.Type.MODULE_INITIALIZED) {
throw new Exception("Unexpected module system event type: " + evt.getType());
}
@@ -43,7 +43,7 @@ m1.MainA
// Poll second MODULE_INITIALIZED event
//
- evt = eventQueue.poll(20L, java.util.concurrent.TimeUnit.SECONDS);
+ evt = eventQueue.poll(10L, java.util.concurrent.TimeUnit.SECONDS);
if (evt.getType() != ModuleSystemEvent.Type.MODULE_INITIALIZED) {
throw new Exception("Unexpected module system event type: " + evt.getType());
}
--- a/test/java/module/modinit/mtest/moduleevent/moduleReleased.mtest Thu Mar 27 15:49:52 2008 -0700
+++ b/test/java/module/modinit/mtest/moduleevent/moduleReleased.mtest Wed Apr 02 17:59:05 2008 -0700
@@ -36,7 +36,7 @@ m1.MainA
// Poll first MODULE_RELEASED event
//
- ModuleSystemEvent evt = eventQueue.poll(20L, java.util.concurrent.TimeUnit.SECONDS);
+ ModuleSystemEvent evt = eventQueue.poll(10L, java.util.concurrent.TimeUnit.SECONDS);
if (evt.getType() != ModuleSystemEvent.Type.MODULE_RELEASED) {
throw new Exception("Unexpected module system event type: " + evt.getType());
}
@@ -47,7 +47,7 @@ m1.MainA
// Poll second MODULE_RELEASED event
//
- evt = eventQueue.poll(20L, java.util.concurrent.TimeUnit.SECONDS);
+ evt = eventQueue.poll(10L, java.util.concurrent.TimeUnit.SECONDS);
if (evt.getType() != ModuleSystemEvent.Type.MODULE_RELEASED) {
throw new Exception("Unexpected module system event type: " + evt.getType());
}
--- a/test/java/module/repository/LegacyJarTest.java Thu Mar 27 15:49:52 2008 -0700
+++ b/test/java/module/repository/LegacyJarTest.java Wed Apr 02 17:59:05 2008 -0700
@@ -61,6 +61,13 @@ public class LegacyJarTest extends Libra
}
private void run(String[] args) throws Throwable {
+ // Enables shadow file copies in the repository if we're running
+ // on Windows. This is to prevent file locking in the
+ // source location.
+ if (System.getProperty("os.platform").equalsIgnoreCase("windows")) {
+ System.setProperty("java.module.repository.shadowcopyfiles", "true");
+ }
+
// Create, compile, and jar "hello, world" main class
File testcaseDir = makeTestDir("testcase");
File testcase = createTestcase(testcaseDir, expectedAnswer);
@@ -143,7 +150,7 @@ public class LegacyJarTest extends Libra
try {
runModule(repo, modName, expectedAnswer);
fail("Run without embedded legacy JAR failed");
- } catch (ClassNotFoundException cnfe) {
+ } catch (ModuleInitializationException mie) {
pass();
} catch (Throwable t) {
unexpected(t);
--- a/test/java/module/repository/LocalRepositoryTest.java Thu Mar 27 15:49:52 2008 -0700
+++ b/test/java/module/repository/LocalRepositoryTest.java Wed Apr 02 17:59:05 2008 -0700
@@ -26,12 +26,18 @@ import java.lang.reflect.Method;
import java.lang.reflect.Method;
import java.module.Module;
import java.module.ModuleArchiveInfo;
+import java.module.ModuleDefinition;
import java.module.Modules;
import java.module.Repository;
+import java.module.RepositoryEvent;
+import java.module.RepositoryListener;
import java.module.ModuleDefinition;
+import java.module.VersionConstraint;
+import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.*;
import sun.module.JamUtils;
import sun.module.repository.RepositoryUtils;
@@ -41,9 +47,19 @@ import sun.module.repository.RepositoryU
* @library ../tools
* @compile -XDignore.symbol.file LocalRepositoryTest.java ../tools/JamBuilder.java
* @run main LocalRepositoryTest
- */
+ * */
public class LocalRepositoryTest {
static final boolean debug = System.getProperty("module.debug") != null;
+
+ // Setup repository listener
+ static final BlockingQueue<RepositoryEvent> initEventQueue =
+ new LinkedBlockingQueue<RepositoryEvent>();
+ static final BlockingQueue<RepositoryEvent> shutdownEventQueue =
+ new LinkedBlockingQueue<RepositoryEvent>();
+ static final BlockingQueue<RepositoryEvent> installEventQueue =
+ new LinkedBlockingQueue<RepositoryEvent>();
+ static final BlockingQueue<RepositoryEvent> uninstallEventQueue =
+ new LinkedBlockingQueue<RepositoryEvent>();
private static void println(String s) {
if (debug) System.err.println(s);
@@ -61,6 +77,14 @@ public class LocalRepositoryTest {
}
public static void realMain(String[] args) throws Throwable {
+
+ // Enables shadow file copies in the repository if we're running
+ // on Windows. This is to prevent file locking in the
+ // source location.
+ if (System.getProperty("os.platform").equalsIgnoreCase("windows")) {
+ System.setProperty("java.module.repository.shadowcopyfiles", "true");
+ }
+
File srcDir =
new File(
System.getProperty("test.scratch", "."), "LocalRepoSrc").getCanonicalFile();
@@ -74,18 +98,43 @@ public class LocalRepositoryTest {
Repository systemRepo = Repository.getSystemRepository();
check(systemRepo != null);
+ RepositoryListener repositoryListener = new RepositoryListener() {
+ public void handleEvent(RepositoryEvent e) {
+ if (e.getType() == RepositoryEvent.Type.REPOSITORY_INITIALIZED) {
+ initEventQueue.add(e);
+ }
+ if (e.getType() == RepositoryEvent.Type.REPOSITORY_SHUTDOWN) {
+ shutdownEventQueue.add(e);
+ }
+ if (e.getType() == RepositoryEvent.Type.MODULE_INSTALLED) {
+ installEventQueue.add(e);
+ }
+ if (e.getType() == RepositoryEvent.Type.MODULE_UNINSTALLED) {
+ uninstallEventQueue.add(e);
+ }
+ }
+ };
+ Repository.addRepositoryListener(repositoryListener);
+
Map<String, String> config = new HashMap<String, String>();
- config.put("sun.module.repository.LocalRepository.expansionDirectory",
+ config.put("sun.module.repository.LocalRepository.cacheDirectory",
expandDir.getAbsolutePath());
Repository repo = Modules.newLocalRepository(
systemRepo,
"test", srcDir, config);
+ // Only REPOSITORY_INITIALIZED event should be fired.
+ check(initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(!installEventExists(repo, null));
+ check(!uninstallEventExists(repo, null));
+
// In a different repository, verify we get an exception if we require
// the source dir to exist, but it does not.
+ Repository r2 = null;
try {
config.put("sun.module.repository.LocalRepository.sourceLocationMustExist", "true");
- Repository r2 = Modules.newLocalRepository(
+ r2 = Modules.newLocalRepository(
systemRepo,
"test", new File("doesNotExist"), config);
fail();
@@ -95,9 +144,15 @@ public class LocalRepositoryTest {
unexpected(t);
}
+ // No event should be fired.
+ check(!initializeEventExists(r2));
+ check(!shutdownEventExists(r2));
+ check(!installEventExists(r2, null));
+ check(!uninstallEventExists(r2, null));
+
// Verify the repository is active and reloadable
check(repo.isActive());
- check(repo.isReloadSupported());
+ check(repo.supportsReload());
// Verify the repository is read-only, since it's source location does
// not yet exist
@@ -111,13 +166,25 @@ public class LocalRepositoryTest {
unexpected(t);
}
+ // No event should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(!installEventExists(repo, null));
+ check(!uninstallEventExists(repo, null));
+
// Check that find() and list() return nothing from repo, since the
// its source dir does not exist.
check(repo.list().size() == 0);
- check(repo.findAll().size() == 12); // java.se, java.classpath, ...
+ check(findModuleDefsInRepository(repo).size() == 0);
srcDir.mkdirs();
repo.reload();
+
+ // No event should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(!installEventExists(repo, null));
+ check(!uninstallEventExists(repo, null));
// Verify that repository is now *not* read-only
check(repo.isReadOnly() == false);
@@ -125,7 +192,7 @@ public class LocalRepositoryTest {
// Check that find() and list() return nothing from repo, since its
// source dir is empty.
check(repo.list().size() == 0);
- check(repo.findAll().size() == 12); // java.se, java.classpath, ...
+ check(findModuleDefsInRepository(repo).size() == 0);
File jamDir = makeTestDir("LocalRepoJam");
@@ -145,7 +212,14 @@ public class LocalRepositoryTest {
List<ModuleArchiveInfo> installed = repo.list();
println("=installed size " + installed.size());
check(installed.size() == 1);
- check(installed.get(0).getName().equals("LocalRepoModuleA"));
+ ModuleArchiveInfo mai = installed.get(0);
+ check(mai.getName().equals("LocalRepoModuleA"));
+
+ // MODULE_INSTALLED event should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(installEventExists(repo, mai));
+ check(!uninstallEventExists(repo, null));
// Verify module is runnable from read-only source location
runModule(repo, "LocalRepoModuleA");
@@ -163,16 +237,28 @@ public class LocalRepositoryTest {
check(installed.size() == 1);
check(installed.get(0).getName().equals("LocalRepoModuleA"));
+ // No event should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(!installEventExists(repo, null));
+ check(!uninstallEventExists(repo, null));
+
// Create platform-specific JAM
- String platform = RepositoryUtils.getPlatform();
- String arch = RepositoryUtils.getArch();
+ final String platform = RepositoryUtils.getPlatform();
+ final String arch = RepositoryUtils.getArch();
jamFile = JamBuilder.createJam(
"localrepotest", "LocalRepoTestB", "LocalRepoModuleB", "4.2",
- platform, arch, false, jamDir);
- ModuleArchiveInfo mai = repo.install(jamFile.getCanonicalFile().toURI().toURL());
+ platform, arch, true, jamDir);
+ mai = repo.install(jamFile.getCanonicalFile().toURI().toURL());
check(mai != null);
println("LocalRepoModuleB mai: " + mai);
+
+ // MODULE_INSTALLED event should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(installEventExists(repo, mai));
+ check(!uninstallEventExists(repo, null));
// Verify that same module cannot be over itself
try {
@@ -183,6 +269,12 @@ public class LocalRepositoryTest {
println("Caught expected " + ex);
}
+ // No event should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(!installEventExists(repo, null));
+ check(!uninstallEventExists(repo, null));
+
// Check that all modules are installed
installed = repo.list();
check(installed.size() == 2);
@@ -197,7 +289,15 @@ public class LocalRepositoryTest {
println("srcDir contains " + f.getName());
}
- repo.uninstall(installed.get(0));
+ mai = installed.get(0);
+ repo.uninstall(mai);
+
+ // MODULE_UNINSTALLED should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(!installEventExists(repo, null));
+ check(uninstallEventExists(repo, mai));
+
installed = repo.list();
check(installed.size() == 1);
check(installed.get(0).getName().equals("LocalRepoModuleB"));
@@ -218,9 +318,17 @@ public class LocalRepositoryTest {
mai = repo.install(jamFile.getCanonicalFile().toURI().toURL());
check(mai != null);
println("LocalRepoModuleC mai: " + mai);
+
+ // MODULE_INSTALLED event should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(installEventExists(repo, mai));
+ check(!uninstallEventExists(repo, null));
+
installed = repo.list();
check(installed.size() == 2);
- String name = installed.get(1).getName();
+ mai = installed.get(1);
+ String name = mai.getName();
check(name.equals("LocalRepoModuleC"));
ModuleDefinition md = repo.find(name);
check(md == null);
@@ -238,14 +346,26 @@ public class LocalRepositoryTest {
repo.reload();
check(repo.find(mai.getName()) == null);
+ // MODULE_UNINSTALLED event should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(!installEventExists(repo, null));
+ check(uninstallEventExists(repo, deleteMe));
+
// Verify that updating a module works
JamBuilder jb = new JamBuilder(
"localrepotest", "LocalRepoTestD", "LocalRepoModuleD", "4.2",
platform, arch, false, jamDir);
jb.setMethod("foo");
jamFile = jb.createJam();
- repo.install(jamFile.getCanonicalFile().toURI().toURL());
+ mai = repo.install(jamFile.getCanonicalFile().toURI().toURL());
runModule(repo, "LocalRepoModuleD", "foo");
+
+ // MODULE_INSTALLED event should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(installEventExists(repo, mai));
+ check(!uninstallEventExists(repo, null));
// Wait a bit before overwriting the just-created JAM
Thread.currentThread().sleep(1000);
@@ -255,11 +375,122 @@ public class LocalRepositoryTest {
jb.setMethod("bar");
jamFile = jb.createJam();
repo.reload();
+
+ // Both MODULE_UNINSTALLED and MODULE_INSTALLED events should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(installEventExists(repo, null));
+ check(uninstallEventExists(repo, mai));
+
runModule(repo, "LocalRepoModuleD", "bar");
- // XXX TODO: try reload() of a .jam.pack.gz
+
+ // If there are three modules that have the same name and version but
+ // different platform binding:
+ // 1. Specific to xyz platform and arch
+ // 2. Specific to current platform and arch
+ // 3. Platform and arch neutral
+ //
+ // If they are installed in the order of #1, #2, #3, then #2 should
+ // be used to provide the module definition.
+ // Then, if they are uninstalled in the order of #1 and #2, then no
+ // module definition would be returned from the repository even
+ // #3 still exists, because #3 has not been loaded by the repository
+ // before.
+ //
+ // On the other hand, if they are installed in the order of #1, #3,
+ // #2, then #3 should be used to provide the module definition.
+ // Then, if they are uninstalled in the order of #3 and #1, then
+ // no module definition would be returned from the repository even
+ // #2 still exists, because #2 has not been loaded by the repository.
+ //
+ File jamFile1, jamFile2, jamFile3;
+ ModuleArchiveInfo mai1, mai2, mai3;
+ jamFile1 = JamBuilder.createJam(
+ "localrepotest", "LocalRepoTestE", "LocalRepoModuleE", "7.0",
+ "xyz-platform", "xyz-arch", false, jamDir);
+ jamFile2 = JamBuilder.createJam(
+ "localrepotest", "LocalRepoTestE", "LocalRepoModuleE", "7.0",
+ platform, arch, false, jamDir);
+ jamFile3 = JamBuilder.createJam(
+ "localrepotest", "LocalRepoTestE", "LocalRepoModuleE", "7.0",
+ null, null, false, jamDir);
+
+ // Installs #1, #2, and #3
+ mai1 = repo.install(jamFile1.getCanonicalFile().toURI().toURL());
+ check(mai1 != null);
+ mai2 = repo.install(jamFile2.getCanonicalFile().toURI().toURL());
+ check(mai2 != null);
+ mai3 = repo.install(jamFile3.getCanonicalFile().toURI().toURL());
+ check(mai3 != null);
+
+ md = repo.find("LocalRepoModuleE", VersionConstraint.valueOf("7.0"));
+ check(md != null);
+ java.module.annotation.PlatformBinding platformBinding = md.getAnnotation
+ (java.module.annotation.PlatformBinding.class);
+ if (platformBinding != null) {
+ if (platformBinding.platform().equals(platform)
+ && platformBinding.arch().equals(arch)) {
+ pass();
+ } else {
+ fail();
+ }
+ } else {
+ fail();
+ }
+
+ // Uninstall #1 and #2
+ check(repo.uninstall(mai1));
+ check(repo.uninstall(mai2));
+
+ md = repo.find("LocalRepoModuleE", VersionConstraint.valueOf("7.0"));
+ check (md == null);
+
+ repo.reload();
+ md = repo.find("LocalRepoModuleE", VersionConstraint.valueOf("7.0"));
+ check (md != null);
+
+ // Uninstall #3
+ check(repo.uninstall(mai3));
+
+ // Installs #1, #3, and #2
+ mai1 = repo.install(jamFile1.getCanonicalFile().toURI().toURL());
+ check(mai1 != null);
+ mai3 = repo.install(jamFile3.getCanonicalFile().toURI().toURL());
+ check(mai3 != null);
+ mai2 = repo.install(jamFile2.getCanonicalFile().toURI().toURL());
+ check(mai2 != null);
+
+ md = repo.find("LocalRepoModuleE", VersionConstraint.valueOf("7.0"));
+ check(md != null);
+ platformBinding = md.getAnnotation
+ (java.module.annotation.PlatformBinding.class);
+ if (platformBinding == null) {
+ pass();
+ } else {
+ fail();
+ }
+
+ // Uninstall #3 and #1
+ check(repo.uninstall(mai3));
+ check(repo.uninstall(mai1));
+
+ md = repo.find("LocalRepoModuleE", VersionConstraint.valueOf("7.0"));
+ check (md == null);
+
+ // Clear event queues for the tests afterwards
+ initEventQueue.clear();
+ shutdownEventQueue.clear();
+ installEventQueue.clear();
+ uninstallEventQueue.clear();
repo.shutdown();
+
+ // REPOSITORY_SHUTDOWN event should be fired.
+ check(!initializeEventExists(repo));
+ check(shutdownEventExists(repo));
+ check(!installEventExists(repo, null));
+ check(!uninstallEventExists(repo, null));
// Verify cannot initialize() after shutdown()
try {
@@ -269,6 +500,12 @@ public class LocalRepositoryTest {
pass();
}
+ // No event should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(!installEventExists(repo, null));
+ check(!uninstallEventExists(repo, null));
+
// When not debugging and there are no failures, remove test dirs
if (!debug && failed == 0) {
JamUtils.recursiveDelete(srcDir);
@@ -276,6 +513,12 @@ public class LocalRepositoryTest {
JamUtils.recursiveDelete(expandDir);
repo.shutdown(); // sic: multiple shutdowns are OK
+
+ // No event should be fired.
+ check(!initializeEventExists(repo));
+ check(!shutdownEventExists(repo));
+ check(!installEventExists(repo, null));
+ check(!uninstallEventExists(repo, null));
}
}
@@ -311,6 +554,90 @@ public class LocalRepositoryTest {
check(methodName.equals(rc));
}
pass();
+ }
+
+ static boolean initializeEventExists(Repository repo) throws Exception {
+ // Poll REPOSITORY_INITIALIZED event
+ //
+ RepositoryEvent evt = initEventQueue.poll(2L, TimeUnit.SECONDS);
+ if (evt != null) {
+ if (evt.getType() != RepositoryEvent.Type.REPOSITORY_INITIALIZED) {
+ throw new Exception("Unexpected repository event type: " + evt.getType());
+ }
+ if (evt.getSource() != repo) {
+ throw new Exception("Unexpected repository event from: " + evt.getSource());
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ static boolean shutdownEventExists(Repository repo) throws Exception {
+ // Poll REPOSITORY_SHUTDOWN event
+ //
+ RepositoryEvent evt = shutdownEventQueue.poll(2L, TimeUnit.SECONDS);
+ if (evt != null) {
+ if (evt.getType() != RepositoryEvent.Type.REPOSITORY_SHUTDOWN) {
+ throw new Exception("Unexpected repository event type: " + evt.getType());
+ }
+ if (evt.getSource() != repo) {
+ throw new Exception("Unexpected repository event from: " + evt.getSource());
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ static boolean installEventExists(Repository repo, ModuleArchiveInfo mai) throws Exception {
+ // Poll MODULE_INSTALLED event
+ //
+ RepositoryEvent evt = installEventQueue.poll(2L, TimeUnit.SECONDS);
+ if (evt != null) {
+ if (evt.getType() != RepositoryEvent.Type.MODULE_INSTALLED) {
+ throw new Exception("Unexpected repository event type: " + evt.getType());
+ }
+ if (evt.getSource() != repo) {
+ throw new Exception("Unexpected repository event from: " + evt.getSource());
+ }
+ if (mai != null && evt.getModuleArchiveInfo() != mai) {
+ throw new Exception("Unexpected repository event for: " + evt.getModuleArchiveInfo());
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ static boolean uninstallEventExists(Repository repo, ModuleArchiveInfo mai) throws Exception {
+ // Poll MODULE_UNINSTALLED event
+ //
+ RepositoryEvent evt = uninstallEventQueue.poll(2L, TimeUnit.SECONDS);
+ if (evt != null) {
+ if (evt.getType() != RepositoryEvent.Type.MODULE_UNINSTALLED) {
+ throw new Exception("Unexpected repository event type: " + evt.getType());
+ }
+ if (evt.getSource() != repo) {
+ throw new Exception("Unexpected repository event from: " + evt.getSource());
+ }
+ if (mai != null && evt.getModuleArchiveInfo() != mai) {
+ throw new Exception("Unexpected repository event for: " + evt.getModuleArchiveInfo());
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ static List<ModuleDefinition> findModuleDefsInRepository(Repository r) {
+ List<ModuleDefinition> result = new ArrayList<ModuleDefinition>();
+ for (ModuleDefinition md : r.findAll()) {
+ if (md.getRepository() == r) {
+ result.add(md);
+ }
+ }
+ return result;
}
//--------------------- Infrastructure ---------------------------
--- a/test/java/module/repository/MetadataCompareTest.java Thu Mar 27 15:49:52 2008 -0700
+++ b/test/java/module/repository/MetadataCompareTest.java Wed Apr 02 17:59:05 2008 -0700
@@ -91,33 +91,53 @@ public class MetadataCompareTest {
check(JamUtils.recursiveDelete(repoDownloadDir));
Map<String, String> config = new HashMap<String, String>();
- config.put("sun.module.repository.URLRepository.downloadDirectory", repoDownloadDir.getCanonicalPath());
+ config.put("sun.module.repository.URLRepository.cacheDirectory", repoDownloadDir.getCanonicalPath());
urlRepo = Modules.newURLRepository(
"MDCompareTestURLRepository",
new URL(urlRepoLocation),
conf