1 | package org.apache.velocity.convert; |
2 | |
3 | /* |
4 | * Copyright 2001,2004 The Apache Software Foundation. |
5 | * |
6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
7 | * you may not use this file except in compliance with the License. |
8 | * You may obtain a copy of the License at |
9 | * |
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | * |
12 | * Unless required by applicable law or agreed to in writing, software |
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | * See the License for the specific language governing permissions and |
16 | * limitations under the License. |
17 | */ |
18 | |
19 | import java.io.File; |
20 | import java.io.FileWriter; |
21 | |
22 | import org.apache.oro.text.perl.Perl5Util; |
23 | import org.apache.velocity.util.StringUtils; |
24 | import org.apache.tools.ant.DirectoryScanner; |
25 | |
26 | /** |
27 | * This class will convert a WebMacro template to |
28 | * a Velocity template. Uses the ORO Regexp package to do the |
29 | * rewrites. Note, it isn't 100% perfect, but will definitely get |
30 | * you about 99.99% of the way to a converted system. Please |
31 | * see the website documentation for more information on how to use |
32 | * this class. |
33 | * |
34 | * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> |
35 | * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> |
36 | * @version $Id: WebMacro.java,v 1.20.8.1 2004/03/03 23:22:54 geirm Exp $ |
37 | */ |
38 | public class WebMacro |
39 | { |
40 | protected static final String VM_EXT = ".vm"; |
41 | protected static final String WM_EXT = ".wm"; |
42 | |
43 | /** |
44 | * The regexes to use for line by line substition. The regexes |
45 | * come in pairs. The first is the string to match, the second is |
46 | * the substitution to make. |
47 | */ |
48 | protected static String[] perLineREs = |
49 | { |
50 | // Make #if directive match the Velocity directive style. |
51 | "#if\\s*[(]\\s*(.*\\S)\\s*[)]\\s*(#begin|{)[ \\t]?", |
52 | "#if( $1 )", |
53 | |
54 | // Remove the WM #end #else #begin usage. |
55 | "[ \\t]?(#end|})[ \\t]*\n(\\s*)#else\\s*(#begin|{)[ \\t]?(\\w)", |
56 | "$2#else#**#$4", // avoid touching followup word with embedded comment |
57 | "[ \\t]?(#end|})[ \\t]*\n(\\s*)#else\\s*(#begin|{)[ \\t]?", |
58 | "$2#else", |
59 | "(#end|})(\\s*#else)\\s*(#begin|{)[ \\t]?", |
60 | "$1\n$2", |
61 | |
62 | // Convert WM style #foreach to Velocity directive style. |
63 | "#foreach\\s+(\\$\\w+)\\s+in\\s+(\\$[^\\s#]+)\\s*(#begin|{)[ \\t]?", |
64 | "#foreach( $1 in $2 )", |
65 | |
66 | // Convert WM style #set to Velocity directive style. |
67 | "#set\\s+(\\$[^\\s=]+)\\s*=\\s*([\\S \\t]+)", |
68 | "#set( $1 = $2 )", |
69 | "(##[# \\t\\w]*)\\)", // fix comments included at end of line |
70 | ")$1", |
71 | |
72 | // Convert WM style #parse to Velocity directive style. |
73 | "#parse\\s+([^\\s#]+)[ \\t]?", |
74 | "#parse( $1 )", |
75 | |
76 | // Convert WM style #include to Velocity directive style. |
77 | "#include\\s+([^\\s#]+)[ \\t]?", |
78 | "#include( $1 )", |
79 | |
80 | // Convert WM formal reference to VTL syntax. |
81 | "\\$\\(([^\\)]+)\\)", |
82 | "${$1}", |
83 | "\\${([^}\\(]+)\\(([^}]+)}\\)", // fix encapsulated brakets: {(}) |
84 | "${$1($2)}", |
85 | |
86 | // Velocity currently does not permit leading underscore. |
87 | "\\$_", |
88 | "$l_", |
89 | "\\${(_[^}]+)}", // within a formal reference |
90 | "${l$1}", |
91 | |
92 | // Eat semi-colons in (converted) VTL #set directives. |
93 | "(#set\\s*\\([^;]+);(\\s*\\))", |
94 | "$1$2", |
95 | |
96 | // Convert explicitly terminated WM statements to VTL syntax. |
97 | "(^|[^\\\\])\\$(\\w[^=\n;'\"]*);", |
98 | "$1${$2}", |
99 | |
100 | // Change extensions when seen. |
101 | "\\.wm", |
102 | ".vm" |
103 | }; |
104 | |
105 | /** |
106 | * Iterate through the set of find/replace regexes |
107 | * that will convert a given WM template to a VM template |
108 | */ |
109 | public void convert(String target) |
110 | { |
111 | File file = new File(target); |
112 | |
113 | if (!file.exists()) |
114 | { |
115 | System.err.println |
116 | ("The specified template or directory does not exist"); |
117 | System.exit(1); |
118 | } |
119 | |
120 | if (file.isDirectory()) |
121 | { |
122 | String basedir = file.getAbsolutePath(); |
123 | String newBasedir = basedir + VM_EXT; |
124 | |
125 | DirectoryScanner ds = new DirectoryScanner(); |
126 | ds.setBasedir(basedir); |
127 | ds.addDefaultExcludes(); |
128 | ds.scan(); |
129 | String[] files = ds.getIncludedFiles(); |
130 | |
131 | for (int i = 0; i < files.length; i++) |
132 | { |
133 | writeTemplate(files[i], basedir, newBasedir); |
134 | } |
135 | } |
136 | else |
137 | { |
138 | writeTemplate(file.getAbsolutePath(), "", ""); |
139 | } |
140 | } |
141 | |
142 | /** |
143 | * Write out the converted template to the given named file |
144 | * and base directory. |
145 | */ |
146 | private boolean writeTemplate(String file, String basedir, |
147 | String newBasedir) |
148 | { |
149 | if (file.indexOf(WM_EXT) < 0) |
150 | { |
151 | return false; |
152 | } |
153 | |
154 | System.out.println("Converting " + file + "..."); |
155 | |
156 | String template; |
157 | String templateDir; |
158 | String newTemplate; |
159 | File outputDirectory; |
160 | |
161 | if (basedir.length() == 0) |
162 | { |
163 | template = file; |
164 | templateDir = ""; |
165 | newTemplate = convertName(file); |
166 | } |
167 | else |
168 | { |
169 | template = basedir + File.separator + file; |
170 | templateDir = newBasedir + extractPath(file); |
171 | |
172 | outputDirectory = new File(templateDir); |
173 | |
174 | if (! outputDirectory.exists()) |
175 | { |
176 | outputDirectory.mkdirs(); |
177 | } |
178 | |
179 | newTemplate = newBasedir + File.separator + convertName(file); |
180 | } |
181 | |
182 | String convertedTemplate = convertTemplate(template); |
183 | |
184 | try |
185 | { |
186 | FileWriter fw = new FileWriter(newTemplate); |
187 | fw.write(convertedTemplate); |
188 | fw.close(); |
189 | } |
190 | catch (Exception e) |
191 | { |
192 | e.printStackTrace(); |
193 | } |
194 | |
195 | return true; |
196 | } |
197 | |
198 | /** |
199 | * Gets the path segment of the full path to a file (i.e. one |
200 | * which originally included the file name). |
201 | */ |
202 | private final String extractPath(String file) |
203 | { |
204 | int lastSepPos = file.lastIndexOf(File.separator); |
205 | return (lastSepPos == -1 ? "" : |
206 | File.separator + file.substring(0, lastSepPos)); |
207 | } |
208 | |
209 | /** |
210 | * Simple extension conversion of .wm to .vm |
211 | */ |
212 | private String convertName(String name) |
213 | { |
214 | if (name.indexOf(WM_EXT) > 0) |
215 | { |
216 | return name.substring(0, name.indexOf(WM_EXT)) + VM_EXT; |
217 | } |
218 | else |
219 | { |
220 | return name; |
221 | } |
222 | } |
223 | |
224 | /** |
225 | * How to use this little puppy :-) |
226 | */ |
227 | private static final void usage() |
228 | { |
229 | System.err.println("Usage: convert-wm <template.wm | directory>"); |
230 | System.exit(1); |
231 | } |
232 | |
233 | /** |
234 | * Apply find/replace regexes to our WM template |
235 | */ |
236 | public String convertTemplate(String template) |
237 | { |
238 | String contents = StringUtils.fileContentsToString(template); |
239 | |
240 | // Overcome Velocity 0.71 limitation. |
241 | // HELP: Is this still necessary? |
242 | if (!contents.endsWith("\n")) |
243 | { |
244 | contents += "\n"; |
245 | } |
246 | |
247 | // Convert most markup. |
248 | Perl5Util perl = new Perl5Util(); |
249 | for (int i = 0; i < perLineREs.length; i += 2) |
250 | { |
251 | contents = perl.substitute(makeSubstRE(i), contents); |
252 | } |
253 | |
254 | // Convert closing curlies. |
255 | if (perl.match("m/javascript/i", contents)) |
256 | { |
257 | // ASSUMPTION: JavaScript is indented, WM is not. |
258 | contents = perl.substitute("s/\n}/\n#end/g", contents); |
259 | } |
260 | else |
261 | { |
262 | contents = perl.substitute("s/(\n\\s*)}/$1#end/g", contents); |
263 | contents = perl.substitute("s/#end\\s*\n\\s*#else/#else/g", |
264 | contents); |
265 | } |
266 | |
267 | return contents; |
268 | } |
269 | |
270 | /** |
271 | * Makes a Perl 5 regular expression for use by ORO. |
272 | */ |
273 | private final String makeSubstRE(int i) |
274 | { |
275 | return ("s/" + perLineREs[i] + '/' + perLineREs[i + 1] + "/g"); |
276 | } |
277 | |
278 | /** |
279 | * Main hook for the conversion process. |
280 | */ |
281 | public static void main(String[] args) |
282 | { |
283 | if (args.length > 0) |
284 | { |
285 | for (int x=0; x < args.length; x++) |
286 | { |
287 | WebMacro converter = new WebMacro(); |
288 | converter.convert(args[x]); |
289 | } |
290 | } |
291 | else |
292 | { |
293 | usage(); |
294 | } |
295 | } |
296 | } |