001: /*
002: * Copyright (c) 2003 The Visigoth Software Society. All rights
003: * reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * 2. Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in
014: * the documentation and/or other materials provided with the
015: * distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowledgement:
019: * "This product includes software developed by the
020: * Visigoth Software Society (http://www.visigoths.org/)."
021: * Alternately, this acknowledgement may appear in the software itself,
022: * if and wherever such third-party acknowledgements normally appear.
023: *
024: * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
025: * project contributors may be used to endorse or promote products derived
026: * from this software without prior written permission. For written
027: * permission, please contact visigoths@visigoths.org.
028: *
029: * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
030: * nor may "FreeMarker" or "Visigoth" appear in their names
031: * without prior written permission of the Visigoth Software Society.
032: *
033: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
034: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
035: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036: * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
037: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
038: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
039: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
040: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
042: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
043: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
044: * SUCH DAMAGE.
045: * ====================================================================
046: *
047: * This software consists of voluntary contributions made by many
048: * individuals on behalf of the Visigoth Software Society. For more
049: * information on the Visigoth Software Society, please see
050: * http://www.visigoths.org/
051: */
052:
053: package freemarker.ext.dom;
054:
055: import java.io.*;
056: import java.util.*;
057: import freemarker.template.*;
058:
059: /**
060: * A class that contains a main() method for command-line invocation
061: * of a FreeMarker XML transformation.
062: *
063: * $id$
064: */
065:
066: public class Transform {
067:
068: private File inputFile, ftlFile, outputFile;
069: private String encoding;
070: private Locale locale;
071: private Configuration cfg;
072:
073: /**
074: * A convenient main() method for command-line invocation.
075: */
076: static public void main(String[] args) {
077: try {
078: Transform proc = transformFromArgs(args);
079: proc.transform();
080: } catch (IllegalArgumentException iae) {
081: System.err.println(iae.getMessage());
082: usage();
083: } catch (Exception e) {
084: e.printStackTrace();
085: }
086: }
087:
088: /**
089: * @param inputFile The file from which to read the XML input
090: * @param ftlFile The file containing the template
091: * @param outputFile The file to which to output. If this is null, we use stdout.
092: * @param locale The locale to use. If this is null, we use the platform default.
093: * @param encoding The character encoding to use for output, if this is null, we use the platform default
094: */
095:
096: Transform(File inputFile, File ftlFile, File outputFile,
097: Locale locale, String encoding) throws IOException {
098: if (encoding == null) {
099: encoding = System.getProperty("file.encoding");
100: }
101: if (locale == null) {
102: locale = Locale.getDefault();
103: }
104: this .encoding = encoding;
105: this .locale = locale;
106: this .inputFile = inputFile;
107: this .ftlFile = ftlFile;
108: this .outputFile = outputFile;
109: File ftlDirectory = ftlFile.getAbsoluteFile().getParentFile();
110: cfg = new Configuration();
111: cfg.setDirectoryForTemplateLoading(ftlDirectory);
112: }
113:
114: /**
115: * Performs the transformation.
116: */
117: void transform() throws Exception {
118: String templateName = ftlFile.getName();
119: Template template = cfg.getTemplate(templateName, locale);
120: NodeModel rootNode = NodeModel.parse(inputFile);
121: OutputStream outputStream = System.out;
122: if (outputFile != null) {
123: outputStream = new FileOutputStream(outputFile);
124: }
125: Writer outputWriter = new OutputStreamWriter(outputStream,
126: encoding);
127: try {
128: template.process(null, outputWriter, null, rootNode);
129: } finally {
130: if (outputFile != null)
131: outputWriter.close();
132: }
133: }
134:
135: static Transform transformFromArgs(String[] args)
136: throws IOException {
137: int i = 0;
138: String input = null, output = null, ftl = null, loc = null, enc = null;
139: while (i < args.length) {
140: String dashArg = args[i++];
141: if (i >= args.length) {
142: throw new IllegalArgumentException("");
143: }
144: String arg = args[i++];
145: if (dashArg.equals("-in")) {
146: if (input != null) {
147: throw new IllegalArgumentException(
148: "The input file should only be specified once");
149: }
150: input = arg;
151: } else if (dashArg.equals("-ftl")) {
152: if (ftl != null) {
153: throw new IllegalArgumentException(
154: "The ftl file should only be specified once");
155: }
156: ftl = arg;
157: } else if (dashArg.equals("-out")) {
158: if (output != null) {
159: throw new IllegalArgumentException(
160: "The output file should only be specified once");
161: }
162: output = arg;
163: } else if (dashArg.equals("-locale")) {
164: if (loc != null) {
165: throw new IllegalArgumentException(
166: "The locale should only be specified once");
167: }
168: loc = arg;
169: } else if (dashArg.equals("-encoding")) {
170: if (enc != null) {
171: throw new IllegalArgumentException(
172: "The encoding should only be specified once");
173: }
174: enc = arg;
175: } else {
176: throw new IllegalArgumentException(
177: "Unknown input argument: " + dashArg);
178: }
179: }
180: if (input == null) {
181: throw new IllegalArgumentException(
182: "No input file specified.");
183: }
184: if (ftl == null) {
185: throw new IllegalArgumentException("No ftl file specified.");
186: }
187: File inputFile = new File(input).getAbsoluteFile();
188: File ftlFile = new File(ftl).getAbsoluteFile();
189: if (!inputFile.exists()) {
190: throw new IllegalArgumentException(
191: "Input file does not exist: " + input);
192: }
193: if (!ftlFile.exists()) {
194: throw new IllegalArgumentException(
195: "FTL file does not exist: " + ftl);
196: }
197: if (!inputFile.isFile() || !inputFile.canRead()) {
198: throw new IllegalArgumentException(
199: "Input file must be a readable file: " + input);
200: }
201: if (!ftlFile.isFile() || !ftlFile.canRead()) {
202: throw new IllegalArgumentException(
203: "FTL file must be a readable file: " + ftl);
204: }
205: File outputFile = null;
206: if (output != null) {
207: outputFile = new File(output).getAbsoluteFile();
208: File outputDirectory = outputFile.getParentFile();
209: if (!outputDirectory.exists()
210: || !outputDirectory.canWrite()) {
211: throw new IllegalArgumentException(
212: "The output directory must exist and be writable: "
213: + outputDirectory);
214: }
215: }
216: Locale locale = Locale.getDefault();
217: if (loc != null) {
218: locale = localeFromString(loc);
219: }
220: return new Transform(inputFile, ftlFile, outputFile, locale,
221: enc);
222: }
223:
224: static Locale localeFromString(String ls) {
225: if (ls == null)
226: ls = "";
227: String lang = "", country = "", variant = "";
228: StringTokenizer st = new StringTokenizer(ls, "_-,");
229: if (st.hasMoreTokens()) {
230: lang = st.nextToken();
231: if (st.hasMoreTokens()) {
232: country = st.nextToken();
233: if (st.hasMoreTokens()) {
234: variant = st.nextToken();
235: }
236: }
237: return new Locale(lang, country, variant);
238: } else {
239: return Locale.getDefault();
240: }
241: }
242:
243: static void usage() {
244: System.err
245: .println("Usage: java freemarker.ext.dom.Transform -in <xmlfile> -ftl <ftlfile> [-out <outfile>] [-locale <locale>] [-encoding <encoding>]");
246: System.exit(-1);
247: }
248: }
|