package org.kohsuke.bali.writer;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Collection;
import java.util.Iterator;
import java.util.zip.GZIPOutputStream;
import org.kohsuke.bali.automaton.TreeAutomaton;
import org.kohsuke.bali.datatype.DatatypeImpl;
import org.kohsuke.bali.datatype.ValidationContextImpl;
import org.kohsuke.bali.datatype.Value;
import org.relaxng.datatype.Datatype;
/**
* Produces Java validatelet source code.
*
* @author Kohsuke Kawaguchi (kk@kohsuke.org)
*/
public class JavaWriter extends StringBasedEncoder {
public JavaWriter( String packageName, String className, File outDir ) throws IOException {
this.packageName = packageName;
this.className = className;
while( packageName.length()!=0 ) {
int idx = packageName.indexOf('.');
if(idx==-1) idx = packageName.length();
String s = packageName.substring(0,idx);
outDir = new File(outDir,s);
outDir.mkdir();
// move to the next part
packageName = packageName.substring(idx);
if(packageName.length()>0) packageName=packageName.substring(1);
}
targetDir = outDir;
out = new FileWriter( new File( outDir, className+".java" ) );
}
private final String packageName;
private final String className;
/** Writer connected to the generated validatelet. */
private final Writer out;
/** The directory to which all the generated files will be placed. */
private final File targetDir;
/**
* Gets the package declaration as a string if the generated file
* should belong to a package.
*/
private String getPackageDeclaration() {
return packageName.length()==0?"":("package "+packageName+";");
}
public void write(TreeAutomaton automaton) throws IOException {
System.err.println("producing a Java validatelet");
super.write(automaton);
}
protected void write(
String encNameCodes,
int defaultNameCode,
String encStates,
String encATr,
String encDTr,
String encETr,
String encITr,
String encLTr,
String encNTr,
String encVTr,
DatatypeImpl[] datatypes,
Value[] values ) throws IOException {
out.write(format("preamble", getPackageDeclaration(), className ));
out.write(Util.toJavaString(encNameCodes));
out.write("/*name literals*/,\n");
out.write(Integer.toString(defaultNameCode));
out.write("/*default name code*/,\n");
out.write(compress(encStates));
out.write("/*states*/,\n");
out.write(compress(encATr));
out.write("/*a-tr*/,\n");
out.write(compress(encDTr));
out.write("/*d-tr*/,\n");
out.write(compress(encETr));
out.write("/*e-tr*/,\n");
out.write(compress(encITr));
out.write("/*i-tr*/,\n");
out.write(compress(encLTr));
out.write("/*l-tr*/,\n");
out.write(compress(encNTr));
out.write("/*n-tr*/,\n");
out.write(compress(encVTr));
out.write("/*v-tr*/,\n");
out.write("new Object[]{");
for( int i=0; i<datatypes.length; i++ ) {
if(i!=0) out.write(',');
out.write(encode(datatypes[i]));
}
out.write("}/*datatypes*/,\n");
out.write("new Object[]{");
for( int i=0; i<values.length; i++ ) {
if(i!=0) out.write(',');
out.write(Util.toJavaString(values[i].value));
out.write(',');
out.write(encodeContext(values[i].context));
}
out.write("}/*values*/");
out.write(format("epilogue", className ));
out.close();
// copy other files necessary to run the generated code
copy("AttributesSet.java");
copy("BuiltinDatatypeLibrary.java");
copy("NameCodeMap.java");
copy("Schema.java");
copy("State.java");
copy("StateFactory.java");
copy("Transition.java");
copy("ValidateletImpl.java");
}
/**
* Copies the resource file with the given file name to the target directory.
* Used to produce runtime code the target directory.
*/
private void copy( String fileName ) throws IOException {
BufferedReader reader = new BufferedReader( new InputStreamReader(
this.getClass().getResourceAsStream("/runtime/"+fileName) ));
PrintWriter writer = new PrintWriter(new FileWriter( new File( targetDir, fileName ) ));
// replace the package declaration
reader.readLine();
writer.write( getPackageDeclaration()+"\n" );
// copy the rest of the lines
String line;
while( (line=reader.readLine())!=null )
writer.println(line);
reader.close();
writer.close();
}
private String compress( String s ) {
if( s.length()<10000 )
return escape(s); // no need for compression
try {
// compress by GZip
OutputStream os = new StringOutputStream();
Writer w = new OutputStreamWriter(new GZIPOutputStream(os),"UTF-8");
w.write(s);
w.close();
StringBuffer out = new StringBuffer();
out.append("Schema.decompress(");
out.append(escape(os.toString()));
out.append(")");
return out.toString();
} catch( IOException e ) {
// impossible
throw new InternalError();
}
}
protected String escape(String str) {
return Util.toJavaString(str);
}
}