All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gate.jape.RightHandSide Maven / Gradle / Ivy

Go to download

ANNIE is a general purpose information extraction system that provides the building blocks of many other GATE applications.

There is a newer version: 9.1
Show newest version
/*
 *  RightHandSide.java - transducer class
 *
 *  Copyright (c) 1995-2012, The University of Sheffield. See the file
 *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
 *
 *  This file is part of GATE (see http://gate.ac.uk/), and is free
 *  software, licenced under the GNU Library General Public License,
 *  Version 2, June 1991 (in the distribution as file licence.html,
 *  and also available at http://gate.ac.uk/gate/licence.html).
 *
 *  Hamish Cunningham, 24/07/98
 *
 *  $Id: RightHandSide.java 17895 2014-04-24 06:21:59Z markagreenwood $
 */


package gate.jape;

import gate.AnnotationSet;
import gate.Document;
import gate.Factory;
import gate.FeatureMap;
import gate.Gate;
import gate.creole.ontology.Ontology;
import gate.util.Err;
import gate.util.GateClassLoader;
import gate.util.GateRuntimeException;
import gate.util.Strings;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;


/**
  * The RHS of a CPSL rule. The action part. Contains an inner class
  * created from the code in the grammar RHS.
  */
public class RightHandSide implements JapeConstants, java.io.Serializable
{
  private static final long serialVersionUID = -4359589687308736378L;

  /** An instance of theActionClass. */
  transient private Object theActionObject;

  /** The string we use to create the action class. */
  private StringBuffer actionClassString;

  /** The name of the action class. */
  private String actionClassName;

  /** Package name for action classes. It's called a "dir name" because
    * we used to dump the action classes to disk and compile them there.
    */
  static private String actionsDirName = "japeactionclasses";

  /** The qualified name of the action class. */
  private String actionClassQualifiedName;

  /** Name of the .java file for the action class. */
  private String actionClassJavaFileName;

  /** Name of the .class file for the action class. */
  private String actionClassClassFileName;
  
  /** A list of source info object for mapping between Java and Jape. */
  //private transient List sourceInfo;
  private transient SourceInfo sourceInfo;
  
  private transient GateClassLoader classloader;

  /** Cardinality of the action class set. Used for ensuring class name
    * uniqueness.
    */
  private static AtomicInteger actionClassNumber = new AtomicInteger();

  /** The set of block names.
    * Used to ensure we only get their annotations once in the action class.
    */
  private Set blockNames;

  /** Returns the string for the java code */
  public String getActionClassString() { return actionClassString.toString(); }

  public String getActionClassName() { return actionClassQualifiedName; }

  /** The LHS of our rule, where we get bindings from. */
  private LeftHandSide lhs;

  /** A list of the files and directories we create. */
  static private List tempFiles = new ArrayList();

  /** Local fashion for newlines. */
  private final String nl = Strings.getNl();

  /** Debug flag. */
  static final boolean debug = false;
  private String phaseName;
  private String ruleName;

  /** Construction from the transducer name, rule name and the LHS. */
  public RightHandSide(
    String transducerName,
    String ruleName,
    LeftHandSide lhs,
    String importblock
  ) {
    // debug = true;
    this.lhs = lhs;
    this.phaseName = transducerName;
    this.ruleName = ruleName;
    actionClassName = new String(
      transducerName + ruleName + "ActionClass" + actionClassNumber.getAndIncrement()
    );
    blockNames = new HashSet();
    actionClassString = new StringBuffer(
      "// " + actionClassName + nl +
      "package " + actionsDirName + "; " + nl +
      importblock + nl +
      "public class " + actionClassName + nl +
      "implements java.io.Serializable, gate.jape.RhsAction { " + nl +
      "  private gate.jape.ActionContext ctx;"+nl+
      "  public java.lang.String ruleName() { return \""+ruleName+"\"; }"+nl+
      "  public java.lang.String phaseName() { return \""+phaseName+"\"; }"+nl+
      "  public void setActionContext(gate.jape.ActionContext ac) { ctx = ac; }"+nl+
      "  public gate.jape.ActionContext getActionContext() { return ctx; }"+nl+
      "  public void doit(gate.Document doc, " + nl +
      "                   java.util.Map bindings, " + nl +
      //"                   gate.AnnotationSet annotations, " + nl +
      "                   gate.AnnotationSet inputAS, gate.AnnotationSet outputAS, " + nl +
      "                   gate.creole.ontology.Ontology ontology) throws gate.jape.JapeException {" + nl
    );

    // initialise various names
    actionClassJavaFileName =
      actionsDirName +  File.separator +
      actionClassName.replace('.', File.separatorChar) + ".java";
    actionClassQualifiedName =
      actionsDirName.
      replace(File.separatorChar, '.').replace('/', '.').replace('\\', '.') +
      "." + actionClassName;
    actionClassClassFileName =
      actionClassQualifiedName.replace('.', File.separatorChar) + ".class";
    
    sourceInfo = new SourceInfo(actionClassQualifiedName, phaseName, ruleName);
  } // Construction from lhs
  
  /** Construction from an existing RHS */
  public RightHandSide(RightHandSide existingRhs) {
    this.lhs = existingRhs.lhs;
    this.phaseName = existingRhs.phaseName;
    this.ruleName = existingRhs.ruleName;
    this.actionClassName = existingRhs.actionClassName;
    this.blockNames = existingRhs.blockNames;
    this.actionClassString = existingRhs.actionClassString;
    this.actionClassJavaFileName = existingRhs.actionClassJavaFileName;
    this.actionClassQualifiedName = existingRhs.actionClassQualifiedName;
    this.actionClassClassFileName = existingRhs.actionClassClassFileName;
    this.sourceInfo = existingRhs.sourceInfo;
    
    // this is the important bit - the cloned RHS needs to create its own
    // instance of the action class the first time its transduce() is called.
    this.theActionObject = null;
  } // Construction from existing RHS

  /** Add an anonymous block to the action class */
  public void addBlock(String anonymousBlock) {
    actionClassString.append(nl);
    actionClassString.append("if (true) {");
    actionClassString.append(nl);
    actionClassString.append(sourceInfo.addBlock(actionClassString.toString(), anonymousBlock));
    actionClassString.append(nl);
    actionClassString.append("}");
    actionClassString.append(nl);
  } // addBlock(anon)

  /** Add a named block to the action class */
  public void addBlock(String name, String namedBlock) {
    // is it really a named block?
    // (dealing with null name cuts code in the parser...)
    if(name == null) {
      addBlock(namedBlock);
      return;
    }

    if(blockNames.add(name)) // it wasn't already a member
      actionClassString.append(
        "    gate.AnnotationSet " + name + "Annots = bindings.get(\""
        + name + "\"); " + nl
      );

    actionClassString.append(
      "    if(" + name + "Annots != null && " + name +
      "Annots.size() != 0) { " + nl);
      
    actionClassString.append(sourceInfo.addBlock(actionClassString.toString(), namedBlock));
      
   actionClassString.append(
      nl + "    }" + nl
    );
  } // addBlock(name, block)
  
  public void finish(GateClassLoader classloader) {
    this.classloader = classloader;
  }
  

  /** Create the action class and an instance of it. */
  public void createActionClass() throws JapeException {
    // terminate the class string
    actionClassString.append("  }" + nl + "}" + nl);
//    try {
//      Javac.loadClass(actionClassString.toString(),
//                           actionClassJavaFileName);
//    } catch(GateException e) {
//      String nl = Strings.getNl();
//      String actionWithNumbers =
//        Strings.addLineNumbers(actionClassString.toString());
//      throw new JapeException(
//        "Couldn't create action class: " + nl + e + nl +
//        "offending code was: " + nl + actionWithNumbers + nl
//      );
//    }
//    instantiateActionClass();
  } // createActionClass

  /** Create an instance of the action class. */
  public void instantiateActionClass() throws JapeException {

    try {
      theActionObject = classloader.
                        loadClass(actionClassQualifiedName).
                        newInstance();
    } catch(Exception e) {
      throw new JapeException(
        "couldn't create instance of action class " + actionClassName + ": "
        + e.getMessage()
      );
    }
  } // instantiateActionClass

  /** Remove class files created for actions. */
  public static void cleanUp() {
    if(tempFiles.size() == 0) return;

    // traverse the list in reverse order, coz any directories we
    // created were done first
    for(ListIterator i = tempFiles.listIterator(tempFiles.size()-1);
        i.hasPrevious();
       ) {
      File tempFile = i.previous();
      tempFile.delete();
    } // for each tempFile

    tempFiles.clear();
  } // cleanUp

  private void writeObject(java.io.ObjectOutputStream out)
  throws IOException{
    out.defaultWriteObject();
    //now we need to save the class for the action
    try{
		Class class1 = classloader.loadClass(actionClassQualifiedName);
		//System.out.println(class1.getName());
		out.writeObject(class1);
    }catch(ClassNotFoundException cnfe){
      throw new GateRuntimeException(cnfe);
    }
  }
  
  private void readObject(java.io.ObjectInputStream in)
  throws IOException, ClassNotFoundException{
    in.defaultReadObject();
    //now read the class
    String className = getActionClassName();
    if (classloader == null)
      classloader = Gate.getClassLoader().getDisposableClassLoader(in.toString(),true);
	
		try{
			Map actionClasses = new HashMap();
			actionClasses.put(className, getActionClassString());
			
			gate.util.Javac.loadClasses(actionClasses, classloader);
		}catch(Exception e1){
			throw new GateRuntimeException (e1);
		}
	
  }
  
  /** Makes changes to the document, using LHS bindings. */
  public void transduce(Document doc, java.util.Map bindings,
                        AnnotationSet inputAS, final AnnotationSet outputAS,
                        Ontology ontology,
                        final ActionContext actionContext)
                        throws JapeException {
    if(theActionObject == null) {
      instantiateActionClass();
    }
      
    // run the action class
    try {
      ((RhsAction) theActionObject).setActionContext(actionContext);
      
      if (actionContext.isDebuggingEnabled()) {
        AnnotationSet outputASproxy =
                (AnnotationSet)Proxy.newProxyInstance(classloader, new Class[] {AnnotationSet.class},
                        new InvocationHandler() {
                          public Object invoke(Object proxy, Method method,
                                  Object[] args) throws Throwable {
                            
                            if (method.getName().equals("add")) {
                              int index = args.length - 1;
                              Class lastArgType = method.getParameterTypes()[index];
                              if (lastArgType.equals(FeatureMap.class)) {
                                FeatureMap features = (FeatureMap)args[index];
                                if (features == null) {
                                  features = Factory.newFeatureMap();
                                  args[index] = features;
                                }
                                
                                features.put("addedByPR", actionContext.getPRName());
                                features.put("addedByPhase", getPhaseName());
                                features.put("addedByRule",getRuleName());
                              }
                            }
                            
                            return method.invoke(outputAS, args);
                          }
                        });
        ((RhsAction)theActionObject).doit(doc, bindings, inputAS, outputASproxy,
                ontology);
      } else {
        ((RhsAction)theActionObject).doit(doc, bindings, inputAS, outputAS, ontology);
      }
    } catch (NonFatalJapeException e) {
      // if the action class throws a non-fatal exception then respond by
      // dumping a whole bunch of useful debug information but then allow
      // processing to continue on as if nothing happened.
      Throwable t = e.getCause();
      Err.println("A non-fatal JAPE exception occurred while processing document '"+doc.getName()+"'.");
      Err.println("The issue occurred during execution of rule '"+getRuleName()+"' in phase '"+getPhaseName()+"':");
      if (t != null) {
        sourceInfo.enhanceTheThrowable(t);
        t.printStackTrace(Err.getPrintWriter());
      } else {
        Err.println("Line number and exception details are not available!");
      }
    } catch (Throwable e) {
      // if the action class throws an exception, re-throw it with a
      // full description of the problem, inc. stack trace and the RHS
      // action class code
      if (sourceInfo != null) sourceInfo.enhanceTheThrowable(e);
      if(e instanceof Error) {
        throw (Error)e;
      }
      if(e instanceof JapeException) {
        throw (JapeException)e;
      }      
      if(e instanceof RuntimeException) {
        throw (RuntimeException)e;
      }
      
      // shouldn't happen...
        throw new JapeException(
          "Couldn't run RHS action", e);
    }
  } // transduce

  /** Create a string representation of the object. */
  @Override
  public String toString() { return toString(""); }

  /** Create a string representation of the object. */
  public String toString(String pad) {
    String nl = Strings.getNl();
    StringBuffer buf = new StringBuffer(
      pad + "RHS: actionClassName(" + actionClassName + "); "
    );
    //buf.append("actionClassString(" + nl + actionClassString + nl);
    buf.append(
      "actionClassClassFileName(" + nl + actionClassClassFileName + nl
    );
    buf.append("actionClassJavaFileName(" + nl + actionClassJavaFileName + nl);
    buf.append(
      "actionClassQualifiedName(" + nl + actionClassQualifiedName + nl
    );

    buf.append("blockNames(" + blockNames.toString() + "); ");

    buf.append(nl + pad + ") RHS." + nl);

    return buf.toString();
  } // toString

  /** Create a string representation of the object. */
  public String shortDesc() {
    String res = "" + actionClassName;
    return res;
  }
  public void setPhaseName(String phaseName) {
    this.phaseName = phaseName;
  }
  public String getPhaseName() {
    return phaseName;
  }
  public void setRuleName(String ruleName) {
    this.ruleName = ruleName;
  }
  public String getRuleName() {
    return ruleName;
  } // toString
  
} // class RightHandSide


// $Log$
// Revision 1.31  2005/10/10 14:59:15  nirajaswani
// bug fixed - reenabled JAPE serialization
//
// Revision 1.30  2005/10/10 10:29:38  valyt
// Serialisatoin to savwe the RHS action class object as well.
//
// Revision 1.29  2005/09/30 16:01:04  valyt
// BUGFIX:
// RHS Java blocks now have braces around them (to reduce visibility of local variables)
//
// Revision 1.28  2005/01/11 13:51:36  ian
// Updating copyrights to 1998-2005 in preparation for v3.0
//
// Revision 1.27  2004/07/21 17:10:08  akshay
// Changed copyright from 1998-2001 to 1998-2004
//
// Revision 1.26  2004/03/25 13:01:14  valyt
// Imports optimisation throughout the Java sources
// (to get rid of annoying warnings in Eclipse)
//
// Revision 1.25  2002/05/14 09:43:17  valyt
//
// Ontology Aware JAPE transducers
//
// Revision 1.24  2002/02/27 15:11:16  valyt
//
// bug 00011:
// Jape access to InputAS
//
// Revision 1.23  2002/02/26 13:27:12  valyt
//
// Error messages from the compiler
//
// Revision 1.22  2002/02/26 10:30:07  valyt
//
// new compile solution
//
// Revision 1.21  2002/02/12 11:39:03  valyt
//
// removed sate and status members for Jape generated classes
//
// Revision 1.20  2002/02/04 13:59:04  hamish
// added status and state members to RhsAction
//
// Revision 1.19  2001/11/16 13:03:35  hamish
// moved line numbers method to Strings
//
// Revision 1.18  2001/11/16 10:29:45  hamish
// JAPE RHS compiler errors now include the RHS code; test added
//
// Revision 1.17  2001/11/15 14:05:09  hamish
// better error messages from JAPE RHS problems
//
// Revision 1.16  2001/11/01 15:49:09  valyt
//
// DEBUG mode for Japes
//
// Revision 1.15  2001/09/13 12:09:50  kalina
// Removed completely the use of jgl.objectspace.Array and such.
// Instead all sources now use the new Collections, typically ArrayList.
// I ran the tests and I ran some documents and compared with keys.
// JAPE seems to work well (that's where it all was). If there are problems
// maybe look at those new structures first.
//
// Revision 1.14  2000/11/08 16:35:03  hamish
// formatting
//
// Revision 1.13  2000/10/26 10:45:30  oana
// Modified in the code style
//
// Revision 1.12  2000/10/16 16:44:34  oana
// Changed the comment of DEBUG variable
//
// Revision 1.11  2000/10/10 15:36:36  oana
// Changed System.out in Out and System.err in Err;
// Added the DEBUG variable seted on false;
// Added in the header the licence;
//
// Revision 1.10  2000/07/04 14:37:39  valyt
// Added some support for Jape-ing in a different annotations et than the default one;
// Changed the L&F for the JapeGUI to the System default
//
// Revision 1.9  2000/06/12 13:33:27  hamish
// removed japeactionclasse create code (static init block
//
// Revision 1.8  2000/05/16 10:38:25  hamish
// removed printout
//
// Revision 1.7  2000/05/16 10:30:33  hamish
// uses new gate.util.Jdk compiler
//
// Revision 1.6  2000/05/05 12:51:12  valyt
// Got rid of deprecation warnings
//
// Revision 1.5  2000/05/05 10:14:09  hamish
// added more to toString
//
// Revision 1.4  2000/05/02 16:54:47  hamish
// porting to new annotation API
//
// Revision 1.3  2000/04/20 13:26:42  valyt
// Added the graph_drawing library.
// Creating of the NFSM and DFSM now works.
//
// Revision 1.2  2000/02/24 17:28:48  hamish
// more porting to new API
//
// Revision 1.1  2000/02/23 13:46:11  hamish
// added
//
// Revision 1.1.1.1  1999/02/03 16:23:02  hamish
// added gate2
//
// Revision 1.21  1998/11/13 17:25:10  hamish
// stop it using sun.tools... when in 1.2
//
// Revision 1.20  1998/10/30 15:31:07  kalina
// Made small changes to make compile under 1.2 and 1.1.x
//
// Revision 1.19  1998/10/29 12:17:12  hamish
// use reflection when using sun compiler classes, so can compile without them
//
// Revision 1.18  1998/10/01 16:06:36  hamish
// new appelt transduction style, replacing buggy version
//
// Revision 1.17  1998/09/18 16:54:17  hamish
// save/restore works except for attribute seq
//
// Revision 1.16  1998/09/18 13:35:44  hamish
// refactored to split up createActionClass
//
// Revision 1.15  1998/09/18 12:15:40  hamish
// bugs fixed: anon block null ptr; no error for some non-existant labelled blocks
//
// Revision 1.14  1998/08/19 20:21:41  hamish
// new RHS assignment expression stuff added
//
// Revision 1.13  1998/08/17 10:43:29  hamish
// action classes have unique names so can be reloaded
//
// Revision 1.12  1998/08/12 15:39:42  hamish
// added padding toString methods
//
// Revision 1.11  1998/08/10 14:16:38  hamish
// fixed consumeblock bug and added batch.java
//
// Revision 1.10  1998/08/07 12:01:46  hamish
// parser works; adding link to backend
//
// Revision 1.9  1998/08/05 21:58:07  hamish
// backend works on simple test
//
// Revision 1.8  1998/08/04 12:42:56  hamish
// fixed annots null check bug
//
// Revision 1.7  1998/08/03 21:44:57  hamish
// moved parser classes to gate.jape.parser
//
// Revision 1.6  1998/08/03 19:51:26  hamish
// rollback added
//
// Revision 1.5  1998/07/31 16:50:18  hamish
// RHS compilation works; it runs - and falls over...
//
// Revision 1.4  1998/07/31 13:12:25  hamish
// done RHS stuff, not tested
//
// Revision 1.3  1998/07/30 11:05:24  hamish
// more jape
//
// Revision 1.2  1998/07/29 11:07:10  hamish
// first compiling version
//
// Revision 1.1.1.1  1998/07/28 16:37:46  hamish
// gate2 lives




© 2015 - 2024 Weber Informatics LLC | Privacy Policy