001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the "License"). You may not use this file except
005: * in compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://jwsdp.dev.java.net/CDDLv1.0.html
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * HEADER in each file and include the License file at
014: * https://jwsdp.dev.java.net/CDDLv1.0.html If applicable,
015: * add the following below this CDDL HEADER, with the
016: * fields enclosed by brackets "[]" replaced with your
017: * own identifying information: Portions Copyright [yyyy]
018: * [name of copyright owner]
019: */
020: package com.sun.codemodel.fmt;
021:
022: import java.io.BufferedReader;
023: import java.io.BufferedWriter;
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.io.InputStreamReader;
027: import java.io.OutputStream;
028: import java.io.OutputStreamWriter;
029: import java.io.PrintWriter;
030: import java.net.URL;
031: import java.text.ParseException;
032: import java.util.Iterator;
033: import java.util.List;
034:
035: import com.sun.codemodel.JClass;
036: import com.sun.codemodel.JPackage;
037: import com.sun.codemodel.JResourceFile;
038: import com.sun.codemodel.JTypeVar;
039:
040: /**
041: * Statically generated Java soruce file.
042: *
043: * <p>
044: * This {@link JResourceFile} implementation will generate a Java source
045: * file by copying the source code from a resource.
046: * <p>
047: * While copying a resource, we look for a package declaration and
048: * replace it with the target package name. This allows the static Java
049: * source code to have an arbitrary package declaration.
050: * <p>
051: * You can also use the getJClass method to obtain a {@link JClass}
052: * object that represents the static file. This allows the client code
053: * to refer to the class from other CodeModel generated code.
054: * <p>
055: * Note that because we don't parse the static Java source code,
056: * the returned {@link JClass} object doesn't respond to methods like
057: * "isInterface" or "_extends",
058: *
059: * @author
060: * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
061: */
062: public final class JStaticJavaFile extends JResourceFile {
063:
064: private final JPackage pkg;
065: private final String className;
066: private final URL source;
067: private final JStaticClass clazz;
068: private final LineFilter filter;
069:
070: public JStaticJavaFile(JPackage _pkg, String className,
071: String _resourceName) {
072: this (_pkg, className, JStaticJavaFile.class.getClassLoader()
073: .getResource(_resourceName), null);
074: }
075:
076: public JStaticJavaFile(JPackage _pkg, String _className,
077: URL _source, LineFilter _filter) {
078: super (_className + ".java");
079: if (_source == null)
080: throw new NullPointerException();
081: this .pkg = _pkg;
082: this .clazz = new JStaticClass();
083: this .className = _className;
084: this .source = _source;
085: this .filter = _filter;
086: }
087:
088: /**
089: * Returns a class object that represents a statically generated code.
090: */
091: public final JClass getJClass() {
092: return clazz;
093: }
094:
095: protected boolean isResource() {
096: return false;
097: }
098:
099: protected void build(OutputStream os) throws IOException {
100: InputStream is = source.openStream();
101:
102: BufferedReader r = new BufferedReader(new InputStreamReader(is));
103: PrintWriter w = new PrintWriter(new BufferedWriter(
104: new OutputStreamWriter(os)));
105: LineFilter filter = createLineFilter();
106: int lineNumber = 1;
107:
108: try {
109: String line;
110: while ((line = r.readLine()) != null) {
111: line = filter.process(line);
112: if (line != null)
113: w.println(line);
114: lineNumber++;
115: }
116: } catch (ParseException e) {
117: throw new IOException("unable to process " + source
118: + " line:" + lineNumber + "\n" + e.getMessage());
119: }
120:
121: w.close();
122: r.close();
123: }
124:
125: /**
126: * Creates a {@link LineFilter}.
127: * <p>
128: * A derived class can override this method to process
129: * the contents of the source file.
130: */
131: private LineFilter createLineFilter() {
132: // this filter replaces the package declaration.
133: LineFilter f = new LineFilter() {
134: public String process(String line) {
135: if (!line.startsWith("package "))
136: return line;
137:
138: // replace package decl
139: if (pkg.isUnnamed())
140: return null;
141: else
142: return "package " + pkg.name() + ";";
143: }
144: };
145: if (filter != null)
146: return new ChainFilter(filter, f);
147: else
148: return f;
149: }
150:
151: /**
152: * Filter that alters the Java source code.
153: * <p>
154: * By implementing this interface, derived classes
155: * can modify the Java source file before it's written out.
156: */
157: public interface LineFilter {
158: /**
159: * @param line
160: * a non-null valid String that corresponds to one line.
161: * No '\n' included.
162: * @return
163: * null to strip the line off. Otherwise the returned
164: * String will be written out. Do not add '\n' at the end
165: * of this string.
166: *
167: * @exception ParseException
168: * when for some reason there's an error in the line.
169: */
170: String process(String line) throws ParseException;
171: }
172:
173: /**
174: * A {@link LineFilter} that combines two {@link LineFilter}s.
175: */
176: public final static class ChainFilter implements LineFilter {
177: private final LineFilter first, second;
178:
179: public ChainFilter(LineFilter first, LineFilter second) {
180: this .first = first;
181: this .second = second;
182: }
183:
184: public String process(String line) throws ParseException {
185: line = first.process(line);
186: if (line == null)
187: return null;
188: return second.process(line);
189: }
190: }
191:
192: private class JStaticClass extends JClass {
193:
194: private final JTypeVar[] typeParams;
195:
196: JStaticClass() {
197: super (pkg.owner());
198: // TODO: allow those to be specified
199: typeParams = new JTypeVar[0];
200: }
201:
202: public String name() {
203: return className;
204: }
205:
206: public String fullName() {
207: if (pkg.isUnnamed())
208: return className;
209: else
210: return pkg.name() + '.' + className;
211: }
212:
213: public JPackage _package() {
214: return pkg;
215: }
216:
217: public JClass _extends() {
218: throw new UnsupportedOperationException();
219: }
220:
221: public Iterator _implements () {
222: throw new UnsupportedOperationException();
223: }
224:
225: public boolean isInterface() {
226: throw new UnsupportedOperationException();
227: }
228:
229: public boolean isAbstract() {
230: throw new UnsupportedOperationException();
231: }
232:
233: public JTypeVar[] typeParams() {
234: return typeParams;
235: }
236:
237: protected JClass substituteParams(JTypeVar[] variables,
238: List<JClass> bindings) {
239: return this;
240: }
241: };
242: }
|