001: package build;
002:
003: import java.lang.reflect.Method;
004: import java.util.Iterator;
005:
006: /**
007:
008: A ClassLoader that will recompile the *.java file corresponding to
009: an out of date or missing *.class file. It also runs rmic to
010: generate *_Stub.class and *_Skel.class files used by RMI.
011:
012: <p>
013: A single CompilingClassLoader uses a sequence of pairs of
014: directories:
015:
016: <ul>
017: <li>classBase - where to look for *.class files.
018: <li>srcBase - where to look for *.java files.
019: </ul>
020:
021: The -Dbootstrap.path System property can contain a sequence of
022: classBase,srcBase pairs separated by ",". The default is
023: "-Dbootstrap.path=.,.". For each class,src pair, a new
024: CompilingClassLoader is constructed and chained to previous ones.
025: <p>
026:
027: <h3>Sample Usage:</h3>
028:
029: Supose we have a Java application, app, with the following files and
030: classes:
031: <ul>
032: <li> app.Main - Main class of the application.
033: <li> app/classlib/ - class file directory.
034: <li> app/src/ - java file directory.
035: <li> app/build/ - where this file is
036: <li> jdk/lib/tools.jar - JDK *.jar file containing javac.
037: </ul>
038:
039: The to compile and run the application, do:
040:
041: <pre>
042: javac -classpath app;jdk/lib/tools.jar -d app
043: app/build/CompilingClassLoader.java
044:
045: java -Dbootstrap.path=app/classlib,app/src
046: -classpath app;jdk/lib/tools.jar
047: CompilingClassLoader app.Main
048: </pre>
049:
050: The -classpath must provide access to CompilingClassLoader and
051: tools.jar. It should not contain any directories for classes that
052: you want recompiled. Specify them in -Dbootstrap.path instead.
053:
054: <p> When getting a class by name, use
055: CompilingClassLoader.forName() rather than Class.forName(). This
056: will recompile such classes as necessary.
057:
058: **/
059: public class CompilingClassLoader extends LoadletClassLoader {
060:
061: public CompilingClassLoader(ClassLoader parent, Loadlet loadlet) {
062: super (parent, loadlet);
063: }
064:
065: private static Iterator crack(final String s, final char separator) {
066: return new Iterator() {
067: int start = 0;
068:
069: public boolean hasNext() {
070: return start < s.length();
071: }
072:
073: public Object next() {
074: int end = s.indexOf(separator, start);
075: end = (end == -1) ? s.length() : end;
076: String result = s.substring(start, end);
077: start = end + 1;
078: return result;
079: }
080:
081: public void remove() {
082: }
083: };
084: }
085:
086: /**
087: Start your Java application through this main() as described
088: above to get automatic compiling behavior.
089: **/
090: public static void main(String[] args) {
091: try {
092: Iterator paths = crack(System.getProperty("bootstrap.path",
093: ".,."), ',');
094: Loadlet loadlet = null;
095: while (paths.hasNext()) {
096: String bin = (String) paths.next();
097: if (paths.hasNext()) {
098: String src = (String) paths.next();
099: loadlet = new CompilingLoadlet(loadlet, bin, src);
100: } else
101: break;
102: }
103: ClassLoader loader = new CompilingClassLoader(
104: CompilingClassLoader.class.getClassLoader(),
105: loadlet);
106: Class c = loader.loadClass(args[0]);
107: Class[] types = new Class[] { String[].class };
108: Method m = c.getMethod("main", types);
109: int n = 1;
110: String[] newArgs = new String[args.length - n];
111: for (int i = 0; i < newArgs.length; i++)
112: newArgs[i] = args[i + n];
113: Object[] parameters = new Object[] { newArgs };
114: m.invoke(null, parameters);
115: } catch (Exception e) {
116: e.printStackTrace();
117: }
118: }
119: }
|