001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.filters;
019:
020: import java.io.IOException;
021: import java.io.Reader;
022: import java.lang.reflect.InvocationTargetException;
023: import java.lang.reflect.Method;
024: import org.apache.tools.ant.BuildException;
025:
026: /**
027: * Assembles the constants declared in a Java class in
028: * <code>key1=value1(line separator)key2=value2</code>
029: * format.
030: *<p>
031: * Notes:
032: * <ol>
033: * <li>This filter uses the BCEL external toolkit.
034: * <li>This assembles only those constants that are not created
035: * using the syntax <code>new whatever()</code>
036: * <li>This assembles constants declared using the basic datatypes
037: * and String only.</li>
038: * <li>The access modifiers of the declared constants do not matter.</li>
039: *</ol>
040: * Example:<br>
041: * <pre><classconstants/></pre>
042: * Or:
043: * <pre><filterreader
044: * classname="org.apache.tools.ant.filters.ClassConstants"/></pre>
045: */
046: public final class ClassConstants extends BaseFilterReader implements
047: ChainableReader {
048: /** Data that must be read from, if not null. */
049: private String queuedData = null;
050:
051: /** Helper Class to be invoked via reflection. */
052: private static final String JAVA_CLASS_HELPER = "org.apache.tools.ant.filters.util.JavaClassHelper";
053:
054: /**
055: * Constructor for "dummy" instances.
056: *
057: * @see BaseFilterReader#BaseFilterReader()
058: */
059: public ClassConstants() {
060: super ();
061: }
062:
063: /**
064: * Creates a new filtered reader. The contents of the passed-in reader
065: * are expected to be the name of the class from which to produce a
066: * list of constants.
067: *
068: * @param in A Reader object providing the underlying stream.
069: * Must not be <code>null</code>.
070: */
071: public ClassConstants(final Reader in) {
072: super (in);
073: }
074:
075: /**
076: * Reads and assembles the constants declared in a class file.
077: *
078: * @return the next character in the list of constants, or -1
079: * if the end of the resulting stream has been reached
080: *
081: * @exception IOException if the underlying stream throws an IOException
082: * during reading, or if the constants for the specified class cannot
083: * be read (for example due to the class not being found).
084: */
085: public int read() throws IOException {
086:
087: int ch = -1;
088:
089: if (queuedData != null && queuedData.length() == 0) {
090: queuedData = null;
091: }
092:
093: if (queuedData != null) {
094: ch = queuedData.charAt(0);
095: queuedData = queuedData.substring(1);
096: if (queuedData.length() == 0) {
097: queuedData = null;
098: }
099: } else {
100: final String clazz = readFully();
101: if (clazz == null) {
102: ch = -1;
103: } else {
104: final byte[] bytes = clazz.getBytes("ISO-8859-1");
105: try {
106: final Class javaClassHelper = Class
107: .forName(JAVA_CLASS_HELPER);
108: if (javaClassHelper != null) {
109: final Class[] params = { byte[].class };
110: final Method getConstants = javaClassHelper
111: .getMethod("getConstants", params);
112: final Object[] args = { bytes };
113: // getConstants is a static method, no need to
114: // pass in the object
115: final StringBuffer sb = (StringBuffer) getConstants
116: .invoke(null, args);
117: if (sb.length() > 0) {
118: queuedData = sb.toString();
119: return read();
120: }
121: }
122: } catch (NoClassDefFoundError ex) {
123: throw ex;
124: } catch (RuntimeException ex) {
125: throw ex;
126: } catch (InvocationTargetException ex) {
127: Throwable t = ex.getTargetException();
128: if (t instanceof NoClassDefFoundError) {
129: throw (NoClassDefFoundError) t;
130: }
131: if (t instanceof RuntimeException) {
132: throw (RuntimeException) t;
133: }
134: throw new BuildException(t);
135: } catch (Exception ex) {
136: throw new BuildException(ex);
137: }
138: }
139: }
140: return ch;
141: }
142:
143: /**
144: * Creates a new ClassConstants using the passed in
145: * Reader for instantiation.
146: *
147: * @param rdr A Reader object providing the underlying stream.
148: * Must not be <code>null</code>.
149: *
150: * @return a new filter based on this configuration, but filtering
151: * the specified reader
152: */
153: public Reader chain(final Reader rdr) {
154: ClassConstants newFilter = new ClassConstants(rdr);
155: return newFilter;
156: }
157: }
|