/*
* AnnotationsByOffset.java
* Copyright: Copyright (c) 2005, Ontotext Lab.
* Company: Ontotext Lab.
* Krasimir Angelov 12/2005 */
package com.ontotext.gate.japec;
import java.io.*;
import java.net.*;
import java.util.*;
import gate.*;
import gate.util.*;
import gate.creole.*;
public class JapecTransducer extends AbstractLanguageAnalyser {
private static final boolean DEBUG = false;
private File grammarFile;
private URL grammarURL;
private File workDir;
private String packageName;
private String encoding;
private String inputASName;
private String outputASName;
private gate.creole.ontology.Ontology ontology;
private List phases;
public JapecTransducer() {
grammarURL = null;
workDir = null;
packageName = null;
encoding = null;
inputASName = null;
outputASName = null;
ontology = null;
phases = new ArrayList();
}
public Resource init() throws ResourceInstantiationException
{
//sanity checks
if(grammarURL == null) throw new ResourceInstantiationException(
"No URL provided for the grammar!");
//Japec can only read file: URLs
if(!grammarURL.getProtocol().equals("file"))
throw new ResourceInstantiationException(
"Japec JAPE Compiler only supports file URLs for input!");
loadGrammar();
return this;
}
public void reInit() throws ResourceInstantiationException
{
loadGrammar();
}
protected void loadGrammar() throws ResourceInstantiationException
{
try{
String gateSym = Gate.genSym();
//create the temporary work directory
workDir = File.createTempFile("japec-workdir", gateSym);
workDir.delete();
workDir.mkdir();
workDir.deleteOnExit();
grammarFile = Files.fileFromURL(grammarURL);
if(DEBUG) {
System.err.println("Loading grammar from file " + grammarFile);
}
packageName = "com.ontotext.gate.japec.grammar" + gateSym;
if(DEBUG) {
System.err.println("Generating classes into package " + packageName);
}
compileGrammar();
Files.rmdir(workDir);
} catch(ResourceInstantiationException rie) {
throw rie;
}catch(Exception e){
throw new ResourceInstantiationException(e);
}
}
public void execute() throws ExecutionException {
for (int i = 0; i < phases.size(); i++)
{
SinglePhaseTransducer phase = (SinglePhaseTransducer) phases.get(i);
phase.setDocument(document);
phase.setInputASName(inputASName);
phase.setOutputASName(outputASName);
phase.execute();
}
}
protected void compileGrammar() throws IOException,
ResourceInstantiationException, ClassNotFoundException, GateException,
InstantiationException, IllegalAccessException
{
//compile the JAPE file(s) to Java
String osname = System.getProperty("os.name").toLowerCase();
// Find Jape_Compiler plugin directory from plugin ResourceData
ResourceData japecRD =
(ResourceData)Gate.getCreoleRegister().get(this.getClass().getName());
URL japecCreoleXML = japecRD.getXmlFileUrl();
if(!"file".equals(japecCreoleXML.getProtocol())) {
throw new ResourceInstantiationException(
"Jape_Compiler plugin must be loaded from a file: URL");
}
File japecCreoleXMLFile = Files.fileFromURL(japecCreoleXML);
// search for Japec compiler binary. We look first for japec (.exe on
// Windows) in the Jape_Compiler plugin directory. If that does not exist,
// we try the OS-specific name (japec-windows.exe, japec-mac, etc). If
// neither of these exist, throw an exception. Searching this way round
// means a locally compiled japec will be found before the default
// japec-platform version.
File japecDir = japecCreoleXMLFile.getParentFile();
String japecBinary = "japec";
if(osname.indexOf("windows") >= 0) japecBinary += ".exe";
File plainJapecPath = new File(japecDir, japecBinary);
File japecPath;
if(plainJapecPath.exists()) {
japecPath = plainJapecPath;
}
else {
String suffix = null;
if (osname.indexOf("windows") >= 0) suffix = "-windows.exe";
else if (osname.indexOf("linux") >= 0) suffix = "-linux";
else if (osname.indexOf("mac") >= 0) suffix = "-mac";
else throw new ResourceInstantiationException(
"Could not find Japec compiler - should be at " + plainJapecPath);
japecPath = new File(japecDir, "japec" + suffix);
if(!japecPath.exists()) {
throw new ResourceInstantiationException(
"Could not find Japec compiler - should be at either "
+ plainJapecPath + " or " + japecPath);
}
}
if(DEBUG) {
Out.prln("Using compiler at " + japecPath);
}
Process p = Runtime.getRuntime().exec(new String[] {japecPath.getPath(),
grammarFile.getPath(),
"--odir", workDir.getPath(),
"--package", packageName
});
BufferedReader error =
new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line;
while ((line = error.readLine()) != null) {
Err.prln(line);
}
error.close();
BufferedReader input =
new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
Err.prln(line);
}
input.close();
//compile the generated classes and load the classes into the classloader
Map sources = new LinkedHashMap();
// phase class names are stored in a List to allow the same phase to be
// used more than once in a multiphase transducer.
List allPhaseClassNames = new ArrayList();
//read the phases file
File phasesFile = new File(workDir, "phases");
phasesFile.deleteOnExit();
BufferedReader phasesReader = new BufferedReader(
new FileReader(phasesFile));
for(line = phasesReader.readLine();
line != null;
line = phasesReader.readLine()){
String phaseName = line.trim();
String phaseClassName = packageName + "." + phaseName;
File phaseFile = new File(workDir, phaseName + ".java");
phaseFile.deleteOnExit();
BufferedReader sourceReader = new BufferedReader(new FileReader(
phaseFile));
StringBuffer source = new StringBuffer();
for(String sourceLine = sourceReader.readLine();
sourceLine != null;
sourceLine = sourceReader.readLine()){
source.append(sourceLine);
source.append(Strings.getNl());
}
sources.put(phaseClassName, source.toString());
allPhaseClassNames.add(phaseClassName);
}
//call the Java compiler
Javac.loadClasses(sources);
// create the phases
phases.clear();
for(Iterator phaseClassNameIter = allPhaseClassNames.iterator();
phaseClassNameIter.hasNext();){
String phaseClassName = (String)phaseClassNameIter.next();
Class phaseClass = Gate.getClassLoader().loadClass(phaseClassName);
SinglePhaseTransducer phase = (SinglePhaseTransducer) phaseClass.newInstance();
phase.setOntology(ontology);
phases.add(phase);
}
}
public URL getGrammarURL()
{
return grammarURL;
}
public void setGrammarURL(URL url)
{
grammarURL = url;
}
/**
*
* Sets the encoding to be used for reding the input file(s) forming the Jape
* grammar. Note that if the input grammar is a multi-file one than the same
* encoding will be used for reding all the files. Multi file grammars with
* different encoding across the composing files are not supported!
*
* @param newEncoding
* a {link String} representing the encoding.
*/
public void setEncoding(String newEncoding) {
encoding = newEncoding;
}
/**
* Gets the encoding used for reding the grammar file(s).
*/
public String getEncoding() {
return encoding;
}
public void setInputASName(String newInputASName) {
inputASName = newInputASName;
}
public String getInputASName() {
return inputASName;
}
public void setOutputASName(String newOutputASName) {
outputASName = newOutputASName;
}
public String getOutputASName() {
return outputASName;
}
public gate.creole.ontology.Ontology getOntology() {
return ontology;
}
public void setOntology(gate.creole.ontology.Ontology newOntology) {
this.ontology = newOntology;
}
}