001    package AST;
002    
003    import java.util.HashSet;
004    import java.io.File;
005    import java.util.*;
006    import beaver.*;
007    import java.util.ArrayList;
008    import java.util.zip.*;
009    import java.io.*;
010    import java.io.FileNotFoundException;
011    import java.util.Collection;
012    
013    /**
014      * @ast class
015     * 
016     */
017    public class FolderPart extends PathPart {
018    
019    
020        /**
021         * Maps package names to a collection of the names of files in
022         * the corresponding package directory.
023         */
024        private Map<String, Collection<String>> packageMap =
025          new HashMap<String, Collection<String>>();
026    
027    
028    
029        /**
030         * The root folder of this path part.
031         */
032        private final File folder;
033    
034    
035    
036        public FolderPart(File folder) {
037          this.folder = folder;
038        }
039    
040    
041    
042        /**
043         * @param name The qualified package name
044         * @return <code>true</code> if the given package exists in this source
045         * folder
046         */
047        public boolean hasPackage(String name) {
048          return !filesInPackage(name).isEmpty();
049        }
050    
051    
052    
053        public boolean hasCompilationUnit(String canonicalName) {
054          int index = canonicalName.lastIndexOf('.');
055          String packageName = index == -1 ? "" : canonicalName.substring(0, index);
056          String typeName = canonicalName.substring(index + 1, canonicalName.length());
057          String fileName = typeName + fileSuffix();
058          return filesInPackage(packageName).contains(fileName);
059        }
060    
061    
062        
063        /**
064         * We need to use getCanonicalFile in order to get the case-sensitive
065         * package name on case-insensitive file systems or we might incorrectly
066         * report a package name conflict.
067         *
068         * NB: This does not work well with symlinks!
069         *
070         * @param packageName The qualified name of the package
071         * @return The names of the files and folders in the package
072         */
073        private Collection<String> filesInPackage(String packageName) {
074          if (!packageMap.containsKey(packageName)) {
075            int index = packageName.lastIndexOf('.');
076            String name = packageName.substring(index == -1 ? 0 : index+1);
077            String folderName = packageName.replace('.', File.separatorChar);
078            File pkgFolder = new File(folder, folderName);
079            Collection<String> fileSet = Collections.emptyList();
080            try {
081              // Make sure that there exists a directory with the same name
082              // (case-sensitive) as the requested package
083              File canonical = pkgFolder.getCanonicalFile();
084              if (canonical.isDirectory() && (packageName.isEmpty() ||
085                    canonical.getName().equals(name))) {
086                String[] files = canonical.list();
087                if (files.length > 0) {
088                  fileSet = new HashSet<String>();
089                  for (String file: files) {
090                    fileSet.add(file);
091                  }
092                }
093              }
094            } catch (Exception e) {
095              // Catch IOExceptions etc.
096              // if the exception was thrown by getCanonicalFile we will put
097              // the empty list in the packageMap, indicating that the package
098              // does not exist
099            }
100            packageMap.put(packageName, fileSet);
101          }
102          return packageMap.get(packageName);
103        }
104    
105    
106        
107        public boolean selectCompilationUnit(String canonicalName) throws IOException {
108          if(hasCompilationUnit(canonicalName)) {
109            String typeName = canonicalName.replace('.', File.separatorChar);
110            String fileName = typeName + fileSuffix();
111            File classFile = new File(folder, fileName);
112            if(classFile.isFile()) {
113              is = new FileInputStream(classFile);
114              age = classFile.lastModified();
115              pathName = classFile.getPath();
116              relativeName = fileName + fileSuffix();
117              fullName = canonicalName;
118              return true;
119            }
120          }
121          return false;
122        }
123    
124    
125    
126        @Override
127        public String toString() {
128          return folder.toString();
129        }
130    
131    
132    }