001: package org.apache.velocity.convert;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.io.File;
023: import java.io.FileWriter;
024: import java.io.IOException;
025:
026: import org.apache.oro.text.perl.Perl5Util;
027: import org.apache.velocity.util.StringUtils;
028: import org.apache.tools.ant.DirectoryScanner;
029:
030: /**
031: * This class will convert a WebMacro template to
032: * a Velocity template. Uses the ORO Regexp package to do the
033: * rewrites. Note, it isn't 100% perfect, but will definitely get
034: * you about 99.99% of the way to a converted system. Please
035: * see the website documentation for more information on how to use
036: * this class.
037: *
038: * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
039: * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
040: * @version $Id: WebMacro.java 463298 2006-10-12 16:10:32Z henning $
041: */
042: public class WebMacro {
043: /**
044: *
045: */
046: protected static final String VM_EXT = ".vm";
047:
048: /**
049: *
050: */
051: protected static final String WM_EXT = ".wm";
052:
053: /**
054: * The regexes to use for line by line substition. The regexes
055: * come in pairs. The first is the string to match, the second is
056: * the substitution to make.
057: */
058: protected static String[] perLineREs = {
059: // Make #if directive match the Velocity directive style.
060: "#if\\s*[(]\\s*(.*\\S)\\s*[)]\\s*(#begin|{)[ \\t]?",
061: "#if( $1 )",
062:
063: // Remove the WM #end #else #begin usage.
064: "[ \\t]?(#end|})[ \\t]*\n(\\s*)#else\\s*(#begin|{)[ \\t]?(\\w)",
065: "$2#else#**#$4", // avoid touching followup word with embedded comment
066: "[ \\t]?(#end|})[ \\t]*\n(\\s*)#else\\s*(#begin|{)[ \\t]?",
067: "$2#else",
068: "(#end|})(\\s*#else)\\s*(#begin|{)[ \\t]?",
069: "$1\n$2",
070:
071: // Convert WM style #foreach to Velocity directive style.
072: "#foreach\\s+(\\$\\w+)\\s+in\\s+(\\$[^\\s#]+)\\s*(#begin|{)[ \\t]?",
073: "#foreach( $1 in $2 )",
074:
075: // Convert WM style #set to Velocity directive style.
076: "#set\\s+(\\$[^\\s=]+)\\s*=\\s*([\\S \\t]+)",
077: "#set( $1 = $2 )",
078: "(##[# \\t\\w]*)\\)", // fix comments included at end of line
079: ")$1",
080:
081: // Convert WM style #parse to Velocity directive style.
082: "#parse\\s+([^\\s#]+)[ \\t]?", "#parse( $1 )",
083:
084: // Convert WM style #include to Velocity directive style.
085: "#include\\s+([^\\s#]+)[ \\t]?", "#include( $1 )",
086:
087: // Convert WM formal reference to VTL syntax.
088: "\\$\\(([^\\)]+)\\)", "${$1}",
089: "\\${([^}\\(]+)\\(([^}]+)}\\)", // fix encapsulated brakets: {(})
090: "${$1($2)}",
091:
092: // Velocity currently does not permit leading underscore.
093: "\\$_", "$l_", "\\${(_[^}]+)}", // within a formal reference
094: "${l$1}",
095:
096: // Eat semi-colons in (converted) VTL #set directives.
097: "(#set\\s*\\([^;]+);(\\s*\\))", "$1$2",
098:
099: // Convert explicitly terminated WM statements to VTL syntax.
100: "(^|[^\\\\])\\$(\\w[^=\n;'\"]*);", "$1${$2}",
101:
102: // Change extensions when seen.
103: "\\.wm", ".vm" };
104:
105: /**
106: * Iterate through the set of find/replace regexes
107: * that will convert a given WM template to a VM template
108: * @param target
109: */
110: public void convert(String target) {
111: File file = new File(target);
112:
113: if (!file.exists()) {
114: throw new RuntimeException(
115: "The specified template or directory does not exist");
116: }
117:
118: if (file.isDirectory()) {
119: String basedir = file.getAbsolutePath();
120: String newBasedir = basedir + VM_EXT;
121:
122: DirectoryScanner ds = new DirectoryScanner();
123: ds.setBasedir(basedir);
124: ds.addDefaultExcludes();
125: ds.scan();
126: String[] files = ds.getIncludedFiles();
127:
128: for (int i = 0; i < files.length; i++) {
129: writeTemplate(files[i], basedir, newBasedir);
130: }
131: } else {
132: writeTemplate(file.getAbsolutePath(), "", "");
133: }
134: }
135:
136: /**
137: * Write out the converted template to the given named file
138: * and base directory.
139: */
140: private boolean writeTemplate(String file, String basedir,
141: String newBasedir) {
142: if (file.indexOf(WM_EXT) < 0) {
143: return false;
144: }
145:
146: System.out.println("Converting " + file + "...");
147:
148: String template = file;
149: String newTemplate = convertName(file);
150:
151: if (basedir.length() > 0) {
152: String templateDir = newBasedir + extractPath(file);
153: File outputDirectory = new File(templateDir);
154:
155: template = basedir + File.separator + file;
156:
157: if (!outputDirectory.exists()) {
158: outputDirectory.mkdirs();
159: }
160:
161: newTemplate = newBasedir + File.separator
162: + convertName(file);
163: }
164:
165: String convertedTemplate = convertTemplate(template);
166:
167: FileWriter fw = null;
168: try {
169: fw = new FileWriter(newTemplate);
170: fw.write(convertedTemplate);
171: } catch (Exception e) {
172: e.printStackTrace();
173: } finally {
174: if (fw != null) {
175: try {
176: fw.close();
177: } catch (IOException io) {
178: // Do nothing
179: }
180: }
181: }
182:
183: return true;
184: }
185:
186: /**
187: * Gets the path segment of the full path to a file (i.e. one
188: * which originally included the file name).
189: */
190: private final String extractPath(String file) {
191: int lastSepPos = file.lastIndexOf(File.separator);
192: return (lastSepPos == -1 ? "" : File.separator
193: + file.substring(0, lastSepPos));
194: }
195:
196: /**
197: * Simple extension conversion of .wm to .vm
198: */
199: private String convertName(String name) {
200: return (name.indexOf(WM_EXT) < 0) ? name : name.substring(0,
201: name.indexOf(WM_EXT))
202: + VM_EXT;
203: }
204:
205: /**
206: * How to use this little puppy :-)
207: */
208: private static final void usage() {
209: System.err
210: .println("Usage: convert-wm <template.wm | directory>");
211: }
212:
213: /**
214: * Apply find/replace regexes to our WM template
215: * @param template
216: * @return Returns the template with all regexprs applied.
217: */
218: public String convertTemplate(String template) {
219: String contents = StringUtils.fileContentsToString(template);
220:
221: // Overcome Velocity 0.71 limitation.
222: // HELP: Is this still necessary?
223: if (!contents.endsWith("\n")) {
224: contents += "\n";
225: }
226:
227: // Convert most markup.
228: Perl5Util perl = new Perl5Util();
229: for (int i = 0; i < perLineREs.length; i += 2) {
230: contents = perl.substitute(makeSubstRE(i), contents);
231: }
232:
233: // Convert closing curlies.
234: if (perl.match("m/javascript/i", contents)) {
235: // ASSUMPTION: JavaScript is indented, WM is not.
236: contents = perl.substitute("s/\n}/\n#end/g", contents);
237: } else {
238: contents = perl
239: .substitute("s/(\n\\s*)}/$1#end/g", contents);
240: contents = perl.substitute("s/#end\\s*\n\\s*#else/#else/g",
241: contents);
242: }
243:
244: return contents;
245: }
246:
247: /**
248: * Makes a Perl 5 regular expression for use by ORO.
249: */
250: private final String makeSubstRE(int i) {
251: return ("s/" + perLineREs[i] + '/' + perLineREs[i + 1] + "/g");
252: }
253:
254: /**
255: * Main hook for the conversion process.
256: * @param args
257: */
258: public static void main(String[] args) {
259: if (args.length > 0) {
260: for (int x = 0; x < args.length; x++) {
261: WebMacro converter = new WebMacro();
262: converter.convert(args[x]);
263: }
264: } else {
265: usage();
266: }
267: }
268: }
|