001/* Look for class files under a directory and return package names.
002
003 Copyright (c) 2006-2015 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.vergil.actor;
029
030import java.io.File;
031import java.io.FileFilter;
032import java.util.HashSet;
033import java.util.Iterator;
034import java.util.Set;
035
036import ptolemy.util.ExecuteCommands;
037
038/** Look for class files under a directory and return package names.
039 *  @author Christopher Brooks
040 *  @version $Id$
041 *  @since Ptolemy II 5.2
042 *  @Pt.ProposedRating Red (cxh)
043 *  @Pt.AcceptedRating Red (cxh)
044 */
045public class FindPackages {
046    /** Look for class files under a directory and return package names.
047     *  Directories that end in adm, CVS and vendors are skipped.
048     *  @param ptII The File under which to look for classes.
049     *  @param executeCommands The ExecuteCommands object in which to report
050     *  status.  If null, then print to standard out.
051     *  @return A string of space separated package names, relative to
052     *  the File named by the ptII argument.
053     */
054    public static String findPackages(File ptII,
055            ExecuteCommands executeCommands) {
056        StringBuffer results = new StringBuffer();
057        Set directoriesSeen = new HashSet();
058        Set classFilesSeen = new HashSet();
059        String ptIIPath = ptII.getPath().replace('\\', '/');
060        if (executeCommands == null) {
061            System.out.println("Searching for .class files in " + ptIIPath);
062        } else {
063            executeCommands.stdout("Searching for .class files in " + ptIIPath);
064        }
065        _getDirectories(ptII, directoriesSeen, classFilesSeen);
066        Set packages = new HashSet();
067        Iterator classFiles = classFilesSeen.iterator();
068        while (classFiles.hasNext()) {
069            File files[] = (File[]) classFiles.next();
070            for (File file : files) {
071                String fullPath = file.toString().replace('\\', '/');
072                String shortPath = fullPath.substring(0,
073                        file.toString().length() - 6);
074                if (shortPath.startsWith(ptIIPath)) {
075                    shortPath = shortPath.substring(ptIIPath.length() + 1);
076                }
077                shortPath = shortPath.substring(0, shortPath.lastIndexOf('/'));
078                String packageName = shortPath.replace('/', '.');
079                if (!packages.contains(packageName)) {
080                    packages.add(packageName);
081                    results.append(" " + packageName);
082                }
083            }
084        }
085        if (executeCommands == null) {
086            System.out.println(results.toString());
087        } else {
088            executeCommands.stdout(results.toString());
089        }
090        return results.toString();
091    }
092
093    /** Print out any packages found under the directory named
094     *  by the first argument.
095     *  <p>Usage: java -classpath $PTII ptolemy.vergil.actor.FindPackages $PTII
096     *  @param args An array of Strings, where the first argument is
097     *  a string that names the directory under which we search for packages.
098     */
099    public static void main(String[] args) {
100        findPackages(new File(args[0]), null);
101    }
102
103    ///////////////////////////////////////////////////////////////////
104    ////                         private methods                   ////
105
106    /** Recursively descend the filesystem.
107     *  Directories that end in adm, CVS and vendors are skipped.
108     *  @param directory  The top level directory.
109     *  @param directoriesSeen A Set of objects of type File
110     *  that name directories that have been seen.
111     */
112    private static void _getDirectories(File directory, Set directoriesSeen,
113            Set classFilesSeen) {
114        File directories[] = directory.listFiles(new DirectoryFileFilter());
115        // Coverity Scan: Dereference null value returns.  directories could be null.
116        if (directories != null) {
117            for (int i = 0; i < directories.length; i++) {
118                if (!directoriesSeen.contains(directories[i])
119                        && !directories[i].getName().endsWith("adm")
120                        && !directories[i].getName().endsWith("CVS")
121                        && !directories[i].getName().endsWith("vendors")) {
122                    File classFiles[] = directories[i]
123                            .listFiles(new ClassFileFilter());
124                    classFilesSeen.add(classFiles);
125                    directoriesSeen.add(directories[i]);
126                    _getDirectories(directories[i], directoriesSeen,
127                            classFilesSeen);
128                }
129            }
130        }
131    }
132
133    /** Filter that returns true if the pathname ends with .class. */
134    private static class ClassFileFilter implements FileFilter {
135        /** Filter that returns true if the file name ends with .class.
136         *  @param pathname The pathname to be checked
137         *  @return true if the pathname ends with .class.
138         */
139        @Override
140        public boolean accept(File pathname) {
141            return pathname.getName().endsWith(".class");
142        }
143    }
144
145    /** Filter that returns true if the pathname is a directory. */
146    private static class DirectoryFileFilter implements FileFilter {
147        /** Filter that returns true if the pathname is a directory.
148         *  @param pathname The pathname to be checked
149         *  @return true if the pathname is a directory.
150         */
151        @Override
152        public boolean accept(File pathname) {
153            return pathname.isDirectory();
154        }
155    }
156
157}