Log in Help
Print
Homereleasesgate-5.1-beta2-build3402-ALLpluginsJape_Compilersrccomontotextgatejapec 〉 JapecTransducer.java
 
/*
* 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;
  }
}