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