package jqian.util; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashSet; import java.util.Enumeration; import java.util.Set; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * Find java classes either in .java format or in .class format. * Directory structures are understood as the package sturcture */ class JavaClassFinder { private Object[] _dirs; private String _ext; private Set<String> _classes; /** * @param srcpath path separated with ';' that contain the .java files * zip, jar files are also supported */ public JavaClassFinder(String srcpath, String ext){ this._ext = ext; String[] paths = srcpath.split(";"); _dirs = new Object[paths.length]; int index = 0; for(String p: paths){ p = p.trim(); File file = new File(p); if(file.isDirectory()){ _dirs[index] = file; } else if(file.exists()){ try{ if(file.getName().contains(".zip")){ _dirs[index] = new ZipFile(file); } else if(file.getName().contains(".jar")){ _dirs[index] = new JarFile(file); } else{ throw new RuntimeException("Unsupported format: "+file); } } catch(IOException e){ throw new RuntimeException(e.getMessage()); } } index++; } } public InputStream findClass(String classname){ try{ for(Object o: _dirs){ if(o==null){ } else if(o instanceof File){ File file = (File)o; File javafile = findFile(file,classname); if(javafile!=null){ InputStream is = new FileInputStream(javafile); if(is!=null){ return is; } } } else if(o instanceof ZipFile){ ZipFile zip = (ZipFile)o; InputStream is = findFile(zip,classname); if(is!=null){ return is; } } else if(o instanceof JarFile){ JarFile jar = (JarFile)o; InputStream is = findFile(jar,classname); if(is!=null){ return is; } } } } catch(Exception e){} return null; } private File findFile(File directory, String target){ StringBuffer path = new StringBuffer(target); int length = path.length(); for(int i=0; i<length; i++){ if(path.charAt(i)=='.'){ path.setCharAt(i, File.separatorChar); } } String tgtPath = directory.getPath() + File.separatorChar + path + _ext; directory = new File(tgtPath); if(directory.exists()){ return directory; } else{ return null; } /*while(target!=null){ int sp = target.indexOf('.'); String fname = null; if(sp<0){ fname = target + _ext; target = null; } else{ fname = target.substring(0,sp); target = target.substring(sp+1); } File[] contents = directory.listFiles(); File found = null; for(File f: contents){ if(f.getName().equals(fname)){ found = f; } } if(found==null){ return null; } directory = found; } return directory;*/ } private InputStream findFile(ZipFile zip, String target){ StringBuffer filename = new StringBuffer(target); for(int i=0; i<target.length(); i++){ if(target.charAt(i)=='.'){ filename.setCharAt(i, '/'); } } filename.append(_ext); ZipEntry entry = zip.getEntry(filename.toString()); if(entry==null){ return null; } try{ InputStream is = zip.getInputStream(entry); return is; }catch(IOException e){} return null; } /** Here only list classes with their names as the names of the .java file. * Inner classes and the second, third, .. classes share the same .java file with * other classes are not considered. */ public Set<String> listClasses(){ if(_classes!=null){ return _classes; } _classes = new HashSet<String>(); try{ for(Object o: _dirs){ if(o==null){ } else if(o instanceof File){ File file = (File)o; listClasses(file,file,_classes); } else if(o instanceof ZipFile){ ZipFile zip = (ZipFile)o; listClasses(zip, _classes); } else if(o instanceof JarFile){ JarFile jar = (JarFile)o; listClasses(jar, _classes); } } } catch(Exception e){} return _classes; } private void listClasses(File root, File file, Set<String> out) throws IOException{ if(!file.isDirectory()){ if(file.getName().endsWith(_ext)){ String fullpath = file.getCanonicalPath(); String rootpath; if(root.isDirectory()){ rootpath = root.getCanonicalPath(); } else{ rootpath = root.getParentFile().getCanonicalPath(); } rootpath = rootpath + File.separatorChar; String classpath = fullpath.substring(rootpath.length(),fullpath.length()-_ext.length()); StringBuffer classname = new StringBuffer(classpath); for(int i=0; i<classpath.length();i++){ if(classname.charAt(i)==File.separatorChar){ classname.setCharAt(i, '.'); } } out.add(classname.toString()); } } else{ File[] contents = file.listFiles(); for(File f: contents){ listClasses(root, f, out); } } } private void listClasses(ZipFile zip, Set<String> out) throws IOException{ for (Enumeration<?> e = zip.entries(); e.hasMoreElements() ;) { ZipEntry entry = (ZipEntry)e.nextElement(); String name = entry.getName(); if(!entry.isDirectory() && name.endsWith(_ext)){ StringBuffer namebuf = new StringBuffer(name); namebuf.setLength(name.length()-_ext.length()); int length = namebuf.length(); for(int i=0; i<length; i++){ if(namebuf.charAt(i)=='/'){ namebuf.setCharAt(i, '.'); } } out.add(namebuf.toString()); } } } }