Source Code Cross Referenced for Depend.java in  » Build » ANT » org » apache » tools » ant » taskdefs » optional » depend » 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.taskdefs.optional.depend 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
003:         *  contributor license agreements.  See the NOTICE file distributed with
004:         *  this work for additional information regarding copyright ownership.
005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
006:         *  (the "License"); you may not use this file except in compliance with
007:         *  the License.  You may obtain a copy of the License at
008:         *
009:         *      http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         *  Unless required by applicable law or agreed to in writing, software
012:         *  distributed under the License is distributed on an "AS IS" BASIS,
013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         *  See the License for the specific language governing permissions and
015:         *  limitations under the License.
016:         *
017:         */
018:        package org.apache.tools.ant.taskdefs.optional.depend;
019:
020:        import java.io.BufferedReader;
021:        import java.io.File;
022:        import java.io.FileReader;
023:        import java.io.FileWriter;
024:        import java.io.IOException;
025:        import java.io.PrintWriter;
026:        import java.net.URL;
027:        import java.util.Enumeration;
028:        import java.util.Hashtable;
029:        import java.util.Vector;
030:        import org.apache.tools.ant.AntClassLoader;
031:        import org.apache.tools.ant.BuildException;
032:        import org.apache.tools.ant.DirectoryScanner;
033:        import org.apache.tools.ant.Project;
034:        import org.apache.tools.ant.taskdefs.MatchingTask;
035:        import org.apache.tools.ant.taskdefs.rmic.DefaultRmicAdapter;
036:        import org.apache.tools.ant.taskdefs.rmic.WLRmic;
037:        import org.apache.tools.ant.types.Path;
038:        import org.apache.tools.ant.types.Reference;
039:        import org.apache.tools.ant.util.FileUtils;
040:        import org.apache.tools.ant.util.depend.DependencyAnalyzer;
041:
042:        /**
043:         * Generates a dependency file for a given set of classes.
044:         *
045:         */
046:        public class Depend extends MatchingTask {
047:            /**
048:             * A class (struct) user to manage information about a class
049:             *
050:             */
051:            private static class ClassFileInfo {
052:                /** The file where the class file is stored in the file system */
053:                private File absoluteFile;
054:
055:                /** The Java class name of this class */
056:                private String className;
057:
058:                /** The source File containing this class */
059:                private File sourceFile;
060:
061:                /** if user has been warned about this file not having a source file */
062:                private boolean isUserWarned = false;
063:            }
064:
065:            /** The path where source files exist */
066:            private Path srcPath;
067:
068:            /** The path where compiled class files exist. */
069:            private Path destPath;
070:
071:            /** The directory which contains the dependency cache. */
072:            private File cache;
073:
074:            /** The list of source paths derived from the srcPath field. */
075:            private String[] srcPathList;
076:
077:            /**
078:             * A map which gives for every class a list of the class which it
079:             * affects.
080:             */
081:            private Hashtable affectedClassMap;
082:
083:            /** A map which gives information about a class */
084:            private Hashtable classFileInfoMap;
085:
086:            /**
087:             * A map which gives the list of jars and classes from the classpath
088:             * that a class depends upon
089:             */
090:            private Hashtable classpathDependencies;
091:
092:            /** The list of classes which are out of date. */
093:            private Hashtable outOfDateClasses;
094:
095:            /**
096:             * indicates that the dependency relationships should be extended beyond
097:             * direct dependencies to include all classes. So if A directly affects
098:             * B and B directly affects C, then A indirectly affects C.
099:             */
100:            private boolean closure = false;
101:
102:            /**
103:             * flag to enable warning if we encounter RMI stubs
104:             */
105:            private boolean warnOnRmiStubs = true;
106:
107:            /**
108:             * Flag which controls whether the reversed dependencies should be
109:             * dumped to the log
110:             */
111:            private boolean dump = false;
112:
113:            /** The classpath to look for additional dependencies */
114:            private Path dependClasspath;
115:
116:            /** constants used with the cache file */
117:            private static final String CACHE_FILE_NAME = "dependencies.txt";
118:            /** String Used to separate classnames in the dependency file */
119:            private static final String CLASSNAME_PREPEND = "||:";
120:
121:            /**
122:             * Set the classpath to be used for this dependency check.
123:             *
124:             * @param classpath the classpath to be used when checking for
125:             *      dependencies on elements in the classpath
126:             */
127:            public void setClasspath(Path classpath) {
128:                if (dependClasspath == null) {
129:                    dependClasspath = classpath;
130:                } else {
131:                    dependClasspath.append(classpath);
132:                }
133:            }
134:
135:            /**
136:             * Gets the classpath to be used for this dependency check.
137:             *
138:             * @return the current dependency classpath
139:             */
140:            public Path getClasspath() {
141:                return dependClasspath;
142:            }
143:
144:            /**
145:             * Adds a classpath to be used for this dependency check.
146:             *
147:             * @return A path object to be configured by Ant
148:             */
149:            public Path createClasspath() {
150:                if (dependClasspath == null) {
151:                    dependClasspath = new Path(getProject());
152:                }
153:                return dependClasspath.createPath();
154:            }
155:
156:            /**
157:             * Adds a reference to a classpath defined elsewhere.
158:             *
159:             * @param r a reference to a path object to be used as the depend
160:             *      classpath
161:             */
162:            public void setClasspathRef(Reference r) {
163:                createClasspath().setRefid(r);
164:            }
165:
166:            /**
167:             * Flag to set to true if you want dependency issues with RMI
168:             * stubs to appear at warning level.
169:             * @param warnOnRmiStubs if true set dependency issues to appear at warning level.
170:             * @since Ant1.7
171:             */
172:            public void setWarnOnRmiStubs(boolean warnOnRmiStubs) {
173:                this .warnOnRmiStubs = warnOnRmiStubs;
174:            }
175:
176:            /**
177:             * Read the dependencies from cache file
178:             *
179:             * @return a collection of class dependencies
180:             * @exception IOException if the dependency file cannot be read
181:             */
182:            private Hashtable readCachedDependencies(File depFile)
183:                    throws IOException {
184:                Hashtable dependencyMap = new Hashtable();
185:
186:                BufferedReader in = null;
187:                try {
188:                    in = new BufferedReader(new FileReader(depFile));
189:                    String line = null;
190:                    Vector dependencyList = null;
191:                    String className = null;
192:                    int prependLength = CLASSNAME_PREPEND.length();
193:                    while ((line = in.readLine()) != null) {
194:                        if (line.startsWith(CLASSNAME_PREPEND)) {
195:                            dependencyList = new Vector();
196:                            className = line.substring(prependLength);
197:                            dependencyMap.put(className, dependencyList);
198:                        } else {
199:                            dependencyList.addElement(line);
200:                        }
201:                    }
202:                } finally {
203:                    if (in != null) {
204:                        in.close();
205:                    }
206:                }
207:
208:                return dependencyMap;
209:            }
210:
211:            /**
212:             * Write the dependencies to cache file
213:             *
214:             * @param dependencyMap the map of dependencies to be written out.
215:             * @exception IOException if the dependency file cannot be written out.
216:             */
217:            private void writeCachedDependencies(Hashtable dependencyMap)
218:                    throws IOException {
219:                if (cache != null) {
220:                    PrintWriter pw = null;
221:                    try {
222:                        cache.mkdirs();
223:                        File depFile = new File(cache, CACHE_FILE_NAME);
224:
225:                        pw = new PrintWriter(new FileWriter(depFile));
226:                        Enumeration e = dependencyMap.keys();
227:                        while (e.hasMoreElements()) {
228:                            String className = (String) e.nextElement();
229:
230:                            pw.println(CLASSNAME_PREPEND + className);
231:
232:                            Vector dependencyList = (Vector) dependencyMap
233:                                    .get(className);
234:                            int size = dependencyList.size();
235:                            for (int x = 0; x < size; x++) {
236:                                pw.println(dependencyList.elementAt(x));
237:                            }
238:                        }
239:                    } finally {
240:                        if (pw != null) {
241:                            pw.close();
242:                        }
243:                    }
244:                }
245:            }
246:
247:            /**
248:             * Get the classpath for dependency checking.
249:             *
250:             * This method removes the dest dirs if it is given from the dependency classpath
251:             */
252:            private Path getCheckClassPath() {
253:                if (dependClasspath == null) {
254:                    return null;
255:                }
256:
257:                String[] destPathElements = destPath.list();
258:                String[] classpathElements = dependClasspath.list();
259:                String checkPath = "";
260:                for (int i = 0; i < classpathElements.length; ++i) {
261:                    String element = classpathElements[i];
262:                    boolean inDestPath = false;
263:                    for (int j = 0; j < destPathElements.length && !inDestPath; ++j) {
264:                        inDestPath = destPathElements[j].equals(element);
265:                    }
266:                    if (!inDestPath) {
267:                        if (checkPath.length() == 0) {
268:                            checkPath = element;
269:                        } else {
270:                            checkPath += ":" + element;
271:                        }
272:                    }
273:                }
274:
275:                if (checkPath.length() == 0) {
276:                    return null;
277:                }
278:
279:                return new Path(getProject(), checkPath);
280:            }
281:
282:            /**
283:             * Determine the dependencies between classes. Class dependencies are
284:             * determined by examining the class references in a class file to other
285:             * classes.
286:             *
287:             * This method sets up the following fields
288:             * <ul>
289:             *   <li>affectedClassMap - the list of classes each class affects</li>
290:             *   <li>classFileInfoMap - information about each class</li>
291:             *   <li>classpathDependencies - the list of jars and classes from the
292:             *                             classpath that each class depends upon.</li>
293:             * </ul>
294:             *
295:             * If required, the dependencies are written to the cache.
296:             *
297:             * @exception IOException if either the dependencies cache or the class
298:             *      files cannot be read or written
299:             */
300:            private void determineDependencies() throws IOException {
301:                affectedClassMap = new Hashtable();
302:                classFileInfoMap = new Hashtable();
303:                boolean cacheDirty = false;
304:
305:                Hashtable dependencyMap = new Hashtable();
306:                File cacheFile = null;
307:                boolean cacheFileExists = true;
308:                long cacheLastModified = Long.MAX_VALUE;
309:
310:                // read the dependency cache from the disk
311:                if (cache != null) {
312:                    cacheFile = new File(cache, CACHE_FILE_NAME);
313:                    cacheFileExists = cacheFile.exists();
314:                    cacheLastModified = cacheFile.lastModified();
315:                    if (cacheFileExists) {
316:                        dependencyMap = readCachedDependencies(cacheFile);
317:                    }
318:                }
319:                Enumeration classfileEnum = getClassFiles(destPath).elements();
320:                while (classfileEnum.hasMoreElements()) {
321:                    ClassFileInfo info = (ClassFileInfo) classfileEnum
322:                            .nextElement();
323:                    log("Adding class info for " + info.className,
324:                            Project.MSG_DEBUG);
325:                    classFileInfoMap.put(info.className, info);
326:
327:                    Vector dependencyList = null;
328:
329:                    if (cache != null) {
330:                        // try to read the dependency info from the map if it is
331:                        // not out of date
332:                        if (cacheFileExists
333:                                && cacheLastModified > info.absoluteFile
334:                                        .lastModified()) {
335:                            // depFile exists and is newer than the class file
336:                            // need to get dependency list from the map.
337:                            dependencyList = (Vector) dependencyMap
338:                                    .get(info.className);
339:                        }
340:                    }
341:
342:                    if (dependencyList == null) {
343:                        // not cached - so need to read directly from the class file
344:                        DependencyAnalyzer analyzer = new AntAnalyzer();
345:                        analyzer.addRootClass(info.className);
346:                        analyzer.addClassPath(destPath);
347:                        analyzer.setClosure(false);
348:                        dependencyList = new Vector();
349:                        Enumeration depEnum = analyzer.getClassDependencies();
350:                        while (depEnum.hasMoreElements()) {
351:                            dependencyList.addElement(depEnum.nextElement());
352:                        }
353:                        cacheDirty = true;
354:                        dependencyMap.put(info.className, dependencyList);
355:                    }
356:
357:                    // This class depends on each class in the dependency list. For each
358:                    // one of those, add this class into their affected classes list
359:                    Enumeration depEnum = dependencyList.elements();
360:                    while (depEnum.hasMoreElements()) {
361:                        String dependentClass = (String) depEnum.nextElement();
362:
363:                        Hashtable affectedClasses = (Hashtable) affectedClassMap
364:                                .get(dependentClass);
365:                        if (affectedClasses == null) {
366:                            affectedClasses = new Hashtable();
367:                            affectedClassMap.put(dependentClass,
368:                                    affectedClasses);
369:                        }
370:
371:                        affectedClasses.put(info.className, info);
372:                    }
373:                }
374:
375:                classpathDependencies = null;
376:                Path checkPath = getCheckClassPath();
377:                if (checkPath != null) {
378:                    // now determine which jars each class depends upon
379:                    classpathDependencies = new Hashtable();
380:                    AntClassLoader loader = getProject().createClassLoader(
381:                            checkPath);
382:
383:                    Hashtable classpathFileCache = new Hashtable();
384:                    Object nullFileMarker = new Object();
385:                    for (Enumeration e = dependencyMap.keys(); e
386:                            .hasMoreElements();) {
387:                        String className = (String) e.nextElement();
388:                        Vector dependencyList = (Vector) dependencyMap
389:                                .get(className);
390:                        Hashtable dependencies = new Hashtable();
391:                        classpathDependencies.put(className, dependencies);
392:                        Enumeration e2 = dependencyList.elements();
393:                        while (e2.hasMoreElements()) {
394:                            String dependency = (String) e2.nextElement();
395:                            Object classpathFileObject = classpathFileCache
396:                                    .get(dependency);
397:                            if (classpathFileObject == null) {
398:                                classpathFileObject = nullFileMarker;
399:
400:                                if (!dependency.startsWith("java.")
401:                                        && !dependency.startsWith("javax.")) {
402:                                    URL classURL = loader
403:                                            .getResource(dependency.replace(
404:                                                    '.', '/')
405:                                                    + ".class");
406:                                    if (classURL != null) {
407:                                        if (classURL.getProtocol()
408:                                                .equals("jar")) {
409:                                            String jarFilePath = classURL
410:                                                    .getFile();
411:                                            int classMarker = jarFilePath
412:                                                    .indexOf('!');
413:                                            jarFilePath = jarFilePath
414:                                                    .substring(0, classMarker);
415:                                            if (jarFilePath.startsWith("file:")) {
416:                                                classpathFileObject = new File(
417:                                                        FileUtils
418:                                                                .getFileUtils()
419:                                                                .fromURI(
420:                                                                        jarFilePath));
421:                                            } else {
422:                                                throw new IOException(
423:                                                        "Bizarre nested path in jar: protocol: "
424:                                                                + jarFilePath);
425:                                            }
426:                                        } else if (classURL.getProtocol()
427:                                                .equals("file")) {
428:                                            classpathFileObject = new File(
429:                                                    FileUtils
430:                                                            .getFileUtils()
431:                                                            .fromURI(
432:                                                                    classURL
433:                                                                            .toExternalForm()));
434:                                        }
435:                                        log("Class " + className
436:                                                + " depends on "
437:                                                + classpathFileObject
438:                                                + " due to " + dependency,
439:                                                Project.MSG_DEBUG);
440:                                    }
441:                                }
442:                                classpathFileCache.put(dependency,
443:                                        classpathFileObject);
444:                            }
445:                            if (classpathFileObject != null
446:                                    && classpathFileObject != nullFileMarker) {
447:                                // we need to add this jar to the list for this class.
448:                                File jarFile = (File) classpathFileObject;
449:                                dependencies.put(jarFile, jarFile);
450:                            }
451:                        }
452:                    }
453:                }
454:
455:                // write the dependency cache to the disk
456:                if (cache != null && cacheDirty) {
457:                    writeCachedDependencies(dependencyMap);
458:                }
459:            }
460:
461:            /**
462:             * Delete all the class files which are out of date, by way of their
463:             * dependency on a class which is out of date
464:             *
465:             * @return the number of files deleted.
466:             */
467:            private int deleteAllAffectedFiles() {
468:                int count = 0;
469:                for (Enumeration e = outOfDateClasses.elements(); e
470:                        .hasMoreElements();) {
471:                    String className = (String) e.nextElement();
472:                    count += deleteAffectedFiles(className);
473:                    ClassFileInfo classInfo = (ClassFileInfo) classFileInfoMap
474:                            .get(className);
475:                    if (classInfo != null && classInfo.absoluteFile.exists()) {
476:                        classInfo.absoluteFile.delete();
477:                        count++;
478:                    }
479:                }
480:                return count;
481:            }
482:
483:            /**
484:             * Delete all the class files of classes which depend on the given class
485:             *
486:             * @param className the name of the class whose dependent classes will be
487:             *      deleted
488:             * @return the number of class files removed
489:             */
490:            private int deleteAffectedFiles(String className) {
491:                int count = 0;
492:
493:                Hashtable affectedClasses = (Hashtable) affectedClassMap
494:                        .get(className);
495:                if (affectedClasses == null) {
496:                    return count;
497:                }
498:                for (Enumeration e = affectedClasses.keys(); e
499:                        .hasMoreElements();) {
500:                    String affectedClass = (String) e.nextElement();
501:                    ClassFileInfo affectedClassInfo = (ClassFileInfo) affectedClasses
502:                            .get(affectedClass);
503:
504:                    if (!affectedClassInfo.absoluteFile.exists()) {
505:                        continue;
506:                    }
507:
508:                    if (affectedClassInfo.sourceFile == null) {
509:                        warnOutOfDateButNotDeleted(affectedClassInfo,
510:                                affectedClass, className);
511:                        continue;
512:                    }
513:
514:                    log("Deleting file "
515:                            + affectedClassInfo.absoluteFile.getPath()
516:                            + " since " + className + " out of date",
517:                            Project.MSG_VERBOSE);
518:
519:                    affectedClassInfo.absoluteFile.delete();
520:                    count++;
521:                    if (closure) {
522:                        count += deleteAffectedFiles(affectedClass);
523:                    } else {
524:                        // without closure we may delete an inner class but not the
525:                        // top level class which would not trigger a recompile.
526:
527:                        if (affectedClass.indexOf("$") == -1) {
528:                            continue;
529:                        }
530:                        // need to delete the main class
531:                        String topLevelClassName = affectedClass.substring(0,
532:                                affectedClass.indexOf("$"));
533:                        log("Top level class = " + topLevelClassName,
534:                                Project.MSG_VERBOSE);
535:                        ClassFileInfo topLevelClassInfo = (ClassFileInfo) classFileInfoMap
536:                                .get(topLevelClassName);
537:                        if (topLevelClassInfo != null
538:                                && topLevelClassInfo.absoluteFile.exists()) {
539:                            log(
540:                                    "Deleting file "
541:                                            + topLevelClassInfo.absoluteFile
542:                                                    .getPath()
543:                                            + " since one of its inner classes was removed",
544:                                    Project.MSG_VERBOSE);
545:                            topLevelClassInfo.absoluteFile.delete();
546:                            count++;
547:                            if (closure) {
548:                                count += deleteAffectedFiles(topLevelClassName);
549:                            }
550:                        }
551:                    }
552:                }
553:                return count;
554:            }
555:
556:            /**
557:             * warn when a class is out of date, but not deleted as its source is unknown.
558:             * MSG_WARN is the normal level, but we downgrade to MSG_VERBOSE for RMI files
559:             * if {@link #warnOnRmiStubs is false}
560:             * @param affectedClassInfo info about the affectd class
561:             * @param affectedClass the name of the affected .class file
562:             * @param className the file that is triggering the out of dateness
563:             */
564:            private void warnOutOfDateButNotDeleted(
565:                    ClassFileInfo affectedClassInfo, String affectedClass,
566:                    String className) {
567:                if (affectedClassInfo.isUserWarned) {
568:                    return;
569:                }
570:                int level = Project.MSG_WARN;
571:                if (!warnOnRmiStubs) {
572:                    //downgrade warnings on RMI stublike classes, as they are generated
573:                    //by rmic, so there is no need to tell the user that their source is
574:                    //missing.
575:                    if (isRmiStub(affectedClass, className)) {
576:                        level = Project.MSG_VERBOSE;
577:                    }
578:                }
579:                log("The class " + affectedClass + " in file "
580:                        + affectedClassInfo.absoluteFile.getPath()
581:                        + " is out of date due to " + className
582:                        + " but has not been deleted because its source file"
583:                        + " could not be determined", level);
584:                affectedClassInfo.isUserWarned = true;
585:            }
586:
587:            /**
588:             * test for being an RMI stub
589:             * @param affectedClass  class being tested
590:             * @param className      possible origin of the RMI stub
591:             * @return whether the class affectedClass is a RMI stub
592:             */
593:            private boolean isRmiStub(String affectedClass, String className) {
594:                return isStub(affectedClass, className,
595:                        DefaultRmicAdapter.RMI_STUB_SUFFIX)
596:                        || isStub(affectedClass, className,
597:                                DefaultRmicAdapter.RMI_SKEL_SUFFIX)
598:                        || isStub(affectedClass, className,
599:                                WLRmic.RMI_STUB_SUFFIX)
600:                        || isStub(affectedClass, className,
601:                                WLRmic.RMI_SKEL_SUFFIX);
602:            }
603:
604:            private boolean isStub(String affectedClass, String baseClass,
605:                    String suffix) {
606:                return (baseClass + suffix).equals(affectedClass);
607:            }
608:
609:            /**
610:             * Dump the dependency information loaded from the classes to the Ant log
611:             */
612:            private void dumpDependencies() {
613:                log("Reverse Dependency Dump for " + affectedClassMap.size()
614:                        + " classes:", Project.MSG_DEBUG);
615:
616:                Enumeration classEnum = affectedClassMap.keys();
617:                while (classEnum.hasMoreElements()) {
618:                    String className = (String) classEnum.nextElement();
619:                    log(" Class " + className + " affects:", Project.MSG_DEBUG);
620:                    Hashtable affectedClasses = (Hashtable) affectedClassMap
621:                            .get(className);
622:                    Enumeration affectedClassEnum = affectedClasses.keys();
623:                    while (affectedClassEnum.hasMoreElements()) {
624:                        String affectedClass = (String) affectedClassEnum
625:                                .nextElement();
626:                        ClassFileInfo info = (ClassFileInfo) affectedClasses
627:                                .get(affectedClass);
628:                        log("    " + affectedClass + " in "
629:                                + info.absoluteFile.getPath(),
630:                                Project.MSG_DEBUG);
631:                    }
632:                }
633:
634:                if (classpathDependencies != null) {
635:                    log("Classpath file dependencies (Forward):",
636:                            Project.MSG_DEBUG);
637:
638:                    Enumeration classpathEnum = classpathDependencies.keys();
639:                    while (classpathEnum.hasMoreElements()) {
640:                        String className = (String) classpathEnum.nextElement();
641:                        log(" Class " + className + " depends on:",
642:                                Project.MSG_DEBUG);
643:                        Hashtable dependencies = (Hashtable) classpathDependencies
644:                                .get(className);
645:
646:                        Enumeration classpathFileEnum = dependencies.elements();
647:                        while (classpathFileEnum.hasMoreElements()) {
648:                            File classpathFile = (File) classpathFileEnum
649:                                    .nextElement();
650:                            log("    " + classpathFile.getPath(),
651:                                    Project.MSG_DEBUG);
652:                        }
653:                    }
654:                }
655:            }
656:
657:            private void determineOutOfDateClasses() {
658:                outOfDateClasses = new Hashtable();
659:                for (int i = 0; i < srcPathList.length; i++) {
660:                    File srcDir = getProject().resolveFile(srcPathList[i]);
661:                    if (srcDir.exists()) {
662:                        DirectoryScanner ds = this .getDirectoryScanner(srcDir);
663:                        String[] files = ds.getIncludedFiles();
664:                        scanDir(srcDir, files);
665:                    }
666:                }
667:
668:                // now check classpath file dependencies
669:                if (classpathDependencies == null) {
670:                    return;
671:                }
672:
673:                Enumeration classpathDepsEnum = classpathDependencies.keys();
674:                while (classpathDepsEnum.hasMoreElements()) {
675:                    String className = (String) classpathDepsEnum.nextElement();
676:                    if (outOfDateClasses.containsKey(className)) {
677:                        continue;
678:                    }
679:                    ClassFileInfo info = (ClassFileInfo) classFileInfoMap
680:                            .get(className);
681:
682:                    // if we have no info about the class - it may have been deleted already and we
683:                    // are using cached info.
684:                    if (info != null) {
685:                        Hashtable dependencies = (Hashtable) classpathDependencies
686:                                .get(className);
687:                        for (Enumeration e2 = dependencies.elements(); e2
688:                                .hasMoreElements();) {
689:                            File classpathFile = (File) e2.nextElement();
690:                            if (classpathFile.lastModified() > info.absoluteFile
691:                                    .lastModified()) {
692:                                log("Class " + className
693:                                        + " is out of date with respect to "
694:                                        + classpathFile, Project.MSG_DEBUG);
695:                                outOfDateClasses.put(className, className);
696:                                break;
697:                            }
698:                        }
699:                    }
700:                }
701:            }
702:
703:            /**
704:             * Does the work.
705:             *
706:             * @exception BuildException Thrown in case of an unrecoverable error.
707:             */
708:            public void execute() throws BuildException {
709:                try {
710:                    long start = System.currentTimeMillis();
711:                    if (srcPath == null) {
712:                        throw new BuildException(
713:                                "srcdir attribute must be set", getLocation());
714:                    }
715:
716:                    srcPathList = srcPath.list();
717:                    if (srcPathList.length == 0) {
718:                        throw new BuildException(
719:                                "srcdir attribute must be non-empty",
720:                                getLocation());
721:                    }
722:
723:                    if (destPath == null) {
724:                        destPath = srcPath;
725:                    }
726:
727:                    if (cache != null && cache.exists() && !cache.isDirectory()) {
728:                        throw new BuildException(
729:                                "The cache, if specified, must "
730:                                        + "point to a directory");
731:                    }
732:
733:                    if (cache != null && !cache.exists()) {
734:                        cache.mkdirs();
735:                    }
736:
737:                    determineDependencies();
738:                    if (dump) {
739:                        dumpDependencies();
740:                    }
741:                    determineOutOfDateClasses();
742:                    int count = deleteAllAffectedFiles();
743:
744:                    long duration = (System.currentTimeMillis() - start) / 1000;
745:
746:                    final int summaryLogLevel;
747:                    if (count > 0) {
748:                        summaryLogLevel = Project.MSG_INFO;
749:                    } else {
750:                        summaryLogLevel = Project.MSG_DEBUG;
751:                    }
752:
753:                    log("Deleted " + count + " out of date files in "
754:                            + duration + " seconds", summaryLogLevel);
755:                } catch (Exception e) {
756:                    throw new BuildException(e);
757:                }
758:            }
759:
760:            /**
761:             * Scans the directory looking for source files that are newer than
762:             * their class files. The results are returned in the class variable
763:             * compileList
764:             *
765:             * @param srcDir the source directory
766:             * @param files the names of the files in the source dir which are to be
767:             *      checked.
768:             */
769:            protected void scanDir(File srcDir, String[] files) {
770:
771:                for (int i = 0; i < files.length; i++) {
772:                    File srcFile = new File(srcDir, files[i]);
773:                    if (files[i].endsWith(".java")) {
774:                        String filePath = srcFile.getPath();
775:                        String className = filePath.substring(srcDir.getPath()
776:                                .length() + 1, filePath.length()
777:                                - ".java".length());
778:                        className = ClassFileUtils.convertSlashName(className);
779:                        ClassFileInfo info = (ClassFileInfo) classFileInfoMap
780:                                .get(className);
781:                        if (info == null) {
782:                            // there was no class file. add this class to the list
783:                            outOfDateClasses.put(className, className);
784:                        } else {
785:                            if (srcFile.lastModified() > info.absoluteFile
786:                                    .lastModified()) {
787:                                outOfDateClasses.put(className, className);
788:                            }
789:                        }
790:                    }
791:                }
792:            }
793:
794:            /**
795:             * Get the list of class files we are going to analyse.
796:             *
797:             * @param classLocations a path structure containing all the directories
798:             *      where classes can be found.
799:             * @return a vector containing the classes to analyse.
800:             */
801:            private Vector getClassFiles(Path classLocations) {
802:                // break the classLocations into its components.
803:                String[] classLocationsList = classLocations.list();
804:
805:                Vector classFileList = new Vector();
806:
807:                for (int i = 0; i < classLocationsList.length; ++i) {
808:                    File dir = new File(classLocationsList[i]);
809:                    if (dir.isDirectory()) {
810:                        addClassFiles(classFileList, dir, dir);
811:                    }
812:                }
813:
814:                return classFileList;
815:            }
816:
817:            /**
818:             * Find the source file for a given class
819:             *
820:             * @param classname the classname in slash format.
821:             */
822:            private File findSourceFile(String classname) {
823:                String sourceFilename = classname + ".java";
824:                int innerIndex = classname.indexOf("$");
825:                if (innerIndex != -1) {
826:                    sourceFilename = classname.substring(0, innerIndex)
827:                            + ".java";
828:                }
829:
830:                // search the various source path entries
831:                for (int i = 0; i < srcPathList.length; ++i) {
832:                    File sourceFile = new File(srcPathList[i], sourceFilename);
833:                    if (sourceFile.exists()) {
834:                        return sourceFile;
835:                    }
836:                }
837:                return null;
838:            }
839:
840:            /**
841:             * Add the list of class files from the given directory to the class
842:             * file vector, including any subdirectories.
843:             *
844:             * @param classFileList a list of ClassFileInfo objects for all the
845:             *      files in the directory tree
846:             * @param dir the directory tree to be searched, recursively, for class
847:             *      files
848:             * @param root the root of the source tree. This is used to determine
849:             *      the absolute class name from the relative position in the
850:             *      source tree
851:             */
852:            private void addClassFiles(Vector classFileList, File dir, File root) {
853:                String[] filesInDir = dir.list();
854:
855:                if (filesInDir == null) {
856:                    return;
857:                }
858:                int length = filesInDir.length;
859:
860:                int rootLength = root.getPath().length();
861:                for (int i = 0; i < length; ++i) {
862:                    File file = new File(dir, filesInDir[i]);
863:                    if (file.isDirectory()) {
864:                        addClassFiles(classFileList, file, root);
865:                    } else if (file.getName().endsWith(".class")) {
866:                        ClassFileInfo info = new ClassFileInfo();
867:                        info.absoluteFile = file;
868:                        String relativeName = file.getPath().substring(
869:                                rootLength + 1, file.getPath().length() - 6);
870:                        info.className = ClassFileUtils
871:                                .convertSlashName(relativeName);
872:                        info.sourceFile = findSourceFile(relativeName);
873:                        classFileList.addElement(info);
874:                    }
875:                }
876:            }
877:
878:            /**
879:             * Set the directories path to find the Java source files.
880:             *
881:             * @param srcPath the source path
882:             */
883:            public void setSrcdir(Path srcPath) {
884:                this .srcPath = srcPath;
885:            }
886:
887:            /**
888:             * Set the destination directory where the compiled Java files exist.
889:             *
890:             * @param destPath the destination areas where build files are written
891:             */
892:            public void setDestDir(Path destPath) {
893:                this .destPath = destPath;
894:            }
895:
896:            /**
897:             * Sets the dependency cache file.
898:             *
899:             * @param cache the dependency cache file
900:             */
901:            public void setCache(File cache) {
902:                this .cache = cache;
903:            }
904:
905:            /**
906:             * If true, transitive dependencies are followed until the
907:             * closure of the dependency set if reached.
908:             * When not set, the depend task will only follow
909:             * direct dependencies between classes.
910:             *
911:             * @param closure indicate if dependency closure is required.
912:             */
913:            public void setClosure(boolean closure) {
914:                this .closure = closure;
915:            }
916:
917:            /**
918:             * If true, the dependency information will be written
919:             * to the debug level log.
920:             *
921:             * @param dump set to true to dump dependency information to the log
922:             */
923:            public void setDump(boolean dump) {
924:                this.dump = dump;
925:            }
926:        }
ww___w__.___j_a__v__a__2_s___.c_o__m___ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.