1   /*
2    *  RightHandSide.java - transducer class
3    *
4    *  Copyright (c) 1998-2005, The University of Sheffield.
5    *
6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
7    *  software, licenced under the GNU Library General Public License,
8    *  Version 2, June 1991 (in the distribution as file licence.html,
9    *  and also available at http://gate.ac.uk/gate/licence.html).
10   *
11   *  Hamish Cunningham, 24/07/98
12   *
13   *  $Id: RightHandSide.java,v 1.31 2005/10/10 14:59:15 nirajaswani Exp $
14   */
15  
16  
17  package gate.jape;
18  
19  import java.io.*;
20  import java.util.*;
21  
22  import gate.*;
23  import gate.creole.ontology.Ontology;
24  import gate.util.GateRuntimeException;
25  import gate.util.Strings;
26  
27  
28  /**
29    * The RHS of a CPSL rule. The action part. Contains an inner class
30    * created from the code in the grammar RHS.
31    */
32  public class RightHandSide implements JapeConstants, java.io.Serializable
33  {
34    /** Debug flag */
35    private static final boolean DEBUG = false;
36  
37    /** An instance of theActionClass. */
38    transient private Object theActionObject;
39  
40    /** The string we use to create the action class. */
41    private StringBuffer actionClassString;
42  
43    /** The bytes of the compiled action class. */
44    private byte[] actionClassBytes;
45  
46    /** The name of the action class. */
47    private String actionClassName;
48  
49    /** Package name for action classes. It's called a "dir name" because
50      * we used to dump the action classes to disk and compile them there.
51      */
52    static private String actionsDirName = "japeactionclasses";
53  
54    /** The qualified name of the action class. */
55    private String actionClassQualifiedName;
56  
57    /** Name of the .java file for the action class. */
58    private String actionClassJavaFileName;
59  
60    /** Name of the .class file for the action class. */
61    private String actionClassClassFileName;
62  
63    /** Cardinality of the action class set. Used for ensuring class name
64      * uniqueness.
65      */
66    private static int actionClassNumber = 0;
67  
68    /** Allow setting of the initial action class number. Used for ensuring
69      * class name uniqueness when running more than one transducer. The
70      * long-term solution is to have separate class loaders for each
71      * transducer.
72      */
73    public static void setActionClassNumber(int n) { actionClassNumber = n; }
74  
75    /** The set of block names.
76      * Used to ensure we only get their annotations once in the action class.
77      */
78    private HashSet blockNames;
79  
80    /** Returns the string for the java code */
81    public String getActionClassString() { return actionClassString.toString(); }
82  
83    public String getActionClassName() { return actionClassQualifiedName; }
84  
85    /** The LHS of our rule, where we get bindings from. */
86    private LeftHandSide lhs;
87  
88    /** A list of the files and directories we create. */
89    static private ArrayList tempFiles = new ArrayList();
90  
91    /** Local fashion for newlines. */
92    private final String nl = Strings.getNl();
93  
94    /** Debug flag. */
95    static final boolean debug = false;
96    private String phaseName;
97    private String ruleName;
98  
99    /** Construction from the transducer name, rule name and the LHS. */
100   public RightHandSide(
101     String transducerName, String ruleName, LeftHandSide lhs
102   ) {
103     // debug = true;
104     this.lhs = lhs;
105     this.phaseName = transducerName;
106     this.ruleName = ruleName;
107     actionClassName = new String(
108       transducerName + ruleName + "ActionClass" + actionClassNumber++
109     );
110     blockNames = new HashSet();
111 
112     // initialise the class action string
113     actionClassString = new StringBuffer(
114       "// " + actionClassName + nl +
115       "package " + actionsDirName + "; " + nl +
116       "import java.io.*;" + nl +
117       "import java.util.*;" + nl +
118       "import gate.*;" + nl +
119       "import gate.jape.*;" + nl +
120       "import gate.creole.ontology.Ontology;" + nl +
121       "import gate.annotation.*;" + nl +
122       "import gate.util.*;" + nl + nl +
123       "public class " + actionClassName + nl +
124       "implements java.io.Serializable, RhsAction { " + nl +
125       "  public void doit(Document doc, java.util.Map bindings, " + nl +
126       "                   AnnotationSet annotations, " + nl +
127       "                   AnnotationSet inputAS, AnnotationSet outputAS, " + nl +
128       "                   Ontology ontology) {" + nl
129     );
130 
131     // initialise various names
132     actionClassJavaFileName =
133       actionsDirName +  File.separator +
134       actionClassName.replace('.', File.separatorChar) + ".java";
135     actionClassQualifiedName =
136       actionsDirName.
137       replace(File.separatorChar, '.').replace('/', '.').replace('\\', '.') +
138       "." + actionClassName;
139     actionClassClassFileName =
140       actionClassQualifiedName.replace('.', File.separatorChar) + ".class";
141   } // Construction from lhs
142 
143   /** Add an anonymous block to the action class */
144   public void addBlock(String anonymousBlock) {
145     actionClassString.append(nl);
146     actionClassString.append("{");
147     actionClassString.append(anonymousBlock);
148     actionClassString.append(nl);
149     actionClassString.append("}");
150     actionClassString.append(nl);
151   } // addBlock(anon)
152 
153   /** Add a named block to the action class */
154   public void addBlock(String name, String namedBlock) {
155     // is it really a named block?
156     // (dealing with null name cuts code in the parser...)
157     if(name == null) {
158       addBlock(namedBlock);
159       return;
160     }
161 
162     if(blockNames.add(name)) // it wasn't already a member
163       actionClassString.append(
164         "    AnnotationSet " + name + "Annots = (AnnotationSet)bindings.get(\""
165         + name + "\"); " + nl
166       );
167 
168     actionClassString.append(
169       "    if(" + name + "Annots != null && " + name +
170       "Annots.size() != 0) { " + nl + "      " + namedBlock +
171       nl + "    }" + nl
172     );
173   } // addBlock(name, block)
174 
175   /** Create the action class and an instance of it. */
176   public void createActionClass() throws JapeException {
177     // terminate the class string
178     actionClassString.append("  }" + nl + "}" + nl);
179 //    try {
180 //      Javac.loadClass(actionClassString.toString(),
181 //                           actionClassJavaFileName);
182 //    } catch(GateException e) {
183 //      String nl = Strings.getNl();
184 //      String actionWithNumbers =
185 //        Strings.addLineNumbers(actionClassString.toString());
186 //      throw new JapeException(
187 //        "Couldn't create action class: " + nl + e + nl +
188 //        "offending code was: " + nl + actionWithNumbers + nl
189 //      );
190 //    }
191 //    instantiateActionClass();
192   } // createActionClass
193 
194   /** Create an instance of the action class. */
195   public void instantiateActionClass() throws JapeException {
196 
197     try {
198       theActionObject = Gate.getClassLoader().
199                         loadClass(actionClassQualifiedName).
200                         newInstance();
201     } catch(Exception e) {
202       throw new JapeException(
203         "couldn't create instance of action class " + actionClassName + ": "
204         + e.getMessage()
205       );
206     }
207   } // instantiateActionClass
208 
209   /** Remove class files created for actions. */
210   public static void cleanUp() {
211     if(tempFiles.size() == 0) return;
212 
213     // traverse the list in reverse order, coz any directories we
214     // created were done first
215     for(ListIterator i = tempFiles.listIterator(tempFiles.size()-1);
216         i.hasPrevious();
217        ) {
218       File tempFile = (File) i.previous();
219       tempFile.delete();
220     } // for each tempFile
221 
222     tempFiles.clear();
223   } // cleanUp
224 
225   private void writeObject(java.io.ObjectOutputStream out)
226   throws IOException{
227     out.defaultWriteObject();
228     //now we need to save the class for the action
229     try{
230     Class class1 = Gate.getClassLoader().loadClass(actionClassQualifiedName);
231     System.out.println(class1.getName());
232     out.writeObject(class1);
233     }catch(ClassNotFoundException cnfe){
234       throw new GateRuntimeException(cnfe);
235     }
236   }
237   
238   private void readObject(java.io.ObjectInputStream in)
239   throws IOException, ClassNotFoundException{
240     in.defaultReadObject();
241     //now read the class
242   String className = getActionClassName();
243   if(Gate.getClassLoader().findExistingClass(getActionClassName()) == null) {
244     try{
245       Map actionClasses = new HashMap();
246       actionClasses.put(getActionClassName(), getActionClassString());
247       gate.util.Javac.loadClasses(actionClasses);
248     }catch(Exception e1){
249       throw new GateRuntimeException (e1);
250     }
251   }
252   }
253   
254   /** Makes changes to the document, using LHS bindings. */
255   public void transduce(Document doc, java.util.Map bindings,
256                         AnnotationSet inputAS, AnnotationSet outputAS,
257                         Ontology ontology)
258                         throws JapeException {
259     if(theActionObject == null) {
260       instantiateActionClass();
261     }
262 
263     // run the action class
264     try {
265       ((RhsAction) theActionObject).doit(doc, bindings, outputAS,
266                                          inputAS, outputAS, ontology);
267 
268     // if the action class throws an exception, re-throw it with a
269     // full description of the problem, inc. stack trace and the RHS
270     // action class code
271     } catch (Exception e) {
272       StringWriter stackTraceWriter = new StringWriter();
273       e.printStackTrace(new PrintWriter(stackTraceWriter));
274       throw new JapeException(
275         "Couldn't run RHS action: " + Strings.getNl() +
276         stackTraceWriter.getBuffer().toString() +
277         Strings.addLineNumbers(actionClassString.toString())
278       );
279     }
280   } // transduce
281 
282   /** Create a string representation of the object. */
283   public String toString() { return toString(""); }
284 
285   /** Create a string representation of the object. */
286   public String toString(String pad) {
287     String nl = Strings.getNl();
288     StringBuffer buf = new StringBuffer(
289       pad + "RHS: actionClassName(" + actionClassName + "); "
290     );
291     //buf.append("actionClassString(" + nl + actionClassString + nl);
292     buf.append(
293       "actionClassClassFileName(" + nl + actionClassClassFileName + nl
294     );
295     buf.append("actionClassJavaFileName(" + nl + actionClassJavaFileName + nl);
296     buf.append(
297       "actionClassQualifiedName(" + nl + actionClassQualifiedName + nl
298     );
299 
300     buf.append("blockNames(" + blockNames.toString() + "); ");
301 
302     buf.append(nl + pad + ") RHS." + nl);
303 
304     return buf.toString();
305   } // toString
306 
307   /** Create a string representation of the object. */
308   public String shortDesc() {
309     String res = "" + actionClassName;
310     return res;
311   }
312   public void setPhaseName(String phaseName) {
313     this.phaseName = phaseName;
314   }
315   public String getPhaseName() {
316     return phaseName;
317   }
318   public void setRuleName(String ruleName) {
319     this.ruleName = ruleName;
320   }
321   public String getRuleName() {
322     return ruleName;
323   } // toString
324 
325 } // class RightHandSide
326 
327 
328 // $Log: RightHandSide.java,v $
329 // Revision 1.31  2005/10/10 14:59:15  nirajaswani
330 // bug fixed - reenabled JAPE serialization
331 //
332 // Revision 1.30  2005/10/10 10:29:38  valyt
333 // Serialisatoin to savwe the RHS action class object as well.
334 //
335 // Revision 1.29  2005/09/30 16:01:04  valyt
336 // BUGFIX:
337 // RHS Java blocks now have braces around them (to reduce visibility of local variables)
338 //
339 // Revision 1.28  2005/01/11 13:51:36  ian
340 // Updating copyrights to 1998-2005 in preparation for v3.0
341 //
342 // Revision 1.27  2004/07/21 17:10:08  akshay
343 // Changed copyright from 1998-2001 to 1998-2004
344 //
345 // Revision 1.26  2004/03/25 13:01:14  valyt
346 // Imports optimisation throughout the Java sources
347 // (to get rid of annoying warnings in Eclipse)
348 //
349 // Revision 1.25  2002/05/14 09:43:17  valyt
350 //
351 // Ontology Aware JAPE transducers
352 //
353 // Revision 1.24  2002/02/27 15:11:16  valyt
354 //
355 // bug 00011:
356 // Jape access to InputAS
357 //
358 // Revision 1.23  2002/02/26 13:27:12  valyt
359 //
360 // Error messages from the compiler
361 //
362 // Revision 1.22  2002/02/26 10:30:07  valyt
363 //
364 // new compile solution
365 //
366 // Revision 1.21  2002/02/12 11:39:03  valyt
367 //
368 // removed sate and status members for Jape generated classes
369 //
370 // Revision 1.20  2002/02/04 13:59:04  hamish
371 // added status and state members to RhsAction
372 //
373 // Revision 1.19  2001/11/16 13:03:35  hamish
374 // moved line numbers method to Strings
375 //
376 // Revision 1.18  2001/11/16 10:29:45  hamish
377 // JAPE RHS compiler errors now include the RHS code; test added
378 //
379 // Revision 1.17  2001/11/15 14:05:09  hamish
380 // better error messages from JAPE RHS problems
381 //
382 // Revision 1.16  2001/11/01 15:49:09  valyt
383 //
384 // DEBUG mode for Japes
385 //
386 // Revision 1.15  2001/09/13 12:09:50  kalina
387 // Removed completely the use of jgl.objectspace.Array and such.
388 // Instead all sources now use the new Collections, typically ArrayList.
389 // I ran the tests and I ran some documents and compared with keys.
390 // JAPE seems to work well (that's where it all was). If there are problems
391 // maybe look at those new structures first.
392 //
393 // Revision 1.14  2000/11/08 16:35:03  hamish
394 // formatting
395 //
396 // Revision 1.13  2000/10/26 10:45:30  oana
397 // Modified in the code style
398 //
399 // Revision 1.12  2000/10/16 16:44:34  oana
400 // Changed the comment of DEBUG variable
401 //
402 // Revision 1.11  2000/10/10 15:36:36  oana
403 // Changed System.out in Out and System.err in Err;
404 // Added the DEBUG variable seted on false;
405 // Added in the header the licence;
406 //
407 // Revision 1.10  2000/07/04 14:37:39  valyt
408 // Added some support for Jape-ing in a different annotations et than the default one;
409 // Changed the L&F for the JapeGUI to the System default
410 //
411 // Revision 1.9  2000/06/12 13:33:27  hamish
412 // removed japeactionclasse create code (static init block
413 //
414 // Revision 1.8  2000/05/16 10:38:25  hamish
415 // removed printout
416 //
417 // Revision 1.7  2000/05/16 10:30:33  hamish
418 // uses new gate.util.Jdk compiler
419 //
420 // Revision 1.6  2000/05/05 12:51:12  valyt
421 // Got rid of deprecation warnings
422 //
423 // Revision 1.5  2000/05/05 10:14:09  hamish
424 // added more to toString
425 //
426 // Revision 1.4  2000/05/02 16:54:47  hamish
427 // porting to new annotation API
428 //
429 // Revision 1.3  2000/04/20 13:26:42  valyt
430 // Added the graph_drawing library.
431 // Creating of the NFSM and DFSM now works.
432 //
433 // Revision 1.2  2000/02/24 17:28:48  hamish
434 // more porting to new API
435 //
436 // Revision 1.1  2000/02/23 13:46:11  hamish
437 // added
438 //
439 // Revision 1.1.1.1  1999/02/03 16:23:02  hamish
440 // added gate2
441 //
442 // Revision 1.21  1998/11/13 17:25:10  hamish
443 // stop it using sun.tools... when in 1.2
444 //
445 // Revision 1.20  1998/10/30 15:31:07  kalina
446 // Made small changes to make compile under 1.2 and 1.1.x
447 //
448 // Revision 1.19  1998/10/29 12:17:12  hamish
449 // use reflection when using sun compiler classes, so can compile without them
450 //
451 // Revision 1.18  1998/10/01 16:06:36  hamish
452 // new appelt transduction style, replacing buggy version
453 //
454 // Revision 1.17  1998/09/18 16:54:17  hamish
455 // save/restore works except for attribute seq
456 //
457 // Revision 1.16  1998/09/18 13:35:44  hamish
458 // refactored to split up createActionClass
459 //
460 // Revision 1.15  1998/09/18 12:15:40  hamish
461 // bugs fixed: anon block null ptr; no error for some non-existant labelled blocks
462 //
463 // Revision 1.14  1998/08/19 20:21:41  hamish
464 // new RHS assignment expression stuff added
465 //
466 // Revision 1.13  1998/08/17 10:43:29  hamish
467 // action classes have unique names so can be reloaded
468 //
469 // Revision 1.12  1998/08/12 15:39:42  hamish
470 // added padding toString methods
471 //
472 // Revision 1.11  1998/08/10 14:16:38  hamish
473 // fixed consumeblock bug and added batch.java
474 //
475 // Revision 1.10  1998/08/07 12:01:46  hamish
476 // parser works; adding link to backend
477 //
478 // Revision 1.9  1998/08/05 21:58:07  hamish
479 // backend works on simple test
480 //
481 // Revision 1.8  1998/08/04 12:42:56  hamish
482 // fixed annots null check bug
483 //
484 // Revision 1.7  1998/08/03 21:44:57  hamish
485 // moved parser classes to gate.jape.parser
486 //
487 // Revision 1.6  1998/08/03 19:51:26  hamish
488 // rollback added
489 //
490 // Revision 1.5  1998/07/31 16:50:18  hamish
491 // RHS compilation works; it runs - and falls over...
492 //
493 // Revision 1.4  1998/07/31 13:12:25  hamish
494 // done RHS stuff, not tested
495 //
496 // Revision 1.3  1998/07/30 11:05:24  hamish
497 // more jape
498 //
499 // Revision 1.2  1998/07/29 11:07:10  hamish
500 // first compiling version
501 //
502 // Revision 1.1.1.1  1998/07/28 16:37:46  hamish
503 // gate2 lives
504