001// Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 002// The Molly framework is freely distributable under the terms of an 003// MIT-style license. For details, see the molly pages web site at: 004// http://www.mollypages.org/. Use, modify, have fun ! 005 006package fc.web.page; 007 008import java.io.*; 009import java.util.*; 010import fc.util.*; 011 012/** 013Used to compile generated pages by invoking the java compiler. 014*/ 015public class PageCompiler 016{ 017private static final boolean dbg = false; 018 019String error; 020File javafile; 021String classpath; 022String encoding; 023 024/** 025Creates a new page compiler that will use the default (system) classpath 026as seen by 'javac' when it is invoked from the command line. No 027seperate "encoding" flag will be specified to the javac. 028 029*/ 030public PageCompiler(File javafile) 031 { 032 this.javafile = javafile; 033 } 034 035/** 036Creates a new page compiler with the specified classpath. This is useful 037when the classpath must contain some directories within the servlet web 038application, just as <tt>WEB-INF/classes</tt>, <tt>WEB-INF/lib</tt> etc. 039 040@param javafile the source java file to compile 041@param classpath classpath to use when compiling 042@param encoding the encoding of the java source file (example ISO-8859-1, UTF-8 etc.). 043 Used by the -encoding flag passed to javac. Specify <tt>null</tt> for 044 no specific encoding. Modern Java platforms *seem* to default to UTF-8 045 (used to be ISO-8859-1 back in the day) if nothing is specified. 046 <p>When invoked/used internally (ie not seperately from the command line), we 047 specify a {@link Page#DEFAULT_SRC_ENCODING} as the src encoding anyway. 048 */ 049public PageCompiler(File javafile, String classpath, String encoding) 050 { 051 this.javafile = javafile; 052 this.classpath = classpath; 053 this.encoding = encoding; 054 } 055 056public String getError() 057 { 058 return error; 059 } 060 061public boolean compile() throws IOException 062 { 063 //javac 1.5.x does not crap out if a 0 byte source file is fed to it 064 //it simply returns 0 (implying success) but does NOT generate a classfile. so this hack. 065 if (javafile.length() == 0) 066 { 067 error = "Java source file [" + 068 javafile.getCanonicalPath() + 069 "] size was 0 bytes. This file cannot be compiled"; 070 071 return false; 072 } 073 074 //this is ok too: {"bash", "-c", "javac -nowarn /tmp/c.java"}); 075 List javac_cmd = new ArrayList(); 076 javac_cmd.add("javac"); 077 javac_cmd.add("-nowarn"); 078 079 if (encoding != null) { 080 javac_cmd.add("-encoding"); 081 javac_cmd.add(encoding); 082 } 083 084 if (classpath != null) { 085 javac_cmd.add("-classpath"); 086 javac_cmd.add(classpath); 087 } 088 javac_cmd.add(javafile.getCanonicalPath()); 089 090 if (dbg) System.out.println("Compile command: " + javac_cmd); 091 092 ProcessBuilder pb = new ProcessBuilder(javac_cmd); 093 094 Process p = pb.start(); 095 096 int exit_val = 0; 097 098 /* 099 have to read out/err from the process otherwise it may hang if 100 javac has lots of output (in case of errors)...waitFor will not 101 return since the process is hung. 102 See: jdk 1.5 docs and 103 http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html 104 105 try 106 { 107 exit_val = p.waitFor(); 108 } 109 catch (InterruptedException e) 110 { 111 throw new IOException(e.toString()); 112 } 113 */ 114 115 CharArrayWriter buf = new CharArrayWriter(1024); 116 117 InputStream stderr = new BufferedInputStream(p.getErrorStream()); 118 InputStream stdout = new BufferedInputStream(p.getInputStream()); 119 120 int c = stderr.read(); 121 while (c != -1) { 122 buf.write((char)c); 123 c = stderr.read(); 124 } 125 126 c = stdout.read(); 127 if (c != -1) 128 buf.append("-------------------------------------------"); 129 130 while (c != -1) { 131 buf.write((char)c); 132 c = stdout.read(); 133 } 134 135 error = buf.toString(); 136 137 try 138 { 139 exit_val = p.waitFor(); 140 } 141 catch (InterruptedException e) 142 { 143 throw new IOException(e.toString()); 144 } 145 146 if (dbg) System.out.println("Exit value: " + exit_val); 147 148 return exit_val == 0; 149 } 150 151public static void main (String args[]) throws Exception 152 { 153 Args myargs = new Args(args); 154 myargs.setUsage("java " + ClassUtil.getClassName() + " -file path-to-file-to-compile [-classpath <class-path> -encoding encoding]"); 155 156 PageCompiler pc = new PageCompiler( 157 new File(myargs.getRequired("file")), 158 myargs.get("classpath", System.getProperty("java.class.path")), 159 myargs.get("encoding", null) 160 ); 161 162 if (! pc.compile()) 163 System.out.println(pc.getError()); 164 } 165}