001: /* ====================================================================
002: * Tea - Copyright (c) 1997-2000 Walt Disney Internet Group
003: * ====================================================================
004: * The Tea Software License, Version 1.1
005: *
006: * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Walt Disney Internet Group (http://opensource.go.com/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact opensource@dig.com.
031: *
032: * 5. Products derived from this software may not be called "Tea",
033: * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
034: * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
035: * written permission of the Walt Disney Internet Group.
036: *
037: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
038: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
039: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
040: * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
041: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
042: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
043: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
044: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
045: * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
046: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
047: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
048: * ====================================================================
049: *
050: * For more information about Tea, please see http://opensource.go.com/.
051: */
052:
053: package com.go.tea.util;
054:
055: import java.io.*;
056: import java.util.*;
057: import com.go.tea.compiler.Compiler;
058: import com.go.tea.compiler.*;
059: import com.go.tea.runtime.*;
060:
061: /******************************************************************************
062: * Command-line tool that puts the 'call' keyword in front of template calls
063: * in templates compatable with pre 3.x.x versions of Tea.
064: *
065: * @author Brian S O'Neill
066: * @version
067: * <!--$$Revision:--> 7 <!-- $-->, <!--$$JustDate:--> 9/07/00 <!-- $-->
068: */
069: public class CallRetrofitter {
070: /**
071: * Entry point for a command-line tool that puts the 'call' keyword in
072: * front of template calls in templates compatable with pre 3.x.x versions
073: * of Tea.
074: *
075: * <pre>
076: * Usage: java com.go.tea.util.CallRetrofitter {options}
077: * <template root directory> {templates}
078: *
079: * where {options} includes:
080: * -context <class> Specify a runtime context class to compile against.
081: * -encoding <encoding> Specify character encoding used by source files.
082: * </pre>
083: */
084: public static void main(String[] args) throws Exception {
085: if (args == null || args.length == 0) {
086: usage();
087: return;
088: }
089:
090: Class context = null;
091: String encoding = null;
092: File rootDir = null;
093: Collection templates = new ArrayList(args.length);
094:
095: try {
096: boolean parsingOptions = true;
097: for (int i = 0; i < args.length;) {
098: String arg = args[i++];
099: if (arg.startsWith("-") && parsingOptions) {
100: if (arg.equals("-context") && context == null) {
101: context = Class.forName(args[i++]);
102: continue;
103: } else if (arg.equals("-encoding")
104: && encoding == null) {
105: encoding = args[i++];
106: continue;
107: }
108: } else {
109: if (parsingOptions) {
110: parsingOptions = false;
111: rootDir = new File(arg);
112: continue;
113: }
114:
115: arg = arg.replace('/', '.');
116: arg = arg.replace(File.separatorChar, '.');
117: while (arg.startsWith(".")) {
118: arg = arg.substring(1);
119: }
120: while (arg.endsWith(".")) {
121: arg = arg.substring(0, arg.length() - 1);
122: }
123: templates.add(arg);
124: continue;
125: }
126:
127: usage();
128: return;
129: }
130: } catch (ArrayIndexOutOfBoundsException e) {
131: usage();
132: return;
133: }
134:
135: if (rootDir == null) {
136: usage();
137: return;
138: }
139:
140: if (context == null) {
141: context = com.go.tea.runtime.UtilityContext.class;
142: }
143:
144: int errorCount, changeCount;
145: int totalChangeCount = 0;
146: do {
147: FileCompiler compiler = new FileCompiler(rootDir, null,
148: null, null, encoding);
149:
150: compiler.setRuntimeContext(context);
151: compiler.setForceCompile(true);
152: compiler.setCodeGenerationEnabled(false);
153:
154: Retrofitter retrofitter = new Retrofitter(compiler,
155: encoding);
156: compiler.addErrorListener(retrofitter);
157:
158: String[] names;
159: if (templates.size() == 0) {
160: names = compiler.compileAll(true);
161: } else {
162: names = (String[]) templates
163: .toArray(new String[templates.size()]);
164: names = compiler.compile(names);
165: }
166:
167: retrofitter.applyChanges();
168:
169: changeCount = retrofitter.getChangeCount();
170: errorCount = compiler.getErrorCount() - changeCount;
171:
172: String msg = String.valueOf(errorCount) + " error";
173: if (errorCount != 1) {
174: msg += 's';
175: }
176: System.out.println(msg);
177:
178: totalChangeCount += changeCount;
179: System.out.println("Total changes made: "
180: + totalChangeCount);
181: } while (changeCount > 0);
182: }
183:
184: private static void usage() {
185: String usageDetail = " -context <class> Specify a runtime context class to compile against.\n"
186: + " -encoding <encoding> Specify character encoding used by source files.\n";
187:
188: System.out.print("\nUsage: ");
189: System.out.print("java ");
190: System.out.print(CallRetrofitter.class.getName());
191: System.out
192: .println(" {options} <template root directory> {templates}");
193: System.out.println();
194: System.out.println("where {options} includes:");
195: System.out.println(usageDetail);
196: }
197:
198: private static class Retrofitter extends DefaultContext implements
199: ErrorListener {
200:
201: private Compiler mCompiler;
202: private String mEncoding;
203:
204: // Maps source files to lists of ErrorEvents.
205: private Map mChanges;
206:
207: private int mChangeCount;
208:
209: private Retrofitter(Compiler c, String encoding) {
210: mCompiler = c;
211: mEncoding = encoding;
212: mChanges = new TreeMap();
213: }
214:
215: public void compileError(ErrorEvent e) {
216: if ("Can't find function".equalsIgnoreCase(e
217: .getErrorMessage())) {
218: File sourceFile = ((FileCompiler.Unit) e
219: .getCompilationUnit()).getSourceFile();
220: List errorEvents = (List) mChanges.get(sourceFile);
221: if (errorEvents == null) {
222: errorEvents = new ArrayList();
223: mChanges.put(sourceFile, errorEvents);
224: }
225: errorEvents.add(e);
226: }
227: }
228:
229: public int getChangeCount() {
230: return mChangeCount;
231: }
232:
233: public void applyChanges() throws IOException {
234: Iterator it = mChanges.entrySet().iterator();
235: while (it.hasNext()) {
236: Map.Entry entry = (Map.Entry) it.next();
237: applyChanges((File) entry.getKey(), (List) entry
238: .getValue());
239: }
240: mChanges = null;
241: }
242:
243: private void applyChanges(File sourceFile, List errorEvents)
244: throws IOException {
245: RandomAccessFile raf = new RandomAccessFile(sourceFile, "r");
246:
247: Map replacements = new HashMap();
248:
249: Iterator it = errorEvents.iterator();
250: while (it.hasNext()) {
251: ErrorEvent event = (ErrorEvent) it.next();
252: SourceInfo info = event.getSourceInfo();
253: CompilationUnit sourceUnit = event.getCompilationUnit();
254:
255: int startPos = info.getStartPosition();
256: int endPos = info.getEndPosition();
257: int len = (endPos - startPos) + 1;
258:
259: byte[] bytes = new byte[len];
260: raf.seek(startPos);
261: raf.readFully(bytes);
262:
263: String text;
264: if (mEncoding == null) {
265: text = new String(bytes);
266: } else {
267: text = new String(bytes, mEncoding);
268: }
269:
270: int index = text.indexOf('(');
271: if (index > 0) {
272: String templateName = text.substring(0, index)
273: .trim();
274: boolean templateExists = mCompiler
275: .getCompilationUnit(templateName,
276: sourceUnit) != null;
277: if (templateExists) {
278: mChangeCount++;
279: replacements.put(text, "call " + text);
280: }
281: }
282: }
283:
284: raf.close();
285:
286: if (replacements.size() <= 0) {
287: return;
288: }
289:
290: print("Modifying: " + sourceFile);
291:
292: InputStream in = new FileInputStream(sourceFile);
293:
294: Reader reader;
295: if (mEncoding == null) {
296: reader = new InputStreamReader(in);
297: } else {
298: reader = new InputStreamReader(in, mEncoding);
299: }
300:
301: reader = new BufferedReader(reader);
302:
303: StringBuffer sourceContents = new StringBuffer(
304: (int) sourceFile.length());
305:
306: int c;
307: while ((c = reader.read()) != -1) {
308: sourceContents.append((char) c);
309: }
310: reader.close();
311:
312: String newContents = replace(sourceContents.toString(),
313: replacements);
314:
315: OutputStream out = new FileOutputStream(sourceFile);
316:
317: Writer writer;
318: if (mEncoding == null) {
319: writer = new OutputStreamWriter(out);
320: } else {
321: writer = new OutputStreamWriter(out, mEncoding);
322: }
323:
324: writer = new BufferedWriter(writer);
325: writer.write(newContents);
326: writer.close();
327: }
328:
329: public void print(Object obj) {
330: System.out.println(toString(obj));
331: }
332: }
333: }
|