KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > types > FilterSet


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18 package org.apache.tools.ant.types;
19
20 import java.io.File JavaDoc;
21 import java.io.FileInputStream JavaDoc;
22 import java.util.Enumeration JavaDoc;
23 import java.util.Hashtable JavaDoc;
24 import java.util.Properties JavaDoc;
25 import java.util.Vector JavaDoc;
26
27 import org.apache.tools.ant.Project;
28 import org.apache.tools.ant.BuildException;
29 import org.apache.tools.ant.util.FileUtils;
30
31 /**
32  * A set of filters to be applied to something.
33  *
34  * A filter set may have begintoken and endtokens defined.
35  *
36  */

37 public class FilterSet extends DataType implements Cloneable JavaDoc {
38
39     /**
40      * Individual filter component of filterset.
41      *
42      */

43     public static class Filter {
44         // CheckStyle:VisibilityModifier OFF - bc
45
/** Token which will be replaced in the filter operation. */
46         String JavaDoc token;
47
48         /** The value which will replace the token in the filtering operation. */
49         String JavaDoc value;
50         // CheckStyle:VisibilityModifier ON
51

52         /**
53          * Constructor for the Filter object.
54          *
55          * @param token The token which will be replaced when filtering.
56          * @param value The value which will replace the token when filtering.
57          */

58         public Filter(String JavaDoc token, String JavaDoc value) {
59            setToken(token);
60            setValue(value);
61         }
62
63         /**
64          * No-argument conmstructor.
65          */

66         public Filter() {
67         }
68
69         /**
70          * Sets the Token attribute of the Filter object.
71          *
72          * @param token The new Token value.
73          */

74         public void setToken(String JavaDoc token) {
75            this.token = token;
76         }
77
78         /**
79          * Sets the Value attribute of the Filter object.
80          *
81          * @param value The new Value value.
82          */

83         public void setValue(String JavaDoc value) {
84            this.value = value;
85         }
86
87         /**
88          * Gets the Token attribute of the Filter object.
89          *
90          * @return The Token value.
91          */

92         public String JavaDoc getToken() {
93            return token;
94         }
95
96         /**
97          * Gets the Value attribute of the Filter object.
98          *
99          * @return The Value value.
100          */

101         public String JavaDoc getValue() {
102            return value;
103         }
104      }
105
106     /**
107      * The filtersfile nested element.
108      *
109      */

110     public class FiltersFile {
111
112         /**
113          * Constructor for the FiltersFile object.
114          */

115         public FiltersFile() {
116         }
117
118         /**
119          * Sets the file from which filters will be read.
120          *
121          * @param file the file from which filters will be read.
122          */

123         public void setFile(File JavaDoc file) {
124            filtersFiles.add(file);
125         }
126     }
127
128     /**
129      * EnumeratedAttribute to set behavior WRT missing filtersfiles:
130      * "fail" (default), "warn", "ignore".
131      * @since Ant 1.7
132      */

133     public static class OnMissing extends EnumeratedAttribute {
134         private static final String JavaDoc[] VALUES
135             = new String JavaDoc[] {"fail", "warn", "ignore"};
136
137         /** Fail value */
138         public static final OnMissing FAIL = new OnMissing("fail");
139         /** Warn value */
140         public static final OnMissing WARN = new OnMissing("warn");
141         /** Ignore value */
142         public static final OnMissing IGNORE = new OnMissing("ignore");
143
144         private static final int FAIL_INDEX = 0;
145         private static final int WARN_INDEX = 1;
146         private static final int IGNORE_INDEX = 2;
147
148         /**
149          * Default constructor.
150          */

151         public OnMissing() {
152         }
153
154         /**
155          * Convenience constructor.
156          * @param value the value to set.
157          */

158         public OnMissing(String JavaDoc value) {
159             setValue(value);
160         }
161
162         //inherit doc
163
/** {@inheritDoc}. */
164         public String JavaDoc[] getValues() {
165             return VALUES;
166         }
167     }
168
169     /** The default token start string */
170     public static final String JavaDoc DEFAULT_TOKEN_START = "@";
171
172     /** The default token end string */
173     public static final String JavaDoc DEFAULT_TOKEN_END = "@";
174
175     private String JavaDoc startOfToken = DEFAULT_TOKEN_START;
176     private String JavaDoc endOfToken = DEFAULT_TOKEN_END;
177
178     /** Contains a list of parsed tokens */
179     private Vector JavaDoc passedTokens;
180     /** if a duplicate token is found, this is set to true */
181     private boolean duplicateToken = false;
182
183     private boolean recurse = true;
184     private Hashtable JavaDoc filterHash = null;
185     private Vector JavaDoc filtersFiles = new Vector JavaDoc();
186     private OnMissing onMissingFiltersFile = OnMissing.FAIL;
187     private boolean readingFiles = false;
188
189     private int recurseDepth = 0;
190
191     /**
192      * List of ordered filters and filter files.
193      */

194     private Vector JavaDoc filters = new Vector JavaDoc();
195
196     /**
197      * Default constructor.
198      */

199     public FilterSet() {
200     }
201
202     /**
203      * Create a Filterset from another filterset.
204      *
205      * @param filterset the filterset upon which this filterset will be based.
206      */

207     protected FilterSet(FilterSet filterset) {
208         super();
209         this.filters = (Vector JavaDoc) filterset.getFilters().clone();
210     }
211
212     /**
213      * Get the filters in the filter set.
214      *
215      * @return a Vector of Filter instances.
216      */

217     protected synchronized Vector JavaDoc getFilters() {
218         if (isReference()) {
219             return getRef().getFilters();
220         }
221         //silly hack to avoid stack overflow...
222
if (!readingFiles) {
223             readingFiles = true;
224             for (int i = 0, sz = filtersFiles.size(); i < sz; i++) {
225                 readFiltersFromFile((File JavaDoc) filtersFiles.get(i));
226             }
227             filtersFiles.clear();
228             readingFiles = false;
229         }
230         return filters;
231     }
232
233     /**
234      * Get the referenced filter set.
235      *
236      * @return the filterset from the reference.
237      */

238     protected FilterSet getRef() {
239         return (FilterSet) getCheckedRef(FilterSet.class, "filterset");
240     }
241
242     /**
243      * Gets the filter hash of the FilterSet.
244      *
245      * @return The hash of the tokens and values for quick lookup.
246      */

247     public synchronized Hashtable JavaDoc getFilterHash() {
248         if (filterHash == null) {
249             filterHash = new Hashtable JavaDoc(getFilters().size());
250             for (Enumeration JavaDoc e = getFilters().elements(); e.hasMoreElements();) {
251                Filter filter = (Filter) e.nextElement();
252                filterHash.put(filter.getToken(), filter.getValue());
253             }
254         }
255         return filterHash;
256     }
257
258     /**
259      * Set the file containing the filters for this filterset.
260      *
261      * @param filtersFile sets the filter file from which to read filters
262      * for this filter set.
263      * @throws BuildException if there is an error.
264      */

265     public void setFiltersfile(File JavaDoc filtersFile) throws BuildException {
266         if (isReference()) {
267             throw tooManyAttributes();
268         }
269         filtersFiles.add(filtersFile);
270     }
271
272     /**
273      * Set the string used to id the beginning of a token.
274      *
275      * @param startOfToken The new Begintoken value.
276      */

277     public void setBeginToken(String JavaDoc startOfToken) {
278         if (isReference()) {
279             throw tooManyAttributes();
280         }
281         if (startOfToken == null || "".equals(startOfToken)) {
282             throw new BuildException("beginToken must not be empty");
283         }
284         this.startOfToken = startOfToken;
285     }
286
287     /**
288      * Get the begin token for this filterset.
289      *
290      * @return the filter set's begin token for filtering.
291      */

292     public String JavaDoc getBeginToken() {
293         if (isReference()) {
294             return getRef().getBeginToken();
295         }
296         return startOfToken;
297     }
298
299     /**
300      * Set the string used to id the end of a token.
301      *
302      * @param endOfToken The new Endtoken value.
303      */

304     public void setEndToken(String JavaDoc endOfToken) {
305         if (isReference()) {
306             throw tooManyAttributes();
307         }
308         if (endOfToken == null || "".equals(endOfToken)) {
309             throw new BuildException("endToken must not be empty");
310         }
311         this.endOfToken = endOfToken;
312     }
313
314     /**
315      * Get the end token for this filterset.
316      *
317      * @return the filter set's end token for replacement delimiting.
318      */

319     public String JavaDoc getEndToken() {
320         if (isReference()) {
321             return getRef().getEndToken();
322         }
323         return endOfToken;
324     }
325
326     /**
327      * Set whether recursive token expansion is enabled.
328      * @param recurse <code>boolean</code> whether to recurse.
329      */

330     public void setRecurse(boolean recurse) {
331         this.recurse = recurse;
332     }
333
334     /**
335      * Get whether recursive token expansion is enabled.
336      * @return <code>boolean</code> whether enabled.
337      */

338     public boolean isRecurse() {
339         return recurse;
340     }
341
342     /**
343      * Read the filters from the given file.
344      *
345      * @param filtersFile the file from which filters are read.
346      * @exception BuildException when the file cannot be read.
347      */

348     public synchronized void readFiltersFromFile(File JavaDoc filtersFile) throws BuildException {
349         if (isReference()) {
350             throw tooManyAttributes();
351         }
352         if (!filtersFile.exists()) {
353            handleMissingFile("Could not read filters from file "
354                                      + filtersFile + " as it doesn't exist.");
355         }
356         if (filtersFile.isFile()) {
357            log("Reading filters from " + filtersFile, Project.MSG_VERBOSE);
358            FileInputStream JavaDoc in = null;
359            try {
360               Properties JavaDoc props = new Properties JavaDoc();
361               in = new FileInputStream JavaDoc(filtersFile);
362               props.load(in);
363
364               Enumeration JavaDoc e = props.propertyNames();
365               Vector JavaDoc filts = getFilters();
366               while (e.hasMoreElements()) {
367                  String JavaDoc strPropName = (String JavaDoc) e.nextElement();
368                  String JavaDoc strValue = props.getProperty(strPropName);
369                  filts.addElement(new Filter(strPropName, strValue));
370               }
371            } catch (Exception JavaDoc ex) {
372               throw new BuildException("Could not read filters from file: "
373                   + filtersFile);
374            } finally {
375               FileUtils.close(in);
376            }
377         } else {
378            handleMissingFile(
379                "Must specify a file rather than a directory in "
380                + "the filtersfile attribute:" + filtersFile);
381         }
382         filterHash = null;
383     }
384
385     /**
386      * Does replacement on the given string with token matching.
387      * This uses the defined begintoken and endtoken values which default
388      * to @ for both.
389      * This resets the passedTokens and calls iReplaceTokens to
390      * do the actual replacements.
391      *
392      * @param line The line in which to process embedded tokens.
393      * @return The input string after token replacement.
394      */

395     public synchronized String JavaDoc replaceTokens(String JavaDoc line) {
396         return iReplaceTokens(line);
397     }
398
399     /**
400      * Add a new filter.
401      *
402      * @param filter the filter to be added.
403      */

404     public synchronized void addFilter(Filter filter) {
405         if (isReference()) {
406             throw noChildrenAllowed();
407         }
408         filters.addElement(filter);
409         filterHash = null;
410     }
411
412     /**
413      * Create a new FiltersFile.
414      *
415      * @return The filtersfile that was created.
416      */

417     public FiltersFile createFiltersfile() {
418         if (isReference()) {
419             throw noChildrenAllowed();
420         }
421         return new FiltersFile();
422     }
423
424     /**
425      * Add a new filter made from the given token and value.
426      *
427      * @param token The token for the new filter.
428      * @param value The value for the new filter.
429      */

430     public synchronized void addFilter(String JavaDoc token, String JavaDoc value) {
431         if (isReference()) {
432             throw noChildrenAllowed();
433         }
434         addFilter(new Filter(token, value));
435     }
436
437     /**
438      * Add a Filterset to this filter set.
439      *
440      * @param filterSet the filterset to be added to this filterset
441      */

442     public synchronized void addConfiguredFilterSet(FilterSet filterSet) {
443         if (isReference()) {
444             throw noChildrenAllowed();
445         }
446         for (Enumeration JavaDoc e = filterSet.getFilters().elements(); e.hasMoreElements();) {
447             addFilter((Filter) e.nextElement());
448         }
449     }
450
451     /**
452     * Test to see if this filter set has filters.
453     *
454     * @return Return true if there are filters in this set.
455     */

456     public synchronized boolean hasFilters() {
457         return getFilters().size() > 0;
458     }
459
460     /**
461      * Clone the filterset.
462      *
463      * @return a deep clone of this filterset.
464      *
465      * @throws BuildException if the clone cannot be performed.
466      */

467     public synchronized Object JavaDoc clone() throws BuildException {
468         if (isReference()) {
469             return ((FilterSet) getRef()).clone();
470         }
471         try {
472             FilterSet fs = (FilterSet) super.clone();
473             fs.filters = (Vector JavaDoc) getFilters().clone();
474             fs.setProject(getProject());
475             return fs;
476         } catch (CloneNotSupportedException JavaDoc e) {
477             throw new BuildException(e);
478         }
479     }
480
481     /**
482      * Set the behavior WRT missing filtersfiles.
483      * @param onMissingFiltersFile the OnMissing describing the behavior.
484      */

485     public void setOnMissingFiltersFile(OnMissing onMissingFiltersFile) {
486         this.onMissingFiltersFile = onMissingFiltersFile;
487     }
488
489     /**
490      * Get the onMissingFiltersFile setting.
491      * @return the OnMissing instance.
492      */

493     public OnMissing getOnMissingFiltersFile() {
494         return onMissingFiltersFile;
495     }
496
497     /**
498      * Does replacement on the given string with token matching.
499      * This uses the defined begintoken and endtoken values which default
500      * to @ for both.
501      *
502      * @param line The line to process the tokens in.
503      * @return The string with the tokens replaced.
504      */

505     private synchronized String JavaDoc iReplaceTokens(String JavaDoc line) {
506         String JavaDoc beginToken = getBeginToken();
507         String JavaDoc endToken = getEndToken();
508         int index = line.indexOf(beginToken);
509
510         if (index > -1) {
511             Hashtable JavaDoc tokens = getFilterHash();
512             try {
513                 StringBuffer JavaDoc b = new StringBuffer JavaDoc();
514                 int i = 0;
515                 String JavaDoc token = null;
516                 String JavaDoc value = null;
517
518                 while (index > -1) {
519                     //can't have zero-length token
520
int endIndex = line.indexOf(endToken,
521                         index + beginToken.length() + 1);
522                     if (endIndex == -1) {
523                         break;
524                     }
525                     token
526                         = line.substring(index + beginToken.length(), endIndex);
527                     b.append(line.substring(i, index));
528                     if (tokens.containsKey(token)) {
529                         value = (String JavaDoc) tokens.get(token);
530                         if (recurse && !value.equals(token)) {
531                             // we have another token, let's parse it.
532
value = replaceTokens(value, token);
533                         }
534                         log("Replacing: " + beginToken + token + endToken
535                             + " -> " + value, Project.MSG_VERBOSE);
536                         b.append(value);
537                         i = index + beginToken.length() + token.length()
538                             + endToken.length();
539                     } else {
540                         // just append beginToken and search further
541
b.append(beginToken);
542                         i = index + beginToken.length();
543                     }
544                     index = line.indexOf(beginToken, i);
545                 }
546
547                 b.append(line.substring(i));
548                 return b.toString();
549             } catch (StringIndexOutOfBoundsException JavaDoc e) {
550                 return line;
551             }
552         } else {
553            return line;
554         }
555     }
556
557     /**
558      * This parses tokens which point to tokens.
559      * It also maintains a list of currently used tokens, so we cannot
560      * get into an infinite loop.
561      * @param line the value / token to parse.
562      * @param parent the parent token (= the token it was parsed from).
563      */

564     private synchronized String JavaDoc replaceTokens(String JavaDoc line, String JavaDoc parent)
565         throws BuildException {
566         String JavaDoc beginToken = getBeginToken();
567         String JavaDoc endToken = getEndToken();
568         if (recurseDepth == 0) {
569             passedTokens = new Vector JavaDoc();
570         }
571         recurseDepth++;
572         if (passedTokens.contains(parent) && !duplicateToken) {
573             duplicateToken = true;
574             System.out.println(
575                 "Infinite loop in tokens. Currently known tokens : "
576                 + passedTokens.toString() + "\nProblem token : " + beginToken
577                 + parent + endToken + " called from " + beginToken
578                 + passedTokens.lastElement().toString() + endToken);
579             recurseDepth--;
580             return parent;
581         }
582         passedTokens.addElement(parent);
583         String JavaDoc value = iReplaceTokens(line);
584         if (value.indexOf(beginToken) == -1 && !duplicateToken
585                 && recurseDepth == 1) {
586             passedTokens = null;
587         } else if (duplicateToken) {
588             // should always be the case...
589
if (passedTokens.size() > 0) {
590                 value = (String JavaDoc) passedTokens.remove(passedTokens.size() - 1);
591                 if (passedTokens.size() == 0) {
592                     value = beginToken + value + endToken;
593                     duplicateToken = false;
594                 }
595             }
596         }
597         recurseDepth--;
598         return value;
599     }
600
601     private void handleMissingFile(String JavaDoc message) {
602         switch (onMissingFiltersFile.getIndex()) {
603         case OnMissing.IGNORE_INDEX:
604             return;
605         case OnMissing.FAIL_INDEX:
606             throw new BuildException(message);
607         case OnMissing.WARN_INDEX:
608             log(message, Project.MSG_WARN);
609             return;
610         default:
611             throw new BuildException("Invalid value for onMissingFiltersFile");
612         }
613     }
614
615 }
616
Popular Tags