/******************************************************************************* * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Exadel, Inc. and Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.model.util; import java.io.*; import java.util.*; import java.util.jar.*; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.model.XModelObjectConstants; import org.jboss.tools.common.model.plugin.ModelPlugin; public class AccessibleJava implements ISimpleTree { private static AccessibleJava instance = null; public static interface IContextPackageProvider { public void setObject(XModelObject object); public String getContextPackage(); } public static AccessibleJava getInstance() { if(instance == null) instance = new AccessibleJava(); return instance; } public static String getClassPath() { StringBuffer sb = new StringBuffer(); String[] s = new String[0]; for (int i = 0; i < s.length; i++) sb.append(File.pathSeparator).append(s[i]); return sb.toString(); } private Map<String,JarFile> jarsmap = null; private Map<String,SortedSet<String>> map = null; private File[] folders = null; private HashSet<String> checkedpackages = new HashSet<String>(); private AccessibleJava() { load(); } private String getJavaLib() { String rt = System.getProperty("java.home") + "/lib/rt.jar"; //$NON-NLS-1$ //$NON-NLS-2$ return rt; } protected String extension() { return ".class"; //$NON-NLS-1$ } private void load() { map = new HashMap<String,SortedSet<String>>(); jarsmap = new HashMap<String,JarFile>(); addJars(getJavaLib()); String paths = getClassPath(); addJars(paths); Iterator c = jarsmap.values().iterator(); while(c.hasNext()) loadJar((JarFile)c.next()); jarsmap = null; addFolders(paths); } private void addJars(String paths) { StringTokenizer st = new StringTokenizer(paths, File.pathSeparator); while(st.hasMoreTokens()) { String t = st.nextToken().trim(); try { addJar(new JarFile(t)); } catch (IOException e) { ModelPlugin.getPluginLog().logError("addJars:" + e.getClass().getName()); //$NON-NLS-1$ } } } private void addJar(JarFile jf) throws IOException { String n = new File(jf.getName()).getCanonicalPath(); if(jarsmap.get(n) != null) return; jarsmap.put(n, jf); addJarManifest(jf); } private void loadJar(JarFile jar) { Enumeration e = jar.entries(); while(e.hasMoreElements()) { Object o = e.nextElement(); if(!(o instanceof JarEntry)) continue; JarEntry je = (JarEntry)o; register(je.getName(), map); } try { jar.close(); } catch (IOException exc) { ModelPlugin.getPluginLog().logError("AccessibleJava:Cannot close jar."); //$NON-NLS-1$ } } private static String[] serviceroots = {"CVS/", "META-INF/", ".svn"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ private void register(String path, Map<String,SortedSet<String>> map) { if(path == null || path.indexOf("$") >= 0 || path.equals(XModelObjectConstants.SEPARATOR)) return; //$NON-NLS-1$ for (int j = 0; j < serviceroots.length; j++) if(path.indexOf(serviceroots[j]) >= 0) return; boolean isPackage = path.endsWith(XModelObjectConstants.SEPARATOR); if(!(isPackage || path.endsWith(extension()))) return; if(path.startsWith(XModelObjectConstants.SEPARATOR)) path = path.substring(1); path = path.substring(0, path.length() - ((isPackage) ? 1 : 6)).replace('/', '.'); register0(path, isPackage, map); } public String[] getContent(String packagename) { checkfolders(packagename); SortedSet<String> list = map.get(packagename); return (list == null) ? null : list.toArray(new String[list.size()]); } private void register0(String path, boolean isPackage, Map<String,SortedSet<String>> map) { String parent, name; int i = path.lastIndexOf('.'); if(i > 0) { parent = path.substring(0, i); name = path.substring(i + 1); } else { parent = "%root%"; //$NON-NLS-1$ name = path; } if(!isJavaName(name)) return; SortedSet<String> list = map.get(parent); if(list == null) { list = new TreeSet<String>(); map.put(parent, list); } String pname = name + "."; //$NON-NLS-1$ if(list.contains(name) || list.contains(pname)) return; list.add((isPackage) ? pname : name); if(i > 0) register0(parent, true, map); } boolean isJavaName(String name) { if(name.length() == 0) return false; if(!Character.isJavaIdentifierStart(name.charAt(0))) return false; for (int i = 1; i < name.length(); i++) { if(!Character.isJavaIdentifierPart(name.charAt(i))) return false; } return true; } private void addFolders(String paths) { StringTokenizer st = new StringTokenizer(paths, File.pathSeparator); ArrayList<File> l = new ArrayList<File>(); while(st.hasMoreTokens()) { String t = st.nextToken().trim(); if(t.length() == 0 || t.indexOf('~') >= 0) continue; File f = new File(t); if(f.isDirectory()) l.add(f); } folders = l.toArray(new File[l.size()]); for (int i = 0; i < folders.length; i++) { File[] fs = folders[i].listFiles(); if(fs != null) for (int j = 0; j < fs.length; j++) { if(fs[j].isDirectory()) register(fs[j].getName() + XModelObjectConstants.SEPARATOR, map); } } } private void checkfolders(String pkg) { if(checkedpackages.contains(pkg)) return; checkedpackages.add(pkg); for (int i = 0; i < folders.length; i++) loadfolder(folders[i], pkg); int i = pkg.lastIndexOf('.'); if(i >= 0) checkfolders(pkg.substring(0, i)); } private void loadfolder(File f, String pkg) { String p = pkg.replace('.', '/'); File pf = new File(f.getAbsolutePath() + '/' + p); if(!pf.exists()) return; File[] fs = pf.listFiles(); if(fs != null) for (int i = 0; i < fs.length; i++) { String n = fs[i].getName(); if(fs[i].isDirectory()) register(p + '/' + n + '/', map); else if(n.endsWith(extension())) register(p + '/' + n, map); } } private void addJarManifest(JarFile jf) throws IOException { Manifest m = jf.getManifest(); Attributes as = m.getMainAttributes(); String classpath = as.getValue("Class-Path"); //$NON-NLS-1$ if(classpath == null) return; String r = new File(jf.getName()).getParentFile().getCanonicalPath() + File.separatorChar; StringTokenizer st = new StringTokenizer(classpath, " "); //$NON-NLS-1$ StringBuffer sb = new StringBuffer(); while(st.hasMoreElements()) { String t = st.nextToken().trim(); if(t.length() > 0) sb.append(r).append(t).append(File.pathSeparator); } addJars(sb.toString()); } }