//----------------------------BEGIN LICENSE----------------------------
/*
* Willow : the Open Source WorkFlow Project
* Distributable under GNU LGPL license by gun.org
*
* Copyright (C) 2004-2010 huihoo.org
* Copyright (C) 2004-2010 ZosaTapo <dertyang@hotmail.com>
*
* ====================================================================
* Project Homepage : http://www.huihoo.org/willow
* Source Forge : http://sourceforge.net/projects/huihoo
* Mailing list : willow@lists.sourceforge.net
*/
//----------------------------END LICENSE-----------------------------
package org.huihoo.workflow.rules.compiler;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Hashtable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.huihoo.workflow.rules.Constants;
import org.huihoo.workflow.rules.ScriptException;
import org.huihoo.workflow.rules.config.Options;
import org.huihoo.workflow.rules.config.ScriptCompilationContext;
import org.huihoo.workflow.rules.util.StringManager;
import org.huihoo.workflow.xpdl.WorkflowCondition;
import org.huihoo.workflow.xpdl.condition.ScriptCondition;
import org.huihoo.workflow.xpdl.condition.XCDATACondition;
/**
* @author zosatapo
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
public class Compiler
{
private static StringManager sm = StringManager.getManager(Constants.RESOURCE_BUNDLE_BASE);
private static Log log = LogFactory.getLog(Compiler.class);
// ----------------------------------------------------- Instance Variables
protected JavaCompiler javac;
protected ScriptCompilationContext ctxt;
protected Options options;
// ------------------------------------------------------------ Constructor
public Compiler(ScriptCompilationContext ctxt)
{
this.ctxt = ctxt;
this.options = ctxt.getOptions();
}
// --------------------------------------------------------- Public Methods
public ScriptCompilationContext getCompilationContext()
{
return ctxt;
}
/**
* Compile the script file from the current engine context
*/
public boolean compile() throws ScriptException, FileNotFoundException, Exception
{
return compile(true);
}
/**
* Compile the script file from the current engine context. As an side-
* effect, tag files that are referenced by this page are also compiled.
* @param compileClass If true, generate both .java and .class file
* If false, generate only .java file
*/
public boolean compile(boolean compileClass) throws ScriptException, FileNotFoundException, Exception
{
if (!isOutDated(compileClass))
{
return true;
}
WorkflowCondition condition=ctxt.getCondition();
if(condition!=null && condition instanceof ScriptCondition)
{
return compileFile((ScriptCondition)condition,compileClass);
}
else if(condition!=null && condition instanceof XCDATACondition)
{
return compileContent((XCDATACondition)condition,compileClass);
}
return true;
}
/**
* This is a protected method intended to be overridden by
* subclasses of Compiler. This is used by the compile method
* to do all the compilation.
*/
public boolean isOutDated()
{
return isOutDated(true);
}
/**
* Determine if a compilation is necessary by checking the time stamp
* of the script page with that of the corresponding .class or .java file.
*
* This method can by overidden by a subclasses of Compiler.
* @param checkClass If true, check against .class file,
* if false, check against .java file.
*/
public boolean isOutDated(boolean checkClass)
{
return true;
}
/**
* Set java compiler info
*/
public void setJavaCompiler(JavaCompiler javac)
{
this.javac = javac;
}
/**
* Change the encoding for the reader if specified.
*/
public String changeEncodingIfNecessary(ScriptReader tmpReader) throws ScriptException
{
// A lot of code replicated from Parser.java
// Main aim is to "get-it-to-work".
while (tmpReader.skipUntil("<%@") != null)
{
tmpReader.skipSpaces();
// check if it is a page directive.
if (tmpReader.matches("script"))
{
tmpReader.advance(4);
tmpReader.skipSpaces();
try
{
Hashtable attrs = tmpReader.parseTagAttributes();
String ct = (String) attrs.get("charset");
if (ct != null)
{
return ct;
}
}
catch (ScriptException ex)
{
// Ignore the exception here, it will be caught later.
return null;
}
}
}
return null;
}
/**
* Remove generated files
*/
public void removeGeneratedFiles()
{
try
{
String classFileName = ctxt.getScriptClassFileName();
if (classFileName != null)
{
File classFile = new File(classFileName);
if (log.isDebugEnabled())
{
log.debug("Deleting " + classFile);
}
classFile.delete();
}
}
catch (Exception e)
{
// Remove as much as possible, ignore possible exceptions
}
try
{
String javaFileName = ctxt.getScriptJavaFileName();
if (javaFileName != null)
{
File javaFile = new File(javaFileName);
log.debug("Deleting " + javaFile);
javaFile.delete();
}
}
catch (Exception e)
{
// Remove as much as possible, ignore possible exceptions
}
}
protected boolean compileFile(ScriptCondition condition, boolean compileClass) throws ScriptException, FileNotFoundException, Exception
{
String javaFileName = ctxt.getScriptJavaFileName();
String scriptEncoding = "ISO-8859-1"; // default per Script spec
String javaEncoding = "UTF8";
String filePath = options.getScriptDir() + File.separator + condition.getContent();
if (true)
{
ScriptReader tmpReader = ScriptReader.createGodjReader(filePath, ctxt, scriptEncoding);
String newEncode = changeEncodingIfNecessary(tmpReader);
if (newEncode != null)
scriptEncoding = newEncode;
}
ScriptReader reader = ScriptReader.createGodjReader(filePath, ctxt, scriptEncoding);
OutputStreamWriter osw;
try
{
osw = new OutputStreamWriter(new FileOutputStream(javaFileName), javaEncoding);
}
catch (java.io.UnsupportedEncodingException ex)
{
// Try to get the java encoding from the "javaEncoding"
// init parameter for JspServlet.
javaEncoding = ctxt.getOptions().getJavaEncoding();
if (javaEncoding != null)
{
try
{
osw = new OutputStreamWriter(new FileOutputStream(javaFileName), javaEncoding);
}
catch (java.io.UnsupportedEncodingException ex2)
{
// no luck :-(
throw new ScriptException(sm.getString("script.error.invalid.javaEncoding", new Object[] { "UTF8", javaEncoding, }));
}
}
else
{
throw new ScriptException(sm.getString("script.error.needAlternateJavaEncoding", new Object[] { "UTF8" }));
}
}
ScriptWriter writer = new ScriptWriter(new PrintWriter(osw));
ctxt.setReader(reader);
ctxt.setWriter(writer);
ParseEventListener listener = new ScriptParseEventListener(ctxt);
Parser p = new Parser(reader, listener);
listener.beginScriptProcessing();
p.parse();
listener.endScriptProcessing();
writer.close();
ByteArrayOutputStream out = new ByteArrayOutputStream(256);
String classpath = ctxt.getClassPath();
javac.setClassDebugInfo(options.getClassDebugInfo());
javac.setClassPath(classpath);
javac.setJavaFilePath(javaFileName);
javac.setJavaEncoding(options.getJavaEncoding());
javac.setOutputDir(options.getScratchDir().getAbsolutePath());
javac.setMsgOutput(out);
/**
* Execute the compiler
*/
boolean status = javac.compile();
if (!ctxt.keepGenerated())
{
File javaFile = new File(javaFileName);
javaFile.delete();
}
if (status == false)
{
String msg = out.toString();
throw new ScriptException(sm.getString("script.error.unable.compile") + msg);
}
return true;
}
protected boolean compileContent(XCDATACondition condition, boolean compileClass) throws ScriptException, FileNotFoundException, Exception
{
String javaFileName = ctxt.getScriptJavaFileName();
String scriptEncoding = "ISO-8859-1"; // default per Script spec
String javaEncoding = "UTF8";
ScriptReader reader = ScriptReader.createGodjReader(condition.getContent(), ctxt);
OutputStreamWriter osw;
try
{
osw = new OutputStreamWriter(new FileOutputStream(javaFileName), javaEncoding);
}
catch (java.io.UnsupportedEncodingException ex)
{
// Try to get the java encoding from the "javaEncoding"
// init parameter for JspServlet.
javaEncoding = ctxt.getOptions().getJavaEncoding();
if (javaEncoding != null)
{
try
{
osw = new OutputStreamWriter(new FileOutputStream(javaFileName), javaEncoding);
}
catch (java.io.UnsupportedEncodingException ex2)
{
// no luck :-(
throw new ScriptException(sm.getString("script.error.invalid.javaEncoding", new Object[] { "UTF8", javaEncoding, }));
}
}
else
{
throw new ScriptException(sm.getString("script.error.needAlternateJavaEncoding", new Object[] { "UTF8" }));
}
}
ScriptWriter writer = new ScriptWriter(new PrintWriter(osw));
ctxt.setReader(reader);
ctxt.setWriter(writer);
ParseEventListener listener = new ScriptParseEventListener(ctxt);
Parser p = new Parser(reader, listener);
listener.beginScriptProcessing();
p.parse();
listener.endScriptProcessing();
writer.close();
ByteArrayOutputStream out = new ByteArrayOutputStream(256);
String classpath = ctxt.getClassPath();
javac.setClassDebugInfo(options.getClassDebugInfo());
javac.setClassPath(classpath);
javac.setJavaFilePath(javaFileName);
javac.setJavaEncoding(options.getJavaEncoding());
javac.setOutputDir(options.getScratchDir().getAbsolutePath());
javac.setMsgOutput(out);
/**
* Execute the compiler
*/
boolean status = javac.compile();
if (!ctxt.keepGenerated())
{
File javaFile = new File(javaFileName);
javaFile.delete();
}
if (status == false)
{
String msg = out.toString();
throw new ScriptException(sm.getString("script.error.unable.compile") + msg);
}
return true;
}
}