001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.java;
031:
032: import com.caucho.java.gen.DependencyComponent;
033: import com.caucho.java.gen.GenClass;
034: import com.caucho.loader.SimpleLoader;
035: import com.caucho.server.util.CauchoSystem;
036: import com.caucho.util.CharBuffer;
037: import com.caucho.vfs.IOExceptionWrapper;
038: import com.caucho.vfs.Path;
039: import com.caucho.vfs.PersistentDependency;
040: import com.caucho.vfs.WriteStream;
041:
042: import java.io.IOException;
043: import java.lang.reflect.Method;
044: import java.util.ArrayList;
045:
046: /**
047: * Generates the Java code for the wrapped object.
048: */
049: public abstract class AbstractGenerator {
050: // The full name of the generated class
051: private String _fullClassName;
052: // The package of the generated class
053: private String _packageName;
054: // The class name of the generated class
055: private String _className;
056:
057: // Parent class loader
058: private ClassLoader _parentLoader;
059: // class loader
060: private ClassLoader _loader;
061:
062: // Write stream for generating the code
063: private WriteStream _os;
064: // The java writer
065: protected JavaWriter _out;
066:
067: // The search path
068: private Path _searchPath;
069:
070: // The work directory
071: private Path _workPath;
072:
073: private GenClass _genClass;
074:
075: private String _initMethod = "_caucho_init";
076: private String _isModifiedMethod = "_caucho_is_modified";
077:
078: /**
079: * Sets the search path.
080: */
081: public void setSearchPath(Path path) {
082: _searchPath = path;
083: }
084:
085: public Path getSearchPath() {
086: return _searchPath;
087: }
088:
089: /**
090: * Sets the full generated class.
091: */
092: public void setFullClassName(String fullClassName) {
093: CharBuffer cb = CharBuffer.allocate();
094: for (int i = 0; i < fullClassName.length(); i++) {
095: char ch = fullClassName.charAt(i);
096:
097: if (ch == '.' || ch == '/')
098: cb.append('.');
099: else if (Character.isJavaIdentifierPart(ch))
100: cb.append(ch);
101: else
102: cb.append('_');
103: }
104:
105: _fullClassName = cb.close();
106:
107: int p = _fullClassName.lastIndexOf('.');
108: if (p > 0) {
109: _packageName = _fullClassName.substring(0, p);
110: _className = _fullClassName.substring(p + 1);
111: } else {
112: _packageName = "";
113: _className = _fullClassName;
114: }
115: }
116:
117: /**
118: * Returns the full class name
119: */
120: public String getFullClassName() {
121: if (_genClass != null)
122: return _genClass.getFullClassName();
123: else
124: return _fullClassName;
125: }
126:
127: /**
128: * Returns the generated package name
129: */
130: public String getPackageName() {
131: if (_genClass != null)
132: return _genClass.getPackageName();
133: else
134: return _packageName;
135: }
136:
137: /**
138: * Returns the generated class name
139: */
140: public String getClassName() {
141: if (_genClass != null)
142: return _genClass.getClassName();
143: else
144: return _className;
145: }
146:
147: /**
148: * Sets the java class.
149: */
150: public void setGenClass(GenClass genClass) {
151: _genClass = genClass;
152: }
153:
154: /**
155: * Gets the java class.
156: */
157: public GenClass getGenClass() {
158: return _genClass;
159: }
160:
161: /**
162: * Sets the parent class loader.
163: *
164: * @param loader parent class loader
165: */
166: public void setParentLoader(ClassLoader loader) {
167: _parentLoader = loader;
168: }
169:
170: /**
171: * Sets the class loader.
172: *
173: * @param loader parent class loader
174: */
175: public void setLoader(ClassLoader loader) {
176: _loader = loader;
177: }
178:
179: /**
180: * Sets the parent class loader.
181: *
182: * @return the parent class loader
183: */
184: public ClassLoader getParentLoader() {
185: if (_parentLoader == null)
186: _parentLoader = Thread.currentThread()
187: .getContextClassLoader();
188:
189: return _parentLoader;
190: }
191:
192: /**
193: * Sets the work path for the generated class.
194: */
195: public void setClassDir(Path workPath) {
196: _workPath = workPath;
197: }
198:
199: /**
200: * Returns the class dir for the generated class.
201: */
202: public Path getClassDir() {
203: if (_workPath == null)
204: return CauchoSystem.getWorkPath();
205: else
206: return _workPath;
207: }
208:
209: /**
210: * Try to preload the class.
211: *
212: * @return true if the preloaded class is still valid.
213: */
214: public Class preload() throws IOException {
215: return loadClass(true);
216: }
217:
218: /**
219: * Call to generate the java source.
220: */
221: public void generate() throws Exception {
222: String className = getFullClassName();
223: String javaPathName = className.replace('.', '/') + ".java";
224: String classPathName = className.replace('.', '/') + ".class";
225:
226: Path javaPath = getClassDir().lookup(javaPathName);
227: Path classPath = getClassDir().lookup(classPathName);
228:
229: try {
230: classPath.remove();
231: } catch (IOException e) {
232: }
233:
234: javaPath.getParent().mkdirs();
235:
236: _os = javaPath.openWrite();
237: _out = new JavaWriter(_os);
238:
239: if (_genClass != null)
240: _genClass.generate(_out);
241: else
242: generateJava();
243:
244: _os.close();
245: }
246:
247: /**
248: * Compiles the Java code
249: */
250: public Class compile() throws Exception {
251: compileJava();
252:
253: return loadClass(false);
254: }
255:
256: /**
257: * Starts generation of the Java code
258: */
259: public void generateJava() throws Exception {
260: }
261:
262: /**
263: * Generates the class dependency code.
264: *
265: * @param depends list of Paths representing dependencies
266: */
267: protected void printDependList(
268: ArrayList<PersistentDependency> depends) throws IOException {
269: DependencyComponent depend = new DependencyComponent();
270: depend.setSearchPath(_searchPath);
271:
272: for (int i = 0; i < depends.size(); i++)
273: depend.addDependency(depends.get(i));
274:
275: depend.generate(getOut());
276: }
277:
278: /**
279: * Prints code to detect a version change.
280: */
281: protected void printVersionChange() throws IOException {
282: println("if (com.caucho.server.util.CauchoSystem.getVersionId() != "
283: + CauchoSystem.getVersionId() + ")");
284: println(" return true;");
285: }
286:
287: /**
288: * Prints a method header.
289: *
290: * @param method the method to print
291: */
292: public void printMethodHeader(Method method) throws IOException {
293: printMethodHeader(method.getName(), method.getParameterTypes(),
294: method.getReturnType(), method.getExceptionTypes());
295: }
296:
297: /**
298: * Prints a method header.
299: *
300: * @param name the method name to print
301: * @param method the method to print
302: */
303: public void printMethodHeader(String name, Method method)
304: throws IOException {
305: printMethodHeader(name, method.getParameterTypes(), method
306: .getReturnType(), method.getExceptionTypes());
307: }
308:
309: /**
310: * Prints a method header.
311: *
312: * @param methodName the method name to print
313: * @param param the method argument classes
314: * @param returnType the return type of the method
315: * @param exn array of exceptions thrown by the method
316: */
317: public void printMethodHeader(String methodName,
318: Class[] parameters, Class returnType, Class[] exn)
319: throws IOException {
320: println();
321: print("public ");
322: printClass(returnType);
323: print(" ");
324: print(methodName);
325: print("(");
326:
327: for (int i = 0; i < parameters.length; i++) {
328: if (i != 0)
329: print(", ");
330:
331: printClass(parameters[i]);
332: print(" a" + i);
333: }
334: println(")");
335:
336: if (exn != null && exn.length > 0) {
337: print(" throws ");
338: printClass(exn[0]);
339:
340: for (int i = 1; i < exn.length; i++) {
341: print(", ");
342: printClass(exn[i]);
343: }
344: println();
345: }
346: }
347:
348: /**
349: * Prints the Java represention of the class
350: */
351: public void printClass(Class cl) throws IOException {
352: if (!cl.isArray())
353: print(cl.getName().replace('$', '.'));
354: else {
355: printClass(cl.getComponentType());
356: print("[]");
357: }
358: }
359:
360: /**
361: * Compiles the class.
362: */
363: public void compileJava() throws IOException,
364: ClassNotFoundException {
365: JavaCompiler compiler = getCompiler();
366:
367: compiler.compile(
368: getFullClassName().replace('.', '/') + ".java", null);
369: }
370:
371: public JavaCompiler getCompiler() {
372: JavaCompiler compiler = JavaCompiler.create(getParentLoader());
373:
374: compiler.setClassLoader(getParentLoader());
375: compiler.setClassDir(getClassDir());
376:
377: return compiler;
378: }
379:
380: /**
381: * Loads the generated class. If any class dependencies have
382: * changed, return null.
383: */
384: public Class loadClass(boolean preload) throws IOException {
385: return loadClass(getFullClassName(), preload);
386: }
387:
388: /**
389: * Loads the generated class. If any class dependencies have
390: * changed, return null.
391: */
392: public Class loadClass(String fullClassName, boolean preload)
393: throws IOException {
394: try {
395: ClassLoader loader;
396:
397: if (!preload && _loader != null)
398: loader = _loader;
399: else {
400: loader = SimpleLoader.create(getParentLoader(),
401: getClassDir(), fullClassName);
402: }
403:
404: Class cl = CauchoSystem.loadClass(fullClassName, false,
405: loader);
406:
407: if (cl == null)
408: return null;
409: if (!preload)
410: return cl;
411:
412: Method method = cl.getMethod(_initMethod,
413: new Class[] { Path.class });
414: method.invoke(null, new Object[] { getSearchPath() });
415:
416: method = cl.getMethod(_isModifiedMethod, new Class[0]);
417: Boolean value = (Boolean) method.invoke(null,
418: new Object[] {});
419:
420: if (value.booleanValue())
421: return null;
422:
423: if (_loader != null)
424: loader = _loader;
425: else {
426: loader = SimpleLoader.create(getParentLoader(),
427: getClassDir(), fullClassName);
428: }
429:
430: return CauchoSystem.loadClass(fullClassName, false, loader);
431: } catch (Throwable e) {
432: if (!preload)
433: throw new IOExceptionWrapper(e);
434: else
435: return null;
436: }
437: }
438:
439: /**
440: * Returns the java writer.
441: */
442: public JavaWriter getOut() {
443: return _out;
444: }
445:
446: /**
447: * Pushes an indentation depth.
448: */
449: public void pushDepth() throws IOException {
450: _out.pushDepth();
451: }
452:
453: /**
454: * Pops an indentation depth.
455: */
456: public void popDepth() throws IOException {
457: _out.popDepth();
458: }
459:
460: /**
461: * Prints a character
462: */
463: public void print(int ch) throws IOException {
464: _out.print(ch);
465: }
466:
467: /**
468: * Prints a character
469: */
470: public void print(char ch) throws IOException {
471: _out.print(ch);
472: }
473:
474: /**
475: * Prints a string
476: */
477: public void print(String s) throws IOException {
478: _out.print(s);
479: }
480:
481: /**
482: * Prints a string
483: */
484: public void printStr(String s) throws IOException {
485: int len = s.length();
486: for (int i = 0; i < len; i++) {
487: char ch = s.charAt(i);
488:
489: switch (ch) {
490: case '\\':
491: _out.print("\\\\");
492: break;
493: case '\n':
494: _out.print("\\n");
495: break;
496: case '\r':
497: _out.print("\\r");
498: break;
499: case '"':
500: _out.print("\\\"");
501: break;
502: default:
503: _out.print(ch);
504: }
505: }
506: }
507:
508: /**
509: * Prints a new line.
510: */
511: public void println() throws IOException {
512: _out.println();
513: }
514:
515: /**
516: * Prints a string with a new line
517: */
518: public void println(String s) throws IOException {
519: _out.println(s);
520: }
521: }
|