View Javadoc
1   /*
2    * $Source$
3    * $Revision$
4    *
5    * Copyright (C) 2006 Tim Pizey
6    *
7    * Part of Melati (http://melati.org), a framework for the rapid
8    * development of clean, maintainable web applications.
9    *
10   * Melati is free software; Permission is granted to copy, distribute
11   * and/or modify this software under the terms either:
12   *
13   * a) the GNU General Public License as published by the Free Software
14   *    Foundation; either version 2 of the License, or (at your option)
15   *    any later version,
16   *
17   *    or
18   *
19   * b) any version of the Melati Software License, as published
20   *    at http://melati.org
21   *
22   * You should have received a copy of the GNU General Public License and
23   * the Melati Software License along with this program;
24   * if not, write to the Free Software Foundation, Inc.,
25   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26   * GNU General Public License and visit http://melati.org to obtain the
27   * Melati Software License.
28   *
29   * Feel free to contact the Developers of Melati (http://melati.org),
30   * if you would like to work out a different arrangement than the options
31   * outlined here.  It is our intention to allow Melati to be used by as
32   * wide an audience as possible.
33   *
34   * This program is distributed in the hope that it will be useful,
35   * but WITHOUT ANY WARRANTY; without even the implied warranty of
36   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37   * GNU General Public License for more details.
38   *
39   * Contact details for copyright holder:
40   *
41   *     Tim Pizey <timp At paneris.org>
42   */
43  package org.melati.template.velocity;
44  
45  import java.io.ByteArrayInputStream;
46  import java.io.IOException;
47  import java.io.InputStream;
48  
49  import org.apache.oro.text.perl.Perl5Util;
50  import org.melati.util.MelatiBugMelatiException;
51  
52  /**
53   * Converter from WebMacro templates to Velocity templates.
54   * 
55   * Note that this does not succeed for modern WebMacro syntax 
56   * which uses optional #begin in #foreach.
57   * 
58   * @author Tim Pizey based on work by Jason vanZyl and Tim Joyce.
59   * 
60   * FIXME Refactor to use java regexp.
61   *
62   */
63  public final class WebMacroConverter {
64  
65    private WebMacroConverter() {}
66    /**
67     * The regexes to use for substitution. The regexes come
68     * in pairs. The first is the string to match, the
69     * second is the substitution to make.
70     */
71    public static final String[] regExps = {
72          // Make #if directive match the Velocity directive style.
73          "#if\\s*[(]\\s*(.*\\S)\\s*[)]\\s*(#begin|{)[ \\t]?",
74          "#if( $1 )",
75  
76          // Remove the WM #end #else #begin usage.
77          "([ \\t])?(#end|})\\s*#else\\s*(#begin|{)([ \\t])?(\\w)",
78          "#{else}$5", // avoid touching a followup word with embedded comment
79          
80          "[ \\t]?(#end|})\\s*#else\\s*(#begin|{)[ \\t]?",
81          "#else",
82  
83          // Convert nulls.
84          // This converts
85          // $var != null
86          // to
87          // $var
88          "\\s*(\\$[^\\s\\!]+)\\s*!=\\s*null\\s*",
89          " $1 ",
90          // This converts
91          // $var == null
92          // to
93          // !$var
94          "\\s*(\\$[^\\s\\!]+)\\s*==\\s*null\\s*",
95          " !$1 ",
96  
97          // Convert WM style #foreach to Velocity directive style.
98          "#foreach\\s+(\\$\\w+)\\s+in\\s+(\\$[^\\s#]+)\\s*(#begin|{)[ \\t]?",
99          "#foreach( $1 in $2 )",
100 
101         // Change the "}" to #end. Have to get more
102         // sophisticated here. Will assume either {}
103         // and no javascript, or #begin/#end with the
104         // possibility of javascript.
105         "\n}", // assumes that javascript is indented, WMs not!!!
106         "\n#end",
107 
108         // Convert WM style #set to Velocity directive style.
109         //"#set\\s+(\\$[^\\s=]+)\\s*=\\s*(.*\\S)[ \\t]*",
110         "#set\\s+(\\$[^\\s=]+)\\s*=\\s*([\\S \\t]+)",
111         "#set( $1 = $2 )",
112         "(##[# \\t\\w]*)\\)", // fix comments included at end of line
113         ")$1",
114 
115         // Convert WM style #parse to Velocity directive style.
116         "#parse\\s+([^\\s#]+)[ \\t]?",
117         "#parse( $1 )",
118 
119         // parse is now deprecated for web macro
120         // include as template is recommended.
121         // Velocity supports only parse
122         // added for melati conversion
123         "#include\\s+as\\s+template\\s+([^\\s#]+)[ \\t]?",
124         "#parse( $1 )",
125 
126         // Convert WM style #include to Velocity directive style.
127         "#include\\s+([^\\s#]+)[ \\t]?",
128         "#include( $1 )",
129 
130         // Convert WM formal reference to VL syntax.
131         "\\$\\(([^\\)]+)\\)",
132         "\\${$1}",
133         "\\${([^}\\(]+)\\(([^}]+)}\\)", // fix encapsulated brackets: {(})
134         "\\${$1($2)}",
135 
136         // Velocity currently does not permit leading underscore.
137         "\\$_",
138         "\\$l_",
139         "\\${(_[^}]+)}", // within a formal reference
140         "\\${l$1}",
141 
142   };
143 
144   /**
145    * Do the conversion.
146    * 
147    * @param in
148    * @return the InputStream with substitutions applied
149    */
150   public static InputStream convert(InputStream in) {
151     byte[] ca;
152     try {
153       ca = new byte[in.available()];
154       in.read(ca);
155       String contents = convert(new String(ca));
156       //System.err.println(contents);
157       return new ByteArrayInputStream(contents.getBytes());
158     } catch (IOException e) {
159       throw new MelatiBugMelatiException(
160               "Problem loading WebMacro template as a VelocityTemplate", e);
161     }
162   }
163   
164   public static String convert(String in) { 
165       /* Regular expression tool */
166       final Perl5Util perl = new Perl5Util();
167       for (int i = 0; i < regExps.length; i += 2) {
168         while (perl.match("/" + regExps[i] + "/", in)) {
169           in = perl.substitute(
170               "s/" + regExps[i] + "/" + regExps[i+1] + "/", in);
171         }
172       }
173       return in;      
174   }
175 }