KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > emf > codegen > jet > JETCompiler


1 /**
2  * <copyright>
3  *
4  * Copyright (c) 2002-2005 IBM Corporation and others.
5  * All rights reserved. This program and the accompanying materials
6  * are made available under the terms of the Eclipse Public License v1.0
7  * which accompanies this distribution, and is available at
8  * http://www.eclipse.org/legal/epl-v10.html
9  *
10  * Contributors:
11  * IBM - Initial API and implementation
12  *
13  * </copyright>
14  *
15  * $Id: JETCompiler.java,v 1.14 2005/06/08 06:15:56 nickb Exp $
16  */

17 package org.eclipse.emf.codegen.jet;
18
19
20 import java.io.BufferedInputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.io.OutputStream JavaDoc;
24 import java.io.PrintWriter JavaDoc;
25 import java.net.MalformedURLException JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.Stack JavaDoc;
33
34 import org.eclipse.core.runtime.IPath;
35 import org.eclipse.core.runtime.Path;
36 import org.eclipse.core.runtime.Platform;
37
38 import org.eclipse.emf.codegen.CodeGenPlugin;
39
40
41 public class JETCompiler implements JETParseEventListener
42 {
43   protected final static char[] NULL_CHAR_ARRAY = {};
44
45   protected String JavaDoc[] templateURIPath;
46
47   protected String JavaDoc templateURI;
48
49   protected JETParser parser;
50
51   protected JETSkeleton skeleton;
52
53   protected JETReader reader;
54
55   protected PrintWriter JavaDoc writer;
56
57   protected List JavaDoc generators = new ArrayList JavaDoc(100);
58
59   protected List JavaDoc constants = new ArrayList JavaDoc(100);
60
61   protected Map JavaDoc constantDictionary = new HashMap JavaDoc(100, 100);
62
63   protected long constantCount = 0;
64
65   /**
66    * If true, the newline immediately preceding a scriptlet or directive (though not a successful include directive),
67    * along with any intervening spaces, will be stripped from the character data.
68    */

69   protected boolean fNoNewLineForScriptlets = true;
70
71   protected boolean fUseStaticFinalConstants = true;
72
73   /**
74    * If fNoNewLineForScriptlets is true, the trailing newline/space sequence is stripped from each character
75    * data segment, and stored in this field. Depending on what follows, it may then be discarded or handled as its
76    * own character data segment.
77    */

78   protected char[] fSavedLine = null;
79
80   /**
81    * The depth of the current section, where 0 is outside of any sections. A section is delimited by start and
82    * end directives, and must be preceded by an include directive with fail="alternative".
83    */

84   protected int sectionDepth = 0;
85
86   /**
87    * Whether content is currently being skipped. This is set according to skipSections, as sections are started and ended.
88    */

89   protected boolean skipping = false;
90
91   /**
92    * A stack of sections and whether to start skipping, one from each include with alternative encountered.
93    */

94   protected Stack JavaDoc skipSections = new Stack JavaDoc();
95
96   /**
97    * A skip section entry, records the depth of the section and whether to start skipping there.
98    */

99   static class SkipSection
100   {
101     int depth;
102     boolean skip;
103
104     SkipSection(int depth, boolean skip)
105     {
106       this.depth = depth;
107       this.skip = skip;
108     }
109   }
110
111   protected static final String JavaDoc CONSTANT_PREFIX = "TEXT_";
112
113   public JETCompiler(String JavaDoc templateURI) throws JETException
114   {
115     this(templateURI, "UTF8");
116   }
117
118   public JETCompiler(String JavaDoc templateURI, String JavaDoc encoding) throws JETException
119   {
120     this(templateURI, openStream(templateURI), encoding);
121   }
122
123   public JETCompiler(String JavaDoc templateURI, InputStream JavaDoc inputStream, String JavaDoc encoding) throws JETException
124   {
125     super();
126
127     this.templateURI = templateURI;
128     this.reader = new JETReader(templateURI, inputStream, encoding);
129   }
130
131   public JETCompiler(String JavaDoc[] templateURIPath, String JavaDoc relativeTemplateURI) throws JETException
132   {
133     this(templateURIPath, relativeTemplateURI, "UTF8");
134   }
135
136   public JETCompiler(String JavaDoc[] templateURIPath, String JavaDoc relativeTemplateURI, String JavaDoc encoding) throws JETException
137   {
138     super();
139
140     this.templateURIPath = templateURIPath;
141     this.templateURI = relativeTemplateURI;
142     String JavaDoc[] actualTemplateURI = findLocation(templateURIPath, 0, relativeTemplateURI);
143     this.reader = new JETReader(actualTemplateURI[1], relativeTemplateURI, openStream(actualTemplateURI[0]), encoding);
144   }
145
146   public String JavaDoc getResolvedTemplateURI()
147   {
148     return reader.getFile(0);
149   }
150
151   public void handleDirective(String JavaDoc directive, JETMark start, JETMark stop, Map JavaDoc attributes) throws JETException
152   {
153     if (directive.equals("include"))
154     {
155       String JavaDoc fileURI = (String JavaDoc)attributes.get("file");
156       if (fileURI != null)
157       {
158         String JavaDoc currentURI = start.getFile();
159         String JavaDoc[] resolvedFileURI = resolveLocation(templateURIPath, currentURI, fileURI);
160         if (resolvedFileURI[0].equals(currentURI))
161         {
162           boolean loop = true;
163           if (templateURIPath != null)
164           {
165             String JavaDoc baseURI = start.getBaseURI();
166             if (baseURI != null)
167             {
168               for (int i = 0; i < templateURIPath.length; ++i)
169               {
170                 if (baseURI.equals(templateURIPath[i]))
171                 {
172                   resolvedFileURI = resolveLocation(templateURIPath, i + 1, currentURI, fileURI);
173                   loop = false;
174                 }
175               }
176             }
177           }
178           if (loop)
179           {
180             // Break the cycle.
181
//
182
return;
183           }
184         }
185         try
186         {
187           BufferedInputStream JavaDoc bufferedInputStream = new BufferedInputStream JavaDoc(openStream(resolvedFileURI[1]));
188           reader.stackStream(resolvedFileURI[2], resolvedFileURI[0], bufferedInputStream, null);
189
190           // The include succeeded, so if there is an alternative and we're not skippping, we need to start.
191
//
192
if ("alternative".equals(attributes.get("fail")))
193           {
194             skipSections.push(new SkipSection(sectionDepth + 1, !skipping));
195           }
196
197           // If a newline from the previous character data remains, add a generator for it.
198
//
199
if (fSavedLine != null)
200           {
201             addCharDataGenerator(fSavedLine);
202           }
203         }
204         catch (JETException exception)
205         {
206           // The include failed, so if there is an alternative, we don't skip it.
207
//
208
String JavaDoc failType = (String JavaDoc)attributes.get("fail");
209           if ("alternative".equals(failType))
210           {
211             skipSections.push(new SkipSection(sectionDepth + 1, false));
212           }
213           else if (!"silent".equals(failType))
214           {
215             throw
216               new JETException
217                 (CodeGenPlugin.getPlugin().getString
218                   ("jet.error.file.cannot.read",
219                    new Object JavaDoc [] { resolvedFileURI[1], start.format("jet.mark.file.line.column") }),
220                  exception);
221           }
222         }
223       }
224       else
225       {
226         throw
227           new JETException
228             (CodeGenPlugin.getPlugin().getString
229               ("jet.error.missing.attribute",
230           new Object JavaDoc []{ "file", start.format("jet.mark.file.line.column") }));
231       }
232     }
233     else if (directive.equals("start"))
234     {
235       sectionDepth++;
236       
237       // A section is not allowed without a preceeding include with alternative.
238
//
239
SkipSection skipSection = skipSections.isEmpty() ? null : (SkipSection)skipSections.peek();
240       if (skipSection == null || skipSection.depth != sectionDepth)
241       {
242         throw new JETException
243           (CodeGenPlugin.getPlugin().getString
244             ("jet.error.section.noinclude",
245              new Object JavaDoc[] { start.format("jet.mark.file.line.column") }));
246       }
247       else if (skipSection.skip)
248       {
249         skipping = true;
250       }
251     }
252     else if (directive.equals("end"))
253     {
254       if (sectionDepth == 0)
255       {
256         throw
257           new JETException
258             (CodeGenPlugin.getPlugin().getString
259               ("jet.error.unmatched.directive",
260                new Object JavaDoc[] { "start", "end", start.format("jet.mark.file.line.column") }));
261       }
262       sectionDepth--;
263
264       // This pop is safe because a section couldn't have been started without an include that pushed.
265
//
266
if (((SkipSection)skipSections.pop()).skip)
267       {
268         skipping = false;
269       }
270     }
271     else if (directive.equals("jet"))
272     {
273       if (skeleton != null)
274       {
275         // Multiple jet directives.
276
}
277       else
278       {
279         skeleton = new JETSkeleton();
280         // Process this first.
281
//
282
String JavaDoc skeletonURI = (String JavaDoc)attributes.get("skeleton");
283         if (skeletonURI != null)
284         {
285           try
286           {
287             BufferedInputStream JavaDoc bufferedInputStream =
288               new BufferedInputStream JavaDoc(openStream(resolveLocation(templateURIPath, templateURI, skeletonURI)[1]));
289             byte[] input = new byte [bufferedInputStream.available()];
290             bufferedInputStream.read(input);
291             bufferedInputStream.close();
292             skeleton.setCompilationUnitContents(new String JavaDoc(input));
293           }
294           catch (IOException JavaDoc exception)
295           {
296             throw new JETException(exception);
297           }
298         }
299
300         for (Iterator JavaDoc entries = attributes.entrySet().iterator(); entries.hasNext();)
301         {
302           Map.Entry JavaDoc entry = (Map.Entry JavaDoc)entries.next();
303
304           // Ignore this now
305
//
306
if (entry.getKey().equals("skeleton"))
307           {
308           }
309           else if (entry.getKey().equals("package"))
310           {
311             skeleton.setPackageName((String JavaDoc)entry.getValue());
312           }
313           else if (entry.getKey().equals("imports"))
314           {
315             skeleton.addImports((String JavaDoc)entry.getValue());
316           }
317           else if (entry.getKey().equals("class"))
318           {
319             skeleton.setClassName((String JavaDoc)entry.getValue());
320           }
321           else if (entry.getKey().equals("nlString"))
322           {
323             skeleton.setNLString((String JavaDoc)entry.getValue());
324           }
325           else if (entry.getKey().equals("startTag"))
326           {
327             parser.setStartTag((String JavaDoc)entry.getValue());
328           }
329           else if (entry.getKey().equals("endTag"))
330           {
331             parser.setEndTag((String JavaDoc)entry.getValue());
332           }
333           else if (entry.getKey().equals("version"))
334           {
335             // Ignore the version
336
}
337
338           /*
339            if ( attr.equals("package") )
340            skeleton.setPackageName((String) attributes.get(attr));
341
342            else if ( attr.equals("imports") )
343            skeleton.setImportsList((String) attributes.get(attr));
344
345            else if ( attr.equals("class") )
346            skeleton.setClassName((String) attributes.get(attr));
347
348            else if ( attr.equals("extends") )
349            skeleton.setExtendsName((String) attributes.get(attr));
350
351            else if ( attr.equals("implements") )
352            skeleton.setImplementsList((String) attributes.get(attr));
353
354            else if ( attr.equals("methodname") || attr.equals("methodName"))
355            skeleton.setMethodName((String) attributes.get(attr));
356
357            else if ( attr.equals("throws") )
358            skeleton.setThrowsList((String) attributes.get(attr));
359
360            else if ( attr.equals("parameters") )
361            skeleton.setParametersList((String) attributes.get(attr));
362
363            else if ( attr.equals("writer") )
364            skeleton.setWriterName((String) attributes.get(attr));
365
366            */

367           else
368             throw
369               new JETException
370                 (CodeGenPlugin.getPlugin().getString
371                   ("jet.error.bad.attribute",
372               new Object JavaDoc []{ entry.getKey(), start.format("jet.mark.file.line.column") }));
373         }
374
375         handleNewSkeleton();
376       }
377     }
378
379     fSavedLine = null;
380   }
381
382   protected void handleNewSkeleton()
383   {
384   }
385
386   public void handleExpression(JETMark start, JETMark stop, Map JavaDoc attributes) throws JETException
387   {
388     if (skipping) return;
389
390     JETGenerator gen = new JETExpressionGenerator(reader.getChars(start, stop));
391     addGenerator(gen);
392   }
393
394   public void handleScriptlet(JETMark start, JETMark stop, Map JavaDoc attributes) throws JETException
395   {
396     if (skipping) return;
397
398     fSavedLine = null;
399     JETGenerator gen = new JETScriptletGenerator(reader.getChars(start, stop));
400     addGenerator(gen);
401   }
402
403   public void handleCharData(char[] chars) throws JETException
404   {
405     if (skipping) return;
406
407     if (fNoNewLineForScriptlets)
408     {
409       char[] strippedChars = stripLastNewLineWithBlanks(chars);
410       if (strippedChars.length > 0)
411       {
412         addCharDataGenerator(strippedChars);
413       }
414     }
415     else
416     {
417       addCharDataGenerator(chars);
418     }
419   }
420
421   public void addGenerator(JETGenerator gen) throws JETException
422   {
423     // If a newline from the previous character data remains, add a generator for it.
424
//
425
if (fSavedLine != null)
426     {
427       addCharDataGenerator(fSavedLine);
428       fSavedLine = null;
429     }
430     generators.add(gen);
431   }
432
433   public void addCharDataGenerator(char[] chars) throws JETException
434   {
435     // An expression with more that 931 "+" will break Sun and IBM javac compilers.
436
//
437
if (chars.length > 500)
438     {
439       int nl = 0;
440       int lf = 0;
441
442       int start = 0;
443       LOOP:
444       for (int i = 0; i < chars.length; ++i)
445       {
446         switch (chars[i])
447         {
448           case '\n':
449           {
450             ++nl;
451             break;
452           }
453           case '\r':
454           {
455             ++lf;
456             break;
457           }
458           default:
459           {
460             continue;
461           }
462         }
463
464         if (lf > 400 || nl > 400)
465         {
466           for (++i; i < chars.length; ++i)
467           {
468             switch (chars[i])
469             {
470               case '\n':
471               case '\r':
472               {
473                 continue;
474               }
475               default:
476               {
477                 int size = i - start;
478                 char [] block = new char [size];
479                 System.arraycopy(chars, start, block, 0, size);
480                 doAddCharDataGenerator(block);
481                 start = i;
482                 nl = 0;
483                 lf = 0;
484                 continue LOOP;
485               }
486             }
487           }
488         }
489       }
490       if (start != 0)
491       {
492         int size = chars.length - start;
493         char [] block = new char [size];
494         System.arraycopy(chars, start, block, 0, size);
495         doAddCharDataGenerator(block);
496         return;
497       }
498     }
499
500     doAddCharDataGenerator(chars);
501   }
502
503   public void doAddCharDataGenerator(char[] chars) throws JETException
504   {
505     if (fUseStaticFinalConstants)
506     {
507       JETConstantDataGenerator gen = (JETConstantDataGenerator)constantDictionary.get(chars);
508       if (gen == null)
509       {
510         if (constantCount == 0)
511         {
512           chars = stripFirstNewLineWithBlanks(chars);
513         }
514         ++constantCount;
515         String JavaDoc label = CONSTANT_PREFIX + constantCount;
516         gen = new JETConstantDataGenerator(chars, label);
517         constantDictionary.put(chars, gen);
518         constants.add(gen);
519       }
520       generators.add(gen);
521     }
522     else
523     {
524       generators.add(new JETCharDataGenerator(chars));
525     }
526   }
527
528   protected char[] stripFirstNewLineWithBlanks(char[] chars)
529   {
530     if (chars.length >= 2 &&
531           (chars[0] == '\n' && chars[1] == '\r' || chars[0] == '\r' && chars[1] == '\n'))
532     {
533       chars = new String JavaDoc(chars, 2, chars.length - 2).toCharArray();
534     }
535     else if (chars.length >= 1 &&
536           (chars[0] == '\n' || chars[0] == '\r'))
537     {
538       chars = new String JavaDoc(chars, 1, chars.length - 1).toCharArray();
539     }
540     return chars;
541   }
542
543   protected char[] stripLastNewLineWithBlanks(char[] chars)
544   {
545     int i = chars.length - 1;
546     while (i > 0 && chars[i] == ' ')
547     {
548       --i;
549     }
550     if (chars[i] == '\n')
551     {
552       if (i > 0 && chars[i - 1] == '\r')
553       {
554         --i;
555       }
556       fSavedLine = (new String JavaDoc(chars, i, chars.length - i)).toCharArray();
557       if (i == 0)
558       {
559         return NULL_CHAR_ARRAY;
560       }
561       else
562       {
563         chars = new String JavaDoc(chars, 0, i).toCharArray();
564         return chars;
565       }
566     }
567     else
568     {
569       return chars;
570     }
571   }
572
573   public void beginPageProcessing()
574   {
575   }
576
577   public void endPageProcessing() throws JETException
578   {
579     if (sectionDepth > 0)
580     {
581       throw
582         new JETException
583           (CodeGenPlugin.getPlugin().getString
584             ("jet.error.unmatched.directive",
585              new Object JavaDoc[] { "end", "start", reader.mark().format("jet.mark.file.line.column") }));
586     }
587
588     if (skeleton == null)
589     {
590       throw
591         new JETException
592           (CodeGenPlugin.getPlugin().getString
593             ("jet.error.missing.jet.directive",
594         new Object JavaDoc []{ reader.mark().format("jet.mark.file.line.column") }));
595     }
596
597     // If a newline from the previous character data remains, add a generator for it.
598
//
599
if (fSavedLine != null)
600     {
601       addCharDataGenerator(fSavedLine);
602     }
603
604     List JavaDoc generatedConstants = new ArrayList JavaDoc(constants.size());
605     for (Iterator JavaDoc i = constants.iterator(); i.hasNext();)
606     {
607       generatedConstants.add(((JETConstantDataGenerator)(i.next())).generateConstant());
608     }
609     skeleton.setConstants(generatedConstants);
610
611     List JavaDoc generatedBody = new ArrayList JavaDoc(generators.size());
612     for (Iterator JavaDoc i = generators.iterator(); i.hasNext();)
613     {
614       generatedBody.add(((JETGenerator)(i.next())).generate());
615     }
616     skeleton.setBody(generatedBody);
617
618     writer.print(skeleton.getCompilationUnitContents());
619   }
620
621   public void parse() throws JETException
622   {
623     // Register our directive.
624
//
625
JETParser.Directive directive = new JETParser.Directive();
626     directive.getDirectives().add("jet");
627     directive.getDirectives().add("include");
628     directive.getDirectives().add("start");
629     directive.getDirectives().add("end");
630
631     JETCoreElement[] coreElements =
632       {
633         directive,
634         new JETParser.QuoteEscape(),
635         new JETParser.Expression(),
636         new JETParser.Scriptlet()
637       };
638
639     Class JavaDoc[] accept =
640       {
641         JETParser.Directive.class,
642         JETParser.QuoteEscape.class,
643         JETParser.Expression.class,
644         JETParser.Scriptlet.class
645       };
646
647     parse(coreElements, accept);
648   }
649
650   protected void parse(JETCoreElement[] coreElements, Class JavaDoc[] accept) throws JETException
651   {
652     parser = new JETParser(reader, this, coreElements);
653     beginPageProcessing();
654     parser.parse(null, accept);
655   }
656
657   public void generate(OutputStream JavaDoc oStream) throws JETException
658   {
659     writer = new PrintWriter JavaDoc(oStream);
660     endPageProcessing();
661     writer.close();
662   }
663
664   public JETSkeleton getSkeleton()
665   {
666     return skeleton;
667   }
668
669   protected static String JavaDoc[] resolveLocation(String JavaDoc[] templateURIPath, String JavaDoc baseLocationURI, String JavaDoc locationURI)
670   {
671      return resolveLocation(templateURIPath, 0, baseLocationURI, locationURI);
672   }
673   
674   protected static String JavaDoc[] resolveLocation(String JavaDoc[] templateURIPath, int start, String JavaDoc baseLocationURI, String JavaDoc locationURI)
675   {
676     String JavaDoc[] result = new String JavaDoc []{ locationURI, locationURI, null};
677     try
678     {
679       String JavaDoc file;
680       try
681       {
682         URL JavaDoc url = new URL JavaDoc(locationURI);
683         url = Platform.resolve(url);
684         file = url.getFile();
685       }
686       catch (MalformedURLException JavaDoc exception)
687       {
688         file = locationURI;
689       }
690
691       IPath path = new Path(file);
692       if (!path.isAbsolute())
693       {
694         String JavaDoc resolvedLocation = "";
695         int index = baseLocationURI.lastIndexOf("/");
696         if (index != -1)
697         {
698           resolvedLocation = baseLocationURI.substring(0, index + 1);
699         }
700         resolvedLocation += path;
701         result[0] = resolvedLocation;
702         if (templateURIPath != null)
703         {
704           String JavaDoc [] location = findLocation(templateURIPath, start, resolvedLocation);
705           resolvedLocation = location[0];
706           result[2] = location[1];
707         }
708         if (resolvedLocation != null)
709         {
710           result[1] = resolvedLocation;
711         }
712       }
713     }
714     catch (IOException JavaDoc exception)
715     {
716     }
717
718     return result;
719   }
720
721   public static String JavaDoc[] findLocation(String JavaDoc[] locationURIPath, int start, String JavaDoc relativeLocationURI)
722   {
723     String JavaDoc[] result = { null, null};
724     for (int i = start; i < locationURIPath.length; ++i)
725     {
726       result[0] = locationURIPath[i];
727       result[1] = locationURIPath[i];
728
729       if (result[0] != null)
730       {
731         try
732         {
733           if (!result[0].endsWith("/"))
734           {
735             result[0] += "/";
736           }
737           result[0] += relativeLocationURI;
738   
739           InputStream JavaDoc inputStream = openStream(result[0]);
740           inputStream.close();
741           break;
742         }
743         catch (JETException exception)
744         {
745           result[0] = null;
746         }
747         catch (IOException JavaDoc exception)
748         {
749           result[0] = null;
750         }
751       }
752     }
753     return result;
754   }
755   
756   public static String JavaDoc find(String JavaDoc[] locationURIPath, String JavaDoc relativeLocationURI)
757   {
758     return findLocation(locationURIPath, 0, relativeLocationURI)[0];
759   }
760
761   public static InputStream JavaDoc openStream(String JavaDoc locationURI) throws JETException
762   {
763     try
764     {
765       URL JavaDoc url = null;
766       try
767       {
768         url = new URL JavaDoc(locationURI);
769         url = Platform.resolve(url);
770       }
771       catch (MalformedURLException JavaDoc exception)
772       {
773         url = new URL JavaDoc("file:" + locationURI);
774       }
775
776       BufferedInputStream JavaDoc bufferedInputStream = new BufferedInputStream JavaDoc(url.openStream());
777       return bufferedInputStream;
778     }
779     catch (IOException JavaDoc exception)
780     {
781       throw new JETException(exception.getLocalizedMessage(), exception);
782     }
783   }
784 }
785
Popular Tags