001package org.jadira.scanner.classpath.projector;
002
003import java.io.File;
004import java.io.FileFilter;
005import java.io.FilenameFilter;
006import java.io.IOException;
007import java.util.ArrayList;
008import java.util.Arrays;
009import java.util.Enumeration;
010import java.util.HashMap;
011import java.util.List;
012import java.util.Map;
013import java.util.jar.JarEntry;
014import java.util.jar.JarFile;
015
016import org.jadira.scanner.core.api.Projector;
017import org.jadira.scanner.core.exception.ClasspathAccessException;
018
019import de.schlichtherle.io.archive.zip.ZipEntry;
020import de.schlichtherle.util.zip.ZipFile;
021
022public class ClasspathProjector implements Projector<File> {
023
024    public static final ClasspathProjector SINGLETON = new ClasspathProjector();
025    
026    private static final Map<File, List<File>> PROJECTION_CACHE = new HashMap<File, List<File>>();
027
028    public ClasspathProjector() {
029        // TODO Preload the projection cache if possible
030    }
031    
032    @Override
033        public List<File> project(File segment) {
034
035            List<File> files = PROJECTION_CACHE.get(segment);
036            if (files != null) {
037                return files;
038            }
039            
040        files = new ArrayList<File>();
041        boolean isArchive = false;
042        
043        if (segment instanceof de.schlichtherle.io.File) {
044            if (((de.schlichtherle.io.File)segment).isArchive()) {
045                isArchive = true;
046            }
047        }
048            
049//          if (segment.toString().startsWith(System.getProperty("java.home"))) {               
050//              String cacheFileKey = buildFileKey(segment);
051//              ClassLoader[] classLoaders = ClassLoaderUtils.getClassLoaders();
052//              
053//              for (ClassLoader cl : classLoaders) {
054//                  
055//                  InputStream is = null;
056//                  InputStreamReader isr = null;
057//                  BufferedReader br = null;
058//                  try {
059//                      is = cl.getResourceAsStream(cacheFileKey);
060//                    if (is != null) {
061//                        isr = new InputStreamReader(is);
062//                          br = new BufferedReader(isr, 16384);
063//                          String nextLine;
064//                          try {
065//                            while ((nextLine = br.readLine()) != null) {
066//                                files.add(new de.schlichtherle.io.File(segment.getPath() + System.getProperty("file.separator") + nextLine));
067//                            }
068//                        } catch (IOException e) {
069//                            throw new ClasspathAccessException("Could not open Cached File List: " + e.getMessage(), e);
070//                        }
071//                        PROJECTION_CACHE.put(segment, files);
072//                        return files;
073//                      }
074//                  } finally {
075//                      if (is != null) {
076//                          try {
077//                            is.close();
078//                        } catch (IOException e) {
079//                        }
080//                      }
081//                      if (isr != null) {
082//                        try {
083//                            isr.close();
084//                        } catch (IOException e) {
085//                        }
086//                    }
087//                      if (br != null) {
088//                        try {
089//                            br.close();
090//                        } catch (IOException e) {
091//                        }
092//                    }
093//                  }
094//              }
095//            projectCachedJavaHome(segment);
096//          }
097            
098            if (!isArchive) {
099                
100                File[] dirs = segment.listFiles(new FileFilter() {
101                        
102                        @Override
103                        public boolean accept(File file) {
104                                return file.isDirectory();
105                        }
106                });
107                
108                for (File dir : dirs) {
109                        files.addAll(project(dir));
110                }
111                
112                File[] classes = segment.listFiles(new FileFilter() {
113                        
114                        @Override
115                        public boolean accept(File file) {
116                                return !file.isDirectory() && file.getName().endsWith(".class");
117                        }
118                });
119                files.addAll(Arrays.asList(classes));
120                
121            } else if (segment.getPath().endsWith("jar")) { // else if ("jar".equals(((de.schlichtherle.io.File)segment).getArchiveDetector().getScheme(segment.getPath()).toString())) {
122                
123                JarFile jarFile = null;
124            try {
125                jarFile = new JarFile(segment.getPath());
126                Enumeration<JarEntry> entries = jarFile.entries();
127                while (entries.hasMoreElements()) {
128                    JarEntry next = entries.nextElement();
129                    if (next.getName().endsWith(".class")) {
130                        files.add(new de.schlichtherle.io.File(segment.getPath() + System.getProperty("file.separator") + next.getName()));
131                    }
132                }
133            } catch (IOException e) {
134                throw new ClasspathAccessException("Could not open JarFile: " + e.getMessage(), e);
135            } finally {
136                if (jarFile != null) {
137                    try {
138                        jarFile.close();
139                    } catch (IOException e) {
140                        // Ignore this
141                    }
142                }
143            }
144        } else if (segment.getPath().endsWith("zip")) { // else if ("zip".equals(((TFile)segment).getArchiveDetector().getScheme(segment.getPath()).toString())) {
145            ZipFile zipFile = null;
146            try {
147                zipFile = new ZipFile(segment.getPath());
148                @SuppressWarnings("unchecked")
149                Enumeration<ZipEntry> entries = zipFile.entries();
150                while (entries.hasMoreElements()) {
151                    ZipEntry next = entries.nextElement();
152                    if (next.getName().endsWith(".class")) {
153                        files.add(new de.schlichtherle.io.File(segment.getPath()  + System.getProperty("file.separator") + next.getName()));
154                    }
155                }
156            } catch (IOException e) {
157                throw new ClasspathAccessException("Could not open ZipFile: " + e.getMessage(), e);
158            } finally {
159                if (zipFile != null) {
160                    try {
161                        zipFile.close();
162                    } catch (IOException e) {
163                        // Ignore this
164                    }
165                }
166            }
167            } else {
168                
169            File[] classes = ((de.schlichtherle.io.File)segment).listFiles(new FilenameFilter() {
170
171                @Override
172                public boolean accept(File dir, String name) {
173                    return name.endsWith(".class");
174                }
175            });
176            files.addAll(Arrays.asList(classes));
177            }
178            PROJECTION_CACHE.put(segment, files);
179                return files;
180        }
181
182//    private String buildFileKey(File segment) {
183//        return ((("java-" 
184//           + System.getProperty("java.vendor") 
185//           + "-" 
186//           + System.getProperty("java.version") 
187//           + (segment.toString().substring(System.getProperty("java.home").length())))
188//               .replace('/', '_')
189//               .replace('\\', '_')
190//               .replace(' ', '_')
191//               .replace('.', '_')) + ".classes");
192//    }
193//
194//    private void projectCachedJavaHome(File segment) {
195//
196//        StringBuilder sb = new StringBuilder(buildFileKey(segment));
197//        sb.append(System.getProperty("line.separator"));
198//        sb.append(System.getProperty("line.separator"));
199//        JarFile jarFile = null;
200//        try {
201//            jarFile = new JarFile(segment.getPath());
202//            Enumeration<JarEntry> entries = jarFile.entries();
203//            while (entries.hasMoreElements()) {
204//                JarEntry next = entries.nextElement();
205//                if (next.getName().endsWith(".class")) {
206//                    sb.append(next.getName());
207//                    sb.append(System.getProperty("line.separator"));
208//                }
209//            }
210//        } catch (IOException e) {
211//            throw new ClasspathAccessException("Could not open JarFile: " + e.getMessage(), e);
212//        } finally {
213//            if (jarFile != null) {
214//                try {
215//                    jarFile.close();
216//                } catch (IOException e) {
217//                    // Ignore this
218//                }
219//            }
220//        }
221//        sb.append(System.getProperty("line.separator"));
222//        sb.append(System.getProperty("line.separator"));
223//        System.err.println(sb);
224//    }
225}