001: /**
002: * InstantJ
003: *
004: * Copyright (C) 2002 Nils Meier
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: */package instantj.compile;
017:
018: import java.io.IOException;
019: import java.io.InputStream;
020: import java.io.ByteArrayInputStream;
021:
022: /**
023: * This type wrapps for Java source. It consists of the
024: * class' name and the source
025: *
026: * @author <A href="mailto:nils@meiers.net">Nils Meier</A>
027: */
028: public class Source {
029:
030: /** the input stream hierarchy */
031: private PrefixValueInputStream nameSniffer;
032: private PrefixValueInputStream packgeSniffer;
033: private InputStream in;
034:
035: /** the name */
036: private String name = null;
037:
038: /** the package */
039: private String packge = null;
040:
041: /**
042: * Constructor - you have to make sure that the
043: * name matches the definition of your class in source
044: * (same as with compiling your file-based source)
045: * @param source the source
046: */
047: public Source(String source) {
048: this (new ByteArrayInputStream(source.getBytes()));
049: }
050:
051: /**
052: * Constructor - you have to make sure that the
053: * name matches the definition of your class in source
054: * (same as with compiling your file-based source)
055: * @param source the source
056: */
057: public Source(InputStream source) {
058: nameSniffer = new PrefixValueInputStream("public class ",
059: source);
060: packgeSniffer = new PrefixValueInputStream("package ",
061: nameSniffer);
062: in = packgeSniffer;
063: }
064:
065: /**
066: * Returns the fully qualified name of the main (public) class
067: * in this Source
068: */
069: public String getClassName() {
070: String p = getPackage();
071: if (p == null)
072: return getName();
073: return p + '.' + getName();
074: }
075:
076: /**
077: * Getter for the name-attribute - this name corresponds
078: * to a filename that is passed to javac. There has to be
079: * exactly one public type in the source corresponding to
080: * this name.
081: * This name is derived automatically from the source
082: * but you can set it explicitly through setName() if
083: * necessary (e.g. you don't have a public class in your
084: * source or your source-encoding wasn't recognized
085: * by the name-sniffer).
086: *
087: * Note: the automatically sniffed name is available
088: * after the header of the class-declaration has been
089: * read from the InputStream (which is early enough for
090: * javac).
091: */
092: public String getName() {
093: if (name == null)
094: name = nameSniffer.getValue();
095: return name;
096: }
097:
098: /**
099: * Getter for package-attribute - the package name
100: * is derived automatically from the source but you
101: * can set it explicitly through setPackage() if
102: * necessary
103: * @see Source#getName()
104: * @param set
105: */
106: public String getPackage() {
107: if (packge == null)
108: packge = packgeSniffer.getValue();
109: return packge;
110: }
111:
112: /**
113: * Accessor - name
114: * @see Source#getName()
115: */
116: public void setName(String set) {
117: name = set;
118: }
119:
120: /**
121: * Accessor - name
122: * @see Source#getPackage()()
123: */
124: public void setPackage(String set) {
125: packge = set;
126: }
127:
128: /**
129: * Getter for the input stream
130: * @return the source
131: */
132: public InputStream getInputStream() {
133: return in;
134: }
135:
136: /**
137: * sniff an input stream for a pattern
138: */
139: private static class PrefixValueInputStream extends InputStream {
140:
141: /** the prefix we're looking for */
142: private char[] prefix;
143:
144: /** the wrapped */
145: private InputStream in;
146:
147: /** the prefix index */
148: private int index = 0;
149:
150: /** the collected value */
151: private StringBuffer buffer = new StringBuffer();
152:
153: /**
154: * Constructor
155: */
156: protected PrefixValueInputStream(String prefix, InputStream in) {
157: this .prefix = prefix.toCharArray();
158: this .in = in;
159: }
160:
161: /**
162: * @see java.io.InputStream#available()
163: */
164: public int available() throws IOException {
165: return in.available();
166: }
167:
168: /**
169: * the resulting value
170: */
171: protected String getValue() {
172: return buffer.length() == 0 ? null : buffer.toString();
173: }
174:
175: /**
176: * @see java.io.InputStream#read()
177: */
178: public int read() throws IOException {
179:
180: // read next
181: int next = in.read();
182:
183: // no more from in?
184: if (next == -1)
185: return next;
186:
187: // no more filtering?
188: if (index < 0)
189: return next;
190:
191: // still looking for completed name prefix?
192: while (index < prefix.length) {
193:
194: // skipping spaces
195: if (Character.isWhitespace(prefix[index])) {
196:
197: if (Character.isWhitespace((char) next))
198: return next;
199:
200: if (++index == prefix.length)
201: break;
202:
203: }
204:
205: // taking what fits
206: if (prefix[index] == next)
207: index++;
208: else
209: index = 0;
210:
211: return next;
212: }
213:
214: // still more text to gather for name?
215: if (Character.isJavaIdentifierPart((char) next)
216: || next == '.') {
217: buffer.append((char) next);
218: return next;
219: }
220:
221: // got it - no more collecting from now on
222: index = -1;
223:
224: // done
225: return next;
226: }
227:
228: } //PatternSnifferInputStream
229:
230: } //Source
|