001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.codemodel.internal.fmt;
027:
028: import java.io.BufferedReader;
029: import java.io.BufferedWriter;
030: import java.io.IOException;
031: import java.io.InputStream;
032: import java.io.InputStreamReader;
033: import java.io.OutputStream;
034: import java.io.OutputStreamWriter;
035: import java.io.PrintWriter;
036: import java.net.URL;
037: import java.text.ParseException;
038: import java.util.Iterator;
039: import java.util.List;
040:
041: import com.sun.codemodel.internal.JClass;
042: import com.sun.codemodel.internal.JPackage;
043: import com.sun.codemodel.internal.JResourceFile;
044: import com.sun.codemodel.internal.JTypeVar;
045:
046: /**
047: * Statically generated Java soruce file.
048: *
049: * <p>
050: * This {@link JResourceFile} implementation will generate a Java source
051: * file by copying the source code from a resource.
052: * <p>
053: * While copying a resource, we look for a package declaration and
054: * replace it with the target package name. This allows the static Java
055: * source code to have an arbitrary package declaration.
056: * <p>
057: * You can also use the getJClass method to obtain a {@link JClass}
058: * object that represents the static file. This allows the client code
059: * to refer to the class from other CodeModel generated code.
060: * <p>
061: * Note that because we don't parse the static Java source code,
062: * the returned {@link JClass} object doesn't respond to methods like
063: * "isInterface" or "_extends",
064: *
065: * @author
066: * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
067: */
068: public final class JStaticJavaFile extends JResourceFile {
069:
070: private final JPackage pkg;
071: private final String className;
072: private final URL source;
073: private final JStaticClass clazz;
074: private final LineFilter filter;
075:
076: public JStaticJavaFile(JPackage _pkg, String className,
077: String _resourceName) {
078: this (_pkg, className, JStaticJavaFile.class.getClassLoader()
079: .getResource(_resourceName), null);
080: }
081:
082: public JStaticJavaFile(JPackage _pkg, String _className,
083: URL _source, LineFilter _filter) {
084: super (_className + ".java");
085: if (_source == null)
086: throw new NullPointerException();
087: this .pkg = _pkg;
088: this .clazz = new JStaticClass();
089: this .className = _className;
090: this .source = _source;
091: this .filter = _filter;
092: }
093:
094: /**
095: * Returns a class object that represents a statically generated code.
096: */
097: public final JClass getJClass() {
098: return clazz;
099: }
100:
101: protected boolean isResource() {
102: return false;
103: }
104:
105: protected void build(OutputStream os) throws IOException {
106: InputStream is = source.openStream();
107:
108: BufferedReader r = new BufferedReader(new InputStreamReader(is));
109: PrintWriter w = new PrintWriter(new BufferedWriter(
110: new OutputStreamWriter(os)));
111: LineFilter filter = createLineFilter();
112: int lineNumber = 1;
113:
114: try {
115: String line;
116: while ((line = r.readLine()) != null) {
117: line = filter.process(line);
118: if (line != null)
119: w.println(line);
120: lineNumber++;
121: }
122: } catch (ParseException e) {
123: throw new IOException("unable to process " + source
124: + " line:" + lineNumber + "\n" + e.getMessage());
125: }
126:
127: w.close();
128: r.close();
129: }
130:
131: /**
132: * Creates a {@link LineFilter}.
133: * <p>
134: * A derived class can override this method to process
135: * the contents of the source file.
136: */
137: private LineFilter createLineFilter() {
138: // this filter replaces the package declaration.
139: LineFilter f = new LineFilter() {
140: public String process(String line) {
141: if (!line.startsWith("package "))
142: return line;
143:
144: // replace package decl
145: if (pkg.isUnnamed())
146: return null;
147: else
148: return "package " + pkg.name() + ";";
149: }
150: };
151: if (filter != null)
152: return new ChainFilter(filter, f);
153: else
154: return f;
155: }
156:
157: /**
158: * Filter that alters the Java source code.
159: * <p>
160: * By implementing this interface, derived classes
161: * can modify the Java source file before it's written out.
162: */
163: public interface LineFilter {
164: /**
165: * @param line
166: * a non-null valid String that corresponds to one line.
167: * No '\n' included.
168: * @return
169: * null to strip the line off. Otherwise the returned
170: * String will be written out. Do not add '\n' at the end
171: * of this string.
172: *
173: * @exception ParseException
174: * when for some reason there's an error in the line.
175: */
176: String process(String line) throws ParseException;
177: }
178:
179: /**
180: * A {@link LineFilter} that combines two {@link LineFilter}s.
181: */
182: public final static class ChainFilter implements LineFilter {
183: private final LineFilter first, second;
184:
185: public ChainFilter(LineFilter first, LineFilter second) {
186: this .first = first;
187: this .second = second;
188: }
189:
190: public String process(String line) throws ParseException {
191: line = first.process(line);
192: if (line == null)
193: return null;
194: return second.process(line);
195: }
196: }
197:
198: private class JStaticClass extends JClass {
199:
200: private final JTypeVar[] typeParams;
201:
202: JStaticClass() {
203: super (pkg.owner());
204: // TODO: allow those to be specified
205: typeParams = new JTypeVar[0];
206: }
207:
208: public String name() {
209: return className;
210: }
211:
212: public String fullName() {
213: if (pkg.isUnnamed())
214: return className;
215: else
216: return pkg.name() + '.' + className;
217: }
218:
219: public JPackage _package() {
220: return pkg;
221: }
222:
223: public JClass _extends() {
224: throw new UnsupportedOperationException();
225: }
226:
227: public Iterator _implements () {
228: throw new UnsupportedOperationException();
229: }
230:
231: public boolean isInterface() {
232: throw new UnsupportedOperationException();
233: }
234:
235: public boolean isAbstract() {
236: throw new UnsupportedOperationException();
237: }
238:
239: public JTypeVar[] typeParams() {
240: return typeParams;
241: }
242:
243: protected JClass substituteParams(JTypeVar[] variables,
244: List<JClass> bindings) {
245: return this;
246: }
247: };
248: }
|