View Javadoc

1   package org.apache.dvsl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileReader;
25  import java.io.FileWriter;
26  import java.io.InputStream;
27  import java.io.InputStreamReader;
28  import java.io.OutputStreamWriter;
29  import java.io.Reader;
30  import java.io.StringWriter;
31  import java.io.Writer;
32  
33  import java.util.Enumeration;
34  import java.util.HashMap;
35  import java.util.Map;
36  import java.util.Properties;
37  
38  import org.apache.velocity.VelocityContext;
39  import org.apache.velocity.app.VelocityEngine;
40  import org.apache.velocity.context.Context;
41  import org.apache.velocity.runtime.log.LogChute;
42  import org.apache.velocity.runtime.log.LogChuteSystem;
43  import org.apache.velocity.runtime.log.LogSystem;
44  
45  import org.dom4j.Document;
46  import org.dom4j.io.SAXReader;
47  
48  /**
49   *  Main DVSL class - use this as the helper class for apps
50   *
51   *  @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
52   *  @author <a href="mailto:billb@progress.com">Bill Burton.</a>
53   */
54  public class DVSL
55  {
56      private static String TOOL_PROP_PREFIX = "toolbox.tool.";
57      private static String STRING_PROP_PREFIX = "toolbox.string.";
58      private static String INTEGER_PROP_PREFIX = "toolbox.integer.";
59      private static String TOOLBOX_NAME = "toolbox.contextname.";
60  
61      private VelocityEngine ve = null;
62      private Document currentDocument = null;
63      private Writer currentWriter = null;
64      private Context toolContext;
65      private Context userContext;
66      private Context styleContext;
67      private DVSLContext baseContext = new DVSLContext();
68      private Transformer transformer;
69      private ClassLoader classLoader;
70      private boolean ready = false;
71  
72      private Map velConfig = null;
73      private File logFile;
74      private LogChute logger;
75  
76      private Map appVals = new HashMap();
77  
78      private TemplateHandler templateHandler = new TemplateHandler();
79  
80      boolean validate = false;
81  
82      public DVSL()
83      {
84          classLoader = DVSL.class.getClassLoader();
85      }
86  
87      /**
88       *  <p>
89       *  lets the user specify a filename for logging.
90       *  </p>
91       */
92      public void setLogFile(File logFile)
93      {
94          this.logFile = logFile;
95  
96          if (velConfig == null)
97          {
98              velConfig = new HashMap();
99          }
100 
101         velConfig.put(VelocityEngine.RUNTIME_LOG, logFile.getAbsolutePath());
102     }
103 
104     /**
105      *  <p>
106      *  lets the user specify a class instance for logging.
107      *  </p>
108      * @deprecated use setLogChute instead
109      */
110     public void setLogSystem(LogSystem logger)
111     {
112         this.logger = new LogAdapter(logger);
113 
114         if (velConfig == null)
115         {
116             velConfig = new HashMap();
117         }
118 
119         velConfig.put(VelocityEngine.RUNTIME_LOG_LOGSYSTEM, logger);
120     }
121 
122     /**
123      *  <p>
124      *  lets the user specify a class instance for logging.
125      *  </p>
126      */
127     public void setLogChute(LogChute logger)
128     {
129         this.logger = logger;
130 
131         if (velConfig == null)
132         {
133             velConfig = new HashMap();
134         }
135 
136         velConfig.put(VelocityEngine.RUNTIME_LOG_LOGSYSTEM, logger);
137     }
138 
139 
140     /**
141      *  <p>
142      *  lets the user pass a java.util.Properties containing
143      *  properties for the configuration of the VelocityEngine
144      *  used by DVSL
145      *  </p>
146      */
147     public void setVelocityConfig(Map map)
148     {
149         if (velConfig != null)
150         {
151             map.putAll(velConfig);
152         }
153 
154         velConfig = map;
155     }
156 
157     /**
158      *  <p>
159      *  Sets the user context.  The user context is
160      *  a Velocity Context containing user-supplied
161      *  objects and data that are to be made available
162      *  in the template
163      *  </p>
164      *
165      *  @param ctx User context of data
166      */
167     public void setUserContext(Context ctx)
168     {
169         ready = false;
170         userContext = ctx;
171     }
172 
173     /**
174      * <p>
175      *  Uses a validating parser on all input documents
176      * </p>
177      *
178      * @param validate
179      */
180 
181     public void setValidatingParser(boolean validate)
182     {
183         this.validate = validate;
184     }
185 
186     /**
187      *  <p>
188      *  Specify a classloader for loading the Toolbox classes.  Setting to null
189      *  resets to the default ClassLoader.
190      *  </p>
191      *
192      *  @param classLoader ClassLoader or null for default ClassLoader
193      */
194     public void setClassLoader(ClassLoader classLoader)
195     {
196         if (classLoader == null)
197         {
198             this.classLoader = this.getClass().getClassLoader();
199         }
200         else
201         {
202             this.classLoader = classLoader;
203         }
204     }
205 
206     /**
207      *  <p>
208      *  Loads the toolbox from the input Properties.
209      *  </p>
210      *
211      *  <p>
212      *  Currently supports specification of the Toolbox
213      *  name in the context, creating classes, and string
214      *  and integer values.  Ex :
215      *  </p>
216      *
217      *  <pre>
218      *  toolbox.contextname = floyd
219      *  toolbox.tool.footool = Footool
220      *  toolbox.string.mystring = Hello there!
221      *  toolbox.integer.myint = 7
222      *  toolbox.string.sourcebase = ./xdocs/
223      *  </pre>
224      *
225      *  <p>
226      *  So in template, this toolbox and it's values would
227      *  be accessed as :
228      *  </p>
229      *  <pre>
230      *    $context.floyd.footool.getFoo()
231      *    $context.floyd.mystring
232      *    $context.floyd.myint
233      *  </pre>
234      */
235     public void setToolbox(Properties p)
236         throws ClassNotFoundException, InstantiationException, IllegalAccessException
237     {
238         ready = false;
239 
240         /*
241          *  for each key that looks like
242          *     toolbox.tool.<token> = class
243          */
244 
245         Map toolbox = new HashMap();
246 
247         String toolboxname = "toolbox";
248 
249         for (Enumeration e = p.propertyNames(); e.hasMoreElements(); )
250         {
251             String key = (String) e.nextElement();
252 
253             String value = p.getProperty(key);
254 
255             if (key.startsWith(TOOL_PROP_PREFIX))
256             {
257                 String toolname = key.substring(TOOL_PROP_PREFIX.length());
258 
259                 Object o = Class.forName(value, true, classLoader).newInstance();
260 
261                 toolbox.put(toolname, o);
262             }
263             else if (key.startsWith(INTEGER_PROP_PREFIX))
264             {
265                 String toolname = key.substring(INTEGER_PROP_PREFIX.length());
266 
267                 int i = 0;
268 
269                 try
270                 {
271                     i = Integer.parseInt(value);
272                 }
273                 catch(Exception ee)
274                 {
275                 }
276 
277                 toolbox.put(toolname, new Integer(i));
278             }
279             else if (key.startsWith(STRING_PROP_PREFIX))
280             {
281                 String toolname = key.substring(STRING_PROP_PREFIX.length());
282                 toolbox.put(toolname, value);
283             }
284             else if (key.startsWith(TOOLBOX_NAME))
285             {
286                 toolboxname = value;
287             }
288         }
289 
290         toolContext = new VelocityContext();
291 
292         toolContext.put(toolboxname, toolbox);
293     }
294 
295     /**
296      *  Convenience function.  See...
297      */
298     public void setStylesheet(String stylesheet)
299         throws Exception
300     {
301         setStylesheet(new File(stylesheet), null);
302     }
303 
304     /**
305      *  Convenience function.  See...
306      */
307     public void setStylesheet(File stylesheet)
308         throws Exception
309     {
310         setStylesheet(stylesheet, null);
311     }
312 
313     /**
314      *  Convenience function.  See...
315      */
316     public void setStylesheet(File stylesheet, String stylesheetEncoding)
317         throws Exception
318     {
319         Reader fr = null;
320 
321         try
322         {
323             if (stylesheetEncoding != null)
324             {
325                 fr = new InputStreamReader(
326                     new FileInputStream(stylesheet), stylesheetEncoding);
327             }
328             else
329             {
330                 fr = new FileReader(stylesheet);
331             }
332 
333             setStylesheet(fr);
334         }
335         finally
336         {
337             if (fr != null)
338                 fr.close();
339         }
340     }
341 
342 
343     /**
344      *  <p>
345      *  Sets the stylesheet for this transformation set
346      *  </p>
347      *
348      *  <p>
349      *  Note that don't need this for each document you want
350      *  to transform.  Just do it once, and transform away...
351      *  </p>
352      *
353      *  @param styleReader Reader with stylesheet char stream
354      */
355     public void setStylesheet(Reader styleReader)
356         throws Exception
357     {
358         ready = false;
359         /*
360          *  now initialize Velocity - we need to do that
361          *  on change of stylesheet
362          */
363 
364         ve = new VelocityEngine();
365 
366         /*
367          * if there are user properties, set those first - carefully
368          */
369 
370         if (velConfig != null)
371         {
372             configureVelocityEngine(ve, velConfig);
373         }
374 
375         /*
376          *  register our template() directive
377          */
378 
379         ve.setProperty("userdirective", "org.apache.dvsl.directive.MatchDirective");
380         ve.init();
381 
382         /*
383          *  add our template accumulator
384          */
385 
386         ve.setApplicationAttribute("org.apache.dvsl.TemplateHandler", templateHandler);
387 
388         /*
389          *  load and render the stylesheet
390          *
391          *  this sets stylesheet specific context
392          *  values
393          */
394 
395         StringWriter junkWriter = new StringWriter();
396 
397         styleContext = new VelocityContext();
398         ve.evaluate(styleContext, junkWriter, "DVSL:stylesheet", styleReader);
399 
400         /*
401          *  now run the base template through for the rules
402          */
403 
404         InputStream is = this.getClass().getClassLoader()
405               .getResourceAsStream("org/apache/dvsl/resource/defaultroot.dvsl");
406 
407         if (is == null)
408         {
409             System.out.println("DEFAULT TRANSFORM RULES NOT FOUND ");
410         }
411         else
412         {
413             ve.evaluate(new VelocityContext(),
414                     junkWriter, "defaultroot.dvsl", new InputStreamReader(is));
415             is.close();
416         }
417 
418         /*
419          *  need a new transformer, as it depends on the
420          *  velocity engine
421          */
422 
423         transformer = new Transformer(ve, templateHandler,  baseContext, appVals,
424                             validate);
425     }
426 
427     /**
428      *  <p>
429      *   Adds the allowed properties from the Properties to the
430      *   velocity engine
431      *  </p>
432      *  <p>
433      *  So far, we support, in RuntimeConstant parlance :
434      *  </p>
435      *  <ul>
436      *  <li>VM_LIBRARY</li>
437      *  <li>FILE_RESOURCE_LOADER_PATH</li>
438      *  <li>RUNTIME_LOG</li>
439      *  <li>RUNTIME_LOG_LOGSYSTEM</li>
440      *  <li>RUNTIME_LOG_LOGSYSTEM_CLASS</li>
441      *  </ul>
442      *
443      *  <p>
444      *  If you are going to use this, ensure you do it *before* setting
445      *  the stylesheet, as that creates the VelocityEngine
446      *  </p>
447      */
448     private void configureVelocityEngine(VelocityEngine ve, Map map)
449     {
450         if (ve == null || map == null)
451         {
452             return;
453         }
454 
455         /*
456          * for now,  keep it simple
457          */
458 
459         Object val = map.get(VelocityEngine.VM_LIBRARY);
460 
461         if (val instanceof String)
462         {
463             ve.setProperty(VelocityEngine.VM_LIBRARY, (String) val);
464         }
465 
466         /*
467          *  assumes that for now, we are using the file loader
468          */
469         val = map.get(VelocityEngine.FILE_RESOURCE_LOADER_PATH);
470 
471         if (val instanceof String)
472         {
473             ve.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, (String) val);
474         }
475 
476         /*
477          *  No real assumptions - pass what you want
478          */
479         val = map.get(VelocityEngine.RUNTIME_LOG);
480 
481         if (val instanceof String)
482         {
483             ve.setProperty(VelocityEngine.RUNTIME_LOG,  val);
484         }
485 
486         val = map.get(VelocityEngine.RUNTIME_LOG_LOGSYSTEM);
487 
488         if (val != null)
489         {
490             ve.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM,  val);
491         }
492 
493         val = map.get(VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS);
494 
495         if (val instanceof String)
496         {
497             ve.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS,  val);
498         }
499 
500     }
501 
502     /**
503      *  sets up all the context goodies
504      */
505     protected void makeReady()
506     {
507         /*
508          *  put all the contexts together
509          */
510 
511         baseContext.clearContexts();
512 
513         baseContext.addContext(userContext);
514         baseContext.addContext(toolContext);
515         baseContext.setStyleContext(styleContext);
516 
517         ready = true;
518      }
519 
520     /**
521      *  does the transformation of the inputstream into
522      *  the output writer
523      */
524     protected long xform(Reader reader, Writer writer)
525         throws Exception
526     {
527         if (!ready)
528             makeReady();
529 
530         return transformer.transform(reader, writer);
531     }
532 
533     protected long xform(Document dom4jdoc, Writer writer)
534         throws Exception
535     {
536         if (!ready)
537             makeReady();
538 
539         return transformer.transform(dom4jdoc, writer);
540     }
541 
542     public long transform(File f, Writer writer)
543         throws Exception
544     {
545         InputStream is = null;
546         try
547         {
548             is = new FileInputStream(f);
549             return transform(is, writer);
550         }
551         finally
552         {
553             if (is != null)
554             {
555                 is.close();
556             }
557         }
558     }
559 
560     public long transform(Reader reader, Writer writer)
561         throws Exception
562     {
563         return xform(reader, writer);
564     }
565 
566     public long transform(InputStream is, Writer writer)
567         throws Exception
568     {
569         SAXReader reader = new SAXReader();
570         return xform(reader.read(is), writer);
571     }
572 
573     /**
574      * Transforms the given dom4j Document into the writer.
575      *
576      * @param dom4jdoc dom4j Document object
577      * @param writer Writer for output
578      */
579     public long transform(Document dom4jdoc, Writer writer)
580         throws Exception
581     {
582         return xform(dom4jdoc, writer);
583     }
584 
585     public long transform(String infile, Writer writer)
586         throws Exception
587     {
588         return transform(new File(infile), writer);
589     }
590 
591 
592     /**
593      *  Gets the application value for the specified key
594      *
595      *  @param key key to use to retrieve value
596      *  @return value if found, null otherwise
597      */
598     public Object getAppValue(Object key)
599     {
600         return appVals.get(key);
601     }
602 
603     /**
604      *  Sets the application value for the specified key
605      *
606      *  @param key key to use to store value
607      *  @param value value to be stored
608      *  @return old value if any, null otherwise
609      */
610     public Object putAppValue(Object key, Object value)
611     {
612         return appVals.put(key, value);
613     }
614 
615     /**
616      *  <p>
617      *  Allows command-line access.
618      *  </p>
619      *  <p>
620      *  Usage :  java -jar dvsl.jar -STYLE stylesheeet [-IN infile] [-OUT outfile] [-TOOL toolboxname]
621      *  </p>
622      */
623     public static void main(String[] args)
624         throws Exception
625     {
626 
627         DVSL dvsl = new DVSL();
628 
629         Reader in = new InputStreamReader(System.in);
630         String infile = null;
631         String style = null;
632         String outfile = null;
633 
634         Writer out = new OutputStreamWriter(System.out);
635         String toolfile = null;
636 
637         for(int i = 0; i < args.length; i++)
638         {
639             if (args[i].equals("-IN"))
640                 infile = args[++i];
641             else if (args[i].equals("-OUT"))
642                 outfile = args[++i];
643            else if (args[i].equals("-STYLE"))
644                 style = args[++i];
645            else if (args[i].equals("-TOOL"))
646                 toolfile = args[++i];
647         }
648 
649         if (style == null)
650         {
651             System.out.println("usage :need to specify a stylesheet. ");
652             System.out.println("java -jar dvsl.jar -STYLE stylesheeet [-IN infile] [-OUT outfile] [-TOOL toolboxname]");
653             return;
654         }
655 
656         if (style != null)
657             dvsl.setStylesheet(style);
658 
659         if (toolfile != null)
660         {
661             Properties p = new Properties();
662 
663             InputStream fis = new FileInputStream(toolfile);
664 
665             p.load(fis);
666 
667             dvsl.setToolbox(p);
668         }
669 
670         if (infile != null)
671             in = new FileReader(infile);
672 
673         if (outfile != null)
674             out = new FileWriter(outfile);
675 
676         long time = dvsl.transform(in, out);
677 
678         out.flush();
679 
680     }
681 
682     /*
683      * inner class to wrap a LogSystem into a LogChute
684      */
685     protected static class LogAdapter extends LogChuteSystem {
686         protected LogAdapter(LogSystem logSystem) {
687             super(logSystem);
688         }
689     }
690 }
691