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.util.Vector;
023: import org.apache.tools.ant.Project;
024: import org.apache.tools.ant.types.Parameter;
025:
026: /**
027: * Filter which includes only those lines that contain all the user-specified
028: * strings.
029: *
030: * Example:
031: *
032: * <pre><linecontains>
033: * <contains value="foo">
034: * <contains value="bar">
035: * </linecontains></pre>
036: *
037: * Or:
038: *
039: * <pre><filterreader classname="org.apache.tools.ant.filters.LineContains">
040: * <param type="contains" value="foo"/>
041: * <param type="contains" value="bar"/>
042: * </filterreader></pre>
043: *
044: * This will include only those lines that contain <code>foo</code> and
045: * <code>bar</code>.
046: *
047: */
048: public final class LineContains extends BaseParamFilterReader implements
049: ChainableReader {
050: /** Parameter name for the words to filter on. */
051: private static final String CONTAINS_KEY = "contains";
052:
053: /** Parameter name for the words to filter on. */
054: private static final String NEGATE_KEY = "negate";
055:
056: /** Vector that holds the strings that input lines must contain. */
057: private Vector contains = new Vector();
058:
059: /**
060: * Remaining line to be read from this filter, or <code>null</code> if
061: * the next call to <code>read()</code> should read the original stream
062: * to find the next matching line.
063: */
064: private String line = null;
065:
066: private boolean negate = false;
067:
068: /**
069: * Constructor for "dummy" instances.
070: *
071: * @see BaseFilterReader#BaseFilterReader()
072: */
073: public LineContains() {
074: super ();
075: }
076:
077: /**
078: * Creates a new filtered reader.
079: *
080: * @param in A Reader object providing the underlying stream.
081: * Must not be <code>null</code>.
082: */
083: public LineContains(final Reader in) {
084: super (in);
085: }
086:
087: /**
088: * Returns the next character in the filtered stream, only including
089: * lines from the original stream which contain all of the specified words.
090: *
091: * @return the next character in the resulting stream, or -1
092: * if the end of the resulting stream has been reached
093: *
094: * @exception IOException if the underlying stream throws an IOException
095: * during reading
096: */
097: public int read() throws IOException {
098: if (!getInitialized()) {
099: initialize();
100: setInitialized(true);
101: }
102:
103: int ch = -1;
104:
105: if (line != null) {
106: ch = line.charAt(0);
107: if (line.length() == 1) {
108: line = null;
109: } else {
110: line = line.substring(1);
111: }
112: } else {
113: final int containsSize = contains.size();
114:
115: for (line = readLine(); line != null; line = readLine()) {
116: boolean matches = true;
117: for (int i = 0; matches && i < containsSize; i++) {
118: String containsStr = (String) contains.elementAt(i);
119: matches = line.indexOf(containsStr) >= 0;
120: }
121: if (matches ^ isNegated()) {
122: break;
123: }
124: }
125: if (line != null) {
126: return read();
127: }
128: }
129: return ch;
130: }
131:
132: /**
133: * Adds a <code>contains</code> element.
134: *
135: * @param contains The <code>contains</code> element to add.
136: * Must not be <code>null</code>.
137: */
138: public void addConfiguredContains(final Contains contains) {
139: this .contains.addElement(contains.getValue());
140: }
141:
142: /**
143: * Set the negation mode. Default false (no negation).
144: * @param b the boolean negation mode to set.
145: */
146: public void setNegate(boolean b) {
147: negate = b;
148: }
149:
150: /**
151: * Find out whether we have been negated.
152: * @return boolean negation flag.
153: */
154: public boolean isNegated() {
155: return negate;
156: }
157:
158: /**
159: * Sets the vector of words which must be contained within a line read
160: * from the original stream in order for it to match this filter.
161: *
162: * @param contains A vector of words which must be contained within a line
163: * in order for it to match in this filter. Must not be <code>null</code>.
164: */
165: private void setContains(final Vector contains) {
166: this .contains = contains;
167: }
168:
169: /**
170: * Returns the vector of words which must be contained within a line read
171: * from the original stream in order for it to match this filter.
172: *
173: * @return the vector of words which must be contained within a line read
174: * from the original stream in order for it to match this filter. The
175: * returned object is "live" - in other words, changes made to the
176: * returned object are mirrored in the filter.
177: */
178: private Vector getContains() {
179: return contains;
180: }
181:
182: /**
183: * Creates a new LineContains using the passed in
184: * Reader for instantiation.
185: *
186: * @param rdr A Reader object providing the underlying stream.
187: * Must not be <code>null</code>.
188: *
189: * @return a new filter based on this configuration, but filtering
190: * the specified reader
191: */
192: public Reader chain(final Reader rdr) {
193: LineContains newFilter = new LineContains(rdr);
194: newFilter.setContains(getContains());
195: newFilter.setNegate(isNegated());
196: return newFilter;
197: }
198:
199: /**
200: * Parses the parameters to add user-defined contains strings.
201: */
202: private void initialize() {
203: Parameter[] params = getParameters();
204: if (params != null) {
205: for (int i = 0; i < params.length; i++) {
206: if (CONTAINS_KEY.equals(params[i].getType())) {
207: contains.addElement(params[i].getValue());
208: } else if (NEGATE_KEY.equals(params[i].getType())) {
209: setNegate(Project.toBoolean(params[i].getValue()));
210: }
211: }
212: }
213: }
214:
215: /**
216: * Holds a contains element
217: */
218: public static class Contains {
219:
220: /** User defined contains string */
221: private String value;
222:
223: /**
224: * Sets the contains string
225: *
226: * @param contains The contains string to set.
227: * Must not be <code>null</code>.
228: */
229: public final void setValue(String contains) {
230: value = contains;
231: }
232:
233: /**
234: * Returns the contains string.
235: *
236: * @return the contains string for this element
237: */
238: public final String getValue() {
239: return value;
240: }
241: }
242: }
|