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:
019: package org.apache.tools.ant.types;
020:
021: import java.io.BufferedReader;
022: import java.io.File;
023: import java.io.FileReader;
024: import java.io.IOException;
025: import java.util.Enumeration;
026: import java.util.StringTokenizer;
027: import java.util.Vector;
028: import org.apache.tools.ant.BuildException;
029: import org.apache.tools.ant.Project;
030:
031: /**
032: * Named collection of include/exclude tags.
033: *
034: * <p>Moved out of MatchingTask to make it a standalone object that
035: * could be referenced (by scripts for example).
036: *
037: */
038: public class PatternSet extends DataType implements Cloneable {
039: private Vector includeList = new Vector();
040: private Vector excludeList = new Vector();
041: private Vector includesFileList = new Vector();
042: private Vector excludesFileList = new Vector();
043:
044: /**
045: * inner class to hold a name on list. "If" and "Unless" attributes
046: * may be used to invalidate the entry based on the existence of a
047: * property (typically set thru the use of the Available task).
048: */
049: public class NameEntry {
050: private String name;
051: private String ifCond;
052: private String unlessCond;
053:
054: /**
055: * Sets the name pattern.
056: *
057: * @param name The pattern string.
058: */
059: public void setName(String name) {
060: this .name = name;
061: }
062:
063: /**
064: * Sets the if attribute. This attribute and the "unless"
065: * attribute are used to validate the name, based in the
066: * existence of the property.
067: *
068: * @param cond A property name. If this property is not
069: * present, the name is invalid.
070: */
071: public void setIf(String cond) {
072: ifCond = cond;
073: }
074:
075: /**
076: * Sets the unless attribute. This attribute and the "if"
077: * attribute are used to validate the name, based in the
078: * existence of the property.
079: *
080: * @param cond A property name. If this property is
081: * present, the name is invalid.
082: */
083: public void setUnless(String cond) {
084: unlessCond = cond;
085: }
086:
087: /**
088: * @return the name attribute.
089: */
090: public String getName() {
091: return name;
092: }
093:
094: /**
095: * This validates the name - checks the if and unless
096: * properties.
097: *
098: * @param p the current project, used to check the presence or
099: * absence of a property.
100: * @return the name attribute or null if the "if" or "unless"
101: * properties are not/are set.
102: */
103: public String evalName(Project p) {
104: return valid(p) ? name : null;
105: }
106:
107: private boolean valid(Project p) {
108: if (ifCond != null && p.getProperty(ifCond) == null) {
109: return false;
110: } else if (unlessCond != null
111: && p.getProperty(unlessCond) != null) {
112: return false;
113: }
114: return true;
115: }
116:
117: /**
118: * @return a printable form of this object.
119: */
120: public String toString() {
121: StringBuffer buf = new StringBuffer();
122: if (name == null) {
123: buf.append("noname");
124: } else {
125: buf.append(name);
126: }
127: if ((ifCond != null) || (unlessCond != null)) {
128: buf.append(":");
129: String connector = "";
130:
131: if (ifCond != null) {
132: buf.append("if->");
133: buf.append(ifCond);
134: connector = ";";
135: }
136: if (unlessCond != null) {
137: buf.append(connector);
138: buf.append("unless->");
139: buf.append(unlessCond);
140: }
141: }
142:
143: return buf.toString();
144: }
145: }
146:
147: /**
148: * Creates a new <code>PatternSet</code> instance.
149: */
150: public PatternSet() {
151: super ();
152: }
153:
154: /**
155: * Makes this instance in effect a reference to another PatternSet
156: * instance.
157: *
158: * <p>You must not set another attribute or nest elements inside
159: * this element if you make it a reference.</p>
160: * @param r the reference to another patternset.
161: * @throws BuildException on error.
162: */
163: public void setRefid(Reference r) throws BuildException {
164: if (!includeList.isEmpty() || !excludeList.isEmpty()) {
165: throw tooManyAttributes();
166: }
167: super .setRefid(r);
168: }
169:
170: /**
171: * This is a patternset nested element.
172: *
173: * @param p a configured patternset nested element.
174: */
175: public void addConfiguredPatternset(PatternSet p) {
176: if (isReference()) {
177: throw noChildrenAllowed();
178: }
179:
180: String[] nestedIncludes = p.getIncludePatterns(getProject());
181: String[] nestedExcludes = p.getExcludePatterns(getProject());
182:
183: if (nestedIncludes != null) {
184: for (int i = 0; i < nestedIncludes.length; i++) {
185: createInclude().setName(nestedIncludes[i]);
186: }
187: }
188:
189: if (nestedExcludes != null) {
190: for (int i = 0; i < nestedExcludes.length; i++) {
191: createExclude().setName(nestedExcludes[i]);
192: }
193: }
194: }
195:
196: /**
197: * add a name entry on the include list
198: * @return a nested include element to be configured.
199: */
200: public NameEntry createInclude() {
201: if (isReference()) {
202: throw noChildrenAllowed();
203: }
204: return addPatternToList(includeList);
205: }
206:
207: /**
208: * add a name entry on the include files list
209: * @return a nested includesfile element to be configured.
210: */
211: public NameEntry createIncludesFile() {
212: if (isReference()) {
213: throw noChildrenAllowed();
214: }
215: return addPatternToList(includesFileList);
216: }
217:
218: /**
219: * add a name entry on the exclude list
220: * @return a nested exclude element to be configured.
221: */
222: public NameEntry createExclude() {
223: if (isReference()) {
224: throw noChildrenAllowed();
225: }
226: return addPatternToList(excludeList);
227: }
228:
229: /**
230: * add a name entry on the exclude files list
231: * @return a nested excludesfile element to be configured.
232: */
233: public NameEntry createExcludesFile() {
234: if (isReference()) {
235: throw noChildrenAllowed();
236: }
237: return addPatternToList(excludesFileList);
238: }
239:
240: /**
241: * Appends <code>includes</code> to the current list of include patterns.
242: * Patterns may be separated by a comma or a space.
243: *
244: * @param includes the string containing the include patterns
245: */
246: public void setIncludes(String includes) {
247: if (isReference()) {
248: throw tooManyAttributes();
249: }
250: if (includes != null && includes.length() > 0) {
251: StringTokenizer tok = new StringTokenizer(includes, ", ",
252: false);
253: while (tok.hasMoreTokens()) {
254: createInclude().setName(tok.nextToken());
255: }
256: }
257: }
258:
259: /**
260: * Appends <code>excludes</code> to the current list of exclude patterns.
261: * Patterns may be separated by a comma or a space.
262: *
263: * @param excludes the string containing the exclude patterns
264: */
265: public void setExcludes(String excludes) {
266: if (isReference()) {
267: throw tooManyAttributes();
268: }
269: if (excludes != null && excludes.length() > 0) {
270: StringTokenizer tok = new StringTokenizer(excludes, ", ",
271: false);
272: while (tok.hasMoreTokens()) {
273: createExclude().setName(tok.nextToken());
274: }
275: }
276: }
277:
278: /**
279: * add a name entry to the given list
280: */
281: private NameEntry addPatternToList(Vector list) {
282: NameEntry result = new NameEntry();
283: list.addElement(result);
284: return result;
285: }
286:
287: /**
288: * Sets the name of the file containing the includes patterns.
289: *
290: * @param includesFile The file to fetch the include patterns from.
291: * @throws BuildException on error.
292: */
293: public void setIncludesfile(File includesFile)
294: throws BuildException {
295: if (isReference()) {
296: throw tooManyAttributes();
297: }
298: createIncludesFile().setName(includesFile.getAbsolutePath());
299: }
300:
301: /**
302: * Sets the name of the file containing the excludes patterns.
303: *
304: * @param excludesFile The file to fetch the exclude patterns from.
305: * @throws BuildException on error.
306: */
307: public void setExcludesfile(File excludesFile)
308: throws BuildException {
309: if (isReference()) {
310: throw tooManyAttributes();
311: }
312: createExcludesFile().setName(excludesFile.getAbsolutePath());
313: }
314:
315: /**
316: * Reads path matching patterns from a file and adds them to the
317: * includes or excludes list (as appropriate).
318: */
319: private void readPatterns(File patternfile, Vector patternlist,
320: Project p) throws BuildException {
321:
322: BufferedReader patternReader = null;
323: try {
324: // Get a FileReader
325: patternReader = new BufferedReader(new FileReader(
326: patternfile));
327:
328: // Create one NameEntry in the appropriate pattern list for each
329: // line in the file.
330: String line = patternReader.readLine();
331: while (line != null) {
332: if (line.length() > 0) {
333: line = p.replaceProperties(line);
334: addPatternToList(patternlist).setName(line);
335: }
336: line = patternReader.readLine();
337: }
338: } catch (IOException ioe) {
339: String msg = "An error occurred while reading from pattern file: "
340: + patternfile;
341: throw new BuildException(msg, ioe);
342: } finally {
343: if (null != patternReader) {
344: try {
345: patternReader.close();
346: } catch (IOException ioe) {
347: //Ignore exception
348: }
349: }
350: }
351: }
352:
353: /**
354: * Adds the patterns of the other instance to this set.
355: * @param other the other PatternSet instance.
356: * @param p the current project.
357: */
358: public void append(PatternSet other, Project p) {
359: if (isReference()) {
360: throw new BuildException("Cannot append to a reference");
361: }
362:
363: String[] incl = other.getIncludePatterns(p);
364: if (incl != null) {
365: for (int i = 0; i < incl.length; i++) {
366: createInclude().setName(incl[i]);
367: }
368: }
369:
370: String[] excl = other.getExcludePatterns(p);
371: if (excl != null) {
372: for (int i = 0; i < excl.length; i++) {
373: createExclude().setName(excl[i]);
374: }
375: }
376: }
377:
378: /**
379: * Returns the filtered include patterns.
380: * @param p the current project.
381: * @return the filtered included patterns.
382: */
383: public String[] getIncludePatterns(Project p) {
384: if (isReference()) {
385: return getRef(p).getIncludePatterns(p);
386: } else {
387: readFiles(p);
388: return makeArray(includeList, p);
389: }
390: }
391:
392: /**
393: * Returns the filtered include patterns.
394: * @param p the current project.
395: * @return the filtered excluded patterns.
396: */
397: public String[] getExcludePatterns(Project p) {
398: if (isReference()) {
399: return getRef(p).getExcludePatterns(p);
400: } else {
401: readFiles(p);
402: return makeArray(excludeList, p);
403: }
404: }
405:
406: /**
407: * Helper for FileSet classes.
408: * Check if there are patterns defined.
409: * @param p the current project.
410: * @return true if there are patterns.
411: */
412: public boolean hasPatterns(Project p) {
413: if (isReference()) {
414: return getRef(p).hasPatterns(p);
415: } else {
416: return includesFileList.size() > 0
417: || excludesFileList.size() > 0
418: || includeList.size() > 0 || excludeList.size() > 0;
419: }
420: }
421:
422: /**
423: * Performs the check for circular references and returns the
424: * referenced PatternSet.
425: */
426: private PatternSet getRef(Project p) {
427: return (PatternSet) getCheckedRef(p);
428: }
429:
430: /**
431: * Convert a vector of NameEntry elements into an array of Strings.
432: */
433: private String[] makeArray(Vector list, Project p) {
434: if (list.size() == 0) {
435: return null;
436: }
437:
438: Vector tmpNames = new Vector();
439: for (Enumeration e = list.elements(); e.hasMoreElements();) {
440: NameEntry ne = (NameEntry) e.nextElement();
441: String pattern = ne.evalName(p);
442: if (pattern != null && pattern.length() > 0) {
443: tmpNames.addElement(pattern);
444: }
445: }
446:
447: String[] result = new String[tmpNames.size()];
448: tmpNames.copyInto(result);
449: return result;
450: }
451:
452: /**
453: * Read includesfile ot excludesfile if not already done so.
454: */
455: private void readFiles(Project p) {
456: if (includesFileList.size() > 0) {
457: Enumeration e = includesFileList.elements();
458: while (e.hasMoreElements()) {
459: NameEntry ne = (NameEntry) e.nextElement();
460: String fileName = ne.evalName(p);
461: if (fileName != null) {
462: File inclFile = p.resolveFile(fileName);
463: if (!inclFile.exists()) {
464: throw new BuildException("Includesfile "
465: + inclFile.getAbsolutePath()
466: + " not found.");
467: }
468: readPatterns(inclFile, includeList, p);
469: }
470: }
471: includesFileList.removeAllElements();
472: }
473:
474: if (excludesFileList.size() > 0) {
475: Enumeration e = excludesFileList.elements();
476: while (e.hasMoreElements()) {
477: NameEntry ne = (NameEntry) e.nextElement();
478: String fileName = ne.evalName(p);
479: if (fileName != null) {
480: File exclFile = p.resolveFile(fileName);
481: if (!exclFile.exists()) {
482: throw new BuildException("Excludesfile "
483: + exclFile.getAbsolutePath()
484: + " not found.");
485: }
486: readPatterns(exclFile, excludeList, p);
487: }
488: }
489: excludesFileList.removeAllElements();
490: }
491: }
492:
493: /**
494: * @return a printable form of this object.
495: */
496: public String toString() {
497: return "patternSet{ includes: " + includeList + " excludes: "
498: + excludeList + " }";
499: }
500:
501: /**
502: * @since Ant 1.6
503: * @return a clone of this patternset.
504: */
505: public Object clone() {
506: try {
507: PatternSet ps = (PatternSet) super .clone();
508: ps.includeList = (Vector) includeList.clone();
509: ps.excludeList = (Vector) excludeList.clone();
510: ps.includesFileList = (Vector) includesFileList.clone();
511: ps.excludesFileList = (Vector) excludesFileList.clone();
512: return ps;
513: } catch (CloneNotSupportedException e) {
514: throw new BuildException(e);
515: }
516: }
517:
518: }
|