Source Code Cross Referenced for DirectoryScanner.java in  » Build » ANT » org » apache » tools » ant » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Build » ANT » org.apache.tools.ant 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
0003:         *  contributor license agreements.  See the NOTICE file distributed with
0004:         *  this work for additional information regarding copyright ownership.
0005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
0006:         *  (the "License"); you may not use this file except in compliance with
0007:         *  the License.  You may obtain a copy of the License at
0008:         *
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         *  Unless required by applicable law or agreed to in writing, software
0012:         *  distributed under the License is distributed on an "AS IS" BASIS,
0013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         *  See the License for the specific language governing permissions and
0015:         *  limitations under the License.
0016:         *
0017:         */
0018:
0019:        package org.apache.tools.ant;
0020:
0021:        import java.io.File;
0022:        import java.io.IOException;
0023:        import java.util.ArrayList;
0024:        import java.util.Arrays;
0025:        import java.util.HashMap;
0026:        import java.util.HashSet;
0027:        import java.util.Iterator;
0028:        import java.util.Map;
0029:        import java.util.Set;
0030:        import java.util.Vector;
0031:
0032:        import org.apache.tools.ant.taskdefs.condition.Os;
0033:        import org.apache.tools.ant.types.Resource;
0034:        import org.apache.tools.ant.types.ResourceFactory;
0035:        import org.apache.tools.ant.types.resources.FileResource;
0036:        import org.apache.tools.ant.types.selectors.FileSelector;
0037:        import org.apache.tools.ant.types.selectors.SelectorScanner;
0038:        import org.apache.tools.ant.types.selectors.SelectorUtils;
0039:        import org.apache.tools.ant.util.FileUtils;
0040:
0041:        /**
0042:         * Class for scanning a directory for files/directories which match certain
0043:         * criteria.
0044:         * <p>
0045:         * These criteria consist of selectors and patterns which have been specified.
0046:         * With the selectors you can select which files you want to have included.
0047:         * Files which are not selected are excluded. With patterns you can include
0048:         * or exclude files based on their filename.
0049:         * <p>
0050:         * The idea is simple. A given directory is recursively scanned for all files
0051:         * and directories. Each file/directory is matched against a set of selectors,
0052:         * including special support for matching against filenames with include and
0053:         * and exclude patterns. Only files/directories which match at least one
0054:         * pattern of the include pattern list or other file selector, and don't match
0055:         * any pattern of the exclude pattern list or fail to match against a required
0056:         * selector will be placed in the list of files/directories found.
0057:         * <p>
0058:         * When no list of include patterns is supplied, "**" will be used, which
0059:         * means that everything will be matched. When no list of exclude patterns is
0060:         * supplied, an empty list is used, such that nothing will be excluded. When
0061:         * no selectors are supplied, none are applied.
0062:         * <p>
0063:         * The filename pattern matching is done as follows:
0064:         * The name to be matched is split up in path segments. A path segment is the
0065:         * name of a directory or file, which is bounded by
0066:         * <code>File.separator</code> ('/' under UNIX, '\' under Windows).
0067:         * For example, "abc/def/ghi/xyz.java" is split up in the segments "abc",
0068:         * "def","ghi" and "xyz.java".
0069:         * The same is done for the pattern against which should be matched.
0070:         * <p>
0071:         * The segments of the name and the pattern are then matched against each
0072:         * other. When '**' is used for a path segment in the pattern, it matches
0073:         * zero or more path segments of the name.
0074:         * <p>
0075:         * There is a special case regarding the use of <code>File.separator</code>s
0076:         * at the beginning of the pattern and the string to match:<br>
0077:         * When a pattern starts with a <code>File.separator</code>, the string
0078:         * to match must also start with a <code>File.separator</code>.
0079:         * When a pattern does not start with a <code>File.separator</code>, the
0080:         * string to match may not start with a <code>File.separator</code>.
0081:         * When one of these rules is not obeyed, the string will not
0082:         * match.
0083:         * <p>
0084:         * When a name path segment is matched against a pattern path segment, the
0085:         * following special characters can be used:<br>
0086:         * '*' matches zero or more characters<br>
0087:         * '?' matches one character.
0088:         * <p>
0089:         * Examples:
0090:         * <p>
0091:         * "**\*.class" matches all .class files/dirs in a directory tree.
0092:         * <p>
0093:         * "test\a??.java" matches all files/dirs which start with an 'a', then two
0094:         * more characters and then ".java", in a directory called test.
0095:         * <p>
0096:         * "**" matches everything in a directory tree.
0097:         * <p>
0098:         * "**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where
0099:         * there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123").
0100:         * <p>
0101:         * Case sensitivity may be turned off if necessary. By default, it is
0102:         * turned on.
0103:         * <p>
0104:         * Example of usage:
0105:         * <pre>
0106:         *   String[] includes = {"**\\*.class"};
0107:         *   String[] excludes = {"modules\\*\\**"};
0108:         *   ds.setIncludes(includes);
0109:         *   ds.setExcludes(excludes);
0110:         *   ds.setBasedir(new File("test"));
0111:         *   ds.setCaseSensitive(true);
0112:         *   ds.scan();
0113:         *
0114:         *   System.out.println("FILES:");
0115:         *   String[] files = ds.getIncludedFiles();
0116:         *   for (int i = 0; i < files.length; i++) {
0117:         *     System.out.println(files[i]);
0118:         *   }
0119:         * </pre>
0120:         * This will scan a directory called test for .class files, but excludes all
0121:         * files in all proper subdirectories of a directory called "modules"
0122:         *
0123:         */
0124:        public class DirectoryScanner implements  FileScanner, SelectorScanner,
0125:                ResourceFactory {
0126:
0127:            /** Is OpenVMS the operating system we're running on? */
0128:            private static final boolean ON_VMS = Os.isFamily("openvms");
0129:
0130:            /**
0131:             * Patterns which should be excluded by default.
0132:             *
0133:             * <p>Note that you can now add patterns to the list of default
0134:             * excludes.  Added patterns will not become part of this array
0135:             * that has only been kept around for backwards compatibility
0136:             * reasons.</p>
0137:             *
0138:             * @deprecated since 1.6.x.
0139:             *             Use the {@link #getDefaultExcludes getDefaultExcludes}
0140:             *             method instead.
0141:             */
0142:            protected static final String[] DEFAULTEXCLUDES = {
0143:            // Miscellaneous typical temporary files
0144:                    "**/*~", "**/#*#", "**/.#*", "**/%*%", "**/._*",
0145:
0146:                    // CVS
0147:                    "**/CVS", "**/CVS/**", "**/.cvsignore",
0148:
0149:                    // SCCS
0150:                    "**/SCCS", "**/SCCS/**",
0151:
0152:                    // Visual SourceSafe
0153:                    "**/vssver.scc",
0154:
0155:                    // Subversion
0156:                    "**/.svn", "**/.svn/**",
0157:
0158:                    // Mac
0159:                    "**/.DS_Store" };
0160:
0161:            /** Helper. */
0162:            private static final FileUtils FILE_UTILS = FileUtils
0163:                    .getFileUtils();
0164:
0165:            /** iterations for case-sensitive scanning. */
0166:            private static final boolean[] CS_SCAN_ONLY = new boolean[] { true };
0167:
0168:            /** iterations for non-case-sensitive scanning. */
0169:            private static final boolean[] CS_THEN_NON_CS = new boolean[] {
0170:                    true, false };
0171:
0172:            /**
0173:             * Patterns which should be excluded by default.
0174:             *
0175:             * @see #addDefaultExcludes()
0176:             */
0177:            private static Vector defaultExcludes = new Vector();
0178:            static {
0179:                resetDefaultExcludes();
0180:            }
0181:
0182:            // CheckStyle:VisibilityModifier OFF - bc
0183:
0184:            /** The base directory to be scanned. */
0185:            protected File basedir;
0186:
0187:            /** The patterns for the files to be included. */
0188:            protected String[] includes;
0189:
0190:            /** The patterns for the files to be excluded. */
0191:            protected String[] excludes;
0192:
0193:            /** Selectors that will filter which files are in our candidate list. */
0194:            protected FileSelector[] selectors = null;
0195:
0196:            /**
0197:             * The files which matched at least one include and no excludes
0198:             * and were selected.
0199:             */
0200:            protected Vector filesIncluded;
0201:
0202:            /** The files which did not match any includes or selectors. */
0203:            protected Vector filesNotIncluded;
0204:
0205:            /**
0206:             * The files which matched at least one include and at least
0207:             * one exclude.
0208:             */
0209:            protected Vector filesExcluded;
0210:
0211:            /**
0212:             * The directories which matched at least one include and no excludes
0213:             * and were selected.
0214:             */
0215:            protected Vector dirsIncluded;
0216:
0217:            /** The directories which were found and did not match any includes. */
0218:            protected Vector dirsNotIncluded;
0219:
0220:            /**
0221:             * The directories which matched at least one include and at least one
0222:             * exclude.
0223:             */
0224:            protected Vector dirsExcluded;
0225:
0226:            /**
0227:             * The files which matched at least one include and no excludes and
0228:             * which a selector discarded.
0229:             */
0230:            protected Vector filesDeselected;
0231:
0232:            /**
0233:             * The directories which matched at least one include and no excludes
0234:             * but which a selector discarded.
0235:             */
0236:            protected Vector dirsDeselected;
0237:
0238:            /** Whether or not our results were built by a slow scan. */
0239:            protected boolean haveSlowResults = false;
0240:
0241:            /**
0242:             * Whether or not the file system should be treated as a case sensitive
0243:             * one.
0244:             */
0245:            protected boolean isCaseSensitive = true;
0246:
0247:            /**
0248:             * Whether or not symbolic links should be followed.
0249:             *
0250:             * @since Ant 1.5
0251:             */
0252:            private boolean followSymlinks = true;
0253:
0254:            /** Whether or not everything tested so far has been included. */
0255:            protected boolean everythingIncluded = true;
0256:
0257:            // CheckStyle:VisibilityModifier ON
0258:
0259:            /**
0260:             * Temporary table to speed up the various scanning methods.
0261:             *
0262:             * @since Ant 1.6
0263:             */
0264:            private Map fileListMap = new HashMap();
0265:
0266:            /**
0267:             * List of all scanned directories.
0268:             *
0269:             * @since Ant 1.6
0270:             */
0271:            private Set scannedDirs = new HashSet();
0272:
0273:            /**
0274:             * Set of all include patterns that are full file names and don't
0275:             * contain any wildcards.
0276:             *
0277:             * <p>If this instance is not case sensitive, the file names get
0278:             * turned to lower case.</p>
0279:             *
0280:             * <p>Gets lazily initialized on the first invocation of
0281:             * isIncluded or isExcluded and cleared at the end of the scan
0282:             * method (cleared in clearCaches, actually).</p>
0283:             *
0284:             * @since Ant 1.6.3
0285:             */
0286:            private Set includeNonPatterns = new HashSet();
0287:
0288:            /**
0289:             * Set of all include patterns that are full file names and don't
0290:             * contain any wildcards.
0291:             *
0292:             * <p>If this instance is not case sensitive, the file names get
0293:             * turned to lower case.</p>
0294:             *
0295:             * <p>Gets lazily initialized on the first invocation of
0296:             * isIncluded or isExcluded and cleared at the end of the scan
0297:             * method (cleared in clearCaches, actually).</p>
0298:             *
0299:             * @since Ant 1.6.3
0300:             */
0301:            private Set excludeNonPatterns = new HashSet();
0302:
0303:            /**
0304:             * Array of all include patterns that contain wildcards.
0305:             *
0306:             * <p>Gets lazily initialized on the first invocation of
0307:             * isIncluded or isExcluded and cleared at the end of the scan
0308:             * method (cleared in clearCaches, actually).</p>
0309:             *
0310:             * @since Ant 1.6.3
0311:             */
0312:            private String[] includePatterns;
0313:
0314:            /**
0315:             * Array of all exclude patterns that contain wildcards.
0316:             *
0317:             * <p>Gets lazily initialized on the first invocation of
0318:             * isIncluded or isExcluded and cleared at the end of the scan
0319:             * method (cleared in clearCaches, actually).</p>
0320:             *
0321:             * @since Ant 1.6.3
0322:             */
0323:            private String[] excludePatterns;
0324:
0325:            /**
0326:             * Have the non-pattern sets and pattern arrays for in- and
0327:             * excludes been initialized?
0328:             *
0329:             * @since Ant 1.6.3
0330:             */
0331:            private boolean areNonPatternSetsReady = false;
0332:
0333:            /**
0334:             * Scanning flag.
0335:             *
0336:             * @since Ant 1.6.3
0337:             */
0338:            private boolean scanning = false;
0339:
0340:            /**
0341:             * Scanning lock.
0342:             *
0343:             * @since Ant 1.6.3
0344:             */
0345:            private Object scanLock = new Object();
0346:
0347:            /**
0348:             * Slow scanning flag.
0349:             *
0350:             * @since Ant 1.6.3
0351:             */
0352:            private boolean slowScanning = false;
0353:
0354:            /**
0355:             * Slow scanning lock.
0356:             *
0357:             * @since Ant 1.6.3
0358:             */
0359:            private Object slowScanLock = new Object();
0360:
0361:            /**
0362:             * Exception thrown during scan.
0363:             *
0364:             * @since Ant 1.6.3
0365:             */
0366:            private IllegalStateException illegal = null;
0367:
0368:            /**
0369:             * Sole constructor.
0370:             */
0371:            public DirectoryScanner() {
0372:            }
0373:
0374:            /**
0375:             * Test whether or not a given path matches the start of a given
0376:             * pattern up to the first "**".
0377:             * <p>
0378:             * This is not a general purpose test and should only be used if you
0379:             * can live with false positives. For example, <code>pattern=**\a</code>
0380:             * and <code>str=b</code> will yield <code>true</code>.
0381:             *
0382:             * @param pattern The pattern to match against. Must not be
0383:             *                <code>null</code>.
0384:             * @param str     The path to match, as a String. Must not be
0385:             *                <code>null</code>.
0386:             *
0387:             * @return whether or not a given path matches the start of a given
0388:             * pattern up to the first "**".
0389:             */
0390:            protected static boolean matchPatternStart(String pattern,
0391:                    String str) {
0392:                return SelectorUtils.matchPatternStart(pattern, str);
0393:            }
0394:
0395:            /**
0396:             * Test whether or not a given path matches the start of a given
0397:             * pattern up to the first "**".
0398:             * <p>
0399:             * This is not a general purpose test and should only be used if you
0400:             * can live with false positives. For example, <code>pattern=**\a</code>
0401:             * and <code>str=b</code> will yield <code>true</code>.
0402:             *
0403:             * @param pattern The pattern to match against. Must not be
0404:             *                <code>null</code>.
0405:             * @param str     The path to match, as a String. Must not be
0406:             *                <code>null</code>.
0407:             * @param isCaseSensitive Whether or not matching should be performed
0408:             *                        case sensitively.
0409:             *
0410:             * @return whether or not a given path matches the start of a given
0411:             * pattern up to the first "**".
0412:             */
0413:            protected static boolean matchPatternStart(String pattern,
0414:                    String str, boolean isCaseSensitive) {
0415:                return SelectorUtils.matchPatternStart(pattern, str,
0416:                        isCaseSensitive);
0417:            }
0418:
0419:            /**
0420:             * Test whether or not a given path matches a given pattern.
0421:             *
0422:             * @param pattern The pattern to match against. Must not be
0423:             *                <code>null</code>.
0424:             * @param str     The path to match, as a String. Must not be
0425:             *                <code>null</code>.
0426:             *
0427:             * @return <code>true</code> if the pattern matches against the string,
0428:             *         or <code>false</code> otherwise.
0429:             */
0430:            protected static boolean matchPath(String pattern, String str) {
0431:                return SelectorUtils.matchPath(pattern, str);
0432:            }
0433:
0434:            /**
0435:             * Test whether or not a given path matches a given pattern.
0436:             *
0437:             * @param pattern The pattern to match against. Must not be
0438:             *                <code>null</code>.
0439:             * @param str     The path to match, as a String. Must not be
0440:             *                <code>null</code>.
0441:             * @param isCaseSensitive Whether or not matching should be performed
0442:             *                        case sensitively.
0443:             *
0444:             * @return <code>true</code> if the pattern matches against the string,
0445:             *         or <code>false</code> otherwise.
0446:             */
0447:            protected static boolean matchPath(String pattern, String str,
0448:                    boolean isCaseSensitive) {
0449:                return SelectorUtils.matchPath(pattern, str, isCaseSensitive);
0450:            }
0451:
0452:            /**
0453:             * Test whether or not a string matches against a pattern.
0454:             * The pattern may contain two special characters:<br>
0455:             * '*' means zero or more characters<br>
0456:             * '?' means one and only one character
0457:             *
0458:             * @param pattern The pattern to match against.
0459:             *                Must not be <code>null</code>.
0460:             * @param str     The string which must be matched against the pattern.
0461:             *                Must not be <code>null</code>.
0462:             *
0463:             * @return <code>true</code> if the string matches against the pattern,
0464:             *         or <code>false</code> otherwise.
0465:             */
0466:            public static boolean match(String pattern, String str) {
0467:                return SelectorUtils.match(pattern, str);
0468:            }
0469:
0470:            /**
0471:             * Test whether or not a string matches against a pattern.
0472:             * The pattern may contain two special characters:<br>
0473:             * '*' means zero or more characters<br>
0474:             * '?' means one and only one character
0475:             *
0476:             * @param pattern The pattern to match against.
0477:             *                Must not be <code>null</code>.
0478:             * @param str     The string which must be matched against the pattern.
0479:             *                Must not be <code>null</code>.
0480:             * @param isCaseSensitive Whether or not matching should be performed
0481:             *                        case sensitively.
0482:             *
0483:             *
0484:             * @return <code>true</code> if the string matches against the pattern,
0485:             *         or <code>false</code> otherwise.
0486:             */
0487:            protected static boolean match(String pattern, String str,
0488:                    boolean isCaseSensitive) {
0489:                return SelectorUtils.match(pattern, str, isCaseSensitive);
0490:            }
0491:
0492:            /**
0493:             * Get the list of patterns that should be excluded by default.
0494:             *
0495:             * @return An array of <code>String</code> based on the current
0496:             *         contents of the <code>defaultExcludes</code>
0497:             *         <code>Vector</code>.
0498:             *
0499:             * @since Ant 1.6
0500:             */
0501:            public static String[] getDefaultExcludes() {
0502:                return (String[]) defaultExcludes
0503:                        .toArray(new String[defaultExcludes.size()]);
0504:            }
0505:
0506:            /**
0507:             * Add a pattern to the default excludes unless it is already a
0508:             * default exclude.
0509:             *
0510:             * @param s   A string to add as an exclude pattern.
0511:             * @return    <code>true</code> if the string was added;
0512:             *            <code>false</code> if it already existed.
0513:             *
0514:             * @since Ant 1.6
0515:             */
0516:            public static boolean addDefaultExclude(String s) {
0517:                if (defaultExcludes.indexOf(s) == -1) {
0518:                    defaultExcludes.add(s);
0519:                    return true;
0520:                }
0521:                return false;
0522:            }
0523:
0524:            /**
0525:             * Remove a string if it is a default exclude.
0526:             *
0527:             * @param s   The string to attempt to remove.
0528:             * @return    <code>true</code> if <code>s</code> was a default
0529:             *            exclude (and thus was removed);
0530:             *            <code>false</code> if <code>s</code> was not
0531:             *            in the default excludes list to begin with.
0532:             *
0533:             * @since Ant 1.6
0534:             */
0535:            public static boolean removeDefaultExclude(String s) {
0536:                return defaultExcludes.remove(s);
0537:            }
0538:
0539:            /**
0540:             * Go back to the hardwired default exclude patterns.
0541:             *
0542:             * @since Ant 1.6
0543:             */
0544:            public static void resetDefaultExcludes() {
0545:                defaultExcludes = new Vector();
0546:                for (int i = 0; i < DEFAULTEXCLUDES.length; i++) {
0547:                    defaultExcludes.add(DEFAULTEXCLUDES[i]);
0548:                }
0549:            }
0550:
0551:            /**
0552:             * Set the base directory to be scanned. This is the directory which is
0553:             * scanned recursively. All '/' and '\' characters are replaced by
0554:             * <code>File.separatorChar</code>, so the separator used need not match
0555:             * <code>File.separatorChar</code>.
0556:             *
0557:             * @param basedir The base directory to scan.
0558:             */
0559:            public void setBasedir(String basedir) {
0560:                setBasedir(basedir == null ? (File) null : new File(basedir
0561:                        .replace('/', File.separatorChar).replace('\\',
0562:                                File.separatorChar)));
0563:            }
0564:
0565:            /**
0566:             * Set the base directory to be scanned. This is the directory which is
0567:             * scanned recursively.
0568:             *
0569:             * @param basedir The base directory for scanning.
0570:             */
0571:            public synchronized void setBasedir(File basedir) {
0572:                this .basedir = basedir;
0573:            }
0574:
0575:            /**
0576:             * Return the base directory to be scanned.
0577:             * This is the directory which is scanned recursively.
0578:             *
0579:             * @return the base directory to be scanned.
0580:             */
0581:            public synchronized File getBasedir() {
0582:                return basedir;
0583:            }
0584:
0585:            /**
0586:             * Find out whether include exclude patterns are matched in a
0587:             * case sensitive way.
0588:             * @return whether or not the scanning is case sensitive.
0589:             * @since Ant 1.6
0590:             */
0591:            public synchronized boolean isCaseSensitive() {
0592:                return isCaseSensitive;
0593:            }
0594:
0595:            /**
0596:             * Set whether or not include and exclude patterns are matched
0597:             * in a case sensitive way.
0598:             *
0599:             * @param isCaseSensitive whether or not the file system should be
0600:             *                        regarded as a case sensitive one.
0601:             */
0602:            public synchronized void setCaseSensitive(boolean isCaseSensitive) {
0603:                this .isCaseSensitive = isCaseSensitive;
0604:            }
0605:
0606:            /**
0607:             * Get whether or not a DirectoryScanner follows symbolic links.
0608:             *
0609:             * @return flag indicating whether symbolic links should be followed.
0610:             *
0611:             * @since Ant 1.6
0612:             */
0613:            public synchronized boolean isFollowSymlinks() {
0614:                return followSymlinks;
0615:            }
0616:
0617:            /**
0618:             * Set whether or not symbolic links should be followed.
0619:             *
0620:             * @param followSymlinks whether or not symbolic links should be followed.
0621:             */
0622:            public synchronized void setFollowSymlinks(boolean followSymlinks) {
0623:                this .followSymlinks = followSymlinks;
0624:            }
0625:
0626:            /**
0627:             * Set the list of include patterns to use. All '/' and '\' characters
0628:             * are replaced by <code>File.separatorChar</code>, so the separator used
0629:             * need not match <code>File.separatorChar</code>.
0630:             * <p>
0631:             * When a pattern ends with a '/' or '\', "**" is appended.
0632:             *
0633:             * @param includes A list of include patterns.
0634:             *                 May be <code>null</code>, indicating that all files
0635:             *                 should be included. If a non-<code>null</code>
0636:             *                 list is given, all elements must be
0637:             *                 non-<code>null</code>.
0638:             */
0639:            public synchronized void setIncludes(String[] includes) {
0640:                if (includes == null) {
0641:                    this .includes = null;
0642:                } else {
0643:                    this .includes = new String[includes.length];
0644:                    for (int i = 0; i < includes.length; i++) {
0645:                        this .includes[i] = normalizePattern(includes[i]);
0646:                    }
0647:                }
0648:            }
0649:
0650:            /**
0651:             * Set the list of exclude patterns to use. All '/' and '\' characters
0652:             * are replaced by <code>File.separatorChar</code>, so the separator used
0653:             * need not match <code>File.separatorChar</code>.
0654:             * <p>
0655:             * When a pattern ends with a '/' or '\', "**" is appended.
0656:             *
0657:             * @param excludes A list of exclude patterns.
0658:             *                 May be <code>null</code>, indicating that no files
0659:             *                 should be excluded. If a non-<code>null</code> list is
0660:             *                 given, all elements must be non-<code>null</code>.
0661:             */
0662:            public synchronized void setExcludes(String[] excludes) {
0663:                if (excludes == null) {
0664:                    this .excludes = null;
0665:                } else {
0666:                    this .excludes = new String[excludes.length];
0667:                    for (int i = 0; i < excludes.length; i++) {
0668:                        this .excludes[i] = normalizePattern(excludes[i]);
0669:                    }
0670:                }
0671:            }
0672:
0673:            /**
0674:             * Add to the list of exclude patterns to use. All '/' and '\'
0675:             * characters are replaced by <code>File.separatorChar</code>, so
0676:             * the separator used need not match <code>File.separatorChar</code>.
0677:             * <p>
0678:             * When a pattern ends with a '/' or '\', "**" is appended.
0679:             *
0680:             * @param excludes A list of exclude patterns.
0681:             *                 May be <code>null</code>, in which case the
0682:             *                 exclude patterns don't get changed at all.
0683:             *
0684:             * @since Ant 1.6.3
0685:             */
0686:            public synchronized void addExcludes(String[] excludes) {
0687:                if (excludes != null && excludes.length > 0) {
0688:                    if (this .excludes != null && this .excludes.length > 0) {
0689:                        String[] tmp = new String[excludes.length
0690:                                + this .excludes.length];
0691:                        System.arraycopy(this .excludes, 0, tmp, 0,
0692:                                this .excludes.length);
0693:                        for (int i = 0; i < excludes.length; i++) {
0694:                            tmp[this .excludes.length + i] = normalizePattern(excludes[i]);
0695:                        }
0696:                        this .excludes = tmp;
0697:                    } else {
0698:                        setExcludes(excludes);
0699:                    }
0700:                }
0701:            }
0702:
0703:            /**
0704:             * All '/' and '\' characters are replaced by
0705:             * <code>File.separatorChar</code>, so the separator used need not
0706:             * match <code>File.separatorChar</code>.
0707:             *
0708:             * <p> When a pattern ends with a '/' or '\', "**" is appended.
0709:             *
0710:             * @since Ant 1.6.3
0711:             */
0712:            private static String normalizePattern(String p) {
0713:                String pattern = p.replace('/', File.separatorChar).replace(
0714:                        '\\', File.separatorChar);
0715:                if (pattern.endsWith(File.separator)) {
0716:                    pattern += "**";
0717:                }
0718:                return pattern;
0719:            }
0720:
0721:            /**
0722:             * Set the selectors that will select the filelist.
0723:             *
0724:             * @param selectors specifies the selectors to be invoked on a scan.
0725:             */
0726:            public synchronized void setSelectors(FileSelector[] selectors) {
0727:                this .selectors = selectors;
0728:            }
0729:
0730:            /**
0731:             * Return whether or not the scanner has included all the files or
0732:             * directories it has come across so far.
0733:             *
0734:             * @return <code>true</code> if all files and directories which have
0735:             *         been found so far have been included.
0736:             */
0737:            public synchronized boolean isEverythingIncluded() {
0738:                return everythingIncluded;
0739:            }
0740:
0741:            /**
0742:             * Scan for files which match at least one include pattern and don't match
0743:             * any exclude patterns. If there are selectors then the files must pass
0744:             * muster there, as well.  Scans under basedir, if set; otherwise the
0745:             * include patterns without leading wildcards specify the absolute paths of
0746:             * the files that may be included.
0747:             *
0748:             * @exception IllegalStateException if the base directory was set
0749:             *            incorrectly (i.e. if it doesn't exist or isn't a directory).
0750:             */
0751:            public void scan() throws IllegalStateException {
0752:                synchronized (scanLock) {
0753:                    if (scanning) {
0754:                        while (scanning) {
0755:                            try {
0756:                                scanLock.wait();
0757:                            } catch (InterruptedException e) {
0758:                                continue;
0759:                            }
0760:                        }
0761:                        if (illegal != null) {
0762:                            throw illegal;
0763:                        }
0764:                        return;
0765:                    }
0766:                    scanning = true;
0767:                }
0768:                try {
0769:                    synchronized (this ) {
0770:                        illegal = null;
0771:                        clearResults();
0772:
0773:                        // set in/excludes to reasonable defaults if needed:
0774:                        boolean nullIncludes = (includes == null);
0775:                        includes = nullIncludes ? new String[] { "**" }
0776:                                : includes;
0777:                        boolean nullExcludes = (excludes == null);
0778:                        excludes = nullExcludes ? new String[0] : excludes;
0779:
0780:                        if (basedir == null) {
0781:                            // if no basedir and no includes, nothing to do:
0782:                            if (nullIncludes) {
0783:                                return;
0784:                            }
0785:                        } else {
0786:                            if (!basedir.exists()) {
0787:                                illegal = new IllegalStateException("basedir "
0788:                                        + basedir + " does not exist");
0789:                            }
0790:                            if (!basedir.isDirectory()) {
0791:                                illegal = new IllegalStateException("basedir "
0792:                                        + basedir + " is not a directory");
0793:                            }
0794:                            if (illegal != null) {
0795:                                throw illegal;
0796:                            }
0797:                        }
0798:                        if (isIncluded("")) {
0799:                            if (!isExcluded("")) {
0800:                                if (isSelected("", basedir)) {
0801:                                    dirsIncluded.addElement("");
0802:                                } else {
0803:                                    dirsDeselected.addElement("");
0804:                                }
0805:                            } else {
0806:                                dirsExcluded.addElement("");
0807:                            }
0808:                        } else {
0809:                            dirsNotIncluded.addElement("");
0810:                        }
0811:                        checkIncludePatterns();
0812:                        clearCaches();
0813:                        includes = nullIncludes ? null : includes;
0814:                        excludes = nullExcludes ? null : excludes;
0815:                    }
0816:                } finally {
0817:                    synchronized (scanLock) {
0818:                        scanning = false;
0819:                        scanLock.notifyAll();
0820:                    }
0821:                }
0822:            }
0823:
0824:            /**
0825:             * This routine is actually checking all the include patterns in
0826:             * order to avoid scanning everything under base dir.
0827:             * @since Ant 1.6
0828:             */
0829:            private void checkIncludePatterns() {
0830:                Map newroots = new HashMap();
0831:                // put in the newroots map the include patterns without
0832:                // wildcard tokens
0833:                for (int i = 0; i < includes.length; i++) {
0834:                    if (FileUtils.isAbsolutePath(includes[i])) {
0835:                        //skip abs. paths not under basedir, if set:
0836:                        if (basedir != null
0837:                                && !SelectorUtils.matchPatternStart(
0838:                                        includes[i], basedir.getAbsolutePath(),
0839:                                        isCaseSensitive())) {
0840:                            continue;
0841:                        }
0842:                    } else if (basedir == null) {
0843:                        //skip non-abs. paths if basedir == null:
0844:                        continue;
0845:                    }
0846:                    newroots.put(
0847:                            SelectorUtils.rtrimWildcardTokens(includes[i]),
0848:                            includes[i]);
0849:                }
0850:                if (newroots.containsKey("") && basedir != null) {
0851:                    // we are going to scan everything anyway
0852:                    scandir(basedir, "", true);
0853:                } else {
0854:                    // only scan directories that can include matched files or
0855:                    // directories
0856:                    Iterator it = newroots.entrySet().iterator();
0857:
0858:                    File canonBase = null;
0859:                    if (basedir != null) {
0860:                        try {
0861:                            canonBase = basedir.getCanonicalFile();
0862:                        } catch (IOException ex) {
0863:                            throw new BuildException(ex);
0864:                        }
0865:                    }
0866:                    while (it.hasNext()) {
0867:                        Map.Entry entry = (Map.Entry) it.next();
0868:                        String currentelement = (String) entry.getKey();
0869:                        if (basedir == null
0870:                                && !FileUtils.isAbsolutePath(currentelement)) {
0871:                            continue;
0872:                        }
0873:                        String originalpattern = (String) entry.getValue();
0874:                        File myfile = new File(basedir, currentelement);
0875:
0876:                        if (myfile.exists()) {
0877:                            // may be on a case insensitive file system.  We want
0878:                            // the results to show what's really on the disk, so
0879:                            // we need to double check.
0880:                            try {
0881:                                String path = (basedir == null) ? myfile
0882:                                        .getCanonicalPath() : FILE_UTILS
0883:                                        .removeLeadingPath(canonBase, myfile
0884:                                                .getCanonicalFile());
0885:                                if (!path.equals(currentelement) || ON_VMS) {
0886:                                    myfile = findFile(basedir, currentelement,
0887:                                            true);
0888:                                    if (myfile != null && basedir != null) {
0889:                                        currentelement = FILE_UTILS
0890:                                                .removeLeadingPath(basedir,
0891:                                                        myfile);
0892:                                    }
0893:                                }
0894:                            } catch (IOException ex) {
0895:                                throw new BuildException(ex);
0896:                            }
0897:                        }
0898:                        if ((myfile == null || !myfile.exists())
0899:                                && !isCaseSensitive()) {
0900:                            File f = findFile(basedir, currentelement, false);
0901:                            if (f != null && f.exists()) {
0902:                                // adapt currentelement to the case we've
0903:                                // actually found
0904:                                currentelement = (basedir == null) ? f
0905:                                        .getAbsolutePath() : FILE_UTILS
0906:                                        .removeLeadingPath(basedir, f);
0907:                                myfile = f;
0908:                            }
0909:                        }
0910:                        if (myfile != null && myfile.exists()) {
0911:                            if (!followSymlinks
0912:                                    && isSymlink(basedir, currentelement)) {
0913:                                continue;
0914:                            }
0915:                            if (myfile.isDirectory()) {
0916:                                if (isIncluded(currentelement)
0917:                                        && currentelement.length() > 0) {
0918:                                    accountForIncludedDir(currentelement,
0919:                                            myfile, true);
0920:                                } else {
0921:                                    if (currentelement.length() > 0) {
0922:                                        if (currentelement
0923:                                                .charAt(currentelement.length() - 1) != File.separatorChar) {
0924:                                            currentelement = currentelement
0925:                                                    + File.separatorChar;
0926:                                        }
0927:                                    }
0928:                                    scandir(myfile, currentelement, true);
0929:                                }
0930:                            } else {
0931:                                boolean included = isCaseSensitive() ? originalpattern
0932:                                        .equals(currentelement)
0933:                                        : originalpattern
0934:                                                .equalsIgnoreCase(currentelement);
0935:                                if (included) {
0936:                                    accountForIncludedFile(currentelement,
0937:                                            myfile);
0938:                                }
0939:                            }
0940:                        }
0941:                    }
0942:                }
0943:            }
0944:
0945:            /**
0946:             * Clear the result caches for a scan.
0947:             */
0948:            protected synchronized void clearResults() {
0949:                filesIncluded = new Vector();
0950:                filesNotIncluded = new Vector();
0951:                filesExcluded = new Vector();
0952:                filesDeselected = new Vector();
0953:                dirsIncluded = new Vector();
0954:                dirsNotIncluded = new Vector();
0955:                dirsExcluded = new Vector();
0956:                dirsDeselected = new Vector();
0957:                everythingIncluded = (basedir != null);
0958:                scannedDirs.clear();
0959:            }
0960:
0961:            /**
0962:             * Top level invocation for a slow scan. A slow scan builds up a full
0963:             * list of excluded/included files/directories, whereas a fast scan
0964:             * will only have full results for included files, as it ignores
0965:             * directories which can't possibly hold any included files/directories.
0966:             * <p>
0967:             * Returns immediately if a slow scan has already been completed.
0968:             */
0969:            protected void slowScan() {
0970:                synchronized (slowScanLock) {
0971:                    if (haveSlowResults) {
0972:                        return;
0973:                    }
0974:                    if (slowScanning) {
0975:                        while (slowScanning) {
0976:                            try {
0977:                                slowScanLock.wait();
0978:                            } catch (InterruptedException e) {
0979:                                // Empty
0980:                            }
0981:                        }
0982:                        return;
0983:                    }
0984:                    slowScanning = true;
0985:                }
0986:                try {
0987:                    synchronized (this ) {
0988:
0989:                        // set in/excludes to reasonable defaults if needed:
0990:                        boolean nullIncludes = (includes == null);
0991:                        includes = nullIncludes ? new String[] { "**" }
0992:                                : includes;
0993:                        boolean nullExcludes = (excludes == null);
0994:                        excludes = nullExcludes ? new String[0] : excludes;
0995:
0996:                        String[] excl = new String[dirsExcluded.size()];
0997:                        dirsExcluded.copyInto(excl);
0998:
0999:                        String[] notIncl = new String[dirsNotIncluded.size()];
1000:                        dirsNotIncluded.copyInto(notIncl);
1001:
1002:                        processSlowScan(excl);
1003:                        processSlowScan(notIncl);
1004:                        clearCaches();
1005:                        includes = nullIncludes ? null : includes;
1006:                        excludes = nullExcludes ? null : excludes;
1007:                    }
1008:                } finally {
1009:                    synchronized (slowScanLock) {
1010:                        haveSlowResults = true;
1011:                        slowScanning = false;
1012:                        slowScanLock.notifyAll();
1013:                    }
1014:                }
1015:            }
1016:
1017:            private void processSlowScan(String[] arr) {
1018:                for (int i = 0; i < arr.length; i++) {
1019:                    if (!couldHoldIncluded(arr[i])) {
1020:                        scandir(new File(basedir, arr[i]), arr[i]
1021:                                + File.separator, false);
1022:                    }
1023:                }
1024:            }
1025:
1026:            /**
1027:             * Scan the given directory for files and directories. Found files and
1028:             * directories are placed in their respective collections, based on the
1029:             * matching of includes, excludes, and the selectors.  When a directory
1030:             * is found, it is scanned recursively.
1031:             *
1032:             * @param dir   The directory to scan. Must not be <code>null</code>.
1033:             * @param vpath The path relative to the base directory (needed to
1034:             *              prevent problems with an absolute path when using
1035:             *              dir). Must not be <code>null</code>.
1036:             * @param fast  Whether or not this call is part of a fast scan.
1037:             *
1038:             * @see #filesIncluded
1039:             * @see #filesNotIncluded
1040:             * @see #filesExcluded
1041:             * @see #dirsIncluded
1042:             * @see #dirsNotIncluded
1043:             * @see #dirsExcluded
1044:             * @see #slowScan
1045:             */
1046:            protected void scandir(File dir, String vpath, boolean fast) {
1047:                if (dir == null) {
1048:                    throw new BuildException("dir must not be null.");
1049:                } else if (!dir.exists()) {
1050:                    throw new BuildException(dir + " doesn't exist.");
1051:                } else if (!dir.isDirectory()) {
1052:                    throw new BuildException(dir + " is not a directory.");
1053:                }
1054:                // avoid double scanning of directories, can only happen in fast mode
1055:                if (fast && hasBeenScanned(vpath)) {
1056:                    return;
1057:                }
1058:                String[] newfiles = dir.list();
1059:
1060:                if (newfiles == null) {
1061:                    /*
1062:                     * two reasons are mentioned in the API docs for File.list
1063:                     * (1) dir is not a directory. This is impossible as
1064:                     *     we wouldn't get here in this case.
1065:                     * (2) an IO error occurred (why doesn't it throw an exception
1066:                     *     then???)
1067:                     */
1068:                    throw new BuildException("IO error scanning directory '"
1069:                            + dir.getAbsolutePath() + "'");
1070:                }
1071:                if (!followSymlinks) {
1072:                    Vector noLinks = new Vector();
1073:                    for (int i = 0; i < newfiles.length; i++) {
1074:                        try {
1075:                            if (FILE_UTILS.isSymbolicLink(dir, newfiles[i])) {
1076:                                String name = vpath + newfiles[i];
1077:                                File file = new File(dir, newfiles[i]);
1078:                                (file.isDirectory() ? dirsExcluded
1079:                                        : filesExcluded).addElement(name);
1080:                            } else {
1081:                                noLinks.addElement(newfiles[i]);
1082:                            }
1083:                        } catch (IOException ioe) {
1084:                            String msg = "IOException caught while checking "
1085:                                    + "for links, couldn't get canonical path!";
1086:                            // will be caught and redirected to Ant's logging system
1087:                            System.err.println(msg);
1088:                            noLinks.addElement(newfiles[i]);
1089:                        }
1090:                    }
1091:                    newfiles = (String[]) (noLinks.toArray(new String[noLinks
1092:                            .size()]));
1093:                }
1094:                for (int i = 0; i < newfiles.length; i++) {
1095:                    String name = vpath + newfiles[i];
1096:                    File file = new File(dir, newfiles[i]);
1097:                    if (file.isDirectory()) {
1098:                        if (isIncluded(name)) {
1099:                            accountForIncludedDir(name, file, fast);
1100:                        } else {
1101:                            everythingIncluded = false;
1102:                            dirsNotIncluded.addElement(name);
1103:                            if (fast && couldHoldIncluded(name)) {
1104:                                scandir(file, name + File.separator, fast);
1105:                            }
1106:                        }
1107:                        if (!fast) {
1108:                            scandir(file, name + File.separator, fast);
1109:                        }
1110:                    } else if (file.isFile()) {
1111:                        if (isIncluded(name)) {
1112:                            accountForIncludedFile(name, file);
1113:                        } else {
1114:                            everythingIncluded = false;
1115:                            filesNotIncluded.addElement(name);
1116:                        }
1117:                    }
1118:                }
1119:            }
1120:
1121:            /**
1122:             * Process included file.
1123:             * @param name  path of the file relative to the directory of the FileSet.
1124:             * @param file  included File.
1125:             */
1126:            private void accountForIncludedFile(String name, File file) {
1127:                processIncluded(name, file, filesIncluded, filesExcluded,
1128:                        filesDeselected);
1129:            }
1130:
1131:            /**
1132:             * Process included directory.
1133:             * @param name path of the directory relative to the directory of
1134:             *             the FileSet.
1135:             * @param file directory as File.
1136:             * @param fast whether to perform fast scans.
1137:             */
1138:            private void accountForIncludedDir(String name, File file,
1139:                    boolean fast) {
1140:                processIncluded(name, file, dirsIncluded, dirsExcluded,
1141:                        dirsDeselected);
1142:                if (fast && couldHoldIncluded(name) && !contentsExcluded(name)) {
1143:                    scandir(file, name + File.separator, fast);
1144:                }
1145:            }
1146:
1147:            private void processIncluded(String name, File file, Vector inc,
1148:                    Vector exc, Vector des) {
1149:
1150:                if (inc.contains(name) || exc.contains(name)
1151:                        || des.contains(name)) {
1152:                    return;
1153:                }
1154:
1155:                boolean included = false;
1156:                if (isExcluded(name)) {
1157:                    exc.add(name);
1158:                } else if (isSelected(name, file)) {
1159:                    included = true;
1160:                    inc.add(name);
1161:                } else {
1162:                    des.add(name);
1163:                }
1164:                everythingIncluded &= included;
1165:            }
1166:
1167:            /**
1168:             * Test whether or not a name matches against at least one include
1169:             * pattern.
1170:             *
1171:             * @param name The name to match. Must not be <code>null</code>.
1172:             * @return <code>true</code> when the name matches against at least one
1173:             *         include pattern, or <code>false</code> otherwise.
1174:             */
1175:            protected boolean isIncluded(String name) {
1176:                ensureNonPatternSetsReady();
1177:
1178:                if (isCaseSensitive() ? includeNonPatterns.contains(name)
1179:                        : includeNonPatterns.contains(name.toUpperCase())) {
1180:                    return true;
1181:                }
1182:                for (int i = 0; i < includePatterns.length; i++) {
1183:                    if (matchPath(includePatterns[i], name, isCaseSensitive())) {
1184:                        return true;
1185:                    }
1186:                }
1187:                return false;
1188:            }
1189:
1190:            /**
1191:             * Test whether or not a name matches the start of at least one include
1192:             * pattern.
1193:             *
1194:             * @param name The name to match. Must not be <code>null</code>.
1195:             * @return <code>true</code> when the name matches against the start of at
1196:             *         least one include pattern, or <code>false</code> otherwise.
1197:             */
1198:            protected boolean couldHoldIncluded(String name) {
1199:                for (int i = 0; i < includes.length; i++) {
1200:                    if (matchPatternStart(includes[i], name, isCaseSensitive())
1201:                            && isMorePowerfulThanExcludes(name, includes[i])
1202:                            && isDeeper(includes[i], name)) {
1203:                        return true;
1204:                    }
1205:                }
1206:                return false;
1207:            }
1208:
1209:            /**
1210:             * Verify that a pattern specifies files deeper
1211:             * than the level of the specified file.
1212:             * @param pattern the pattern to check.
1213:             * @param name the name to check.
1214:             * @return whether the pattern is deeper than the name.
1215:             * @since Ant 1.6.3
1216:             */
1217:            private boolean isDeeper(String pattern, String name) {
1218:                Vector p = SelectorUtils.tokenizePath(pattern);
1219:                Vector n = SelectorUtils.tokenizePath(name);
1220:                return p.contains("**") || p.size() > n.size();
1221:            }
1222:
1223:            /**
1224:             *  Find out whether one particular include pattern is more powerful
1225:             *  than all the excludes.
1226:             *  Note:  the power comparison is based on the length of the include pattern
1227:             *  and of the exclude patterns without the wildcards.
1228:             *  Ideally the comparison should be done based on the depth
1229:             *  of the match; that is to say how many file separators have been matched
1230:             *  before the first ** or the end of the pattern.
1231:             *
1232:             *  IMPORTANT : this function should return false "with care".
1233:             *
1234:             *  @param name the relative path to test.
1235:             *  @param includepattern one include pattern.
1236:             *  @return true if there is no exclude pattern more powerful than this include pattern.
1237:             *  @since Ant 1.6
1238:             */
1239:            private boolean isMorePowerfulThanExcludes(String name,
1240:                    String includepattern) {
1241:                String soughtexclude = name + File.separator + "**";
1242:                for (int counter = 0; counter < excludes.length; counter++) {
1243:                    if (excludes[counter].equals(soughtexclude)) {
1244:                        return false;
1245:                    }
1246:                }
1247:                return true;
1248:            }
1249:
1250:            /**
1251:             * Test whether all contents of the specified directory must be excluded.
1252:             * @param name the directory name to check.
1253:             * @return whether all the specified directory's contents are excluded.
1254:             */
1255:            private boolean contentsExcluded(String name) {
1256:                name = (name.endsWith(File.separator)) ? name : name
1257:                        + File.separator;
1258:                for (int i = 0; i < excludes.length; i++) {
1259:                    String e = excludes[i];
1260:                    if (e.endsWith("**")
1261:                            && SelectorUtils.matchPath(e.substring(0, e
1262:                                    .length() - 2), name, isCaseSensitive())) {
1263:                        return true;
1264:                    }
1265:                }
1266:                return false;
1267:            }
1268:
1269:            /**
1270:             * Test whether or not a name matches against at least one exclude
1271:             * pattern.
1272:             *
1273:             * @param name The name to match. Must not be <code>null</code>.
1274:             * @return <code>true</code> when the name matches against at least one
1275:             *         exclude pattern, or <code>false</code> otherwise.
1276:             */
1277:            protected boolean isExcluded(String name) {
1278:                ensureNonPatternSetsReady();
1279:
1280:                if (isCaseSensitive() ? excludeNonPatterns.contains(name)
1281:                        : excludeNonPatterns.contains(name.toUpperCase())) {
1282:                    return true;
1283:                }
1284:                for (int i = 0; i < excludePatterns.length; i++) {
1285:                    if (matchPath(excludePatterns[i], name, isCaseSensitive())) {
1286:                        return true;
1287:                    }
1288:                }
1289:                return false;
1290:            }
1291:
1292:            /**
1293:             * Test whether a file should be selected.
1294:             *
1295:             * @param name the filename to check for selecting.
1296:             * @param file the java.io.File object for this filename.
1297:             * @return <code>false</code> when the selectors says that the file
1298:             *         should not be selected, <code>true</code> otherwise.
1299:             */
1300:            protected boolean isSelected(String name, File file) {
1301:                if (selectors != null) {
1302:                    for (int i = 0; i < selectors.length; i++) {
1303:                        if (!selectors[i].isSelected(basedir, name, file)) {
1304:                            return false;
1305:                        }
1306:                    }
1307:                }
1308:                return true;
1309:            }
1310:
1311:            /**
1312:             * Return the names of the files which matched at least one of the
1313:             * include patterns and none of the exclude patterns.
1314:             * The names are relative to the base directory.
1315:             *
1316:             * @return the names of the files which matched at least one of the
1317:             *         include patterns and none of the exclude patterns.
1318:             */
1319:            public synchronized String[] getIncludedFiles() {
1320:                if (filesIncluded == null) {
1321:                    throw new IllegalStateException("Must call scan() first");
1322:                }
1323:                String[] files = new String[filesIncluded.size()];
1324:                filesIncluded.copyInto(files);
1325:                Arrays.sort(files);
1326:                return files;
1327:            }
1328:
1329:            /**
1330:             * Return the count of included files.
1331:             * @return <code>int</code>.
1332:             * @since Ant 1.6.3
1333:             */
1334:            public synchronized int getIncludedFilesCount() {
1335:                if (filesIncluded == null) {
1336:                    throw new IllegalStateException("Must call scan() first");
1337:                }
1338:                return filesIncluded.size();
1339:            }
1340:
1341:            /**
1342:             * Return the names of the files which matched none of the include
1343:             * patterns. The names are relative to the base directory. This involves
1344:             * performing a slow scan if one has not already been completed.
1345:             *
1346:             * @return the names of the files which matched none of the include
1347:             *         patterns.
1348:             *
1349:             * @see #slowScan
1350:             */
1351:            public synchronized String[] getNotIncludedFiles() {
1352:                slowScan();
1353:                String[] files = new String[filesNotIncluded.size()];
1354:                filesNotIncluded.copyInto(files);
1355:                return files;
1356:            }
1357:
1358:            /**
1359:             * Return the names of the files which matched at least one of the
1360:             * include patterns and at least one of the exclude patterns.
1361:             * The names are relative to the base directory. This involves
1362:             * performing a slow scan if one has not already been completed.
1363:             *
1364:             * @return the names of the files which matched at least one of the
1365:             *         include patterns and at least one of the exclude patterns.
1366:             *
1367:             * @see #slowScan
1368:             */
1369:            public synchronized String[] getExcludedFiles() {
1370:                slowScan();
1371:                String[] files = new String[filesExcluded.size()];
1372:                filesExcluded.copyInto(files);
1373:                return files;
1374:            }
1375:
1376:            /**
1377:             * <p>Return the names of the files which were selected out and
1378:             * therefore not ultimately included.</p>
1379:             *
1380:             * <p>The names are relative to the base directory. This involves
1381:             * performing a slow scan if one has not already been completed.</p>
1382:             *
1383:             * @return the names of the files which were deselected.
1384:             *
1385:             * @see #slowScan
1386:             */
1387:            public synchronized String[] getDeselectedFiles() {
1388:                slowScan();
1389:                String[] files = new String[filesDeselected.size()];
1390:                filesDeselected.copyInto(files);
1391:                return files;
1392:            }
1393:
1394:            /**
1395:             * Return the names of the directories which matched at least one of the
1396:             * include patterns and none of the exclude patterns.
1397:             * The names are relative to the base directory.
1398:             *
1399:             * @return the names of the directories which matched at least one of the
1400:             * include patterns and none of the exclude patterns.
1401:             */
1402:            public synchronized String[] getIncludedDirectories() {
1403:                if (dirsIncluded == null) {
1404:                    throw new IllegalStateException("Must call scan() first");
1405:                }
1406:                String[] directories = new String[dirsIncluded.size()];
1407:                dirsIncluded.copyInto(directories);
1408:                Arrays.sort(directories);
1409:                return directories;
1410:            }
1411:
1412:            /**
1413:             * Return the count of included directories.
1414:             * @return <code>int</code>.
1415:             * @since Ant 1.6.3
1416:             */
1417:            public synchronized int getIncludedDirsCount() {
1418:                if (dirsIncluded == null) {
1419:                    throw new IllegalStateException("Must call scan() first");
1420:                }
1421:                return dirsIncluded.size();
1422:            }
1423:
1424:            /**
1425:             * Return the names of the directories which matched none of the include
1426:             * patterns. The names are relative to the base directory. This involves
1427:             * performing a slow scan if one has not already been completed.
1428:             *
1429:             * @return the names of the directories which matched none of the include
1430:             * patterns.
1431:             *
1432:             * @see #slowScan
1433:             */
1434:            public synchronized String[] getNotIncludedDirectories() {
1435:                slowScan();
1436:                String[] directories = new String[dirsNotIncluded.size()];
1437:                dirsNotIncluded.copyInto(directories);
1438:                return directories;
1439:            }
1440:
1441:            /**
1442:             * Return the names of the directories which matched at least one of the
1443:             * include patterns and at least one of the exclude patterns.
1444:             * The names are relative to the base directory. This involves
1445:             * performing a slow scan if one has not already been completed.
1446:             *
1447:             * @return the names of the directories which matched at least one of the
1448:             * include patterns and at least one of the exclude patterns.
1449:             *
1450:             * @see #slowScan
1451:             */
1452:            public synchronized String[] getExcludedDirectories() {
1453:                slowScan();
1454:                String[] directories = new String[dirsExcluded.size()];
1455:                dirsExcluded.copyInto(directories);
1456:                return directories;
1457:            }
1458:
1459:            /**
1460:             * <p>Return the names of the directories which were selected out and
1461:             * therefore not ultimately included.</p>
1462:             *
1463:             * <p>The names are relative to the base directory. This involves
1464:             * performing a slow scan if one has not already been completed.</p>
1465:             *
1466:             * @return the names of the directories which were deselected.
1467:             *
1468:             * @see #slowScan
1469:             */
1470:            public synchronized String[] getDeselectedDirectories() {
1471:                slowScan();
1472:                String[] directories = new String[dirsDeselected.size()];
1473:                dirsDeselected.copyInto(directories);
1474:                return directories;
1475:            }
1476:
1477:            /**
1478:             * Add default exclusions to the current exclusions set.
1479:             */
1480:            public synchronized void addDefaultExcludes() {
1481:                int excludesLength = excludes == null ? 0 : excludes.length;
1482:                String[] newExcludes;
1483:                newExcludes = new String[excludesLength
1484:                        + defaultExcludes.size()];
1485:                if (excludesLength > 0) {
1486:                    System.arraycopy(excludes, 0, newExcludes, 0,
1487:                            excludesLength);
1488:                }
1489:                String[] defaultExcludesTemp = getDefaultExcludes();
1490:                for (int i = 0; i < defaultExcludesTemp.length; i++) {
1491:                    newExcludes[i + excludesLength] = defaultExcludesTemp[i]
1492:                            .replace('/', File.separatorChar).replace('\\',
1493:                                    File.separatorChar);
1494:                }
1495:                excludes = newExcludes;
1496:            }
1497:
1498:            /**
1499:             * Get the named resource.
1500:             * @param name path name of the file relative to the dir attribute.
1501:             *
1502:             * @return the resource with the given name.
1503:             * @since Ant 1.5.2
1504:             */
1505:            public synchronized Resource getResource(String name) {
1506:                return new FileResource(basedir, name);
1507:            }
1508:
1509:            /**
1510:             * Return a cached result of list performed on file, if
1511:             * available.  Invokes the method and caches the result otherwise.
1512:             *
1513:             * @param file File (dir) to list.
1514:             * @since Ant 1.6
1515:             */
1516:            private String[] list(File file) {
1517:                String[] files = (String[]) fileListMap.get(file);
1518:                if (files == null) {
1519:                    files = file.list();
1520:                    if (files != null) {
1521:                        fileListMap.put(file, files);
1522:                    }
1523:                }
1524:                return files;
1525:            }
1526:
1527:            /**
1528:             * From <code>base</code> traverse the filesystem in order to find
1529:             * a file that matches the given name.
1530:             *
1531:             * @param base base File (dir).
1532:             * @param path file path.
1533:             * @param cs whether to scan case-sensitively.
1534:             * @return File object that points to the file in question or null.
1535:             *
1536:             * @since Ant 1.6.3
1537:             */
1538:            private File findFile(File base, String path, boolean cs) {
1539:                if (FileUtils.isAbsolutePath(path)) {
1540:                    if (base == null) {
1541:                        String[] s = FILE_UTILS.dissect(path);
1542:                        base = new File(s[0]);
1543:                        path = s[1];
1544:                    } else {
1545:                        File f = FILE_UTILS.normalize(path);
1546:                        String s = FILE_UTILS.removeLeadingPath(base, f);
1547:                        if (s.equals(f.getAbsolutePath())) {
1548:                            //removing base from path yields no change; path not child of base
1549:                            return null;
1550:                        }
1551:                        path = s;
1552:                    }
1553:                }
1554:                return findFile(base, SelectorUtils.tokenizePath(path), cs);
1555:            }
1556:
1557:            /**
1558:             * From <code>base</code> traverse the filesystem in order to find
1559:             * a file that matches the given stack of names.
1560:             *
1561:             * @param base base File (dir).
1562:             * @param pathElements Vector of path elements (dirs...file).
1563:             * @param cs whether to scan case-sensitively.
1564:             * @return File object that points to the file in question or null.
1565:             *
1566:             * @since Ant 1.6.3
1567:             */
1568:            private File findFile(File base, Vector pathElements, boolean cs) {
1569:                if (pathElements.size() == 0) {
1570:                    return base;
1571:                }
1572:                String current = (String) pathElements.remove(0);
1573:                if (base == null) {
1574:                    return findFile(new File(current), pathElements, cs);
1575:                }
1576:                if (!base.isDirectory()) {
1577:                    return null;
1578:                }
1579:                String[] files = list(base);
1580:                if (files == null) {
1581:                    throw new BuildException("IO error scanning directory "
1582:                            + base.getAbsolutePath());
1583:                }
1584:                boolean[] matchCase = cs ? CS_SCAN_ONLY : CS_THEN_NON_CS;
1585:                for (int i = 0; i < matchCase.length; i++) {
1586:                    for (int j = 0; j < files.length; j++) {
1587:                        if (matchCase[i] ? files[j].equals(current) : files[j]
1588:                                .equalsIgnoreCase(current)) {
1589:                            return findFile(new File(base, files[j]),
1590:                                    pathElements, cs);
1591:                        }
1592:                    }
1593:                }
1594:                return null;
1595:            }
1596:
1597:            /**
1598:             * Do we have to traverse a symlink when trying to reach path from
1599:             * basedir?
1600:             * @param base base File (dir).
1601:             * @param path file path.
1602:             * @since Ant 1.6
1603:             */
1604:            private boolean isSymlink(File base, String path) {
1605:                return isSymlink(base, SelectorUtils.tokenizePath(path));
1606:            }
1607:
1608:            /**
1609:             * Do we have to traverse a symlink when trying to reach path from
1610:             * basedir?
1611:             * @param base base File (dir).
1612:             * @param pathElements Vector of path elements (dirs...file).
1613:             * @since Ant 1.6
1614:             */
1615:            private boolean isSymlink(File base, Vector pathElements) {
1616:                if (pathElements.size() > 0) {
1617:                    String current = (String) pathElements.remove(0);
1618:                    try {
1619:                        return FILE_UTILS.isSymbolicLink(base, current)
1620:                                || isSymlink(new File(base, current),
1621:                                        pathElements);
1622:                    } catch (IOException ioe) {
1623:                        String msg = "IOException caught while checking "
1624:                                + "for links, couldn't get canonical path!";
1625:                        // will be caught and redirected to Ant's logging system
1626:                        System.err.println(msg);
1627:                    }
1628:                }
1629:                return false;
1630:            }
1631:
1632:            /**
1633:             * Has the directory with the given path relative to the base
1634:             * directory already been scanned?
1635:             *
1636:             * <p>Registers the given directory as scanned as a side effect.</p>
1637:             *
1638:             * @since Ant 1.6
1639:             */
1640:            private boolean hasBeenScanned(String vpath) {
1641:                return !scannedDirs.add(vpath);
1642:            }
1643:
1644:            /**
1645:             * This method is of interest for testing purposes.  The returned
1646:             * Set is live and should not be modified.
1647:             * @return the Set of relative directory names that have been scanned.
1648:             */
1649:            /* package-private */Set getScannedDirs() {
1650:                return scannedDirs;
1651:            }
1652:
1653:            /**
1654:             * Clear internal caches.
1655:             *
1656:             * @since Ant 1.6
1657:             */
1658:            private synchronized void clearCaches() {
1659:                fileListMap.clear();
1660:                includeNonPatterns.clear();
1661:                excludeNonPatterns.clear();
1662:                includePatterns = null;
1663:                excludePatterns = null;
1664:                areNonPatternSetsReady = false;
1665:            }
1666:
1667:            /**
1668:             * Ensure that the in|exclude &quot;patterns&quot;
1669:             * have been properly divided up.
1670:             *
1671:             * @since Ant 1.6.3
1672:             */
1673:            private synchronized void ensureNonPatternSetsReady() {
1674:                if (!areNonPatternSetsReady) {
1675:                    includePatterns = fillNonPatternSet(includeNonPatterns,
1676:                            includes);
1677:                    excludePatterns = fillNonPatternSet(excludeNonPatterns,
1678:                            excludes);
1679:                    areNonPatternSetsReady = true;
1680:                }
1681:            }
1682:
1683:            /**
1684:             * Add all patterns that are not real patterns (do not contain
1685:             * wildcards) to the set and returns the real patterns.
1686:             *
1687:             * @param set Set to populate.
1688:             * @param patterns String[] of patterns.
1689:             * @since Ant 1.6.3
1690:             */
1691:            private String[] fillNonPatternSet(Set set, String[] patterns) {
1692:                ArrayList al = new ArrayList(patterns.length);
1693:                for (int i = 0; i < patterns.length; i++) {
1694:                    if (!SelectorUtils.hasWildcards(patterns[i])) {
1695:                        set.add(isCaseSensitive() ? patterns[i] : patterns[i]
1696:                                .toUpperCase());
1697:                    } else {
1698:                        al.add(patterns[i]);
1699:                    }
1700:                }
1701:                return set.size() == 0 ? patterns : (String[]) al
1702:                        .toArray(new String[al.size()]);
1703:            }
1704:
1705:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.