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