6724362: (jam-tool) make jam tool compliant with EDR II specification, rev 1.
authorksrini
Tue Aug 05 13:00:39 2008 -0700 (15 months ago)
changeset 455ffb2dafa2dbb
parent 425af85cd8f8b56
child 4569267a03c3a44
6724362: (jam-tool) make jam tool compliant with EDR II specification, rev 1.
Summary: Incorporates most of the new features specified in latest EDR2 277 spec.
Reviewed-by: bristor, mchung, jjg
make/java/module/Makefile
src/share/classes/sun/module/JamUtils.java
src/share/classes/sun/module/MetadataParser.java
src/share/classes/sun/module/ModuleParsingException.java
src/share/classes/sun/module/tools/Jam.java
src/share/classes/sun/module/tools/Messenger.java
src/share/classes/sun/module/tools/resources/messenger.properties
src/share/classes/sun/module/tools/util/JamModuleMetadata.java
src/share/classes/sun/module/tools/util/JamToolUtils.java
src/share/classes/sun/module/tools/util/ModuleMetadata.java
src/share/classes/sun/tools/jar/Main.java
src/share/classes/sun/tools/jar/resources/jar.properties
src/share/sample/modules/README
src/share/sample/modules/dependencies/dep/Entry.java
src/share/sample/modules/dependencies/dep/module_info.java
src/share/sample/modules/dependencies/module-info.java
src/share/sample/modules/hello-world/hello/Main.java
src/share/sample/modules/hello-world/hello/module_info.java
src/share/sample/modules/hello-world/module-info.java
test/java/module/basic/BasicLauncherTests.java
test/java/module/basic/HttpRepositoryTest.java
test/java/module/basic/LauncherTestHelper.java
test/java/module/basic/Utils.java
test/java/module/query/QueryTest.java
test/java/module/repository/LegacyJarTest.java
test/java/module/repository/LibraryTest.java
test/java/module/repository/NativeLibraryTest.java
test/java/module/tools/JamBuilder.java
test/java/module/tools/jam/ChangeDirTest.java
test/java/module/tools/jam/JamTester.java
test/java/module/tools/jam/Pack200Test.java
test/java/module/tools/jam/hello/module-info.java
test/java/module/tools/jam/hello/module_info.java
test/tools/jar/ChangeDir.java
test/tools/jar/JarEntryTime.java
test/tools/jar/UpdateManifest.java
test/tools/jar/index/MetaInf.java
--- a/make/java/module/Makefile Thu Jul 24 16:11:33 2008 -0700
+++ b/make/java/module/Makefile Tue Aug 05 13:00:39 2008 -0700
@@ -60,6 +60,9 @@ SYSTEM_EXTENSION_DIR = $(LIBDIR)/module/
#
REPOSITORY_METADATA_XML = $(PKGDIR)/RepositoryMetadata.xml
+LOCALE_SET_DEFINITION = jdk
+NEW_RESOURCE_BUNDLES_PROPERTIES = sun/module/tools/resources/messenger.properties
+
#
# Rules
#
--- a/src/share/classes/sun/module/JamUtils.java Thu Jul 24 16:11:33 2008 -0700
+++ b/src/share/classes/sun/module/JamUtils.java Tue Aug 05 13:00:39 2008 -0700
@@ -60,22 +60,58 @@ public final class JamUtils {
public static final String MODULE_METADATA = "MODULE.METADATA";
+ // for Jar's sake slash is / not File.separaror
public static final String MODULE_INF_METADATA = MODULE_INF + "/" + MODULE_METADATA;
-
+ public static final String MODULE_INFO_CLASS = "module-info.class";
+ public static final String MODULE_INFO_JAVA = "module-info.java";
private static File tempDirectory = null;
static {
// Determines the temp directory.
- try {
- File tempFile = File.createTempFile("temp-directory-test-", ".tmp");
+ File tempFile = null;
+ try {
+ tempFile = File.createTempFile("temp-directory-test-", ".tmp");
tempDirectory = tempFile.getParentFile();
- tempFile.deleteOnExit();
+ } catch (IOException ioe) {
+ if (DEBUG) {
+ ioe.printStackTrace();
+ }
+ } finally {
tempFile.delete();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
+ }
+ }
+
+ public static final FileFilter DIRECTORY_FILTER = new FileFilter() {
+ public boolean accept(File pathname) {
+ return pathname.isDirectory();
+ }
+ };
+
+ public static final FilenameFilter JAM_JAR_FILTER = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".jam") || name.endsWith(".jar");
+ }
+ };
+
+ public static final FilenameFilter JAM_FILTER = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".jar") || name.endsWith(".jam") || name.endsWith(".jam.pack.gz");
+ }
+ };
+
+ public static final FilenameFilter JAR_FILTER = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".jar");
+ }
+ };
+
+ public static final FilenameFilter CLASS_FILTER = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".class");
+ }
+ };
+
+ // All static
private JamUtils() {
}
@@ -91,45 +127,34 @@ public final class JamUtils {
}
}
- public static final FileFilter DIRECTORY_FILTER = new FileFilter() {
- public boolean accept(File pathname) {
- return pathname.isDirectory();
- }
- };
-
- public static final FilenameFilter JAM_JAR_FILTER = new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return name.endsWith(".jam") || name.endsWith(".jar");
- }
- };
-
- public static final FilenameFilter JAM_FILTER = new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return name.endsWith(".jar") || name.endsWith(".jam") || name.endsWith(".jam.pack.gz");
- }
- };
-
- public static final FilenameFilter JAR_FILTER = new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return name.endsWith(".jar");
- }
- };
-
- public static final FilenameFilter CLASS_FILTER = new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return name.endsWith(".class");
- }
- };
-
-
+ /**
+ * Creates a temporary directory for jam/modules use, this is of the form
+ * /var/tmp/jam-uniqid.tmp, this can be used as a scratch
+ * directory and deleted after use.
+ * @return a File representing the temporary directory
+ * @throws java.io.IOException
+ */
public static File createTempDir() throws IOException {
- File rc = File.createTempFile("jam-" + System.currentTimeMillis(), ".tmp");
- rc.deleteOnExit();
- rc.delete();
- return rc.getParentFile();
- }
-
- public static File getTempDir() {
+ File rc = new File(getTempDir(),
+ "jam-" + System.currentTimeMillis() + ".tmp");
+ return rc.mkdirs() ? rc : null;
+ }
+
+ /**
+ * Returns system temporary directory such as /var/tmp on Unix,
+ * and whatever the temp directory is on Windows.
+ * @return the File representing the system temporary directory.
+ * @throws java.io.IOException
+ */
+ public static File getTempDir() throws IOException {
+ // initialized in the static constructor for whatever reason that fails
+ // simply retry the operation.
+ if (tempDirectory == null) {
+ File rc = File.createTempFile("jam-" + System.currentTimeMillis(), ".tmp");
+ // cache it for future use.
+ tempDirectory = rc.getParentFile().getCanonicalFile();
+ rc.delete();
+ }
return tempDirectory;
}
@@ -210,7 +235,6 @@ public final class JamUtils {
close(is);
close(os);
}
-
/**
* Unpacks data from {@code is} that is in .pack.gz form, and writes it
@@ -263,9 +287,11 @@ public final class JamUtils {
/**
* Recursively delete the given {@code dir} and all its contents.
+ * @param dir
* @return true if all deletions were successful; false if any were
* unsuccessful (all recursive deletions are attempted regardless of any
* failures).
+ * @throws java.io.IOException
*/
public static boolean recursiveDelete(File dir) throws IOException {
boolean rc = true;
@@ -302,7 +328,7 @@ public final class JamUtils {
* @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");
+ JarEntry je = jamFile.getJarEntry(MODULE_INF_METADATA);
if (je == null) {
throw new IOException(
jamFile + " does not contain MODULE-INF/MODULE.METADATA");
--- a/src/share/classes/sun/module/tools/Jam.java Thu Jul 24 16:11:33 2008 -0700
+++ b/src/share/classes/sun/module/tools/Jam.java Tue Aug 05 13:00:39 2008 -0700
@@ -30,28 +30,26 @@ import java.io.FileInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
-import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.Executors;
import java.util.jar.JarInputStream;
import java.util.jar.Pack200;
import java.util.jar.Pack200.Packer;
import java.util.zip.GZIPOutputStream;
-import java.text.MessageFormat;
+import javax.tools.JavaCompiler;
+import javax.tools.ToolProvider;
import sun.module.JamUtils;
+import sun.module.tools.util.JamModuleMetadata;
+import sun.module.ModuleParsingException;
+import sun.module.tools.util.JamToolUtils;
import sun.tools.jar.Main;
import sun.tools.jar.CommandLine;
/**
* Prototype of the Jam packaging tool.
- *
- * So far, the only feature of 'jam' not supported by the 'jar' tool is the
- * copying of the compiled module-info file to MODULE-INF/MODULE.METADATA.
- * This will likely change in the full implementation.
*
* This prototype implementation consists of some command line parsing code
* (copied from jar), plus a bit of code to deal with the module-info file
@@ -65,9 +63,10 @@ public final class Jam {
private final String program;
private String moduleName;
- private File moduleInfoDir;
private String fname, tfname;
private List<String> jarArgs;
+ private boolean printModuleInfo;
+ private boolean verbose;
public Jam(PrintStream out, PrintStream err, String program) {
this.out = out;
@@ -78,12 +77,12 @@ public final class Jam {
/*
* Starts main program with the specified arguments.
*/
- public synchronized boolean run(String args[]) {
-
- // initialize instance variables - to avoid side
- // effects if run is executed more than once.
+ public synchronized boolean run(String...args) {
+ /*
+ * initialize instance variables - to avoid side
+ * effects if run is executed more than once.
+ */
moduleName = null;
- moduleInfoDir = null;
fname = null;
tfname = null;
jarArgs = null;
@@ -91,89 +90,35 @@ public final class Jam {
if (!parseArgs(args)) {
return false;
}
- // generate module filename if not specified
- File moduleInfoFile = null;
- if (moduleInfoDir == null) {
- moduleInfoFile = new File(moduleName.replace('.', File.separatorChar)
- + File.separatorChar + "module_info.class");
- }
- else {
- moduleInfoFile = new File(moduleInfoDir,
- moduleName.replace('.', File.separatorChar)
- + File.separatorChar + "module_info.class");
- }
-
- // verify the specified module exists
- if (moduleInfoFile.isFile() == false) {
- error("Module not found: " + moduleInfoFile);
- return false;
- }
- // copy module-info file to MODULE-INF/MODULE.METADATA
- InputStream fin = null;
- OutputStream fout = null;
- File tmpDir;
- try {
- // create temp directory
- tmpDir = new File(JamUtils.createTempDir(),
- "jamtmp-" + System.currentTimeMillis());
- tmpDir.mkdirs();
- final File deleteThisDir = tmpDir;
- Runtime.getRuntime().addShutdownHook(
- Executors.defaultThreadFactory().newThread(
- new Runnable() {
- public void run() {
- try {
- JamUtils.recursiveDelete(deleteThisDir);
- } catch (IOException ex) {
- // XXX log this exception
- }
- }
- }));
-
- // copy module-info file into MODULE-INF/MODULE.METADATA
- fin = new FileInputStream(moduleInfoFile);
- File moduleInfoDir = new File(tmpDir, "MODULE-INF");
- moduleInfoDir.mkdirs();
- moduleInfoDir.deleteOnExit();
- File metadataFile = new File(moduleInfoDir, "MODULE.METADATA");
- fout = new FileOutputStream(metadataFile);
- metadataFile.deleteOnExit();
- byte[] buffer = new byte[2048];
- while (true) {
- int n = fin.read(buffer);
- if (n < 0) {
- break;
- }
- fout.write(buffer, 0, n);
- }
-
- // if the output file should be pack200-gzipped, generate the JAR
- // as a temp file.
- if (fname.endsWith(".jam.pack.gz")) {
- File tmpOutputFile = File.createTempFile("output", ".jam", tmpDir);
- tmpOutputFile.deleteOnExit();
- tfname = tmpOutputFile.getCanonicalPath();
-
- // replaces output file in jar tool's arguments
- jarArgs.remove(1);
- jarArgs.add(1, tfname);
- }
- } catch (IOException e) {
- fatalError(e);
- return false;
- } finally {
- JamUtils.close(fin);
- JamUtils.close(fout);
+ if (printModuleInfo) {
+ try {
+ if (new File(fname).exists()) {
+ output(JamModuleMetadata.printDiagnostics(fname, verbose));
+ return true;
+ }
+ error(Messenger.formatMsg("error.file.notfound", fname));
+ return false;
+ } catch (IOException ex) {
+ fatalError(ex);
+ } catch (ModuleParsingException ex) {
+ fatalError(ex);
+ }
}
// construct final arguments to JAR
- jarArgs.add("-C");
- jarArgs.add(tmpDir.getAbsolutePath());
- jarArgs.add("MODULE-INF");
- String[] argsArray = jarArgs.toArray(new String[0]);
-
+ String[] argsArray = jarArgs.toArray(new String[jarArgs.size()]);
+ JamModuleMetadata metadata = null;
+ if (moduleName != null) {
+ try {
+ metadata = new JamModuleMetadata(createMetadata());
+ } catch (IOException ex) {
+ fatalError(ex);
+ } catch (ModuleParsingException ex) {
+ fatalError(ex);
+ }
+ }
// call JAR
Main jar = new Main(out, err, program);
- if (jar.run(argsArray) == false) {
+ if (jar.jamRun(metadata, argsArray) == false) {
return false;
}
@@ -184,9 +129,10 @@ public final class Jam {
// otherwise, compress output file with pack200-gzip
JarInputStream is = null;
OutputStream os = null;
- try {
- is = new JarInputStream(new BufferedInputStream(
- new FileInputStream(tfname)));
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(tfname);
+ is = new JarInputStream(new BufferedInputStream(fis));
os = new GZIPOutputStream(new FileOutputStream(fname), 8192);
Packer packer = Pack200.newPacker();
packer.pack(is, os);
@@ -195,9 +141,10 @@ public final class Jam {
return false;
} finally {
JamUtils.close(is);
+ JamUtils.close(fis);
JamUtils.close(os);
- }
-
+ new File(tfname).delete();
+ }
return true;
}
@@ -209,15 +156,17 @@ public final class Jam {
try {
args = CommandLine.parse(args);
} catch (FileNotFoundException e) {
- fatalError(formatMsg("error.cant.open", e.getMessage()));
+ fatalError(Messenger.formatMsg("error.cant.open", e.getMessage()));
return false;
} catch (IOException e) {
fatalError(e);
return false;
}
- // Parse the args to make sure that the module is specified and only
- // 'jar' options supported by 'jam' are listed. Also, build the
- // arguments to pass to 'jar' by filtering out the module arguments.
+ /*
+ * Parse the args to make sure that the module is specified and only
+ * 'jar' options supported by 'jam' are listed. Also, build the
+ * arguments to pass to 'jar' by filtering out the module arguments.
+ */
jarArgs = new ArrayList<String>();
StringBuilder jarFlags = new StringBuilder();
int count = 1;
@@ -226,131 +175,127 @@ public final class Jam {
if (flags.startsWith("-")) {
flags = flags.substring(1);
}
- boolean cflag = false;
for (int i = 0; i < flags.length(); i++) {
char ch = flags.charAt(i);
switch (ch) {
- case 'c':
- break;
- case 'v':
- // ignore here, passed to jar
- break;
- case 'f':
- fname = args[count++];
- break;
- case 's':
- moduleName = args[count++];
- ch = '\0';
- break;
- case 'S':
- moduleInfoDir = new File(args[count++]);
- ch = '\0';
- break;
- case '0':
- // ignore here, passed to jar
- break;
- default:
- error(formatMsg("error.illegal.option",
+ case 'p':
+ printModuleInfo = true;
+ break;
+ case 'x':
+ case 't':
+ case 'c':
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'f':
+ fname = args[count++];
+ break;
+ case '0':
+ // ignore here, passed to jar
+ break;
+ default:
+ error(Messenger.formatMsg("error.invalid.option",
String.valueOf(ch)));
- usageError();
- return false;
- }
- if (ch != '\0') {
+ usageError();
+ return false;
+ }
+ if (ch != 'p') {
jarFlags.append(ch);
}
+ }
+
+ // the other args needed for jam
+ for( ; count < args.length ; count++) {
+ String opt = args[count];
+ if (opt.startsWith("-N")) {
+ moduleName = checkValue("module", args[++count]);
+ continue;
+ }
+ jarArgs.add(opt);
}
} catch (ArrayIndexOutOfBoundsException e) {
usageError();
return false;
}
- if (fname == null || moduleName == null) {
+ if (printModuleInfo == true && fname != null) {
+ return true;
+ }
+
+ if (moduleName != null) {
+ if (fname != null) {
+ error(Messenger.formatMsg("error.module.filename.conflict"));
+ usageError();
+ return false;
+ }
+ jarFlags = jarFlags.append("f");
+ fname = moduleName + ".jam";
+ } else if (fname == null) {
usageError();
return false;
}
- // module name must not contain file separator
- if (moduleName.indexOf('/') != -1 || moduleName.indexOf('\\') != -1) {
- error(program + ": module name must not contain \\ or / character.");
- return false;
- }
+
// checks file extensions
if ((fname.endsWith(".jar")
|| fname.endsWith(".jam")
|| fname.endsWith(".jam.pack.gz")) == false) {
- error(program + ": jam filename must end with .jar, .jam, or .jam.pack.gz extension.");
- return false;
- }
-
- jarArgs.add(jarFlags.toString());
- jarArgs.add(fname);
+ error(Messenger.formatMsg("error.file.suffix"));
+ return false;
+ }
+
+ jarArgs.add(0,jarFlags.toString());
+ if (fname.endsWith(".jam.pack.gz")) {
+ File tmpFile = null;
+ try {
+ File baseDir = new File(fname).getCanonicalFile().getParentFile();
+ tmpFile = File.createTempFile(program, ".tmp", baseDir);
+ tfname = tmpFile.getCanonicalPath();
+ } catch (IOException ex) {
+ fatalError(Messenger.formatMsg("error.file.create", tmpFile.getAbsolutePath()));
+ return false;
+ }
+ jarArgs.add(1, tfname);
+ } else {
+ jarArgs.add(1, fname);
+ }
for (int i = count; i < args.length; i++) {
jarArgs.add(args[i]);
}
return true;
}
- private String getMsg(String key) {
- return key;
-// try {
-// return (rsrc.getString(key));
-// } catch (MissingResourceException e) {
-// throw new Error("Error in message file");
-// }
- }
-
- private String formatMsg(String key, String arg) {
- String msg = getMsg(key);
- String[] args = new String[1];
- args[0] = arg;
- return MessageFormat.format(msg, (Object[]) args);
- }
-
+ private String checkValue(String value, String in) {
+ if (in.startsWith("-")) {
+ error(Messenger.formatMsg("error.invalid.value", value));
+ usageError();
+ }
+ return in;
+ }
/*
* Print usage message.
*/
private void usageError() {
- error("Usage: jam cfs[v0S] jam-file module-name [module-info-dir] [-C dir] files ...");
- error("Options:");
-
- error(" -c create new module archive");
- error(" -v generate verbose output on standard output");
- error(" -0 store only; use no ZIP compression");
- error(" -f specify module archive file name");
- error(" -s specify module name");
- error(" -S specify where to find module-info file");
- error(" -C change to the specified directory and include the following file");
- error("If any file is a directory then it is processed recursively.");
- error("");
- error("Example 1: to archive the hello module and its class files into a module");
- error(" archive called 'hello.jam':");
- error(" jam cvfs hello.jam hello hello/*.class");
- error("");
- error("Example 2: to archive the hello module, its class files, and all files in");
- error(" the foo/ directory into a module archive called 'hello.jam':");
- error(" jam cvfs hello.jam hello hello/*.class -C foo/ .");
- error("");
- error("Example 3: to find the module-info file from the foo/ directory and to");
- error(" archive the hello module and its class files into a module archive");
- error(" called 'hello.jam':");
- error(" jam cvfsS hello.jam hello foo/ hello/*.class");
- error("");
- error("Example 4: to archive the hello module and its class files into a module");
- error(" archive compressed with pack200-gzip called 'hello.jam.pack.gz':");
- error(" jam cvfs hello.jam.pack.gz hello hello/*.class");
+ error(program + ":" + Messenger.formatMsg("error.usage",
+ JamUtils.MODULE_INF_METADATA, JamUtils.MODULE_INFO_CLASS));
+ System.exit(1);
}
/*
* A fatal exception has been caught. No recovery possible
*/
private void fatalError(Exception e) {
- e.printStackTrace();
+ error(program + ":" + Messenger.formatMsg("error.fatal.0"));
+// e.printStackTrace(); // for debugging, FIXME
+ System.exit(1);
}
/*
* A fatal condition has been detected; message is "s".
* No recovery possible
*/
- private void fatalError(String s) {
- error(program + ": " + s);
+ private void fatalError(String msg) {
+ error(program + ":" + msg);
+ System.exit(1);
}
/**
@@ -365,11 +310,66 @@ public final class Jam {
*/
private void error(String s) {
err.println(s);
+ }
+
+ /**
+ * creates a basic metadata file with the given parameters
+ * @param module, a module name
+ * @return the metadata as a byte array
+ * @throws java.io.IOException
+ */
+ private byte[] createMetadata() throws IOException {
+ File tmpDir = null;
+ FileInputStream fis = null;
+ PrintStream mstream = null;
+ byte[] oarray = null;
+ try {
+ StringBuilder s = new StringBuilder();
+ /*
+ * note at least one annotation is required for the generation of a
+ * class file. So insert only the absolutely required annotation.
+ */
+ s = s.append("@ImportModules({\n");
+ s = s.append("@ImportModule(name=\"java.se\", version=\"1.7+\")\n");
+ s = s.append("})\n");
+ s = s.append("module " + moduleName + ";\n");
+
+ tmpDir = JamUtils.createTempDir();
+ File javaFile = new File(tmpDir, JamUtils.MODULE_INFO_JAVA);
+ mstream = new PrintStream(javaFile);
+ mstream.print(s.toString());
+ mstream.close();
+ String[] args = {"-source", "7", javaFile.getAbsolutePath()};
+ /*
+ * note we need to use JavaCompiler as this class is in jte jre,
+ * do not use com.sun.tools.javac.Main.compile(..) entry poing, then
+ * all the classloading at run time will be a-ok.
+ */
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ int rc = compiler.run(null, null, null, args);
+ if (rc != 0) {
+ throw new IOException(Messenger.formatMsg("error.file.create",
+ "metadata file"));
+ }
+
+ fis = new FileInputStream(new File(tmpDir, JamUtils.MODULE_INFO_CLASS));
+ oarray = JamUtils.getInputStreamAsBytes(fis);
+ return oarray;
+ } finally {
+ if (mstream != null) {
+ mstream.close();
+ }
+ if (fis != null) {
+ fis.close();
+ }
+ if (tmpDir != null) {
+ JamUtils.recursiveDelete(tmpDir);
+ }
+ }
}
public static void main(String[] args) {
Jam jam = new Jam(System.out, System.err, "jam");
System.exit(jam.run(args) ? 0 : 1);
}
-
}
--- a/src/share/classes/sun/module/tools/Messenger.java Thu Jul 24 16:11:33 2008 -0700
+++ b/src/share/classes/sun/module/tools/Messenger.java Tue Aug 05 13:00:39 2008 -0700
@@ -30,16 +30,25 @@ import java.io.PrintStream;
import java.io.PrintStream;
import java.security.AccessController;
import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
import sun.security.action.GetPropertyAction;
/**
* Provides a means for tools to emit messages.
*/
-class Messenger {
+public class Messenger {
public static final boolean DEBUG;
+ private static ResourceBundle rsrc;
static {
- DEBUG = (AccessController.doPrivileged(new GetPropertyAction("sun.module.tools.debug")) != null);
+ DEBUG = (AccessController.doPrivileged(new GetPropertyAction("sun.module.tools.debug")) != null);
+ try {
+ rsrc = ResourceBundle.getBundle("sun.module.tools.resources.messenger");
+ } catch (MissingResourceException e) {
+ throw new Error("Fatal: Resource for jam is missing");
+ }
+
}
protected final String program;
@@ -53,22 +62,31 @@ class Messenger {
this.err = err;
this.reader = reader;
}
-
- String getMsg(String key) {
- return key;
- // XXX i18n
-// try {
-// return (rsrc.getString(key));
-// } catch (MissingResourceException e) {
-// throw new Error("Error in message file");
-// }
+ /**
+ * Fetches the approriate message from its resource bundle
+ * @param key a string specifying the key
+ * @return the message
+ */
+ public static String getMsg(String key) {
+ //return key;
+ try {
+ return (rsrc.getString(key));
+ } catch (MissingResourceException e) {
+ return "missing resource bundle: key = \"" + key + "\", " +
+ "arguments = \"{0}\", \"{1}\", \"{2}...\"";
+ }
}
- String formatMsg(String key, String arg) {
+ /**
+ * Gets a formatted message given a key and arguments
+ * @param key a String denoting the key
+ * @param margs a set of arguments
+ * @return the desired formatted message
+ */
+ public static String formatMsg(
+ String key, String... margs) {
String msg = getMsg(key);
- String[] args = new String[1];
- args[0] = arg;
- return MessageFormat.format(msg, (Object[]) args);
+ return MessageFormat.format(msg, (Object[]) margs);
}
/*
--- a/src/share/classes/sun/tools/jar/Main.java Thu Jul 24 16:11:33 2008 -0700
+++ b/src/share/classes/sun/tools/jar/Main.java Tue Aug 05 13:00:39 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,11 @@ import java.util.jar.Manifest;
import java.util.jar.Manifest;
import java.text.MessageFormat;
import sun.misc.JarIndex;
+import sun.module.JamUtils;
+import sun.module.tools.util.JamModuleMetadata;
+import sun.module.ModuleParsingException;
+import sun.module.tools.Messenger;
+import sun.module.tools.util.JamToolUtils;
/**
* This class implements a simple utility for creating files in the JAR
@@ -70,6 +75,11 @@ class Main {
private static ResourceBundle rsrc;
+ // Jam related
+ private JamModuleMetadata metadata;
+ // Indicates if jam support is required in this instance.
+ private boolean jamSupport = false;
+
/**
* If true, maintain compatibility with JDK releases prior to 6.0 by
* timestamping extracted files with the time at which they are extracted.
@@ -120,6 +130,26 @@ class Main {
private boolean ok;
+ private String getModuleInfoClass(String[] infiles) {
+ for (String x : infiles) {
+ if (JamToolUtils.isModuleInfoClassEntry(x)) {
+ return x;
+ }
+ }
+ return null;
+ }
+
+ /*
+ * The jar tool entry point so that the jam tool can tunnel special
+ * arguments, like the metadata it also turns on the required support.
+ */
+ public synchronized boolean jamRun(JamModuleMetadata metadata, String... args) {
+ jamSupport = true;
+ this.metadata = metadata;
+ boolean rc = run(args);
+ return rc;
+ }
+
/*
* Starts main program with the specified arguments.
*/
@@ -128,6 +158,9 @@ class Main {
if (!parseArgs(args)) {
return false;
}
+ InputStream in = null;
+ OutputStream out = null;
+ FileInputStream fis = null;
try {
if (cflag || uflag) {
if (fname != null) {
@@ -142,7 +175,6 @@ class Main {
}
if (cflag) {
Manifest manifest = null;
- InputStream in = null;
if (!Mflag) {
if (mname != null) {
@@ -163,7 +195,6 @@ class Main {
addMainClass(manifest, ename);
}
}
- OutputStream out;
if (fname != null) {
out = new FileOutputStream(fname);
} else {
@@ -175,15 +206,28 @@ class Main {
vflag = false;
}
}
- create(new BufferedOutputStream(out), expand(files), manifest);
+
+ String[] infiles = expand(files);
+
+ if (jamSupport && metadata == null) {
+ String moduleinfoclass = getModuleInfoClass(infiles);
+ if (moduleinfoclass == null) {
+ fatalError(Messenger.formatMsg(
+ "error.module.file.notfound",
+ JamUtils.MODULE_INFO_CLASS));
+ return false;
+ }
+ fis = new FileInputStream(moduleinfoclass);
+ metadata = new JamModuleMetadata(fis);
+ }
+
+ create(new BufferedOutputStream(out), infiles, manifest);
if (in != null) {
in.close();
}
out.close();
} else if (uflag) {
File inputFile = null, tmpFile = null;
- FileInputStream in;
- FileOutputStream out;
if (fname != null) {
inputFile = new File(fname);
String path = inputFile.getParent();
@@ -198,8 +242,23 @@ class Main {
}
InputStream manifest = (!Mflag && (mname != null)) ?
(new FileInputStream(mname)) : null;
- expand(files);
- boolean updateOk = update(in, new BufferedOutputStream(out), manifest);
+ String[] infiles = expand(files);
+
+ if (jamSupport) {
+ String moduleinfo = getModuleInfoClass(infiles);
+ // dig the module out, as it is not being updated
+ if (moduleinfo == null) {
+ // read the module info, but don't process the Jar
+ metadata = new JamModuleMetadata(fname, false);
+ } else {
+ fis = new FileInputStream(moduleinfo);
+ metadata = new JamModuleMetadata(fis);
+ }
+ }
+
+ boolean updateOk =
+ update(in, new BufferedOutputStream(out), manifest);
+
if (ok) {
ok = updateOk;
}
@@ -218,7 +277,6 @@ class Main {
tmpFile.delete();
}
} else if (xflag || tflag) {
- InputStream in;
if (fname != null) {
in = new FileInputStream(fname);
} else {
@@ -233,6 +291,10 @@ class Main {
} else if (iflag) {
genIndex(rootjar, files);
}
+ } catch (ModuleParsingException mpe) {
+ // simply emit an error
+ error(mpe.getMessage());
+ ok = false;
} catch (IOException e) {
fatalError(e);
ok = false;
@@ -242,8 +304,12 @@ class Main {
} catch (Throwable t) {
t.printStackTrace();
ok = false;
- }
- out.flush();
+ } finally {
+ JamUtils.close(in);
+ JamUtils.close(out);
+ JamUtils.close(fis);
+ }
+ this.out.flush();
err.flush();
return ok;
}
@@ -338,6 +404,17 @@ class Main {
usageError();
return false;
}
+
+ /*
+ * support jam creation or updates of files only if jam tunnels through.
+ */
+ if ((!jamSupport && (cflag || uflag)) &&
+ (fname.endsWith(".jam") || fname.endsWith(".jam.pack.gz"))) {
+ error(getMsg("error.jam.not.supported"));
+ usageError();
+ return false;
+ }
+
/* parse file arguments */
int n = args.length - count;
if (n > 0) {
@@ -428,11 +505,12 @@ class Main {
}
/*
- * Creates a new JAR file.
+ * Creates a new JAR/JAM file.
*/
void create(OutputStream out, String[] files, Manifest manifest)
- throws IOException
+ throws IOException, ModuleParsingException
{
+ boolean haveModuleInf = false;
ZipOutputStream zos = new JarOutputStream(out);
if (flag0) {
zos.setMethod(ZipOutputStream.STORED);
@@ -456,16 +534,55 @@ class Main {
zos.closeEntry();
}
for (int i = 0; i < files.length; i++) {
+ if (!haveModuleInf) {
+ haveModuleInf = JamToolUtils.isModuleInfDirEntry(files[i]);
+ }
addFile(zos, new File(files[i]));
}
- zos.close();
+ try {
+ addMetadata(zos, vflag, flag0, haveModuleInf);
+ } finally {
+ if (zos != null)
+ zos.close();
+ }
+ }
+
+ /*
+ * adds/updates a metadata entry MODULE-INF/MODULE.METADATA to the archive
+ */
+ private void addMetadata(ZipOutputStream zos,
+ boolean vflag, boolean flag0, boolean haveModuleInf)
+ throws IOException, ModuleParsingException {
+ if (metadata != null) {
+ if (vflag) {
+ output(formatMsg("out.adding", JamUtils.MODULE_INF_METADATA));
+ }
+ ZipEntry e;
+ if (!haveModuleInf) {
+ // add the module-inf directory
+ e = new ZipEntry(JamToolUtils.getModuleInfDir());
+ e.setTime(System.currentTimeMillis());
+ e.setSize(0);
+ e.setCrc(0);
+ zos.putNextEntry(e);
+ }
+ // add the metadata now
+ e = new ZipEntry(JamUtils.MODULE_INF_METADATA);
+ e.setTime(System.currentTimeMillis());
+ if (flag0) {
+ crc32Stream(e, metadata.getInputStream());
+ }
+ zos.putNextEntry(e);
+ metadata.writeTo(zos);
+ zos.closeEntry();
+ }
}
/*
* update an existing jar file.
*/
- boolean update(InputStream in, OutputStream out,
- InputStream newManifest) throws IOException
+ boolean update(InputStream in, OutputStream out, InputStream newManifest)
+ throws IOException, ModuleParsingException
{
Hashtable t = filesTable;
Vector v = this.v;
@@ -476,6 +593,7 @@ class Main {
byte[] buf = new byte[1024];
int n = 0;
boolean updateOk = true;
+ boolean haveModuleInf = false;
if (t.containsKey(INDEX)) {
addIndex((JarIndex)t.get(INDEX), zos);
@@ -484,10 +602,11 @@ class Main {
// put the old entries first, replace if necessary
while ((e = zis.getNextEntry()) != null) {
String name = e.getName();
+ if (!haveModuleInf)
+ haveModuleInf = JamToolUtils.isModuleInfDirEntry(name);
boolean isManifestEntry = name.toUpperCase(
- java.util.Locale.ENGLISH).
- equals(MANIFEST);
+ java.util.Locale.ROOT).equals(MANIFEST);
if ((name.toUpperCase().equals(INDEX)
&& t.containsKey(INDEX))
|| (Mflag && isManifestEntry)) {
@@ -513,6 +632,9 @@ class Main {
old.read(newManifest);
}
updateManifest(old, zos);
+ } else if (jamSupport && JamToolUtils.isModuleInfMetaData(name)) {
+ // skip metadata, add it later
+ continue;
} else {
if (!t.containsKey(name)) { // copy the old stuff
@@ -558,11 +680,11 @@ class Main {
updateManifest(new Manifest(), zos);
}
}
+ addMetadata(zos, false, true, haveModuleInf);
zis.close();
zos.close();
return updateOk;
}
-
private void addIndex(JarIndex index, ZipOutputStream zos)
throws IOException
@@ -607,7 +729,6 @@ class Main {
}
}
-
private String entryName(String name) {
name = name.replace(File.separatorChar, '/');
String matchPath = "";
@@ -666,7 +787,8 @@ class Main {
/*
* Adds a new file entry to the ZIP output stream.
*/
- void addFile(ZipOutputStream zos, File file) throws IOException {
+ void addFile(ZipOutputStream zos, File file)
+ throws IOException, ModuleParsingException {
String name = file.getPath();
boolean isDir = file.isDirectory();
@@ -711,6 +833,11 @@ class Main {
zos.write(buf, 0, len);
}
is.close();
+ if (metadata != null &&
+ (file.getName().endsWith(".class") ||
+ file.getName().endsWith(".jar"))) {
+ metadata.analyzeClass(file);
+ }
}
zos.closeEntry();
/* report how much compression occurred. */
@@ -749,21 +876,26 @@ class Main {
*/
private void crc32File(ZipEntry e, File f) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(f));
+ long nread = crc32Stream(e, is);
+ long len = f.length();
+ if (nread != len) {
+ throw new JarException(formatMsg(
+ "error.incorrect.length", f.getPath()));
+ }
+ }
+
+ private long crc32Stream(ZipEntry e, InputStream is) throws IOException {
byte[] buf = new byte[1024];
crc32.reset();
int r = 0;
- int nread = 0;
- long len = f.length();
+ long nread = 0;
while ((r = is.read(buf)) != -1) {
nread += r;
crc32.update(buf, 0, r);
}
is.close();
- if (nread != (int) len) {
- throw new JarException(formatMsg(
- "error.incorrect.length", f.getPath()));
- }
e.setCrc(crc32.getValue());
+ return nread;
}
/*
@@ -902,7 +1034,8 @@ class Main {
* Output the class index table to the INDEX.LIST file of the
* root jar file.
*/
- void dumpIndex(String rootjar, JarIndex index) throws IOException {
+ void dumpIndex(String rootjar, JarIndex index) throws IOException,
+ ModuleParsingException {
filesTable.put(INDEX, index);
File scratchFile = File.createTempFile("scratch", null, new File("."));
File jarFile = new File(rootjar);
@@ -963,7 +1096,8 @@ class Main {
/**
* Generate class index file for the specified root jar file.
*/
- void genIndex(String rootjar, String[] files) throws IOException {
+ void genIndex(String rootjar, String[] files)
+ throws IOException, ModuleParsingException {
Vector jars = getJarPath(rootjar);
int njars = jars.size();
String[] jarfiles;
@@ -1044,7 +1178,6 @@ class Main {
System.exit(jartool.run(args) ? 0 : 1);
}
}
-
/*
* an OutputStream that doesn't send its output anywhere, (but could).
* It's here to find the CRC32 of a manifest, necessary for STORED only
--- a/src/share/classes/sun/tools/jar/resources/jar.properties Thu Jul 24 16:11:33 2008 -0700
+++ b/src/share/classes/sun/tools/jar/resources/jar.properties Tue Aug 05 13:00:39 2008 -0700
@@ -24,7 +24,7 @@
#
error.cant.open=\
- can''t open: {0}
+ cannot open: {0}
error.illegal.option=\
Illegal option: {0}
error.bad.option=\
@@ -34,8 +34,8 @@ error.bad.uflag=\
error.bad.uflag=\
'u' flag requires manifest, 'e' flag or input files to be specified!
error.bad.eflag=\
- 'e' flag and manifest with the 'Main-Class' attribute cannot be specified \n\
- together!
+ 'e' flag and manifest with the 'Main-Class' attribute cannot be specified \n\
+ together!
error.nosuch.fileordir=\
{0} : no such file or directory
error.write.file=\
@@ -44,6 +44,8 @@ error.create.dir=\
{0} : could not create directory
error.incorrect.length=\
incorrect length while processing: {0}
+error.jam.not.supported=\
+ jar cannot be used to create or update jam files
out.added.manifest=\
added manifest
out.update.manifest=\
--- a/src/share/sample/modules/dependencies/dep/Entry.java Thu Jul 24 16:11:33 2008 -0700
+++ b/src/share/sample/modules/dependencies/dep/Entry.java Tue Aug 05 13:00:39 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -21,6 +21,8 @@
* have any questions.
*/
+module dep;
+
package dep;
import hello.Main;
@@ -28,24 +30,6 @@ import hello.Main;
/**
* Main class of the "dep" module, which has a dependency on the "hello"
* module.
- *
- * To create the JAM file:
- * % cd sample/modules/depedencies
- * % javac -sourcepath ../hello-world dep/*.java
- * % jam cfs dep.jam dep dep/*.class
- *
- * The sample also includes pre-built files for a URLRepository in the
- * "urlrepository" directory. It can be used to launch the module either
- * locally or directly from a remote web server, for example using
- * % java -repository http://openjdk.java.net/projects/modules/samplerepo/ -module dep
- *
- * This causes the module and its dependencies to be downloaded and executed.
- * Note that the module system automatically determines from the information
- * declared in the module info file that the "hello" module is a dependency
- * and downloads and initializes it as well.
- *
- * (Note: running with a security manager is not yet supported. Execute
- * JAM files downloaded from remote servers at your own risk)
*/
public class Entry {
@@ -57,5 +41,4 @@ public class Entry {
public static void main(String[] args) {
new Entry().run(args);
}
-
}
--- a/src/share/sample/modules/dependencies/dep/module_info.java Thu Jul 24 16:11:33 2008 -0700
+++ b/src/share/sample/modules/dependencies/dep/module_info.java Tue Aug 05 13:00:39 2008 -0700
@@ -1,44 +0,0 @@
-/*
- * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package dep;
-
-import java.lang.ModuleInfo.*;
-import java.module.annotation.*;
-
-/**
- * Declare the module "dep" with its exported class "dep.Entry".
- *
- * <p>This is a emulation of a module definition. It will be changed to
- * the proper format once modules are supported by javac.
- */
-@MainClass("dep.Entry")
-@Version("1.0")
-@ImportModules({
- @ImportModule(name="java.se"),
- @ImportModule(name="hello")
-})
-// XXX: Syntax will be replaced by JSR 294
-class module_info {
- exports dep$Entry;
-}
--- a/src/share/sample/modules/hello-world/hello/Main.java Thu Jul 24 16:11:33 2008 -0700
+++ b/src/share/sample/modules/hello-world/hello/Main.java Tue Aug 05 13:00:39 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -21,21 +21,10 @@
* have any questions.
*/
+module hello;
+
package hello;
-/**
- * Main class of the module.
- *
- * <p>To build and run the module:
- * <pre>
- * [set your path to point to the "bin" directory of a OpenJDK Modules build]
- * % cd sample/modules/hello-world
- * % javac hello/*.java
- * % jam cfs hello.jam hello hello/*.class
- * % java -jam hello.jam
- * Hello world from module hello 1.0
- * </pre>
- */
public class Main {
public void run(String[] args) {
--- a/src/share/sample/modules/hello-world/hello/module_info.java Thu Jul 24 16:11:33 2008 -0700
+++ b/src/share/sample/modules/hello-world/hello/module_info.java Tue Aug 05 13:00:39 2008 -0700
@@ -1,43 +0,0 @@
-/*
- * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package hello;
-
-import java.lang.ModuleInfo.*;
-import java.module.annotation.*;
-
-/**
- * Declare the module "hello" with its exported class "hello.Main".
- *
- * <p>This is a emulation of a module definition. It will be changed to
- * the proper format once modules are supported by javac.
- */
-@MainClass("hello.Main")
-@Version("1.0")
-@ImportModules({
- @ImportModule(name="java.se")
-})
-// XXX: Syntax will be replaced by JSR 294
-class module_info {
- exports hello$Main;
-}
--- a/test/java/module/basic/BasicLauncherTests.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/java/module/basic/BasicLauncherTests.java Tue Aug 05 13:00:39 2008 -0700
@@ -23,10 +23,9 @@
/**
* @test
- * @compile -XDignore.symbol.file BasicLauncherTests.java Utils.java HttpRepositoryTest.java ../repository/URLRepositoryServer.java
+ * @compile -XDignore.symbol.file BasicLauncherTests.java Utils.java LauncherTestHelper.java HttpRepositoryTest.java ../repository/URLRepositoryServer.java
* @run main/othervm/timeout=300 BasicLauncherTests
*/
-
/*
* This is the main driver for the launcher tests, to ensure that
@@ -45,376 +44,33 @@
*/
import java.io.BufferedReader;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.io.PrintStream;
-import java.module.Version;
import java.net.URL;
-import javax.tools.JavaCompiler;
-import javax.tools.ToolProvider;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import javax.tools.JavaFileObject;
-import javax.tools.StandardJavaFileManager;
-
-enum RepoType {
- JAR_REPO, JAM_REPO, PACK_REPO
-}
+
public class BasicLauncherTests {
-
- private static RepoType repoType;
-
- final static String SEP = File.separator;
- final static String MINF = "MODULE-INF";
- final static String MD = "MODULE.METADATA";
- final static String JAVA_EXT = ".java";
- final static String CLASS_EXT = ".class";
- final static String JAM_EXT = ".jam";
- final static String JAR_EXT = ".jar";
- final static String PACK_EXT = ".pack.gz";
- final static String JAM_VERSION = "1.0.0.0";
- final static String JAM_SEP = "-";
- final static String REPO_XML = "repository-metadata.xml";
- final static String SP_NAME = "module_info";
- final static String REPODIRNAME = "repodir";
- final static String T1_JAM = "t1" + JAM_EXT;
- final static String T1_PACK = "t1" + JAM_EXT + PACK_EXT;
-
- static final String TESTJAVA = System.getProperty("java.home");
-
- private final static String WARNING_HEADER =
- "// This is a machine generated file, do not edit\n";
-
- private final static String[] JAVAC_OPTS = new String[] {
- "-source",
- "6",
- "-target",
- "6",
- "-implicit:none",
- "-Xlint:all",
- "-XDignore.symbol.file"
- };
-
-
- // The children repository directories
- static String expRepository;
- static String jamRepository;
- static String jarRepository;
- static String urlRepository ;
- static String packRepository;
-
- private final static String EXPANDED_REPO = "raw-repo";
- private final static String JAMBASED_REPO = "jam-repo";
- private final static String JARBASED_REPO = "jar-repo";
- private final static String URLBASED_REPO = "url-repo";
- private final static String PACKBASED_REPO = "pack-repo";
-
- private final static String PGM_TAIL =
- "System.exit(0);\n}\n}\n";
-
// A singleton
private BasicLauncherTests() {}
- private static JavaCompiler compiler;
-
- static {
- compiler = ToolProvider.getSystemJavaCompiler();
- }
-
- static ArrayList<File> javaFiles = new ArrayList();
- static ArrayList<File> modFiles = new ArrayList();
-
- private static void doPrintStream(String filename, StringBuilder in)
- throws FileNotFoundException {
- File f = new File(filename);
- if (f.exists()) f.delete();
- File parent = f.getParentFile();
- parent.mkdirs();
- PrintStream p = new PrintStream(f);
- p.print(new String(in));
- p.flush();
- p.close();
- if (filename.contains(SP_NAME)) {
- modFiles.add(f);
- }
- javaFiles.add(f);
- }
-
- private static void createModule(String basepath,
- String pkg,
- String otherpkg,
- String klass,
- String otherklass) throws IOException {
-
- String outpath = basepath + SEP + pkg + SEP + pkg + SEP;
- // Create the java files
- StringBuilder out = new StringBuilder();
- out = out.append(WARNING_HEADER);
- out = out.append("package " + pkg + ";\n");
- out = out.append("import java.util.*;\n");
- out = out.append("public class " + klass + " {\n");
- out = out.append(" static String[] inargs = {\"one\", \"two\", \"three\", \"four\"};\n");
- out = out.append(" public static void main(String[] args) throws Exception {\n");
- out = out.append(" Class clazz = " + klass + CLASS_EXT + ";\n");
- out = out.append(" ClassLoader cl = clazz.getClassLoader();\n");
- out = out.append(" while (cl != null) {\n");
- out = out.append(" System.out.println(\" -->\" + cl);\n");
- out = out.append(" cl = cl.getParent();\n");
- out = out.append(" }\n");
- out = out.append(" ClassLoader scl = ClassLoader.getSystemClassLoader();\n");
- out = out.append(" if (scl.getParent() != null){ \n");
- out = out.append(" System.out.println(\"Parent of System ClassLoader must be bootstrap\");\n");
- out = out.append(" System.exit(1);");
- out = out.append(" }\n");
-
- out = out.append(" System.out.println(\"System ClassLoader: \" + scl);\n");
- out = out.append(" if (!(scl instanceof sun.module.core.ProxyModuleLoader)) {\n");
- out = out.append(" throw new Exception(\"Unexpected system classloader\");\n");
- out = out.append(" }\n");
- out = out.append(" System.out.println(\"running: \" + clazz + \"/\" + clazz.getClassLoader());\n");
- out = out.append(" System.out.println(\"Args: \" + Arrays.toString(args));\n");
- out = out.append(" if (args.length != inargs.length)\n");
- out = out.append(" throw new Exception(\"Error: incorrect number of arguments\");\n");
- out = out.append(" for (int i = 0 ; i < args.length ; i++)\n");
- out = out.append(" if (!inargs[i].equals(args[i]))\n");
- out = out.append(" throw new Exception(\"Error: expected \'\" + inargs[i] + \"\' got\'\" + args[i] + \"\'\");\n");
- if (otherpkg != null) {
- out = out.append(otherpkg + "." + otherklass + ".main(args);");
- }
-
- out = out.append(PGM_TAIL);
-
- String java_file = outpath + klass + JAVA_EXT;
-
- doPrintStream(java_file, out);
-
- // Create the java definition files
- out = new StringBuilder();
- out = out.append(WARNING_HEADER);
- out = out.append("package " + pkg + ";\n");
- out = out.append("import java.lang.ModuleInfo.*;\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");
- out = out.append(" @ImportModule(name=\"java.classpath\")");
- if (otherpkg != null) {
- out = out.append(",\n @ImportModule(name=\"" + otherpkg + "\")");
- }
- out = out.append("})\n");
- out = out.append("class " + SP_NAME + "{\n");
- if (otherpkg == null) {
- out = out.append(" exports " + pkg + "$" + klass + ";");
- }
- out = out.append("\n}\n");
- String modfile = outpath + SP_NAME + JAVA_EXT;
- doPrintStream(modfile, out);
- }
-
- // Simple single file compiler
- private static void compileFile(String srcPath) throws IOException {
- String[] args = Arrays.copyOf(JAVAC_OPTS, JAVAC_OPTS.length + 1);
- args[JAVAC_OPTS.length] = srcPath;
- abort(compiler.run(null, null, null, args)==0,
- "Single-file compilation failed");
- }
-
- private static void compileFiles() throws IOException {
- @SuppressWarnings("unchecked")
- List<String> args = new ArrayList<String>(Arrays.asList(JAVAC_OPTS));
- for (File srcFile: javaFiles) {
- args.add(srcFile.getAbsolutePath());
- }
- String[] a = args.toArray(new String[0]);
- abort(compiler.run(null, null, null, a)==0,
- "Multi-file compilation failed");
- }
-
- private static void createTestJarFile() {
- PrintStream p = null;
- File clsFile = null;
- File srcFile = new File("HelloWorld.java");
-
- if (srcFile.exists()) {
- abort(srcFile.delete(), "Could not delete" + srcFile);
- }
-
- try {
- StringBuilder out = new StringBuilder(WARNING_HEADER);
- out = out.append("import java.util.logging.Level;\n");
- out = out.append("import java.util.logging.Logger;\n");
- out = out.append("public class HelloWorld {\n");
- out = out.append("public static void main(String[] args) {\n");
- out = out.append("Logger.getLogger(\"global\").log(Level.INFO,\"A Test\");\n");
- out = out.append("for (String x : args) {\n");
- out = out.append("Logger.getLogger(\"global\").log(Level.INFO, null, \"arg:\" + x);\n");
- out = out.append("System.exit(0);\n");
- out = out.append("}\n");
- out = out.append("}\n");
- out = out.append("}\n");
- p = new PrintStream(srcFile);
- p.print(new String(out));
- p.flush();
- p.close();
- compileFile(srcFile.getName());
- String fName = Utils.baseName(srcFile);
- clsFile = new File(fName + CLASS_EXT);
- sun.tools.jar.Main jartool = new sun.tools.jar.Main(
- System.out, System.err, "JarCreator");
-
- String[] args = new String[] {
- "cfe",
- jarRepository + SEP + fName + JAR_EXT,
- fName,
- clsFile.getName(),
- };
- abort(jartool.run(args), "JarCreator Failed") ;
- } catch (Exception ex) {
- unexpected(ex);
- } finally {
- if (p != null) {
- p.close();
- }
- srcFile.delete();
- clsFile.delete();
- }
- }
-
- private static void createAltMain(String basepath,
- String pkg,
- String klass,
- String altklass) throws IOException {
- StringBuilder out = new StringBuilder();
- out = out.append(WARNING_HEADER);
- out = out.append("package " + pkg + ";\n");
- out = out.append("import java.util.*;\n");
- out = out.append("import java.lang.reflect.*;\n");
- out = out.append("public class " + altklass + " {\n");
- out = out.append("public static void main(String[] args) throws Exception {\n");
- out = out.append(" Class<?> clazz = " + altklass + CLASS_EXT + ";\n");
- out = out.append(" System.out.println(\"running: \" + clazz + \"/\" +"
- + " clazz.getClassLoader());\n");
- out = out.append(" ClassLoader scl = ClassLoader.getSystemClassLoader();\n");
- out = out.append(" clazz = scl.loadClass(\"HelloWorld\");\n");
- out = out.append(" Method main = clazz.getMethod(\"main\",String[].class);\n");
- out = out.append(" main.invoke(null, (Object)args);\n");
- out = out.append(" System.exit(1);\n"); // The other main should exit with 0
- out = out.append("}\n");
- out = out.append("}\n");
- doPrintStream(basepath + SEP + pkg + SEP + pkg + SEP + altklass + JAVA_EXT, out);
- }
-
- private static void createJarRepo() throws IOException {
- createRepo0(repoType.JAR_REPO);
- createTestJarFile();
- }
-
- private static void createJamRepo() throws IOException {
- createRepo0(repoType.JAM_REPO);
- }
-
- private static void createPackRepo() throws IOException {
- createRepo0(repoType.PACK_REPO);
- }
-
- private static void createRepo0(RepoType type) throws IOException {
- for (File src: Utils.getDirs(expRepository)) {
- String dst = null;
- switch(type) {
- case JAR_REPO:
- new File(jarRepository).mkdirs();
- dst = jarRepository + SEP + src.getName() + JAR_EXT;
- Utils.makeJar(src, new File(jarRepository + SEP
- + src.getName() + JAR_EXT), "t2.Maint2");
- break;
- case JAM_REPO:
- new File(jamRepository).mkdirs();
- dst = jamRepository + SEP + src.getName() + JAM_EXT;
- Utils.makeJam(src, new File(dst));
- break;
- case PACK_REPO:
- new File(packRepository).mkdirs();
- dst = packRepository + SEP + src.getName() + JAM_EXT + PACK_EXT;
- Utils.makeJam(src, new File(dst));
- break;
- default:
- abort(false, "Should not reach here");
- }
- }
- }
-
- private static void createURLRepo() throws IOException {
- if (!new File(urlRepository).mkdirs()) {
- throw new IOException("could not mkdir " + urlRepository);
- }
-
- String httpMetaXML = urlRepository + SEP + REPO_XML;
- PrintStream repoxml = new PrintStream(httpMetaXML);
-
- repoxml.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
- repoxml.println("<modules>");
-
- File[] jamfiles = new File(jamRepository).listFiles(Utils.JAM_FILTER);
- for (File src: jamfiles) {
- repoxml.println("\t<module>");
- repoxml.println("\t\t<name>" + Utils.baseName(src) + "</name>");
- repoxml.println("\t\t<version>" + Version.valueOf(JAM_VERSION) + "</version>");
- repoxml.println("\t</module>");
- // Copy the jamFile to url repo with a version #
- File dst = new File(urlRepository + SEP + Utils.baseName(src) + SEP
- + Version.valueOf(JAM_VERSION) + SEP + Utils.baseName(src)
- + JAM_SEP + Version.valueOf(JAM_VERSION) + JAM_EXT);
- Utils.copyFile(src, dst);
- File f = new File(urlRepository + SEP + Utils.baseName(src) + SEP
- + Version.valueOf(JAM_VERSION));
- File md_src = new File(expRepository + SEP + Utils.baseName(src)
- + SEP + Utils.baseName(src) + SEP + SP_NAME + CLASS_EXT);
- File md_dst = new File(f.getCanonicalPath() + SEP + MD);
- Utils.copyFile(md_src, md_dst);
- }
- repoxml.println("</modules>");
- repoxml.flush();
- repoxml.close();
- }
-
- public static void createExpandedRepo() throws IOException {
- createModule(expRepository, "t2", null, "Maint2", null);
- createModule(expRepository, "t1", "t2", "Maint1", "Maint2");
- createAltMain(expRepository, "t1", "Maint1", "AltMaint1");
- compileFiles();
- }
public static void realMain(String[] args) throws Exception {
- abort(TESTJAVA != null, "java.home must be set");
- File testRepoDir = new File("." + SEP + REPODIRNAME).getCanonicalFile();
- Utils.recursiveDelete(testRepoDir);
-
- expRepository = testRepoDir + SEP + EXPANDED_REPO;
- createExpandedRepo();
-
- jarRepository = testRepoDir + SEP + JARBASED_REPO;
- jamRepository = testRepoDir + SEP + JAMBASED_REPO;
- packRepository = testRepoDir + SEP + PACKBASED_REPO;
- createJarRepo();
- createJamRepo();
- createPackRepo();
-
- urlRepository = testRepoDir + SEP + URLBASED_REPO;
- createURLRepo();
-
- ArrayList<TestExec> tests = new ArrayList();
+ LauncherTestHelper.createRepo();
+ // Setup the test list
+ ArrayList<TestExec> tests = new ArrayList<TestExec>();
addNegativeTests(tests);
- // XXX Uncomment when ModuleLauncher provides an ExpandedRepository
+
+ // TODO: XXX Uncomment when ModuleLauncher provides an ExpandedRepository
// addModuleTests(tests);
addJamTests(tests);
- // XXX Uncomment when ModuleLauncher supports .jam.pack.gz
+ // TODO: XXX Uncomment when ModuleLauncher supports .jam.pack.gz
// addPackTests(tests);
+
+ // run all the tests
for (TestExec t: tests) {
t.run();
}
@@ -437,7 +93,7 @@ public class BasicLauncherTests {
// run module test at an absolute directory with wrong args
t = new TestExec("negative: wrong arguments", false);
- t.repository = urlRepository;
+ t.repository = LauncherTestHelper.urlRepository;
String[] args = {"one"};
t.cmdArgs = args;
params.add(t);
@@ -447,23 +103,23 @@ public class BasicLauncherTests {
params.add(t);
t = new TestExec("negative: module and jam", false);
- t.jam = jamRepository + SEP + t.module + JAM_EXT;
- params.add(t);
-
- String jamfile = jamRepository + SEP + t.module + JAM_EXT;
+ t.jam = LauncherTestHelper.jamRepository + Utils.SEP + t.module + Utils.JAM_EXT;
+ params.add(t);
+
+ String jamfile = LauncherTestHelper.jamRepository + Utils.SEP + t.module + Utils.JAM_EXT;
t = new TestExec("negative: repository and jam", false);
- t.repository = urlRepository;
+ t.repository = LauncherTestHelper.urlRepository;
t.jam = jamfile;
t.module = null;
params.add(t);
t = new TestExec("negative: module, repository and jam", false);
t.jam = jamfile;
- t.repository = urlRepository;
- params.add(t);
-
- String jarfile = jamRepository + SEP + "t2" + JAR_EXT;
+ t.repository = LauncherTestHelper.urlRepository;
+ params.add(t);
+
+ String jarfile = LauncherTestHelper.jamRepository + Utils.SEP + "t2" + Utils.JAR_EXT;
t = new TestExec("negative: module and jar", false);
t.jar = jarfile;
@@ -471,7 +127,7 @@ public class BasicLauncherTests {
t = new TestExec("negative: repository and jar", false);
t.module = null;
- t.repository = urlRepository;
+ t.repository = LauncherTestHelper.urlRepository;
t.jar = jarfile;
params.add(t);
@@ -483,7 +139,7 @@ public class BasicLauncherTests {
t = new TestExec("negative: module, repository, jam, jar", false);
t.jam = jamfile;
- t.repository = urlRepository;
+ t.repository = LauncherTestHelper.urlRepository;
t.jar = jarfile;
params.add(t);
}
@@ -491,36 +147,38 @@ public class BasicLauncherTests {
static void addModuleTests(List<TestExec> params) throws IOException {
TestExec t;
t = new TestExec("modules: current directory");
- t.workingdir = expRepository;
+ t.workingdir = LauncherTestHelper.rawRepository;
params.add(t);
t = new TestExec("modules: relative directory");
t.workingdir = ".";
- t.repository = "." + SEP + REPODIRNAME + SEP + EXPANDED_REPO;
+ t.repository = "." + Utils.SEP + LauncherTestHelper.REPODIRNAME + Utils.SEP +
+ LauncherTestHelper.RAW_REPO;
params.add(t);
t = new TestExec("modules: absolute directory");
- t.repository = expRepository;
+ t.repository = LauncherTestHelper.rawRepository;
params.add(t);
t = new TestExec("modules: file protocol");
- t.repository =new File(urlRepository).toURI().toURL().toString();
+ t.repository =new File(LauncherTestHelper.urlRepository).toURI().toURL().toString();
params.add(t);
}
static void addJamTests(List<TestExec>params) throws IOException {
- String jamfile = jamRepository + SEP + T1_JAM;
+ String jamfile = LauncherTestHelper.jamRepository + Utils.SEP + Utils.T1_JAM;
TestExec t;
t = new TestExec("jam: current directory");
- t.workingdir = jamRepository;
- t.jam = T1_JAM;
+ t.workingdir = LauncherTestHelper.jamRepository;
+ t.jam = Utils.T1_JAM;
t.module = null;
params.add(t);
t = new TestExec("jam: relative directory");
t.workingdir = ".";
- t.jam = "." + SEP + REPODIRNAME + SEP + JAMBASED_REPO + SEP + T1_JAM;
+ t.jam = "." + Utils.SEP + LauncherTestHelper.REPODIRNAME + Utils.SEP +
+ LauncherTestHelper.JAM_REPO + Utils.SEP + Utils.T1_JAM;
t.module = null;
params.add(t);
@@ -530,15 +188,16 @@ public class BasicLauncherTests {
params.add(t);
t = new TestExec("jam: absolute directory with an alternate main");
- t.classpath = jarRepository + SEP + "HelloWorld" + JAR_EXT;
- t.jam = jamfile;
- t.module = null;
- t.modulemain = "t1.AltMaint1";
+ t.classpath = LauncherTestHelper.jarRepository + Utils.SEP +
+ "HelloWorld" + Utils.JAR_EXT;
+ t.jam = jamfile;
+ t.module = null;
+ t.modulemain = "p1.AltMaint1";
params.add(t);
}
static void addPackTests(List<TestExec>params) throws IOException {
- String jamfile = packRepository + SEP + T1_PACK;
+ String jamfile = LauncherTestHelper.packRepository + Utils.SEP + Utils.T1_PACK;
TestExec t;
t = new TestExec("jam-packed: absolute directory");
@@ -549,35 +208,15 @@ public class BasicLauncherTests {
t = new TestExec("jam-packed: absolute directory with an alternate main");
t.jam = jamfile;
t.module = null;
- t.modulemain = "t1.AltMaint1";
- params.add(t);
- }
-
-
- //--------------------- Infrastructure ---------------------------
- static volatile int passed = 0, failed = 0;
- static void abort(boolean cond, String msg) {
- if (!cond) {
- System.out.println(msg);
- ++failed;
- Thread.dumpStack();
- System.exit(1);
- }
- }
- static boolean pass() {passed++; return true;}
- static boolean fail() {failed++; Thread.dumpStack(); return false;}
- static boolean fail(String msg) {System.out.println(msg); return fail();}
- static void unexpected(Throwable t) {failed++; t.printStackTrace();}
- static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
- static boolean check(boolean cond, String msg) { boolean ret = check(cond); if (!ret) System.out.println(msg); return ret;}
- static boolean equal(Object x, Object y) {
- if (x == null ? y == null : x.equals(y)) return pass();
- else return fail(x + " not equal to " + y);}
+ t.modulemain = "p1.AltMaint1";
+ params.add(t);
+ }
public static void main(String[] args) throws Throwable {
- try {realMain(args);} catch (Throwable t) {unexpected(t);}
- System.out.println("\nPassed = " + passed + " failed = " + failed);
- if (failed > 0) throw new AssertionError("Some tests failed");
+ try {realMain(args);} catch (Throwable t) {Utils.unexpected(t);}
+ System.out.println("\nPassed = " + Utils.passed + " failed = " +
+ Utils.failed);
+ if (Utils.failed > 0) throw new AssertionError("Some tests failed");
}
}
@@ -600,8 +239,8 @@ class TestExec {
String[] cmdArgs = { "one", "two", "three", "four" };
static BasicLauncherTests blt;
- private ArrayList<String> javaCmdArgs = new ArrayList();
- private ArrayList<String> errlog = new ArrayList();
+ private ArrayList<String> javaCmdArgs = new ArrayList<String>();
+ private ArrayList<String> errlog = new ArrayList<String>();
public TestExec(String tname) {
testname = tname;
@@ -624,7 +263,8 @@ class TestExec {
}
void run() {
- String javaCmd = blt.TESTJAVA + File.separator + "bin" + File.separator + "java";
+ String javaCmd = Utils.TESTJAVA + File.separator + "bin" +
+ File.separator + "java";
if (!new File(javaCmd).exists()) {
javaCmd = javaCmd + ".exe";
}
@@ -694,19 +334,19 @@ class TestExec {
int retval = p.waitFor();
System.out.print(testname);
if (positive && retval != 0) {
- blt.fail(this.toString());
+ Utils.fail(this.toString());
System.out.println(":FAIL");
} else if (!positive && retval == 0) {
- blt.fail(this.toString());
+ Utils.fail(this.toString());
System.out.println(":FAIL");
} else {
- blt.pass();
+ Utils.pass();
System.out.println(":PASS");
}
p.destroy();
} catch (Exception ex) {
- blt.unexpected(ex);
+ Utils.unexpected(ex);
}
try {
--- a/test/java/module/basic/HttpRepositoryTest.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/java/module/basic/HttpRepositoryTest.java Tue Aug 05 13:00:39 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,12 +33,12 @@ public class HttpRepositoryTest {
public static void realMain(String[] args) throws Exception {
URLRepositoryServer server = new URLRepositoryServer(
- new File(blt.urlRepository));
+ new File(LauncherTestHelper.urlRepository));
try {
server.start();
blt.runHttpTests(server.getURL());
} catch (Throwable t) {
- blt.unexpected(t);
+ Utils.unexpected(t);
} finally {
server.stop();
}
--- a/test/java/module/basic/Utils.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/java/module/basic/Utils.java Tue Aug 05 13:00:39 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -21,31 +21,108 @@
* have any questions.
*/
+/*
+ * Utils.java
+ */
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.channels.FileChannel;
-
-/*
- * Utils.java
- *
- * Created on Jun 21, 2007, 7:56:11 AM
- *
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
-
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import javax.tools.JavaCompiler;
+import javax.tools.ToolProvider;
public class Utils {
+ final static String SEP = File.separator;
+ final static String JAVA_EXT = ".java";
+ final static String CLASS_EXT = ".class";
+ final static String JAM_EXT = ".jam";
+ final static String JAR_EXT = ".jar";
+ final static String PACK_EXT = ".pack.gz";
+ final static String JAM_VERSION = "1.0.0.0";
+ final static String JAM_SEP = "-";
+ final static String REPO_XML = "repository-metadata.xml";
+
+ final static String REPODIRNAME = "repodir";
+
+ final static String T1_JAM = "t1" + JAM_EXT;
+ final static String T1_PACK = "t1" + JAM_EXT + PACK_EXT;
+
+ static final String TESTJAVA = System.getProperty("java.home");
+
+ final static String[] JAVAC_OPTS = new String[]{
+ "-source",
+ "7",
+ "-implicit:none",
+ "-Xlint:all",
+ "-XDignore.symbol.file"
+ };
+
+ private static JavaCompiler compiler;
+
+ static {
+ compiler = ToolProvider.getSystemJavaCompiler();
+ }
// All static
private Utils() {}
- private static BasicLauncherTests blt;
+ // Simple single file compiler
+ static void compileFile(String srcPath) throws IOException {
+ String[] args = Arrays.copyOf(JAVAC_OPTS, JAVAC_OPTS.length + 1);
+ args[JAVAC_OPTS.length] = srcPath;
+ Utils.abort(compiler.run(null, null, null, args) == 0,
+ "Single-file compilation failed");
+ }
+
+ // Compiles the modules hierachy
+ static void compileFiles(File dir, String... mods) throws IOException {
+ List<String> args = new ArrayList<String>(Arrays.asList(JAVAC_OPTS));
+ for (String mod : mods) {
+ File[] pkgDirs = new File(dir, mod).listFiles(Utils.DIRECTORY_FILTER);
+ for (File pkgDir : pkgDirs) {
+ for (File srcFile : pkgDir.listFiles(Utils.JAVA_FILTER)) {
+ args.add(srcFile.getAbsolutePath());
+ }
+ }
+ }
+ String[] a = args.toArray(new String[args.size()]);
+ Utils.abort(compiler.run(null, null, null, a) == 0,
+ "Multi-file compilation failed");
+ }
+
+ /*
+ * finds files in the start directory using the the filter, appends
+ * the files to the dirList.
+ */
+ static void findFiles(File startDir, List<String> dirList, FileFilter filter)
+ throws IOException {
+ File[] foundFiles = startDir.listFiles(filter);
+ for (File f : foundFiles) {
+ dirList.add(f.toString());
+ }
+ File[] dirs = startDir.listFiles(DIRECTORY_FILTER);
+ for (File dir : dirs) {
+ findFiles(dir, dirList, filter);
+ }
+ }
+
+ // Compiles all the java files in a directory.
+ static void compileFiles(File dir) throws IOException {
+ List<String> args = new ArrayList<String>(Arrays.asList(JAVAC_OPTS));
+ findFiles(dir, args, Utils.JAVA_FILTER);
+ Utils.abort(compiler.run(null, null, null,
+ args.toArray(new String[args.size()])) == 0,
+ "Recursive compilation failed");
+ }
static String baseName(File f) {
return baseName(f.getName());
@@ -57,13 +134,19 @@ public class Utils {
static final FileFilter CLASS_FILTER = new FileFilter() {
public boolean accept(File pathname) {
- return pathname.getName().endsWith(blt.CLASS_EXT);
+ return pathname.getName().endsWith(CLASS_EXT);
+ }
+ };
+
+ static final FileFilter JAVA_FILTER = new FileFilter() {
+ public boolean accept(File pathname) {
+ return pathname.getName().endsWith(JAVA_EXT);
}
};
static final FileFilter JAM_FILTER = new FileFilter() {
public boolean accept(File pathname) {
- return pathname.getName().endsWith(blt.JAM_EXT);
+ return pathname.getName().endsWith(JAM_EXT);
}
};
@@ -73,20 +156,8 @@ public class Utils {
}
};
- // Makes a jam file in dst with contents that are in srcDir.
- static void makeJam(File srcDir, File dst) {
- sun.module.tools.Jam jamtool =
- new sun.module.tools.Jam(System.out, System.err, "JamCreator");
- String[] args = new String[] {
- "cfsS",
- dst.getAbsolutePath(),
- srcDir.getName(),
- srcDir.getAbsolutePath(),
- "-C",
- srcDir.getAbsolutePath(),
- srcDir.getName()
- };
- blt.abort(jamtool.run(args), "JamCreator Failed");
+ static void makeJar(File srcDir, File dst) {
+ makeJar(srcDir, dst, null);
}
// Makes a jar file in dst with contents that are in srcDir.
@@ -112,7 +183,64 @@ public class Utils {
"."
};
}
- blt.abort(jartool.run(args), "JarCreator Failed") ;
+ abort(jartool.run(args), "JarCreator Failed") ;
+ }
+
+ static boolean makeJar(String...args) {
+ sun.tools.jar.Main jartool =
+ new sun.tools.jar.Main(System.out, System.err, "JarCreator");
+ return jartool.run(args);
+ }
+
+ static boolean makeJar(List<String> args) {
+ return makeJar(args.toArray(new String[args.size()]));
+ }
+
+ static void makeJam(File srcDir, File dst) {
+ sun.module.tools.Jam jamtool =
+ new sun.module.tools.Jam(System.out, System.err, "JamCreator");
+ String[] args = new String[]{
+ "cf",
+ dst.getAbsolutePath(),
+ "-C",
+ srcDir.getAbsolutePath(),
+ "."
+ };
+ abort(jamtool.run(args), "JamCreator");
+ }
+
+ static boolean makeJam(String...args) {
+ sun.module.tools.Jam jamtool =
+ new sun.module.tools.Jam(System.out, System.err, "JamCreator");
+ return jamtool.run(args);
+ }
+
+ static boolean makeJam(List<String> args) {
+ return makeJam(args.toArray(new String[args.size()]));
+ }
+
+ /*
+ * given a File (ZipFile) in, extracts name to the output file
+ */
+ static void extractFileTo(File in, String name, File outFile) throws IOException {
+ ZipFile z = new ZipFile(in);
+ for (ZipEntry ze : Collections.list(z.entries())) {
+ if (ze.getName().equals(name)) {
+ byte buf[] = new byte[8192];
+ InputStream is = z.getInputStream(ze);
+ int n = is.read(buf);
+ FileOutputStream fos = new FileOutputStream(outFile);
+ while (n > 0) {
+ fos.write(buf, 0, n);
+ n = is.read(buf);
+ }
+ is.close();
+ fos.close();
+ z.close();
+ return;
+ }
+ }
+ z.close();
}
// A very fast copying method for files, takes advantage of the OS.
@@ -156,4 +284,24 @@ public class Utils {
static File[] getDirs(File dirFile) {
return dirFile.listFiles(DIRECTORY_FILTER);
}
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static void abort(boolean cond, String msg) {
+ if (!cond) {
+ System.out.println(msg);
+ ++failed;
+ Thread.dumpStack();
+ System.exit(1);
+ }
+ }
+ static boolean pass() {passed++; return true;}
+ static boolean fail() {failed++; Thread.dumpStack(); return false;}
+ static boolean fail(String msg) {System.out.println(msg); return fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
+ static boolean check(boolean cond, String msg) { boolean ret = check(cond); if (!ret) System.out.println(msg); return ret;}
+ static boolean equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) return pass();
+ else return fail(x + " not equal to " + y);}
}
--- a/test/java/module/query/QueryTest.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/java/module/query/QueryTest.java Tue Aug 05 13:00:39 2008 -0700
@@ -32,6 +32,7 @@ import java.module.PackageDefinition;
import java.module.PackageDefinition;
import java.module.Repository;
import java.module.annotation.ImportPolicyClass;
+import java.module.annotation.ExportLegacyClasses;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
@@ -44,7 +45,6 @@ import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import sun.module.annotation.LegacyClasses;
/*
* @test QueryTest.java
@@ -422,22 +422,19 @@ public class QueryTest {
try {
Map<Class, Annotation> annotations = new HashMap<Class, Annotation>();
- LegacyClasses legacyClassesAnnotation = new LegacyClasses() {
- public String[] value() {
- return new String[0];
- }
+ ExportLegacyClasses legacyClassesAnnotation = new ExportLegacyClasses() {
public Class<? extends Annotation> annotationType() {
- return LegacyClasses.class;
+ return ExportLegacyClasses.class;
}
};
- annotations.put(LegacyClasses.class, legacyClassesAnnotation);
+ annotations.put(ExportLegacyClasses.class, legacyClassesAnnotation);
HashMap<String, String> attributes = new HashMap<String, String>();
ModuleDefinition moduleDef1 = new MockModuleDefinition("javax.swing", Version.valueOf(1, 0, 0), attributes);
ModuleDefinition moduleDef2 = new MockModuleDefinition("org.foo.xml", Version.valueOf(2, 0, 0), attributes, annotations);
- Query query = Query.annotation(LegacyClasses.class);
+ Query query = Query.annotation(ExportLegacyClasses.class);
check(query.match(moduleDef1) == false);
check(query.match(moduleDef2) == true);
@@ -445,7 +442,7 @@ public class QueryTest {
check(query.equals(Query.module("org.foo.xml")) == false);
check(query.equals(Query.module("org.foo.xml", VersionConstraint.valueOf("1.0.0"))) == false);
check(query.equals(Query.attribute("my.name")) == false);
- check(query.equals(Query.annotation(LegacyClasses.class)) == true);
+ check(query.equals(Query.annotation(ExportLegacyClasses.class)) == true);
try {
query.getIndexHints(Query.MODULE_NAME_INDEX_HINTS);
--- a/test/java/module/repository/LegacyJarTest.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/java/module/repository/LegacyJarTest.java Tue Aug 05 13:00:39 2008 -0700
@@ -167,17 +167,7 @@ public class LegacyJarTest extends Libra
println("=legacyJarDir: " + legacyJarDir.getCanonicalPath());
check(legacyJarDir.isDirectory() || legacyJarDir.mkdirs());
JamUtils.copyFile(jarFile, new File(legacyJarDir, "hello.jar"));
- String[] jarArgs = new String[] {
- "uf",
- jamFile.getCanonicalPath(),
- "-C",
- jarDir.getCanonicalPath(),
- jarPath
- };
- sun.tools.jar.Main jartool =
- new sun.tools.jar.Main(System.out, System.err, "LegacyJarTest");
- jartool.run(jarArgs);
-
+ updateJam("LegacyJarTest", jamFile, jarDir, jarPath);
ModuleArchiveInfo mai = repo.install(jamFile.toURI());
check(mai != null);
try {
--- a/test/java/module/repository/LibraryTest.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/java/module/repository/LibraryTest.java Tue Aug 05 13:00:39 2008 -0700
@@ -129,6 +129,30 @@ public abstract class LibraryTest {
check(answer.equals(expectedResult));
}
+ /*
+ * FIXME, TODO, jam tool does not support update (u) option and the
+ * jar tool will not create or update a jam, the workaround for now
+ * is to rename the jam file as a jar file to get these tests to
+ * work, until the jam tool supports update.
+ */
+ void updateJam(String testName, File jamFile, File changeDir, String dirname) throws IOException {
+ String jarName = jamFile.getAbsolutePath().replace(".jam", ".jar");
+ File jarFile = new File(jarName);
+ jamFile.renameTo(jarFile);
+
+ String[] jarArgs = new String[] {
+ "uf",
+ jarFile.getCanonicalPath(),
+ "-C",
+ changeDir.getCanonicalPath(),
+ dirname
+ };
+ sun.tools.jar.Main jartool =
+ new sun.tools.jar.Main(System.out, System.err, testName);
+ jartool.run(jarArgs);
+ jarFile.renameTo(jamFile);
+ }
+
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static boolean pass() {passed++; return true;}
--- a/test/java/module/repository/NativeLibraryTest.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/java/module/repository/NativeLibraryTest.java Tue Aug 05 13:00:39 2008 -0700
@@ -210,16 +210,7 @@ public class NativeLibraryTest extends L
println("=jamLibDir: " + jamLibDir);
check(jamLibDir.isDirectory() || jamLibDir.mkdirs());
JamUtils.copyFile(nativeLibFile, new File(jamLibDir, nativeLibFile.getName()));
- String[] jarArgs = new String[] {
- "uf",
- jamFile.getCanonicalPath(),
- "-C",
- nativeLibDir.getCanonicalPath(),
- libPath
- };
- sun.tools.jar.Main jartool =
- new sun.tools.jar.Main(System.out, System.err, "NativeLibraryTest");
- jartool.run(jarArgs);
+ updateJam("NativeLibraryTest", jamFile, nativeLibDir, libPath);
}
File addTestcaseToJam(File jamFile, File nativeLibFile) throws Exception {
@@ -234,16 +225,7 @@ public class NativeLibraryTest extends L
File jamClassDir = new File(jamFile.getParentFile(), getPkgName());
println("=jamClassDir: " + jamClassDir.getCanonicalPath());
check(jamClassDir.isDirectory() || jamClassDir.mkdirs());
- String jarArgs[] = new String[] {
- "uf",
- jamFile.getCanonicalPath(),
- "-C",
- pkgDir.getCanonicalPath(),
- testcase.getParentFile().getName()
- };
- sun.tools.jar.Main jartool =
- new sun.tools.jar.Main(System.out, System.err, "NativeLibraryTest");
- jartool.run(jarArgs);
+ updateJam("NativeLibraryTest", jamFile, pkgDir, testcase.getParentFile().getName());
return testcaseDir;
}
--- a/test/java/module/tools/JamBuilder.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/java/module/tools/JamBuilder.java Tue Aug 05 13:00:39 2008 -0700
@@ -39,7 +39,17 @@ public class JamBuilder {
static final boolean DEBUG = System.getProperty("module.debug") != null;
private static void debug(String s) {
- if (DEBUG) System.err.println("### JamBuilder: " + s);
+ if (DEBUG) System.out.println("### JamBuilder: " + s);
+ }
+
+ private static void debug(String s, Object...args) {
+ if (DEBUG) {
+ System.out.print("### JamBuilder: " + s);
+ for (Object x : args) {
+ System.out.print(x + " ");
+ }
+ System.out.println("");
+ }
}
/* Directory in which this builder is started. */
@@ -231,15 +241,11 @@ public class JamBuilder {
public File createJam() throws Exception {
PrintWriter pw;
- // Create source files with the super package and main class
- File modDir = new File(tmpDir, modName);
- JamUtils.recursiveDelete(modDir);
- modDir.mkdirs();
- File modFile = new File(modDir, "module_info.java");
-
+ // Create source files with the module-info.java and main
File srcDir = new File(tmpDir, srcPkgName);
JamUtils.recursiveDelete(srcDir);
srcDir.mkdirs();
+ File modFile = new File(srcDir, JamUtils.MODULE_INFO_JAVA);
File srcFile = new File(srcDir, srcName + ".java");
createSrcFiles(modFile, srcFile);
@@ -315,29 +321,30 @@ public class JamBuilder {
platform == null ? "" : "-" + platform + "-" + arch;
File rc = new File(destDir,
modName + "-" + version + binding + ".jam");
+ String cmd = (DEBUG) ? "cvf" : "cf";
String[] args = new String[] {
- "cMf",
+ cmd,
rc.getCanonicalPath(),
"-C",
contentDir.getCanonicalPath(),
- "MODULE-INF/MODULE.METADATA",
- "-C",
- contentDir.getCanonicalPath(),
- srcPkgName + File.separator + srcName + ".class"
+ srcPkgName
};
- sun.tools.jar.Main jartool =
- new sun.tools.jar.Main(System.out, System.err, "JamBuilder");
- jartool.run(args);
- return rc;
+ sun.module.tools.Jam jamtool =
+ new sun.module.tools.Jam(System.out, System.err, "JamBuilder");
+ debug("jam args: ", (java.lang.Object[])args);
+ boolean status = jamtool.run(args);
+ if (DEBUG) {
+ debug("+module listing: " + rc.getAbsolutePath());
+ jamtool.run("pf", rc.getAbsolutePath());
+ }
+ return (status) ? rc : null;
}
/* Create a module's directory structure like this:
* <dir-path>
- * MODULE.METADATA
- * MODULE-INF
- * MODULE.METADATA
* urlrepotest
* Sample.class
+ * module-info.class
* <path>/<name>-<version>[-<platform>-<arch>].jam
* where dir-path depends on version, platform, and name: If path
* is given, then dir-path is path. If platform is given, then it
@@ -348,19 +355,13 @@ public class JamBuilder {
File contentDir = new File(tmpDir, "JamBuilderContent");
debug("content dir.mkdirs returns " + contentDir.mkdirs());
- File spFile = new File(modFile.getParent(), "module_info.class");
- JamUtils.copyFile(spFile,
- new File(contentDir, "MODULE.METADATA"));
-
- File modInfDir = new File(contentDir, "MODULE-INF");
- modInfDir.mkdirs();
- JamUtils.copyFile(spFile,
- new File(modInfDir, "MODULE.METADATA"));
-
File pkgDir = new File(contentDir, srcPkgName);
pkgDir.mkdirs();
JamUtils.copyFile(new File(srcFile.getParent(), srcName + ".class"),
new File(pkgDir, srcName + ".class"));
+ JamUtils.copyFile(new File(modFile.getParent(), JamUtils.MODULE_INFO_CLASS),
+ new File(pkgDir, JamUtils.MODULE_INFO_CLASS));
+
return contentDir;
}
@@ -369,8 +370,6 @@ public class JamBuilder {
PrintWriter pw;
pw = new PrintWriter(new FileWriter(modFile));
- pw.printf("package %s;\n\n", modName);
- pw.printf("import java.module.annotation.*;\n\n");
pw.printf("@Version(\"%s\")\n", version);
pw.printf("@MainClass(\"%s.%s\")\n", srcPkgName, srcName);
if (platform != null && arch != null) {
@@ -382,14 +381,14 @@ public class JamBuilder {
pw.printf("@ImportModules({\n");
pw.printf("\t@ImportModule(name=\"java.se\")\n");
pw.printf("})\n");
- pw.printf("class module_info {\n");
- pw.printf("}\n");
+ pw.printf("module " + modName + ";");
pw.close();
if (pw.checkError()) {
throw new Exception("Failed to write module");
}
pw = new PrintWriter(new FileWriter(srcFile));
+ pw.printf("module " + modName + ";");
pw.printf("package %s;\n\n", srcPkgName);
pw.printf("import java.util.*;\n\n");
pw.printf("public class %s {\n", srcName);
@@ -415,7 +414,7 @@ public class JamBuilder {
public static void compileFile(File src, File dest) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
- String cmd = "-source 6 -target 6 -implicit:none";
+ String cmd = "-source 7 -implicit:none";
if (DEBUG) {
cmd += " -verbose";
}
@@ -423,6 +422,9 @@ public class JamBuilder {
cmd += " -d " + dest.getCanonicalPath();
}
cmd += " " + src.getCanonicalPath();
+ if (DEBUG) {
+ debug("javac args: " + cmd);
+ }
int rc = compiler.run(null, null, null, cmd.split(" "));
if (rc != 0) {
throw new Exception("Failed to compile " + src);
--- a/test/java/module/tools/jam/ChangeDirTest.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/java/module/tools/jam/ChangeDirTest.java Tue Aug 05 13:00:39 2008 -0700
@@ -50,8 +50,10 @@ public class ChangeDirTest {
scratchDir = new File(
System.getProperty("test.scratch", ".")).getCanonicalFile();
- File modSrcFile = new File(srcDir, moduleName + File.separator + "module_info.java");
- File classSrcFile = new File(srcDir, moduleName + File.separator + "Main.java");
+ File modSrcFile = new File(srcDir, moduleName +
+ File.separator + JamUtils.MODULE_INFO_JAVA);
+ File classSrcFile = new File(srcDir, moduleName +
+ File.separator + "Main.java");
// Compile the source files
JamBuilder.compileFile(modSrcFile, scratchDir);
@@ -75,23 +77,20 @@ public class ChangeDirTest {
try {
// Create a jam file from the module-info and the classes, and the
// hello.txt file in the subdirectory. The command is equivalent to:
- //
- // jam cfsS {test.scratch}/hello.jam hello {test.scratch} \
+ // jam cf {test.scratch}/hello.jam \
// -C {test.scratch} hello/Main.class \
// -C {test.scratch} hello/module_info.class \
// -C {test.src}/a/b hello.txt
//
List<String> argList = new ArrayList<String>();
- argList.add("cfsS");
+ argList.add("cf");
argList.add(new File(scratchDir, jamName).getCanonicalPath());
- argList.add(moduleName);
- argList.add(scratchDir.getCanonicalPath());
argList.add("-C");
argList.add(scratchDir.getCanonicalPath());
argList.add(moduleName + sep + "Main.class");
argList.add("-C");
argList.add(scratchDir.getCanonicalPath());
- argList.add(moduleName + sep + "module_info.class");
+ argList.add(moduleName + sep + JamUtils.MODULE_INFO_CLASS);
argList.add("-C");
argList.add(new File(srcDir, "a" + sep + "b").getCanonicalPath());
argList.add(fileName);
@@ -99,7 +98,7 @@ public class ChangeDirTest {
String jamArgs[] = new String[argList.size()];
jamArgs = argList.toArray(jamArgs);
- Jam jamTool = new Jam(System.out, System.err, "jam");
+ Jam jamTool = new Jam(System.out, System.err, "Jammmer");
if (!jamTool.run(jamArgs)) {
fail("Could not create jam file.");
}
--- a/test/java/module/tools/jam/Pack200Test.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/java/module/tools/jam/Pack200Test.java Tue Aug 05 13:00:39 2008 -0700
@@ -37,6 +37,7 @@ import javax.tools.ToolProvider;
import javax.tools.ToolProvider;
import sun.module.JamUtils;
import sun.module.tools.Jam;
+import sun.module.tools.util.JamToolUtils;
public class Pack200Test {
private final static String jamName = "tmp.hello.jam";
@@ -55,35 +56,35 @@ public class Pack200Test {
try {
// Compile the source files
- File modSrcFile = new File(srcDir, moduleName + File.separator + "module_info.java");
- File classSrcFile = new File(srcDir, moduleName + File.separator + "Main.java");
+ File modSrcFile = new File(srcDir, moduleName +
+ File.separator + JamUtils.MODULE_INFO_JAVA);
+ File classSrcFile = new File(srcDir, moduleName +
+ File.separator + "Main.java");
JamBuilder.compileFile(modSrcFile, scratchDir);
JamBuilder.compileFile(classSrcFile, scratchDir);
// Create a pack200-gzipped jam file from the module-info and
// the classes. The command is equivalent to:
//
- // jam cfsS {test.scratch}/hello.jam.pack.gz hello {test.scratch} \
+ // jam cf {test.scratch}/hello.jam.pack.gz \
// -C {test.scratch} hello/Main.class \
- // -C {test.scratch} hello/module_info.class
+ // -C {test.scratch} hello/module-info.class
//
List<String> argList = new ArrayList<String>();
argList = new ArrayList<String>();
- argList.add("cfsS");
+ argList.add("cf");
argList.add(new File(scratchDir, packgzName).getCanonicalPath());
- argList.add(moduleName);
- argList.add(scratchDir.getCanonicalPath());
argList.add("-C");
argList.add(scratchDir.getCanonicalPath());
argList.add(moduleName + File.separator + "Main.class");
argList.add("-C");
argList.add(scratchDir.getCanonicalPath());
- argList.add(moduleName + File.separator + "module_info.class");
+ argList.add(moduleName + File.separator + JamUtils.MODULE_INFO_CLASS);
String jamArgs[] = new String[argList.size()];
jamArgs = argList.toArray(jamArgs);
- Jam jamTool = new Jam(System.out, System.err, "jam");
+ Jam jamTool = new Jam(System.out, System.err, "Jammer");
if (!jamTool.run(jamArgs)) {
fail("Could not create jam.pack.gz file.");
}
@@ -93,9 +94,12 @@ public class Pack200Test {
JarOutputStream os = null;
try {
is = new GZIPInputStream(new BufferedInputStream(
- new FileInputStream(new File(scratchDir, packgzName))), 8192);
+ new FileInputStream(
+ new File(scratchDir, packgzName))),
+ 8192);
os = new JarOutputStream(new BufferedOutputStream(
- new FileOutputStream(new File(scratchDir, jamName))));
+ new FileOutputStream(
+ new File(scratchDir, jamName))));
Pack200.Unpacker unpacker = Pack200.newUnpacker();
unpacker.unpack(is, os);
} catch (IOException e) {
@@ -114,10 +118,10 @@ public class Pack200Test {
String name = je.getName();
if ((name.equals("META-INF/")
|| name.equals("META-INF/MANIFEST.MF")
- || name.equals("MODULE-INF/")
- || name.equals("MODULE-INF/MODULE.METADATA")
- || name.equals("hello/Main.class")
- || name.equals("hello/module_info.class")) == false) {
+ || JamToolUtils.isModuleInfDirEntry(name)
+ || JamToolUtils.isModuleInfMetaData(name)
+ || JamToolUtils.isModuleInfoClassEntry(name)
+ || name.equals("hello/Main.class")) == false) {
fail("Unexpected entry: " + name);
}
if (je.isDirectory() == false && je.getSize() <= 0) {
--- a/test/java/module/tools/jam/hello/module_info.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/java/module/tools/jam/hello/module_info.java Tue Aug 05 13:00:39 2008 -0700
@@ -1,43 +0,0 @@
-/*
- * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package hello;
-
-import java.lang.ModuleInfo.*;
-import java.module.annotation.*;
-
-/**
- * Declare the module "hello" with its exported class "hello.Main".
- *
- * <p>This is a emulation of a module definition. It will be changed to
- * the proper format once modules are supported by javac.
- */
-@MainClass("hello.Main")
-@ImportModules({
- @ImportModule(name="java.se")
-})
-@Version("1.0")
-class module_info {
-
- exports hello$Main;
-}
--- a/test/tools/jar/ChangeDir.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/tools/jar/ChangeDir.java Tue Aug 05 13:00:39 2008 -0700
@@ -23,6 +23,7 @@
/**
* @test
+ * @compile -XDignore.symbol.file ChangeDir.java
* @bug 4806786
* @summary jar -C doesn't ignore multiple // in path
*/
--- a/test/tools/jar/JarEntryTime.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/tools/jar/JarEntryTime.java Tue Aug 05 13:00:39 2008 -0700
@@ -23,6 +23,7 @@
/**
* @test
+ * @compile -XDignore.symbol.file JarEntryTime.java
* @bug 4225317
* @summary Check extracted files have date as per those in the .jar file
*/
--- a/test/tools/jar/UpdateManifest.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/tools/jar/UpdateManifest.java Tue Aug 05 13:00:39 2008 -0700
@@ -23,6 +23,7 @@
/**
* @test
+ * @compile -XDignore.symbol.file UpdateManifest.java
* @bug 6434207 6442687
* @summary Ensure that jar ufm actually updates the
* existing jar file's manifest with contents of the
--- a/test/tools/jar/index/MetaInf.java Thu Jul 24 16:11:33 2008 -0700
+++ b/test/tools/jar/index/MetaInf.java Tue Aug 05 13:00:39 2008 -0700
@@ -23,6 +23,7 @@
/*
* @test
+ * @compile -XDignore.symbol.file MetaInf.java
* @bug 4408526
* @summary Index the non-meta files in META-INF, such as META-INF/services.
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/module/MetadataParser.java Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,531 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.module;
+
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * This class is a simplistic and basic class file reader, its designed
+ * specifically for the runtime classloader to read the metadata
+ * in the most efficient manner, but primarily to keep the ClassLoader footprint
+ * as small as possible.
+ *
+ * Hence it is crucial to keep this class as *lean* as possible, meaning with
+ * very few absolutely required dependencies. In order to keep the classloading
+ * to a minimum, the messages, are not resourced as we do not want to loaded
+ * resource classes, this may need to be revisited.
+ *
+ * At this time it reads a few attributes needed for module
+ * loader, and does not support Annotations as there is no specific
+ * requirement to do so, as the classloader reads annotations reflectively.
+ */
+public class MetadataParser {
+
+ int minor_version;
+ int major_version;
+ final HashMap<String, List<String>> moduleInfoMap;
+ ConstantPool cpool;
+ static final String MODULE_EXPORT_CLASS_LIST =
+ "ModuleExportClassList";
+ static final String MODULE_EXPORT_PACKAGE_LIST =
+ "ModuleExportPackageList";
+ static final String MODULE_MEMBER_PACKAGE_LIST =
+ "ModuleMemberPackageList";
+ private final ByteArrayAccessor mbuf;
+
+ boolean haveModuleExportTable = false;
+ boolean haveModuleMemberTable = false;
+
+ private static final int DEFAULT_VALUE = 0;
+
+ // the attributes we care about, the others will be ignored
+ private static final int Attribute_SourceFile = 0;
+ private static final int Attribute_Module = 1;
+ private static final int Attribute_ModuleExportTable = 2;
+ private static final int Attribute_ModuleMemberTable = 3;
+ private final String[] requiredAttributes = {
+ "SourceFile",
+ "Module",
+ "ModuleExportTable",
+ "ModuleMemberTable"
+ };
+
+ /**
+ * Construct an object given a byte array
+ * @param buf - a byte buffer
+ * @param off - an offset
+ * @param len - max length to read
+ * @throws sun.module.ModuleParsingException
+ */
+ public MetadataParser(byte[] buf, int off, int len)
+ throws ModuleParsingException {
+ mbuf = new ByteArrayAccessor(buf, off, len);
+ moduleInfoMap = parseBytes();
+ }
+
+ /**
+ * Construct an object given a byte array.
+ * @param in
+ * @throws sun.module.ModuleParsingException
+ */
+ public MetadataParser(byte[] in) throws ModuleParsingException {
+ mbuf = new ByteArrayAccessor(in);
+ moduleInfoMap = parseBytes();
+ }
+
+ private HashMap<String, List<String>> parseBytes() throws ModuleParsingException {
+ int magic = mbuf.u4();
+ if (magic != 0xCAFEBABE) {
+ throw new ModuleParsingException("content is not a metadata");
+ }
+ minor_version = mbuf.u2();
+ major_version = mbuf.u2();
+ if (major_version < 51) {
+ throw new ModuleParsingException("expected version 52+, but found " +
+ Integer.toString(major_version));
+ }
+ cpool = new ConstantPool();
+ int access_flags = mbuf.u2();
+
+ String this_class = cpool.getString(mbuf.u2());
+ if (!(this_class + ".class").endsWith(JamUtils.MODULE_INFO_CLASS)) {
+ throw new ModuleParsingException("not a valid " +
+ JamUtils.MODULE_METADATA);
+ }
+
+ String super_class = cpool.getString(mbuf.u2());
+ int interface_count = mbuf.u2();
+ if (interface_count > 0) {
+ throw new ModuleParsingException("should not contain any interfaces");
+ }
+ int fields_count = mbuf.u2();
+ if (fields_count > 0) {
+ throw new ModuleParsingException("should not contain any fields");
+ }
+
+ int methods_count = mbuf.u2();
+ if (methods_count > 0) {
+ throw new ModuleParsingException("should not contain any methods");
+ }
+ return new Attributes().getModuleInfoMap();
+ }
+
+ /**
+ * Returns the module's name as coded into the module-info file.
+ * @return a {@link String} representing the module name
+ */
+ public String getModuleName() {
+ return moduleInfoMap.get(requiredAttributes[Attribute_Module]).get(DEFAULT_VALUE);
+ }
+
+ /**
+ * Returns the module's exported class attributes as a List with or without
+ * class signature (field descriptor).
+ * Ex: with signature is L/java/lang/Object;
+ * Ex: without signature is java.lang.Object
+ * @param asSignature
+ * @return a {@link List} containing the elements
+ */
+ public List<String> getModuleExportClassList(boolean asSignature) {
+ ArrayList<String> out = new ArrayList<String>();
+ if (moduleInfoMap.get(MODULE_EXPORT_CLASS_LIST) != null) {
+ for (String x : moduleInfoMap.get(MODULE_EXPORT_CLASS_LIST)) {
+ if (asSignature) {
+ out.add(getStringAsSignature(x));
+ } else {
+ out.add(stripClassSignature(x));
+ }
+ }
+ }
+ return out;
+ }
+
+ /**
+ * Returns a list of the module's exported packages in the module metadata.
+ * Noting that an anonymous package will be denoted as an empty string ie. "".
+ * @return a {@link List} containing the elements
+ */
+ public List<String> getModuleExportPackageList() {
+ ArrayList<String> out = new ArrayList<String>();
+ if (moduleInfoMap.get(MODULE_EXPORT_PACKAGE_LIST) != null) {
+ for (String x : moduleInfoMap.get(MODULE_EXPORT_PACKAGE_LIST)) {
+ out.add(x);
+ }
+ }
+ return out;
+ }
+
+ /**
+ * returns the module's member package attribute List, without the signatures
+ * ex: com.sun.util
+ * @return a {@link List} containing the elements
+ */
+ public List<String> getModuleMemberPackageList() {
+ ArrayList<String> out = new ArrayList<String>();
+ if (moduleInfoMap.get(MODULE_MEMBER_PACKAGE_LIST) != null) {
+ for (String x : moduleInfoMap.get(MODULE_MEMBER_PACKAGE_LIST)) {
+ out.add(stripClassSignature(x));
+ }
+ }
+ return out;
+ }
+
+ /**
+ * a human readable representation of the module metadata.
+ * @return a {@link String} representation of this metadata object
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (String x : moduleInfoMap.keySet()) {
+ if (x == null) {
+ continue;
+ }
+ sb = sb.append(x + ":" + moduleInfoMap.get(x) + "\n");
+ }
+ return sb.toString();
+ }
+
+ public HashMap<String, List<String>> getModuleInfoMap() {
+ return moduleInfoMap;
+ }
+
+ public static String getPackageName(String in) {
+ int idx = in.lastIndexOf('.');
+ return (idx >= 0) ? in.substring(0, idx) : "";
+ }
+
+ public static String stripClassSignature(String in) {
+ return in.startsWith("L") && in.endsWith(";")
+ ? in.substring(1, in.length() - 1).replace("/", ".")
+ : in.replace("/", ".");
+ }
+
+ public static String getStringAsSignature(String s) {
+ return (s.startsWith("L") && s.endsWith(";"))
+ ? s
+ : "L" + s.replace(".", "/") + ";";
+ }
+
+ /*
+ * A helper class to read the Attributes we need
+ */
+ private class Attributes {
+
+ HashMap<String, List<String>> map = new HashMap<String, List<String>>();
+
+ Attributes() throws ModuleParsingException {
+ int attribute_count = mbuf.u2();
+ for (int i = 0; i < attribute_count; i++) {
+ String attributeName = cpool.getString(mbuf.u2());
+ int attribute_length = mbuf.u4();
+ if (attributeName.equals(
+ requiredAttributes[Attribute_SourceFile])) {
+ addToMap(attributeName, cpool.getString(mbuf.u2()));
+ } else if (attributeName.equals(
+ requiredAttributes[Attribute_Module])) {
+ addToMap(attributeName,
+ stripClassSignature(cpool.getString(mbuf.u2())));
+ } else if (attributeName.equals(
+ requiredAttributes[Attribute_ModuleMemberTable])) {
+ haveModuleMemberTable = true;
+ int table_length = mbuf.u2();
+ ArrayList<String> values = new ArrayList<String>();
+ for (int k = 0; k < table_length; k++) {
+ values.add(cpool.getString(mbuf.u2()));
+ }
+ addToMap(MODULE_MEMBER_PACKAGE_LIST, values);
+ } else if (attributeName.equals(
+ requiredAttributes[Attribute_ModuleExportTable])) {
+ haveModuleExportTable = true;
+
+ // ModuleExportPackageList
+ ArrayList<String> values = new ArrayList<String>();
+ int export_package_length = mbuf.u2();
+
+ for (int k = 0; k < export_package_length; k++) {
+ values.add(cpool.getString(mbuf.u2()));
+ }
+ addToMap(MODULE_EXPORT_PACKAGE_LIST, values);
+
+ // ModuleExportClassList
+ values = new ArrayList<String>();
+ int export_type_length = mbuf.u2();
+ for (int k = 0; k < export_type_length; k++) {
+ values.add(stripClassSignature(cpool.getString(mbuf.u2())));
+ }
+ addToMap(MODULE_EXPORT_CLASS_LIST, values);
+ } else {
+ long len = mbuf.skip(attribute_length);
+ if (len != attribute_length) {
+ throw new ModuleParsingException("metadata is corrupted");
+ }
+ }
+ }
+ }
+
+ private void addToMap(String name, ArrayList<String> out) {
+ out.trimToSize();
+ Collections.sort(out);
+ map.put(name, out);
+ }
+
+ private void addToMap(String name, String attrValue) {
+ ArrayList<String> tmp = new ArrayList<String>();
+ tmp.add(attrValue);
+ addToMap(name, tmp);
+ }
+
+ private HashMap<String, List<String>> getModuleInfoMap() {
+ return map;
+ }
+ }
+
+ /*
+ * A helper class to read the ConstantPool
+ */
+ private class ConstantPool {
+
+ public static final String UTF8_ENCODING = "UTF8";
+ // The constant pool constants
+ public static final int CONSTANT_Utf8 = 1;
+ public static final int CONSTANT_Integer = 3;
+ public static final int CONSTANT_Float = 4;
+ public static final int CONSTANT_Long = 5;
+ public static final int CONSTANT_Double = 6;
+ public static final int CONSTANT_Class = 7;
+ public static final int CONSTANT_String = 8;
+ public static final int CONSTANT_Fieldref = 9;
+ public static final int CONSTANT_Methodref = 10;
+ public static final int CONSTANT_InterfaceMethodref = 11;
+ public static final int CONSTANT_NameAndType = 12;
+ ArrayList<CPInfo> cpoolList = new ArrayList<CPInfo>();
+ String[] cpName;
+ byte[] cpTag;
+ int cpLen;
+ ByteArrayOutputStream buf = new ByteArrayOutputStream(1024);
+ private final String[] cpTagName = {
+ /* 0: */null,
+ /* 1: */ "Utf8",
+ /* 2: */ null,
+ /* 3: */ "Integer",
+ /* 4: */ "Float",
+ /* 5: */ "Long",
+ /* 6: */ "Double",
+ /* 7: */ "Class",
+ /* 8: */ "String",
+ /* 9: */ "Fieldref",
+ /* 10: */ "Methodref",
+ /* 11: */ "InterfaceMethodref",
+ /* 12: */ "NameAndType",
+ null
+ };
+
+ private ConstantPool() throws ModuleParsingException {
+ cpoolList.add(null);
+ cpLen = mbuf.u2();
+ cpName = new String[cpLen];
+ cpTag = new byte[cpLen];
+ readCP();
+ }
+
+ private void readCP() throws ModuleParsingException {
+ int cpTem[][] = new int[cpLen][];
+ for (int i = 1; i < cpLen; i++) {
+ try {
+ cpTag[i] = (byte) mbuf.u1();
+ switch (cpTag[i]) {
+ case CONSTANT_Utf8:
+ buf.reset();
+ for (int len = mbuf.u2(), j = 0; j < len; j++) {
+ buf.write(mbuf.u1());
+ }
+ cpName[i] = buf.toString(UTF8_ENCODING);
+ break;
+ case CONSTANT_Integer:
+ cpName[i] = String.valueOf(mbuf.u4());
+ break;
+ case CONSTANT_Float:
+ cpName[i] =
+ String.valueOf(Float.intBitsToFloat(mbuf.u4()));
+ break;
+ case CONSTANT_Long:
+ cpName[i] = String.valueOf(mbuf.u8());
+ i += 1;
+ break;
+ case CONSTANT_Double:
+ cpName[i] =
+ String.valueOf(Double.longBitsToDouble(mbuf.u8()));
+ i += 1;
+ break;
+ case CONSTANT_Class:
+ case CONSTANT_String:
+ cpTem[i] = new int[]{mbuf.u2()};
+ break;
+ case CONSTANT_Fieldref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InterfaceMethodref:
+ case CONSTANT_NameAndType:
+ cpTem[i] = new int[]{mbuf.u2(), mbuf.u2()};
+ break;
+ }
+ } catch (UnsupportedEncodingException ex) {
+ throw new ModuleParsingException(ex);
+ }
+ }
+ for (int i = 1; i < cpLen; i++) {
+ switch (cpTag[i]) {
+ case CONSTANT_Class:
+ case CONSTANT_String:
+ cpName[i] = cpName[cpTem[i][0]];
+ break;
+ case CONSTANT_NameAndType:
+ cpName[i] = cpName[cpTem[i][0]] + " " +
+ cpName[cpTem[i][1]];
+ break;
+ }
+ }
+ // do fieldref et al after nameandtype are all resolved
+ for (int i = 1; i < cpLen; i++) {
+ switch (cpTag[i]) {
+ case CONSTANT_Fieldref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InterfaceMethodref:
+ cpName[i] = cpName[cpTem[i][0]] + " " +
+ cpName[cpTem[i][1]];
+ break;
+ }
+ }
+ for (int i = 0; i < cpName.length; i++) {
+ if (cpName[i] == null) {
+ continue;
+ }
+ CPInfo cpinfo = new CPInfo(getCpTagName(cpTag[i]), cpName[i]);
+ cpoolList.add(i, cpinfo);
+ }
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (CPInfo x : cpoolList) {
+ sb = sb.append(x);
+ }
+ return sb.toString();
+ }
+
+ public String getString(int index) {
+ return cpoolList.get(index).cpname;
+ }
+
+ private String getCpName(int id) {
+ if (id >= 0 && id < cpName.length) {
+ return cpName[id];
+ } else {
+ return "[CP#" + Integer.toHexString(id) + "]";
+ }
+ }
+
+ private String getCpTagName(int t) {
+ t &= 0xFF;
+ String ts = null;
+ if (t < cpTagName.length) {
+ ts = cpTagName[t];
+ }
+ if (ts != null) {
+ return ts;
+ }
+ return ("UnknownTag" + t).intern();
+ }
+
+ private class CPInfo {
+ String cptag;
+ String cpname;
+
+ CPInfo(String cptag, String cpname) {
+ this.cptag = cptag;
+ this.cpname = cpname;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb = sb.append(cptag);
+ sb = sb.append(":");
+ sb = sb.append(cpname);
+ return sb.toString();
+ }
+ }
+ }
+
+ /*
+ * a simple byte area reader, it is designed to read directly from
+ * a byte array without the need for the ByteArrayInputStream.
+ */
+ private class ByteArrayAccessor {
+ private final byte[] in;
+ private int pos;
+ private int len;
+
+ ByteArrayAccessor(byte[] buffer) {
+ this.in = buffer;
+ this.pos = 0;
+ this.len = buffer.length;
+ }
+
+ ByteArrayAccessor(byte[] buffer, int off, int len) {
+ this.in = buffer;
+ this.pos = off;
+ this.len = len;
+ }
+
+ private long u8() {
+ return ((long) u4() << 32) + (((long) u4() << 32) >>> 32);
+ }
+
+ private int u4() {
+ return (u2() << 16) + u2();
+ }
+
+ private int u2() {
+ return (u1() << 8) + u1();
+ }
+
+ private int u1() {
+ int x = this.in[pos];
+ pos++;
+ return x & 0xFF;
+ }
+
+ private int skip(int len) {
+ if ((pos + len) > this.len || len < 0) {
+ return -1;
+ }
+ pos += len;
+ return len;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/module/ModuleParsingException.java Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.module;
+
+
+public class ModuleParsingException extends Exception {
+ static final long serialVersionUID = -3387516993124229948L;
+
+ /**
+ * a null constructor
+ */
+ public ModuleParsingException() { }
+
+ /**
+ * Creates an exception with the given parameter
+ * @param message
+ */
+ public ModuleParsingException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates an exception with the given parameter
+ * @param t
+ */
+ public ModuleParsingException(Throwable t) {
+ super(t);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/module/tools/resources/messenger.properties Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,107 @@
+#
+# Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+error.usage=\
+Usage: jam cptxf[v0] jam-file [-N module] [-C dir] files ...\n\
+\ Options:\n\
+\ -c create new module archive\n\
+\ -p print the {0}\n\
+\ -x extract the archive\n\
+\ -t list the contents of the archive\n\
+\ -v generate verbose output on standard output\n\
+\ -0 store only; use no ZIP compression\n\
+\ -f specify module archive file name\n\
+\ -C change to the specified directory and include the following file\n\
+\ -N module-name to be used, to construct the\n\
+\ {0}\n\
+If any file is a directory, then it is processed recursively.\n\n\
+Example 1: to archive the hello module and its class files into a module\n\
+\ archive called 'hello.jam':\n\
+\ jam cvf hello.jam hello/*.class\n\n\
+Example 2: to archive the hello module, its class files, and all files in\n\
+\ the foo/ directory into a module archive called 'hello.jam':\n\
+\ jam cvf hello.jam hello/*.class -C foo/ .\n\n\
+Example 3: to archive the hello module and its class files into a module\n\
+\ archive compressed with pack200-gzip called 'hello.jam.pack.gz':\n\
+\ jam cvf hello.jam.pack.gz hello/*.class\n\n\
+Example 4: to print the {0} in the archive\n\
+\ jam pf hello.jam\n\n\
+Example 5: to print the {0} in the archive and learn why a class\n\
+\ a class is not being exported:
+\ jam pvf hello.jam\n\n\
+Example 6: to create a module without a {1}\n\
+\ jam cv -N foo.bar.AModule foo\n\
+\ will create module foo.bar.AModule.jam in the current directory
+error.cant.open=\
+ cannnot open: {0}
+error.file.create =\
+ could not create file {0}
+error.file.notfound =\
+ file not found {0}
+error.file.not.contain =\
+ {0} does not contain {1}
+error.file.suffix =\
+ jam filename must end with .jar, .jam or .jam.pack.gz extensions
+error.fatal.0 =\
+ a fatal error has occured
+error.fatal.1 =\
+ a fatal error has occured, {0}
+error.module.file.notfound =\
+ no {0} found in the input files
+error.module.files.notfound =\
+ no {0} or {1} found in the archive
+error.module.file.found =\
+ the input files should not contain {0}
+error.module.files.found =\
+ this archive {0} should not contain {1} or {2}
+error.module.parsing.done =\
+ all analysis of classes has been completed;
+error.jam.signer =\
+ not all entries in the JAM file are signed consistently by the same set of signers: {0}
+error.url.notfile =\
+ not a file URL: {0}
+error.url.parsing =\
+ URI parsing error
+error.invalid.option =\
+ error invalid option {0}
+error.invalid.value =\
+ error {0} cannot start with '-'
+error.module.filename.conflict =\
+ a filename cannot be specified with -N option
+error.module.wrong.module =\
+ the module {0} should not contain class {1} which is a member of {2}
+info.class.notmodule =\
+ is not a member of any module
+info.class.notpublic =\
+ is not public
+info.jar.notembedded =\
+ ignored: {0} is not an embedded jar
+info.unexported.header =\
+ Classes not exported:
+error.module.not.file =\
+ is not a {0} file
+error.module.version.mismatch =\
+ expected version {0} but found {1}
+error.module.not.contain =\
+ metadata should not contain {0}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/module/tools/util/JamModuleMetadata.java Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,655 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.module.tools.util;
+
+import com.sun.tools.classfile.AccessFlags;
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.Attributes;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ClassTranslator;
+import com.sun.tools.classfile.ClassWriter;
+import com.sun.tools.classfile.ConstantPool.CPInfo;
+import com.sun.tools.classfile.ConstantPool;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.ModuleExportTable_attribute;
+import com.sun.tools.classfile.ModuleMemberTable_attribute;
+import com.sun.tools.classfile.Module_attribute;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+import sun.module.JamUtils;
+import sun.module.MetadataParser;
+import sun.module.ModuleParsingException;
+import sun.module.tools.Messenger;
+
+
+/**
+ * This class is the main helper class for the jar and jam utility tools,
+ * which constructs and prepares a module metdata files, based on the
+ * rules by analyzing the classes or Jars fed to it.
+ */
+public class JamModuleMetadata extends ModuleMetadata {
+ private Set<String> moduleExportClassList;
+ private Set<String> moduleExportPackageList;
+ private Set<String> moduleMemberPackageList;
+ private Set<UnexportedClass> moduleUnexportedClassList;
+ // the modified module_info
+ private ClassFile moduleInfoClassFile;
+ private boolean done = false;
+
+ /**
+ * Construct an object from a JAR-file, based on {@code analyze}, if true
+ * will completely build an unmodifiable object, if it is set to false then,
+ * analyzeClass can be called to incrementally to analyze and update the
+ * metadata object. This method is called and required for jar update logic.
+ *
+ * @param jarFile
+ * @param analyze
+ * @throws java.io.IOException
+ * @throws sun.module.ModuleParsingException
+ */
+ public JamModuleMetadata(File jarFile, boolean analyze)
+ throws IOException, ModuleParsingException {
+ super(jarFile);
+ initSets();
+ if (analyze) {
+ processJar(jarFile, true);
+ }
+ }
+
+ public JamModuleMetadata(String jarFileName, boolean analyze)
+ throws IOException, ModuleParsingException {
+ this(new File(jarFileName), analyze);
+ }
+ /**
+ * Construct an object with a given skeletal module metadata file, this
+ * typically created by the JAM tool, as an ease of use feature for simple
+ * modules.
+ * @param metadata a metadata files
+ * @throws sun.module.ModuleParsingException
+ */
+ public JamModuleMetadata(byte[] metadata) throws ModuleParsingException {
+ super(metadata);
+ initSets();
+ }
+
+ /**
+ * Contruct an object with an InputStream of a ModuleMetaData
+ * file this is used by the Jar tool to create a JamModuleMetaData file and
+ * incrementally update, by calling analyzeClass methods.
+ * @param is
+ * @throws java.io.IOException
+ * @throws sun.module.ModuleParsingException
+ */
+ public JamModuleMetadata(InputStream is)
+ throws IOException, ModuleParsingException {
+ super(is);
+ initSets();
+ }
+
+ /*
+ * Construct an unmodifiable object from a JAR-file, it is used internally
+ * for analyzing an entire jar, solely for diagnostic purposes.
+ * @param jarFileName
+ * @param analyze
+ * @throws java.io.IOException
+ * @throws sun.module.tools.util.ModuleParsingException
+ */
+ private JamModuleMetadata(File jarFile)
+ throws IOException, ModuleParsingException {
+ super(jarFile);
+ initSets();
+ processJar(jarFile, false);
+ }
+
+ private void initSets() {
+ moduleExportClassList = new LinkedHashSet<String>();
+ moduleExportPackageList = new LinkedHashSet<String>();
+ moduleMemberPackageList = new LinkedHashSet<String>();
+ moduleUnexportedClassList = new LinkedHashSet<UnexportedClass>();
+ }
+ /**
+ * Writes the newly created module metadata file to a desired
+ * OutputStream, once this method is called this object can no
+ * longer be modified.
+ * @param os
+ * @throws java.io.IOException
+ * @throws sun.module.ModuleParsingException
+ */
+ public void writeTo(OutputStream os)
+ throws IOException, ModuleParsingException {
+ if (moduleInfoClassFile == null) {
+ finish();
+ }
+ ClassWriter c = new ClassWriter();
+ c.write(moduleInfoClassFile, os);
+ }
+
+ /**
+ * Returns the new created module meta data file as an @see InputStream,
+ * once this method is called the object can no longer be modified.
+ * @return {@link InputStream}
+ * @throws java.io.IOException
+ * @throws sun.module.ModuleParsingException
+ */
+ public InputStream getInputStream()
+ throws IOException, ModuleParsingException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ writeTo(baos);
+ return new ByteArrayInputStream(baos.toByteArray());
+ }
+
+ /**
+ * Analyze a class for module information.
+ * @param is
+ * @throws java.io.IOException
+ * @throws sun.module.ModuleParsingException
+ */
+ public void analyzeClass(InputStream is)
+ throws IOException, ModuleParsingException {
+ analyzeClass(is, null);
+ }
+
+ private void analyzeClass(InputStream is, UnexportedClass uc)
+ throws IOException, ModuleParsingException {
+ if (done) {
+ throw new ModuleParsingException(Messenger.getMsg(
+ "error.module.parsing.done"));
+ }
+ try {
+ ClassFile cf = ClassFile.read(is, afactory);
+ String cls = cf.getName();
+ String member = getMemberPackage(cf);
+ if (member != null) {
+ moduleMemberPackageList.add(member);
+ }
+ if (canExportClass(cf, uc)) {
+ moduleExportClassList.add("L" + cls + ";");
+ moduleExportPackageList.add(MetadataParser.getPackageName(
+ cls.replace("/", ".")));
+ }
+ } catch (ConstantPoolException cpe) {
+ throw new ModuleParsingException(cpe.getMessage());
+ }
+ }
+
+ /**
+ * Analyze a class for module information, if the File is JarFile then
+ * the contents of the JarFile will be analyzed, each entry in the archive
+ * will be treated as if it is any other class.
+ * @param in
+ * @throws sun.module.ModuleParsingException
+ * @throws java.io.IOException
+ */
+ public void analyzeClass(File in)
+ throws ModuleParsingException, IOException {
+ if (done) {
+ throw new ModuleParsingException(
+ Messenger.getMsg("error.module.parsing.done"));
+ }
+ if (in.getName().endsWith(".jar")) {
+ analyzeJar(in);
+ } else if (!JamToolUtils.isModuleInfoClass(in.getName())) {
+ FileInputStream is = new FileInputStream(in);
+ try {
+ analyzeClass(is);
+ } finally {
+ JamUtils.close(is);
+ }
+ }
+ }
+
+ /**
+ * Analyzes the contents of an entire JAR archive, it is intended to be used
+ * while analyzing an embedded JAR archive in a JAM, the analysis proceeds
+ * only if the JAR exists in specified directory MODULE-INF/lib or if
+ * specified by the JarLibraryPath annotation.
+ * @param in
+ * @throws sun.module.ModuleParsingException
+ * @throws java.io.IOException
+ */
+ public void analyzeJar(File in) throws ModuleParsingException, IOException {
+ if (!isEmbeddedJar(in)) {
+ return; // check and return without much ado
+ }
+ ZipFile zf = null;
+ try {
+ zf = new ZipFile(in);
+ for (ZipEntry ze : Collections.list(zf.entries())) {
+ if (ze.getName().endsWith(".class")) {
+ analyzeClass(zf.getInputStream(ze));
+ } else if (JamToolUtils.isModuleInfoClassEntry(ze.getName()) ||
+ JamToolUtils.isModuleInfMetaData(ze.getName())){
+ throw new ModuleParsingException(
+ Messenger.formatMsg("error.module.files.found",
+ in.getAbsolutePath(),
+ JamUtils.MODULE_INF_METADATA,
+ JamUtils.MODULE_INF_METADATA));
+ }
+ }
+ } finally {
+ JamUtils.close(zf);
+ }
+ }
+
+ private boolean isEmbeddedJar(String in) {
+ return isEmbeddedJar(new File(in));
+ }
+
+ private boolean isEmbeddedJar(File in) {
+ String entryDirname = in.getParent().replace('\\', '/');
+ if (entryDirname.endsWith(JamToolUtils.getModuleInfDir() + "lib")) {
+ return true;
+ } else {
+ String s = getJarLibraryPath();
+ if (s != null) {
+ return entryDirname.endsWith(s);
+ }
+ }
+ return false;
+ }
+
+ /*
+ * a strict check if a class does belong to a module, and throw
+ * an Exception if it does not follow the rules.
+ * Assumption:
+ * A legacy class has no module affliation.
+ * Logic:
+ * a. a legacy class is false
+ * b. a module class affiliated to this module, true.
+ * c. a module class not affliated to this module, error.
+ */
+ private boolean isMemberClass(ClassFile cf) throws ModuleParsingException {
+ try {
+ Module_attribute modAttr =
+ (Module_attribute) cf.getAttribute(Attribute.Module);
+ if (modAttr != null) {
+ String modmember = modAttr.getModuleName(cf.constant_pool);
+ if (getModuleName().equals(modmember)) {
+ return true;
+ } else {
+ String msg = Messenger.formatMsg("error.module.wrong.module",
+ getModuleName(), cf.getName(), modmember);
+ throw new ModuleParsingException(msg);
+ }
+ }
+ return false;
+ } catch (ConstantPoolException cpe) {
+ throw new ModuleParsingException(cpe);
+ }
+ }
+
+ /*
+ * checks to see if the class should be exported, based on
+ * on the module attribute and ExportLegacyClass.
+ * The rule:
+ * a> a legacy class (one without any module affliation), can be exported
+ only if @ExportLegacyClasses is indicated.
+ * b> a module class marked public with affilation to this module.
+ * Note: in b if the class is affliated to a different module it is
+ * an error.
+ */
+ private boolean canExportClass(ClassFile cf, UnexportedClass uc) throws
+ IOException, ModuleParsingException {
+ if (cf.access_flags.is(AccessFlags.ACC_PUBLIC)) {
+ boolean member = isMemberClass(cf);
+ if (member || isExportLegacyClasses()) {
+ return true;
+ } else if (uc != null) {
+ uc.reason = Messenger.getMsg("info.class.notmodule");
+ moduleUnexportedClassList.add(uc);
+ }
+ } else if (uc != null) {
+ uc.reason = Messenger.getMsg("info.class.notpublic");
+ moduleUnexportedClassList.add(uc);
+ }
+ return false;
+ }
+
+ private String getMemberPackage(ClassFile cf) throws IOException {
+ try {
+ String name = cf.getName().replace("/", ".");
+ int idx = name.lastIndexOf('.');
+ return (idx == -1 ) ? "" : name.substring(0, idx);
+ } catch (ConstantPoolException ex) {
+ throw new IOException(ex.getMessage());
+ }
+ }
+
+ private int[] combineListsAsArray(CpArrayList cpList,
+ List<String> oldList, Set<String> newList) {
+ LinkedHashSet<Integer> out = new LinkedHashSet<Integer>();
+ for (String x : oldList) {
+ out.add(cpList.getUTF8Index(x));
+ }
+ for (String x : newList) {
+ out.add(cpList.getUTF8Index(x));
+ }
+ int[] outArray = new int[out.size()];
+ int i = 0;
+ for (int x : out) {
+ outArray[i] = x;
+ i++;
+ }
+ return outArray;
+ }
+
+ /*
+ * Here is the logic to add new module tables
+ * Step 1. Create a Constant Pool (CP)
+ * a. Create a local ordered constant pool image.
+ * b. Check the old metadata if it has any entries copy them over
+ * c. Add the new entries to that list.
+ * Step 2. Create the new real CP from the list
+ * Step 3. Create the new arrays/tables with indices to the CP, using
+ * the new CP created in Step 1.
+ * Step 4. Create an Attribute List from the old metadata
+ * Step 5. Get the Attributes list from the old metadata, repeat for each
+ * attribute.
+ * a. if the old does not have the said attribute add new
+ * b. otherwise swap the old one with the new one.
+ * Step 6. convert the list to an array using the CP in 2.
+ * Step 7. return the classfile container
+ */
+ private ClassFile addModuleTables(ClassFile cf)
+ throws ModuleParsingException {
+ try {
+ // Step 1: Create a Constant Pool (CP)
+ CpArrayList cpList = new CpArrayList(cf.constant_pool);
+ List<String> oldModuleExportClassList = getModuleExportClassList(true);
+ List<String> oldModuleExportPackageList = getModuleExportPackageList();
+ List<String> oldModuleMemberList = getModuleMemberPackageList();
+
+ if (oldModuleExportClassList.isEmpty()) {
+ cpList.add(Attribute.ModuleExportTable);
+ }
+ cpList.addAll(moduleExportClassList);
+ cpList.addAll(moduleExportPackageList);
+
+ if (oldModuleMemberList.isEmpty()) {
+ cpList.add(Attribute.ModuleMemberTable);
+ }
+ cpList.addAll(moduleMemberPackageList);
+
+ // Step 2: Create the new real CP from the list
+ ConstantPool ncp = cpList.toConstantPool();
+
+ // Step 3: Create the new arrays/tables
+ int[] metClassEntries = combineListsAsArray(cpList,
+ oldModuleExportClassList, moduleExportClassList);
+ int[] metPackageEntries = combineListsAsArray(cpList,
+ oldModuleExportPackageList, moduleExportPackageList);
+
+ int[] mmtEntries = combineListsAsArray(cpList,
+ oldModuleMemberList, moduleMemberPackageList);
+
+
+ // Step 4: Create an Attribute List from the old metadata
+ ArrayList<Attribute> attrsList =
+ new ArrayList<Attribute>(Arrays.asList(cf.attributes.attrs));
+
+ // Step 5 for ModuleExportTable
+ ModuleExportTable_attribute metAttr =
+ new ModuleExportTable_attribute(ncp,
+ metPackageEntries, metClassEntries);
+
+ int attrindex = getAttributeIndex(cf, Attribute.ModuleExportTable);
+ if (attrindex == -1) { // add the new one
+ attrsList.add(metAttr);
+ } else { // replace the existing one
+ attrsList.set(attrindex, metAttr);
+ }
+
+ // Step 5 for ModuleMemberTable
+ ModuleMemberTable_attribute mmtAttr =
+ new ModuleMemberTable_attribute(ncp, mmtEntries);
+
+ attrindex = getAttributeIndex(cf, Attribute.ModuleMemberTable);
+ if (attrindex == -1) { // add the new one
+ attrsList.add(mmtAttr);
+ } else { // replace the existing one
+ attrsList.set(attrindex, mmtAttr);
+ }
+ attrsList.trimToSize();
+
+ // Step 6: convert the list to an array using the CP in 2
+ Attributes nattrs = new Attributes(ncp,
+ attrsList.toArray(new Attribute[attrsList.size()]));
+
+ // Step 7: return the classfile container
+ return new ClassFile(cf.magic, cf.major_version, cf.minor_version,
+ ncp, cf.access_flags, cf.this_class, cf.super_class,
+ cf.interfaces, cf.fields, cf.methods, nattrs);
+ } catch (ConstantPoolException ex) {
+ throw new ModuleParsingException(ex);
+ }
+ }
+
+ private int getAttributeIndex(ClassFile cf, String attributeName) {
+// TODO uncomment when 6716452 is integrated, and remove
+// the logic following this.
+// return cf.attributes.getIndex(cf.constant_pool,
+// attributeName);
+// Remove this
+ if (cf.getAttribute(attributeName) == null) {
+ return -1;
+ }
+ for (int i = 0 ; i < cf.attributes.size() ; i++) {
+ if (cf.attributes.attrs[i].equals(attributeName)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /*
+ * Indicates that further anaylsis of class-files are no longer required
+ * and it is safe to generate the new module metadata file.
+ * @throws ModuleParsingException
+ */
+ void finish() throws ModuleParsingException {
+ ClassFile mdClassFile = super.getClassFile();
+ if (mdClassFile == null) { // auto generate a new one ??
+ // TODO
+ throw new UnsupportedOperationException("not yet implemented");
+ }
+ ClassTranslator ctr = new ClassTranslator();
+ ClassFile mutatedClassFile = addModuleTables(mdClassFile);
+ HashMap<Object, Object> map = new HashMap<Object, Object>();
+ map.put( mdClassFile.constant_pool,mutatedClassFile.constant_pool);
+ map.put(mdClassFile.attributes, mutatedClassFile.attributes);
+ moduleInfoClassFile = ctr.translate(mdClassFile, map);
+ done = true;
+ }
+
+ private void processJar(File jarFile, boolean shouldFinish)
+ throws ModuleParsingException, IOException {
+ ZipFile zf = null;
+ ZipInputStream zis = null;
+ UnexportedClass uc;
+ try {
+ zf = new ZipFile(jarFile);
+ for (ZipEntry ze : Collections.list(zf.entries())) {
+ String entry = ze.getName();
+ if ( entry.endsWith(".class") &&
+ !JamToolUtils.isModuleInfoClassEntry(entry)) {
+ uc = new UnexportedClass(jarFile.getName(), entry, null);
+ analyzeClass(zf.getInputStream(ze), uc);
+ } else if (entry.endsWith(".jar")) {
+ if (isEmbeddedJar(entry)) {
+ zis = new ZipInputStream(zf.getInputStream(ze));
+ processJar(zis, entry);
+ } else {
+ Messenger.formatMsg("info.jar.notembedded", entry);
+ }
+ }
+ }
+ // create the new module metadata file.
+ if (shouldFinish)
+ finish();
+ } finally {
+ JamUtils.close(zf);
+ JamUtils.close(zis);
+ }
+ }
+
+ private void processJar(ZipInputStream zin, String enclosingJar)
+ throws ModuleParsingException, IOException {
+ ZipEntry ze = zin.getNextEntry();
+ while (ze != null) {
+ String entry = ze.getName();
+ if (entry.endsWith(".class") &&
+ !JamToolUtils.isModuleInfoClassEntry(entry)) {
+ UnexportedClass uc = new UnexportedClass(enclosingJar, entry, null);
+ analyzeClass(zin, uc);
+ zin.closeEntry();
+ }
+ ze = zin.getNextEntry();
+ }
+ }
+
+ /**
+ * Returns a String representation of the metadata file.
+ * @param jarfile
+ * @param verbose
+ * @return a string
+ * @throws java.io.IOException
+ * @throws sun.module.ModuleParsingException
+ */
+ public static String printDiagnostics(String jarfile, boolean verbose)
+ throws IOException, ModuleParsingException {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+
+ JamModuleMetadata metadata = new JamModuleMetadata(new File(jarfile));
+ pw.println(metadata.toString());
+ if (verbose && !metadata.moduleUnexportedClassList.isEmpty()) {
+ pw.println(Messenger.getMsg("info.unexported.header"));
+ for (UnexportedClass c : metadata.moduleUnexportedClassList) {
+ pw.println(" " + c.toString());
+ }
+ }
+ pw.flush();
+ sw.flush();
+ return sw.toString();
+ }
+
+ /*
+ * A helper class to manage constant pool entries
+ */
+ class CpArrayList extends ArrayList<CPInfo> {
+ CpArrayList(ConstantPool cp) {
+ super();
+ // initialization, add the 0th entry manually, as access is a no-no,
+ // through the javap library.
+ add(0, null);
+ // add the rest of the entries
+ for (int i = 1; i < cp.size(); i++) {
+ try {
+ super.add(cp.get(i));
+ } catch (ConstantPool.InvalidIndex ii) {
+ // skip a double-word entry
+ super.add(i, null);
+ }
+ }
+ }
+
+ void add(String utf8) {
+ super.add(new ConstantPool.CONSTANT_Utf8_info(utf8));
+ }
+
+ void addAll(Collection<String> list) {
+ for (String x : list) {
+ add(x);
+ }
+ }
+
+ int getUTF8Index(String str) {
+ if (str == null) {
+ return -1;
+ }
+ CPInfo cmp = new ConstantPool.CONSTANT_Utf8_info(str);
+ for (int i = 1; i < size(); i++) {
+ CPInfo c = get(i);
+ if (c != null && c.getTag() == ConstantPool.CONSTANT_Utf8 &&
+ cmp.toString().equals(c.toString())) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ ConstantPool toConstantPool() {
+ return new ConstantPool(super.toArray(new CPInfo[size()]));
+ }
+ }
+
+ /*
+ * A container class to encapsulate the diagnostic information as to why a
+ * class could not be exported.
+ */
+ class UnexportedClass {
+
+ String location;
+ String classname;
+ String reason;
+
+ UnexportedClass() {
+ location = null;
+ classname = null;
+ reason = null;
+ }
+
+ UnexportedClass(String location, String classname, String reason) {
+ this.location = location;
+ this.classname = classname;
+ this.reason = reason;
+ }
+
+ public String toString() {
+ return (classname +
+ "@" + ((location == null) ? "input-file" : location) +
+ ":" + reason);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/module/tools/util/JamToolUtils.java Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.module.tools.util;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import sun.module.JamUtils;
+
+public class JamToolUtils {
+ /**
+ * This class provides a set of static utility methods for the jam and
+ * jar tools. The directory or filename utilities will convert from
+ * platform specific file separators to '/', the '/' being the specified
+ * separator for zip entries.
+ */
+
+ // a singleton utility class for the tools
+ private JamToolUtils() {}
+
+ /**
+ * @return the module-inf directory with the trailing slash, like the
+ * way zip expects for directory names.
+ */
+ public static String getModuleInfDir() {
+ return JamUtils.MODULE_INF + "/";
+ }
+
+ /**
+ * Tests whether input string is, a module inf directory, after converting
+ * file separator to /.
+ * @param in a String denoting a directory name
+ * @return true or false
+ */
+ public static boolean isModuleInfDir(String in) {
+ return in.toUpperCase(java.util.Locale.ROOT).equals(getModuleInfDir());
+ }
+
+ /**
+ * Tests whether the input string is a module inf entry, after converting
+ * file separator is replaced with /, noting that entry
+ * could be preceded by other path elements. Note that a trailing
+ * "/" will be added if the input string does not contain one.
+ * @param in a String denoting a directory name could have have prefix dirs.
+ * @return true or false
+ */
+ public static boolean isModuleInfDirEntry(String in) {
+ String s = (in.endsWith("/") ? in : in.concat("/")).replace('\\', '/');
+ return s.toUpperCase(java.util.Locale.ROOT).endsWith(getModuleInfDir());
+ }
+
+ /**
+ * Tests whether the input string is a metadata file, after converting
+ * the input from file separators to /.
+ * @param in a String denoting an entry name
+ * @return true or false
+ */
+ public static boolean isModuleInfMetaData(String in) {
+ return in.replace('\\', '/').toUpperCase(
+ java.util.Locale.ROOT).equals(JamUtils.MODULE_INF_METADATA);
+ }
+
+ /**
+ * Tests whether the string is a module-info.class
+ * @param in a String denoting an entry name
+ * @return true or false
+ */
+ public static boolean isModuleInfoClass(String in) {
+ return in.toLowerCase(java.util.Locale.ROOT).equals(JamUtils.MODULE_INFO_CLASS);
+ }
+
+ /**
+ * Tests whether the entry (after converting file separator to /) is
+ * module-info.class noting that an entry could be preceded by directory
+ * path elements.
+ * @param in a String denoting an entry name
+ * @return true or false
+ */
+ public static boolean isModuleInfoClassEntry(String in) {
+ return in.replace('\\', '/').toLowerCase(
+ java.util.Locale.ROOT).endsWith(JamUtils.MODULE_INFO_CLASS);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/module/tools/util/ModuleMetadata.java Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.module.tools.util;
+
+import com.sun.tools.classfile.Annotation.Annotation_element_value;
+import com.sun.tools.classfile.Annotation.Array_element_value;
+import com.sun.tools.classfile.Annotation.Class_element_value;
+import com.sun.tools.classfile.Annotation.Enum_element_value;
+import com.sun.tools.classfile.Annotation.Primitive_element_value;
+import com.sun.tools.classfile.Annotation.element_value;
+import com.sun.tools.classfile.Annotation;
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPool;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import sun.module.JamUtils;
+import sun.module.MetadataParser;
+import sun.module.ModuleParsingException;
+import sun.module.tools.Messenger;
+
+
+/**
+ * This clases reads and creates a module metadata object, given the
+ * module-info.class, its primary purpose is to parse the annotations
+ * that are available in the module-info.class. The rest of the attributes
+ * are read by the light weight MetadataParser.
+ */
+class ModuleMetadata {
+ private ClassFile mdClassFile;
+ private static final String ANNOTATION_PREFIX =
+ "java.module.annotation.";
+ private static final String EXPORT_LEGACY_CLASSES_ANNOTATION =
+ ANNOTATION_PREFIX + "ExportLegacyClasses";
+ private static final String JAR_LIBRARY_PATH =
+ ANNOTATION_PREFIX + "JarLibraryPath";
+
+ HashMap<String, List<String>> moduleInfoMap = null;
+
+ MetadataParser mdp = null;
+ Attribute.Factory afactory = new Attribute.Factory();
+
+ /**
+ * Construct a module metadata object from an {@link InputStream}.
+ * @param is
+ * @throws java.io.IOException
+ * @throws sun.module.tools.util.ModuleParsingException
+ */
+ ModuleMetadata(InputStream is) throws IOException, ModuleParsingException {
+ byte[] buf = JamUtils.getInputStreamAsBytes(is);
+ init(buf);
+ }
+
+ /**
+ * Construct a module metadata using a byte buffer.
+ * @param buf
+ * @throws sun.module.tools.util.ModuleParsingException
+ */
+ ModuleMetadata(byte[] buf) throws ModuleParsingException {
+ try {
+ init(buf);
+ } catch (IOException ioe) {
+ throw new ModuleParsingException(ioe);
+ }
+ }
+
+ /**
+ * Construct a module metadata object from a JAR-file, noting that the
+ * archive must contain a module metadata file, if a
+ * MODULE-INF/MODULE.METADATA exist then will be used in preference to
+ * the one found as module-info.class, it is an error if either of them
+ * don't exist.
+ * @param jarname
+ * @throws java.io.IOException
+ * @throws sun.module.tools.util.ModuleParsingException
+ */
+ ModuleMetadata(File jarFile) throws IOException, ModuleParsingException {
+ ZipFile zf = null;
+ InputStream minfois = null;
+ try {
+ zf = new ZipFile(jarFile);
+ for (ZipEntry ze : Collections.list(zf.entries())) {
+ if (JamToolUtils.isModuleInfMetaData(ze.getName())) {
+ byte[] buf = JamUtils.getInputStreamAsBytes(zf.getInputStream(ze));
+ init(buf);
+ return;
+ } else if (JamToolUtils.isModuleInfoClassEntry(ze.getName())) {
+ minfois = zf.getInputStream(ze);
+ }
+ }
+ if (minfois == null) {
+ throw new IOException(
+ Messenger.formatMsg("error.module.files.notfound",
+ JamUtils.MODULE_INF_METADATA,
+ JamUtils.MODULE_INFO_CLASS)
+ );
+ }
+ init(JamUtils.getInputStreamAsBytes(minfois));
+ } finally {
+ JamUtils.close(minfois);
+ JamUtils.close(zf);
+ }
+ }
+
+ private void init(byte[] buf) throws ModuleParsingException, IOException {
+ mdp = new MetadataParser(buf);
+ moduleInfoMap = mdp.getModuleInfoMap();
+ ByteArrayInputStream bis = new ByteArrayInputStream(buf);
+ afactory.setJSR277(true);
+ try {
+ mdClassFile = ClassFile.read(bis, afactory);
+ } catch (ConstantPoolException cpe) {
+ throw new ModuleParsingException(cpe);
+ }
+ parseAnnotations();
+ }
+
+ /**
+ * Returns the module's name as coded into the module-info file.
+ * @return a {@link String} representing the module name.
+ */
+ String getModuleName() {
+ return mdp.getModuleName().replace('.', '/');
+ }
+
+ /**
+ * Returns the module's member package attribute List, without the signatures.
+ * Example: com.sun.util
+ * @return a {@link List} containing the elements
+ */
+ List<String> getModuleMemberPackageList() {
+ return mdp.getModuleMemberPackageList();
+ }
+
+ /**
+ * Returns the module's exported class attributes as a List with or
+ * without class signature (field descriptor).
+ * Example: with signature is L/java/lang/Object;
+ * Example: without signature is java.lang.Object
+ * @param asSignature
+ * @return a {@link List} containing the elements
+ */
+ List<String> getModuleExportClassList(boolean asSignature) {
+ return mdp.getModuleExportClassList(asSignature);
+ }
+
+ /**
+ * Returns a list of the module's exported packages in the module metadata.
+ * Noting that an anonymous package will be denoted as a \"\".
+ * @return a {@link List} containing the elements
+ */
+ List<String> getModuleExportPackageList() {
+ return mdp.getModuleExportPackageList();
+ }
+
+
+
+ /**
+ * A human readable representation of the module metadata.
+ * @return a {@link String} representation of this metadata object
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (String x : moduleInfoMap.keySet()) {
+ if (x == null) continue;
+ sb = sb.append(x + ":" + moduleInfoMap.get(x) + "\n");
+ }
+
+ return sb.toString();
+ }
+
+ ClassFile getClassFile() {
+ return this.mdClassFile;
+ }
+
+ String getJarLibraryPath() {
+ List<String> list = moduleInfoMap.get(JAR_LIBRARY_PATH);
+ return (list != null && list.size() > 0) ? list.get(0) : null;
+ }
+
+ boolean isExportLegacyClasses() {
+ return moduleInfoMap.containsKey(EXPORT_LEGACY_CLASSES_ANNOTATION);
+ }
+
+ private List<String> parseAnnotation(Annotation a) {
+ List<String> aList = null;
+ if (a.num_element_value_pairs > 0) {
+ ElementVisitor elementVisitor = new ElementVisitor();
+ aList = new ArrayList<String>();
+ for (Annotation.element_value_pair ev : a.element_value_pairs) {
+ aList = elementVisitor.visit(ev.value);
+ }
+ Collections.sort(aList);
+ }
+ return aList;
+ }
+
+ private void parseAnnotations() throws ModuleParsingException {
+ RuntimeVisibleAnnotations_attribute rva =
+ (RuntimeVisibleAnnotations_attribute)
+ mdClassFile.getAttribute(Attribute.RuntimeVisibleAnnotations);
+ for (Annotation a : rva.annotations) {
+ try {
+ String s = mdClassFile.constant_pool.getUTF8Value(a.type_index);
+ moduleInfoMap.put(MetadataParser.stripClassSignature(s), parseAnnotation(a));
+ } catch (ConstantPool.InvalidIndex ex) {
+ throw new ModuleParsingException(ex);
+ } catch (ConstantPool.UnexpectedEntry ex) {
+ throw new ModuleParsingException(ex);
+ }
+ }
+ }
+
+ /* TODO: fix review comments:
+ * make the visitor stateless, by changing the supertype of the
+ * visitor from Visitor<Void,Void> to Visitor<ArrayList<String,ArrayList<String>>
+ * therefore line 254, 265, 293: redundant.
+ */
+ class ElementVisitor implements Annotation.element_value.Visitor<Void, Void> {
+ ConstantPool cp = mdClassFile.constant_pool;
+ List<String> visitList = new ArrayList<String>();
+ public Void visitPrimitive(Primitive_element_value ev, Void p) {
+ try {
+ visitList.add(cp.getUTF8Value(ev.const_value_index));
+ return null;
+ } catch (Exception ex) {
+ // TODO: provide way for extra debugging
+ }
+ return null;
+ }
+
+ public Void visitEnum(Enum_element_value ev, Void p) {
+ try {
+ visitList.add(cp.getUTF8Value(ev.const_name_index));
+ visitList.add(cp.getUTF8Value(ev.type_name_index));
+ return null;
+ } catch (Exception ex) {
+ // TODO: provide way for extra debugging
+ }
+ return null;
+ }
+
+ public Void visitClass(Class_element_value ev, Void p) {
+ try {
+ visitList.add(cp.getUTF8Value(ev.class_info_index));
+ return null;
+ } catch (Exception ex) {
+ // TODO: provide way for extra debugging
+ }
+ return null;
+ }
+
+ public Void visitAnnotation(Annotation_element_value ev, Void p) {
+ visitList.addAll(parseAnnotation(ev.annotation_value));
+ return null;
+ }
+
+ public Void visitArray(Array_element_value ev, Void p) {
+ try {
+ ElementVisitor aev = new ElementVisitor();
+ for (element_value e : ev.values) {
+ this.visitList = aev.visit(e);
+ }
+ return null;
+ } catch (Exception ex) {
+ System.err.println(ex.getCause());
+ }
+ return null;
+ }
+
+ public List<String> visit(element_value ev) {
+ ev.accept(this, null);
+ Collections.sort(this.visitList);
+ return this.visitList;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/sample/modules/README Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,35 @@
+
+This directory contains two modules
+ A. A simple hello-world module in the directory hello-world
+ B. A simple module dep which depends on the hello module in A
+
+
+The directory hello-world contains the following:
+ a. module-info.java - the 'hello' module description file
+ b. hello/Main.java - a simple Java application
+
+To build and run the module:
+ [set your path to point to the "bin" directory of a OpenJDK Modules build]
+ % find hello-world -name "*.java" > hello.classes
+ % javac -source 7 @hello.classes
+ % jam cvf hello.jam -C hello-world module-info.class -C hello-world hello/Main.class
+ % java -jam hello.jam
+ Hello world from module hello 1.0
+
+The directory dependencies contains the module dep
+ a. module-info.java - the 'dep' module description file
+ b. dep/Entry.java - a simple application which depends on 'hello'
+
+Now lets try the other module:
+ % find dependencies -name "*.java" > dep.classes
+ % javac -source 7 -sourcepath hello-world/ @dep.classes
+ % jam cvf dep.jam -C dependencies module-info.class -C dependencies dep/Entry.class
+ % java -jam dep.jam
+ Module 'dep' calling module 'hello'...
+ Hello world from module instance hello v1.0 (application repository)
+
+
+Thank you for trying out modules.
+Feel free to ask any questions at modules-dev@openjdk.java.net
+
+- The Modules team
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/sample/modules/dependencies/module-info.java Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+/**
+ * Declare the module "dep" with its exported class "dep.Entry".
+ */
+@MainClass("dep.Entry")
+@Version("1.0")
+@ImportModules({
+ @ImportModule(name="java.se"),
+ @ImportModule(name="hello")
+})
+module dep;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/sample/modules/hello-world/module-info.java Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * Declare the module "hello" with its exported class "hello.Main".
+ */
+@MainClass("hello.Main")
+@Version("1.0")
+@ImportModules({
+ @ImportModule(name="java.se")
+})
+module hello;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/basic/LauncherTestHelper.java Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,373 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.module.Version;
+import sun.module.JamUtils;
+
+public class LauncherTestHelper {
+ enum RepoType {
+ JAR_REPO, JAM_REPO, PACK_REPO
+ }
+
+ private static RepoType repoType;
+
+ private final static String WARNING_HEADER =
+ "// This is a machine generated file, do not edit\n";
+
+ // the parent of the repository directories
+ final static String REPODIRNAME = "repodir";
+
+ // The children repository directories
+ static String rawRepository;
+ static String jamRepository;
+ static String jarRepository;
+ static String urlRepository ;
+ static String packRepository;
+
+ final static String RAW_REPO = "raw-repo";
+ final static String JAM_REPO = "jam-repo";
+ final static String JAR_REPO = "jar-repo";
+ final static String URL_REPO = "url-repo";
+ final static String PACK_REPO = "pack-repo";
+
+ private final static String PGM_TAIL =
+ "System.exit(0);\n}\n}\n";
+
+ private LauncherTestHelper() {} // all static
+
+ private static void doPrintStream(File out, StringBuilder in)
+ throws FileNotFoundException {
+ if (out.exists()) out.delete();
+ File parent = out.getParentFile();
+ parent.mkdirs();
+ PrintStream p = new PrintStream(out);
+ p.print(new String(in));
+ p.flush();
+ p.close();
+ }
+
+ /*
+ * The raw repository layout is as follows:
+ * raw-repo
+ * module1
+ * pkg1
+ * java-files
+ * class-files
+ * pkg2
+ * .....
+ * module2
+ * pkg1
+ * .....
+ */
+
+ public static void createRawRepo(File testRepoDir) throws IOException {
+ File rawrepoDir = new File(testRepoDir, RAW_REPO);
+ rawRepository = rawrepoDir.getAbsolutePath();
+ if (!rawrepoDir.mkdirs()) {
+ throw new IOException("could not mkdir " + rawRepository);
+ }
+ createModule(rawrepoDir, "t2", "p2", null, null, "Maint2", true, null);
+ createModule(rawrepoDir, "t1", "p1", "t2", "p2", "Maint1", true, "Maint2");
+ createModule(rawrepoDir, "t2", "p3", null, null, "Foo", false, null);
+ createAltMain(rawrepoDir, "t1", "p1", "Maint1", "AltMaint1");
+ Utils.compileFiles(rawrepoDir, "t1", "t2");
+ }
+
+ private static void createModule(File baseDir,
+ String module,
+ String pkg,
+ String importModule,
+ String otherpkg,
+ String klass,
+ boolean mainclass,
+ String otherklass) throws IOException {
+
+ File modDir = new File(baseDir, module);
+ // Create the java files
+ StringBuilder out = new StringBuilder();
+ out = out.append(WARNING_HEADER);
+ out = out.append("module " + module + ";\n");
+ out = out.append("package " + pkg + ";\n");
+ out = out.append("import java.util.*;\n");
+ out = out.append("public class " + klass + " {\n");
+ out = out.append(" static String[] inargs = {\"one\", \"two\", \"three\", \"four\"};\n");
+ out = out.append(" public static void main(String[] args) throws Exception {\n");
+ out = out.append(" Class clazz = " + klass + Utils.CLASS_EXT + ";\n");
+ out = out.append(" ClassLoader cl = clazz.getClassLoader();\n");
+ out = out.append(" while (cl != null) {\n");
+ out = out.append(" System.out.println(\" -->\" + cl);\n");
+ out = out.append(" cl = cl.getParent();\n");
+ out = out.append(" }\n");
+ out = out.append(" ClassLoader scl = ClassLoader.getSystemClassLoader();\n");
+ out = out.append(" if (scl.getParent() != null){ \n");
+ out = out.append(" System.out.println(\"Parent of System ClassLoader must be bootstrap\");\n");
+ out = out.append(" System.exit(1);");
+ out = out.append(" }\n");
+
+ out = out.append(" System.out.println(\"System ClassLoader: \" + scl);\n");
+ out = out.append(" if (!(scl instanceof sun.module.core.ProxyModuleLoader)) {\n");
+ out = out.append(" throw new Exception(\"Unexpected system classloader\");\n");
+ out = out.append(" }\n");
+ out = out.append(" System.out.println(\"running: \" + clazz + \"/\" + clazz.getClassLoader());\n");
+ out = out.append(" System.out.println(\"Args: \" + Arrays.toString(args));\n");
+ out = out.append(" if (args.length != inargs.length)\n");
+ out = out.append(" throw new Exception(\"Error: incorrect number of arguments\");\n");
+ out = out.append(" for (int i = 0 ; i < args.length ; i++)\n");
+ out = out.append(" if (!inargs[i].equals(args[i]))\n");
+ out = out.append(" throw new Exception(\"Error: expected \'\" + inargs[i] + \"\' got\'\" + args[i] + \"\'\");\n");
+ if (otherpkg != null) {
+ out = out.append(otherpkg + "." + otherklass + ".main(args);");
+ }
+
+ out = out.append(PGM_TAIL);
+ File pkgDir = new File(modDir, pkg);
+ File javaFile = new File(pkgDir, klass + Utils.JAVA_EXT);
+
+ doPrintStream(javaFile, out);
+ if (mainclass) {
+ // Create the java definition files
+ out = new StringBuilder();
+ out = out.append(WARNING_HEADER);
+ out = out.append("@Version(\"" + Version.valueOf(Utils.JAM_VERSION) + "\")\n");
+ out = out.append("@MainClass(\"" + pkg + "." + klass + "\")\n");
+ out = out.append("@ImportModules({\n");
+ out = out.append(" @ImportModule(name=\"java.se\"),\n");
+ out = out.append(" @ImportModule(name=\"java.classpath\")");
+ if (importModule != null) {
+ out = out.append(",\n @ImportModule(name=\"" + importModule + "\")");
+ }
+ out = out.append("\n})\n");
+// TODO comment it out for now
+// if (otherpkg == null) {
+// out = out.append(" exports " + pkg + "$" + klass + ";");
+// }
+ out = out.append("\nmodule " + module + ";\n");
+ File modFile = new File(pkgDir, JamUtils.MODULE_INFO_JAVA);
+ doPrintStream(modFile, out);
+ }
+ }
+
+
+ private static void createTestJarFile() {
+ PrintStream p = null;
+ File clsFile = null;
+ File srcFile = new File("HelloWorld.java");
+
+ if (srcFile.exists()) {
+ Utils.abort(srcFile.delete(), "Could not delete" + srcFile);
+ }
+
+ try {
+ StringBuilder out = new StringBuilder(WARNING_HEADER);
+ out = out.append("import java.util.logging.Level;\n");
+ out = out.append("import java.util.logging.Logger;\n");
+ out = out.append("public class HelloWorld {\n");
+ out = out.append("public static void main(String[] args) {\n");
+ out = out.append("Logger.getLogger(\"global\").log(Level.INFO,\"A Test\");\n");
+ out = out.append("for (String x : args) {\n");
+ out = out.append("Logger.getLogger(\"global\").log(Level.INFO, null, \"arg:\" + x);\n");
+ out = out.append("System.exit(0);\n");
+ out = out.append("}\n");
+ out = out.append("}\n");
+ out = out.append("}\n");
+ p = new PrintStream(srcFile);
+ p.print(new String(out));
+ p.flush();
+ p.close();
+ Utils.compileFile(srcFile.getName());
+ String fName = Utils.baseName(srcFile);
+ clsFile = new File(fName + Utils.CLASS_EXT);
+ sun.tools.jar.Main jartool = new sun.tools.jar.Main(
+ System.out, System.err, "JarCreator");
+
+ String[] args = new String[] {
+ "cfe",
+ new File(jarRepository, fName + Utils.JAR_EXT).getAbsolutePath(),
+ fName,
+ clsFile.getName(),
+ };
+ Utils.abort(jartool.run(args), "JarCreator Failed") ;
+ } catch (Exception ex) {
+ Utils.unexpected(ex);
+ } finally {
+ JamUtils.close(p);
+ srcFile.delete();
+ clsFile.delete();
+ }
+ }
+
+ private static void createAltMain(File baseDir,
+ String module,
+ String pkg,
+ String klass,
+ String altklass) throws IOException {
+ StringBuilder out = new StringBuilder();
+ out = out.append(WARNING_HEADER);
+ out = out.append("module " + module + ";\n");
+ out = out.append("package " + pkg + ";\n");
+ out = out.append("import java.util.*;\n");
+ out = out.append("import java.lang.reflect.*;\n");
+ out = out.append("public class " + altklass + " {\n");
+ out = out.append("public static void main(String[] args) throws Exception {\n");
+ out = out.append(" Class<?> clazz = " + altklass + Utils.CLASS_EXT + ";\n");
+ out = out.append(" System.out.println(\"running: \" + clazz + \"/\" +"
+ + " clazz.getClassLoader());\n");
+ out = out.append(" ClassLoader scl = ClassLoader.getSystemClassLoader();\n");
+ out = out.append(" clazz = scl.loadClass(\"HelloWorld\");\n");
+ out = out.append(" Method main = clazz.getMethod(\"main\",String[].class);\n");
+ out = out.append(" main.invoke(null, (Object)args);\n");
+ out = out.append(" System.exit(1);\n"); // The other main should exit with 0
+ out = out.append("}\n");
+ out = out.append("}\n");
+ File modDir = new File(baseDir, module);
+ File pkgDir = new File(modDir, pkg);
+ File javaFile = new File(pkgDir, altklass + Utils.JAVA_EXT);
+ doPrintStream(javaFile, out);
+ }
+
+ private static void createJarRepo(File testRepoDir) throws IOException {
+ File jarrepoDir = new File(testRepoDir, JAR_REPO);
+ if (!jarrepoDir.mkdirs()) {
+ throw new IOException("could not mkdir " + jarRepository);
+ }
+ jarRepository = jarrepoDir.getAbsolutePath();
+ createRepo0(repoType.JAR_REPO);
+ createTestJarFile();
+ }
+
+ private static void createJamRepo(File testRepoDir) throws IOException {
+ File jamrepoDir = new File(testRepoDir, JAM_REPO);
+ if (!jamrepoDir.mkdirs()) {
+ throw new IOException("could not mkdir " + jamRepository);
+ }
+ jamRepository = jamrepoDir.getAbsolutePath();
+ createRepo0(repoType.JAM_REPO);
+ }
+
+ private static void createPackRepo(File testRepoDir) throws IOException {
+ File packrepoDir = new File(testRepoDir, PACK_REPO);
+ if (!packrepoDir.mkdirs()) {
+ throw new IOException("could not mkdir " + packRepository);
+ }
+ packRepository = packrepoDir.getAbsolutePath();
+ createRepo0(repoType.PACK_REPO);
+ }
+
+ private static void createRepo0(RepoType type) throws IOException {
+ for (File src: Utils.getDirs(rawRepository)) {
+ switch(type) {
+ case JAR_REPO:
+ {
+ File dst = new File(jarRepository, src.getName() + Utils.JAR_EXT);
+ Utils.makeJar(src, dst, "t2.Maint2");
+ break;
+ }
+ case JAM_REPO:
+ {
+ File dst = new File(jamRepository, src.getName() + Utils.JAM_EXT);
+ Utils.makeJam(src, dst);
+ break;
+ }
+ case PACK_REPO:
+ {
+ File dst = new File(packRepository,
+ src.getName() + Utils.JAM_EXT + Utils.PACK_EXT);
+ Utils.makeJam(src, dst);
+ break;
+ }
+ default:
+ Utils.abort(false, "Should not reach here");
+ }
+ }
+ }
+
+ /*
+ * The repository layout is as follows:
+ * repository-dir
+ * repository-metadata.xml
+ * module1
+ * version (1.0, 2.0, etc)
+ * MODULE-METADATA
+ * module1-$version.jam
+ * module2
+ * ....
+ * module3
+ * ....
+ */
+
+ private static void createURLRepo(File testRepoDir) throws IOException {
+ File urlrepoDir = new File(testRepoDir, URL_REPO);
+ urlRepository = urlrepoDir.getAbsolutePath();
+ if (!urlrepoDir.mkdirs()) {
+ throw new IOException("could not mkdir " + urlRepository);
+ }
+
+ PrintStream repoxml = new PrintStream(new File(urlrepoDir, Utils.REPO_XML));
+
+ repoxml.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ repoxml.println("<modules>");
+
+ File[] jamfiles = new File(jamRepository).listFiles(Utils.JAM_FILTER);
+ for (File src: jamfiles) {
+ repoxml.println("\t<module>");
+ repoxml.println("\t\t<name>" + Utils.baseName(src) + "</name>");
+ repoxml.println("\t\t<version>" + Version.valueOf(Utils.JAM_VERSION) + "</version>");
+ repoxml.println("\t</module>");
+
+ // Copy the jamFile to url repo with a version #
+ File d1 = new File(urlRepository, Utils.baseName(src));
+ File d2 = new File(d1, Version.valueOf(Utils.JAM_VERSION).toString());
+
+ File dst = new File(d2, Utils.baseName(src) +
+ Utils.JAM_SEP + Version.valueOf(Utils.JAM_VERSION) + Utils.JAM_EXT );
+ Utils.copyFile(src, dst);
+
+ File mdDst =new File(d2, JamUtils.MODULE_METADATA);
+ Utils.extractFileTo(dst, JamUtils.MODULE_INF_METADATA, mdDst);
+ }
+ repoxml.println("</modules>");
+ repoxml.flush();
+ repoxml.close();
+ }
+
+ static void createRepo() throws IOException {
+ Utils.abort(Utils.TESTJAVA != null, "createRepo: java.home must be set");
+ File testRepoDir = new File(".", REPODIRNAME).getAbsoluteFile();
+ Utils.recursiveDelete(testRepoDir);
+
+ // create all our repos
+ createRawRepo(testRepoDir);
+ createJarRepo(testRepoDir);
+ createJamRepo(testRepoDir);
+ createPackRepo(testRepoDir);
+ createURLRepo(testRepoDir);
+ System.out.println("Repository created: " + testRepoDir);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/tools/jam/JamTester.java Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,444 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary Test packaging tools jam and jar
+ * @compile -XDignore.symbol.file JamTester.java ../../basic/Utils.java ../JamBuilder.java
+ * @run main JamTester
+ */
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.module.Version;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import java.util.jar.JarFile;
+import sun.module.JamUtils;
+import sun.module.MetadataParser;
+import sun.module.ModuleParsingException;
+
+public class JamTester {
+ /* Mutliple packages in a module are tested with several different
+ * variations. The repository layout is as follows:
+ * repotop
+ * [ module.jam ] the target jam.
+ * module
+ * MODULE-INF/lib/
+ * platform/lib
+ * pkg1
+ * java-files
+ * class-files
+ * pkg2
+ * .....
+ * the embedded jars are staged as follows:
+ * repotop
+ * module
+ * ......
+ * embedded
+ * standard // jarred into MODULE-INF/lib
+ * alpha
+ * nonstandard // jarred into platform/lib
+ * beta
+ */
+
+ private static BitSet dipSwitch = new BitSet();
+ private static final int NEGATIVE_TEST = 0;
+ private static final int MISSING_MODINF0 = 1;
+ private static final int EXPORT_LEGACY = 2;
+ private static final int EMBEDDED_NONSTD = 3;
+ private static final int WRONG_MODULE = 4;
+ private static final int AUTO_CREATE = 5;
+ final static String testNames[] = {
+ "Negative_Test",
+ "Missing_ModInfo",
+ "Export_legacy",
+ "Embedded_NonStd_Jar",
+ "Wrong_Module",
+ "Auto_Create_Module"
+ };
+ static enum ClassType {
+ PUBLIC, PROTECTED, MODULE, PRIVATE
+ };
+
+ static File createJavaFile(ClassType cType, File baseDir,
+ String module, String pkg, String className) throws IOException {
+
+ File modDir = new File(baseDir, module == null ? "." : module);
+ File pkgDir = new File(modDir, pkg == null ? "." : pkg);
+ File javaFile = new File(pkgDir, className + Utils.JAVA_EXT);
+ if (!pkgDir.exists()) {
+ Utils.abort(pkgDir.mkdirs(), "cannot mkdir " + pkgDir);
+ }
+ PrintWriter pw = new PrintWriter(new FileWriter(javaFile));
+ String indent = " ";
+ if (module != null) {
+ pw.println("module " + module + ";");
+ }
+ if (pkg != null) {
+ pw.println("package " + pkg + ";");
+ }
+ switch (cType) {
+ case PUBLIC:
+ pw.print("public ");
+ break;
+ case PROTECTED:
+ pw.print("protected ");
+ break;
+ case MODULE:
+ pw.print("module ");
+ break;
+ case PRIVATE:
+ pw.print("private ");
+ break;
+ default:
+ pw.print("");
+ break;
+ }
+ pw.println("class " + className + "{");
+ pw.println(indent + "public static void main(String...args) {");
+ pw.println(indent + indent + "for (String x : args){");
+ pw.println(indent + indent + indent + "System.out.println(x);");
+ pw.println(indent + indent + "}");
+ pw.println(indent + "}");
+ pw.println(indent + "public void aPublicMethod(){}");
+ pw.println(indent + "protected void aProtectedMethod(){}");
+ pw.println(indent + "private void aPrivateMethod(){}");
+// pw.println(indent + "module void aModuleMethod()"); TODO
+ pw.println("}");
+ pw.close();
+ return javaFile;
+ }
+
+ static File createModuleInfoFile(File baseDir, String module,
+ String mainClass, String jarLibraryPath, boolean exportLegacy)
+ throws IOException {
+ File modDir = new File(baseDir, module);
+ File modFile = new File(modDir, JamUtils.MODULE_INFO_JAVA);
+ PrintWriter pw = new PrintWriter(new FileWriter(modFile));
+ String indent = " ";
+ pw.println("@Version(\"" + Version.DEFAULT + "\")");
+ if (mainClass != null) {
+ pw.println("@MainClass(\"" + mainClass + "\")");
+ }
+ if (exportLegacy) {
+ pw.println("@ExportLegacyClasses");
+ }
+ if (jarLibraryPath != null) {
+ pw.println("@JarLibraryPath(\"" + jarLibraryPath + "\")");
+ }
+ pw.println("@ImportModules({");
+ pw.println(indent + "@ImportModule(name=\"java.se\", version=\"1.7+\"),");
+ pw.println(indent + "@ImportModule(name=\"java.classpath\")");
+ pw.println("})");
+ pw.println("module " + module + ";");
+ pw.close();
+ return modFile;
+ }
+ private static File testDir = null;
+
+ static void init(int... switches) throws IOException {
+ Utils.abort(Utils.TESTJAVA != null, "java.home must be set");
+ testDir = new File(".", "repotop").getAbsoluteFile();
+ Utils.abort(JamUtils.recursiveDelete(testDir), "directory delete problem");
+ dipSwitch.clear();
+ for (int i : switches) {
+ dipSwitch.set(i);
+ }
+ }
+
+ static String getTestName() {
+ StringBuilder sb = new StringBuilder();
+ for (int i = dipSwitch.nextSetBit(0); i >= 0; i = dipSwitch.nextSetBit(i + 1)) {
+ sb = sb.append(testNames[i] + "+");
+ }
+ return sb.toString();
+ }
+
+ private static void printTestGoals() {
+ System.out.print("Test goals: ");
+ System.out.println(getTestName());
+ }
+
+ static void createModule(int... switches)
+ throws Exception {
+
+ init(switches);
+
+ String moduleName = dipSwitch.isEmpty() ? "test.m1" : "m1";
+ String mainClass = "p1.APublic";
+
+ printTestGoals();
+ // create two packages belonging to the same module one
+ // with public class and the other module private
+ createJavaFile(ClassType.PUBLIC, testDir, moduleName, "p1", "APublic");
+ createJavaFile(ClassType.MODULE, testDir, moduleName, "p3", "AModule");
+
+ if (dipSwitch.get(WRONG_MODULE)) {
+ /*
+ * create a module with a different module membership
+ * and move the file to the module being created.
+ */
+ createJavaFile(ClassType.PUBLIC, testDir, "m2", "p2", "AWrongModule");
+ }
+
+ File embeddedDir = new File(testDir, "embedded");
+
+ // an embedded jar in the standard location
+ createJavaFile(ClassType.PUBLIC, embeddedDir, moduleName, "standard",
+ "AModuleEmbeddedStandard");
+ // with no module affiliation
+ createJavaFile(ClassType.PUBLIC, embeddedDir, null, "alpha",
+ "AModuleEmbeddedLegacyStandard");
+ // an embedded jar in the non standard location
+ createJavaFile(ClassType.PUBLIC, embeddedDir, moduleName, "nonstandard",
+ "AModuleEmbeddedNonStandard");
+ // with no module affiliation
+ createJavaFile(ClassType.PUBLIC, embeddedDir, null, "beta",
+ "AModuleEmbeddedLegacyNonStandard");
+
+ if (!dipSwitch.get(MISSING_MODINF0)) {
+ createModuleInfoFile(testDir, moduleName, mainClass,
+ dipSwitch.get(EMBEDDED_NONSTD) ? "platform/lib" : null,
+ dipSwitch.get(EXPORT_LEGACY));
+ }
+
+ Utils.compileFiles(testDir);
+
+ // jar and copy the embedded jars
+ // A. the standard location
+ File minfDir = new File(new File(testDir, moduleName), JamUtils.MODULE_INF);
+ File stdlibDir = new File(minfDir, "lib");
+ stdlibDir.mkdirs();
+ File stdJar = new File(stdlibDir, "standard.jar");
+ Utils.makeJar("cvf", stdJar.getAbsolutePath(),
+ "-C", new File(embeddedDir, moduleName).getAbsolutePath(), "standard",
+ "-C", embeddedDir.getAbsolutePath(), "alpha");
+
+ // B. the non standard location
+ File nonstdDir = new File(new File(testDir, moduleName), "platform");
+ File nonstdlibDir = new File(nonstdDir, "lib");
+ nonstdlibDir.mkdirs();
+ File nonstdJar = new File(nonstdlibDir, "nonstandard.jar");
+ Utils.makeJar("cvf", nonstdJar.getAbsolutePath(),
+ "-C", new File(embeddedDir, moduleName).getAbsolutePath(), "nonstandard",
+ "-C", embeddedDir.getAbsolutePath(), "beta");
+
+ // Setup the expected strings
+ String moduleVersion = Version.DEFAULT.toString();
+ String moduleImport = "1.7+, java.classpath, java.se";
+ String moduleExportClasses = "p1.APublic, standard.AModuleEmbeddedStandard";
+ String moduleMemberPackages = "alpha, p1, p3, standard";
+ String moduleExportPackages = "p1, standard";
+
+ if (dipSwitch.get(EMBEDDED_NONSTD)) {
+ moduleExportClasses =
+ ("nonstandard.AModuleEmbeddedNonStandard, ").concat(moduleExportClasses);
+ moduleMemberPackages = "alpha, beta, nonstandard, p1, p3, standard";
+ moduleExportPackages = "nonstandard, ".concat(moduleExportPackages);
+ }
+
+ if (dipSwitch.get(EXPORT_LEGACY)) {
+ moduleExportClasses =
+ "alpha.AModuleEmbeddedLegacyStandard, ".concat(moduleExportClasses);
+ moduleExportPackages = ("alpha, ").concat(moduleExportPackages);
+ }
+
+ if (dipSwitch.get(AUTO_CREATE)) {
+ mainClass = null;
+ moduleVersion = null;
+ moduleImport = "1.7+, java.se";
+ }
+
+ File jamFile = new File(testDir, moduleName + Utils.JAM_EXT);
+ String jamfileName = jamFile.getAbsolutePath();
+
+ // setup the arguments
+ ArrayList<String> argsList = new ArrayList<String>();
+ if (dipSwitch.get(AUTO_CREATE)) {
+ argsList.add("cv");
+ argsList.add("-N");
+ argsList.add(moduleName);
+ argsList.add("-C");
+ File modDir = new File(testDir, moduleName);
+ argsList.add(modDir.getAbsolutePath());
+ argsList.add(".");
+ jamFile = new File(moduleName + Utils.JAM_EXT);
+ jamfileName = jamFile.getAbsolutePath();
+ // delete module-info.* if any
+ File toDelete = new File(modDir, JamUtils.MODULE_INFO_CLASS);
+ toDelete.delete();
+ toDelete = new File(modDir, JamUtils.MODULE_INFO_JAVA);
+ toDelete.delete();
+ } else {
+ argsList.add("cvf");
+ argsList.add(jamfileName);
+ argsList.add("-C");
+ argsList.add(new File(testDir, moduleName).getAbsolutePath());
+ argsList.add(".");
+ }
+
+ if (dipSwitch.get(WRONG_MODULE)) {
+ argsList.add("-C");
+ argsList.add(new File(testDir, "m2").getAbsolutePath());
+ argsList.add(".");
+ }
+
+ boolean rc = false;
+ // test jam tool
+ jamFile.delete();
+ rc = Utils.makeJam(argsList);
+ verifyJam(dipSwitch.get(NEGATIVE_TEST), rc, jamfileName,
+ moduleName,
+ mainClass,
+ moduleVersion,
+ moduleImport,
+ moduleExportClasses,
+ moduleMemberPackages,
+ moduleExportPackages);
+ }
+
+ /*
+ * There are two ways to get the metadata the jam pvf and jam pf,
+ * as well as direct access to the metadata noting that this does
+ * not carry the annotations.
+ */
+ static void verifyJam(boolean negative, boolean rc, String jamfile,
+ String module, String mainClass,
+ String version, String imports,
+ String exportClassList, String memberPackageList,
+ String exportPackageTable) throws IOException {
+ if (negative) {
+ if (rc) {
+ System.err.println("negative test should have failed");
+ Utils.fail();
+ } else {
+ Utils.pass();
+ }
+ return;
+ }
+
+ // the expected strings in the output
+ ArrayList<String> expectedList = new ArrayList<String>();
+
+ if (mainClass != null) {
+ expectedList.add("java.module.annotation.MainClass:[" + mainClass + "]");
+ }
+ if (version != null) {
+ expectedList.add("java.module.annotation.Version:[" + version + "]");
+ }
+ if (imports != null) {
+ expectedList.add("java.module.annotation.ImportModules:[" + imports + "]");
+ }
+ if (exportClassList != null) {
+ expectedList.add("ModuleExportClassList:[" + exportClassList + "]");
+ }
+ if (memberPackageList != null) {
+ expectedList.add("ModuleMemberPackageList:[" + memberPackageList + "]");
+ }
+ if (exportPackageTable != null) {
+ expectedList.add("ModuleExportPackageList:[" + exportPackageTable + "]");
+ }
+ if (module != null) {
+ expectedList.add("Module:[" + module + "]");
+ }
+
+ // using jam pvf for extra diagnostics.
+ checkOutput("diags", expectedList, getJamOutput("pvf", jamfile));
+ JarFile jf = new JarFile(jamfile);
+ try {
+ // use metadata, first we strip the annnotations off
+ ArrayList<String> attributeList = new ArrayList<String>();
+ for (String x : expectedList) {
+ if (!x.startsWith("java.module.annotation")) {
+ attributeList.add(x);
+ }
+ }
+ byte[] mbuf = JamUtils.getMetadataBytes(jf);
+ MetadataParser metadata = new MetadataParser(mbuf);
+ String mout = metadata.toString();
+ System.out.println("###Output of metadata " + getTestName());
+ System.out.println(mout);
+ System.out.println("###End");
+ checkOutput("metadata", attributeList, mout);
+ } catch (ModuleParsingException ex) {
+ Utils.unexpected(ex);
+ } finally {
+ JamUtils.close(jf);
+ }
+ }
+
+ static String getJamOutput(String... jamCmds) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream pw = new PrintStream(baos);
+ sun.module.tools.Jam jamTool =
+ new sun.module.tools.Jam(pw, System.err, "JamTool");
+ jamTool.run(jamCmds);
+ String output = baos.toString();
+ System.out.println("###Output of " + jamCmds[0] + ":" + getTestName());
+ System.out.println(output);
+ System.out.println("###End");
+ return output;
+ }
+
+ static void checkOutput(String label, List<String> expectedList, String cmpOutput) {
+ boolean ok = true;
+ for (String x : expectedList) {
+ if (!cmpOutput.contains(x)) {
+ System.err.println(getTestName() + "[jam-" + label + ":error: did not find " + x);
+ ok = false;
+ }
+ }
+ if (ok) {
+ Utils.pass();
+ } else {
+ Utils.fail();
+ }
+ }
+
+ public static void realMain(String... args) throws Exception {
+ createModule(NEGATIVE_TEST, MISSING_MODINF0);
+ createModule(NEGATIVE_TEST, WRONG_MODULE);
+ createModule();
+ createModule(EXPORT_LEGACY);
+ createModule(EMBEDDED_NONSTD);
+ createModule(AUTO_CREATE);
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ public static void main(String[] args) throws Throwable {
+ try {
+ realMain(args);
+ } catch (Throwable t) {
+ Utils.unexpected(t);
+ }
+ System.out.println("\nPassed = " + Utils.passed + " failed = " + Utils.failed);
+ if (Utils.failed > 0) {
+ throw new AssertionError("Some tests failed");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/tools/jam/hello/module-info.java Tue Aug 05 13:00:39 2008 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * Declare the module "hello" with its exported class "hello.Main".
+ */
+@MainClass("hello.Main")
+@ImportModules({
+ @ImportModule(name="java.se")
+})
+@Version("1.0")
+module hello;