001    package org.extendj.ast;
002    
003    import java.util.HashSet;
004    import java.io.File;
005    import java.util.Set;
006    import java.util.Collections;
007    import java.util.Collection;
008    import java.util.ArrayList;
009    import beaver.*;
010    import java.util.*;
011    import java.io.ByteArrayOutputStream;
012    import java.io.PrintStream;
013    import java.lang.reflect.InvocationTargetException;
014    import java.lang.reflect.Method;
015    import org.jastadd.util.*;
016    import java.util.zip.*;
017    import java.io.*;
018    import org.jastadd.util.PrettyPrintable;
019    import org.jastadd.util.PrettyPrinter;
020    import java.io.FileNotFoundException;
021    import java.io.BufferedInputStream;
022    import java.io.DataInputStream;
023    /**
024     * @ast class
025     * @aspect PathPart
026     * @declaredat /home/jesper/git/extendj/java4/frontend/PathPart.jadd:510
027     */
028    public class JarFilePath extends PathPart {
029      
030        private Collection<String> packageIndex = null;
031    
032      
033        private final ZipFile jar;
034    
035      
036        private final String jarPath;
037    
038      
039    
040        public JarFilePath(String jarPath) throws IOException {
041          super(false);
042          this.jar = new ZipFile(jarPath);
043          this.jarPath = jarPath;
044        }
045    
046      
047    
048        public JarFilePath(File jarFile) throws IOException {
049          super(false);
050          this.jar = new ZipFile(jarFile);
051          this.jarPath = jarFile.getPath();
052        }
053    
054      
055    
056        @Override
057        public String getPath() {
058          return jarPath;
059        }
060    
061      
062    
063        private static void scanJar(ZipFile jar, Collection<String> packages,
064            String fileSuffix) {
065          // Add all zip entries to a set so that we can quickly check if the Jar
066          // contains a given class
067          for (Enumeration entries = jar.entries(); entries.hasMoreElements(); ) {
068            ZipEntry entry = (ZipEntry) entries.nextElement();
069            String path = entry.getName();
070            if (path.endsWith(fileSuffix)) {
071              addPackages(packages, path);
072            }
073          }
074        }
075    
076      
077    
078        private static void addPackages(Collection<String> packages, String path) {
079          String name = path.replace('/', '.');
080          int index = path.length();
081          do {
082            index = path.lastIndexOf('/', index-1);
083          } while (index >= 0 && packages.add(name.substring(0, index)));
084        }
085    
086      
087    
088        /**
089         * Caches the package index from the Jar file so that subsequent calls to
090         * this method are quicker.
091         */
092        @Override
093        public boolean hasPackage(String name) {
094          synchronized (this) {
095            if (packageIndex == null) {
096              packageIndex = new HashSet<String>();
097              scanJar(jar, packageIndex, fileSuffix);
098            }
099          }
100          return packageIndex.contains(name);
101        }
102    
103      
104    
105        @Override
106        public ClassSource findSource(String name) {
107          // ZipFiles always use '/' as separator
108          String jarName = name.replace('.', '/') + fileSuffix;
109          ZipEntry entry = jar.getEntry(jarName);
110          if (entry != null) {
111            return new JarClassSource(this, jar, entry, jarPath);
112          } else {
113            return ClassSource.NONE;
114          }
115        }
116    
117      
118    
119        @Override
120        public String toString() {
121          return "jar:" + jarPath;
122        }
123    
124    
125    }