View Javadoc

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