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
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*/
047public PageCompiler(File javafile, String classpath, String encoding)
048  {
049  this.javafile = javafile;
050  this.classpath  = classpath;
051  this.encoding = encoding;
052  }
053  
054public String getError()
055  {
056  return error;
057  }
058  
059public 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
149public 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}