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 }