Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.sigil.eclipse.model.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.regex.Pattern; import org.apache.felix.sigil.common.config.Resource; import org.apache.felix.sigil.common.model.IModelElement; import org.apache.felix.sigil.common.model.IModelWalker; import org.apache.felix.sigil.common.model.ModelElementFactory; import org.apache.felix.sigil.common.model.eclipse.ISigilBundle; import org.apache.felix.sigil.common.model.osgi.IBundleModelElement; import org.apache.felix.sigil.common.model.osgi.IPackageExport; import org.apache.felix.sigil.common.model.osgi.IPackageImport; import org.apache.felix.sigil.common.model.osgi.IRequiredBundle; import org.apache.felix.sigil.common.osgi.VersionRange; import org.apache.felix.sigil.common.repository.IRepositoryManager; import org.apache.felix.sigil.common.repository.IResolution; import org.apache.felix.sigil.common.repository.ResolutionConfig; import org.apache.felix.sigil.common.repository.ResolutionException; import org.apache.felix.sigil.eclipse.PathUtil; import org.apache.felix.sigil.eclipse.SigilCore; import org.apache.felix.sigil.eclipse.model.project.ISigilProjectModel; import org.apache.felix.sigil.eclipse.progress.ProgressAdapter; import org.apache.felix.sigil.eclipse.repository.ResolutionMonitorAdapter; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.content.IContentDescription; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.core.runtime.content.IContentTypeManager; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jdt.core.IAccessRule; import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.IClasspathAttribute; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IImportDeclaration; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaModel; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.ILocalVariable; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IParent; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeHierarchy; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.osgi.framework.Version; /** * @author dave * */ public class JavaHelper { public static final IAccessRule DENY_RULE = JavaCore.newAccessRule(new Path("**"), IAccessRule.K_NON_ACCESSIBLE | IAccessRule.IGNORE_IF_BETTER); public static final IAccessRule ALLOW_ALL_RULE = JavaCore.newAccessRule(new Path("**"), IAccessRule.K_ACCESSIBLE); private static Map<String, Collection<IClasspathEntry>> entryCache = new HashMap<String, Collection<IClasspathEntry>>(); public static Collection<IClasspathEntry> findClasspathEntries(ISigilBundle bundle) { LinkedList<IClasspathEntry> cp = new LinkedList<IClasspathEntry>(); ISigilProjectModel sp = bundle.getAncestor(ISigilProjectModel.class); if (sp != null) { IJavaProject p = sp.getJavaModel(); for (String enc : bundle.getClasspathEntrys()) { IClasspathEntry e = p.decodeClasspathEntry(enc); if (e != null) { cp.add(e); } } } return cp; } public static Collection<ICompilationUnit> findCompilationUnits(ISigilProjectModel project) throws JavaModelException { LinkedList<ICompilationUnit> ret = new LinkedList<ICompilationUnit>(); IJavaProject java = project.getJavaModel(); for (IClasspathEntry cp : findClasspathEntries(project.getBundle())) { IPackageFragmentRoot[] roots = java.findPackageFragmentRoots(cp); for (IPackageFragmentRoot rt : roots) { for (IJavaElement j : rt.getChildren()) { IPackageFragment p = (IPackageFragment) j; ICompilationUnit[] units = p.getCompilationUnits(); for (ICompilationUnit u : units) { ret.add(u); } } } } return ret; } /** * @param project * @param packageName * @return */ public static Collection<IPackageExport> findExportsForPackage(ISigilProjectModel project, final String packageName) { final LinkedList<IPackageExport> results = new LinkedList<IPackageExport>(); project.getRepositoryManager().visit(new IModelWalker() { public boolean visit(IModelElement element) { if (element instanceof IPackageExport) { IPackageExport e = (IPackageExport) element; if (e.getPackageName().equals(packageName)) { results.add(e); } } return true; } }); return results; } public static String[] findUses(String packageName, ISigilProjectModel projectModel) throws CoreException { ArrayList<String> uses = new ArrayList<String>(); for (final String dependency : findPackageDependencies(packageName, projectModel)) { if (!dependency.equals(packageName)) { final boolean[] found = new boolean[1]; projectModel.visit(new IModelWalker() { public boolean visit(IModelElement element) { if (element instanceof IPackageImport) { IPackageImport pi = (IPackageImport) element; if (pi.getPackageName().equals(dependency)) { found[0] = true; } } return !found[0]; } }); if (found[0]) { uses.add(dependency); } } } return uses.toArray(new String[uses.size()]); } private static String[] findPackageDependencies(String packageName, ISigilProjectModel projectModel) throws CoreException { HashSet<String> imports = new HashSet<String>(); IPackageFragment p = (IPackageFragment) projectModel.getJavaModel() .findElement(new Path(packageName.replace('.', '/'))); if (p == null) { throw SigilCore.newCoreException("Unknown package " + packageName, null); } for (ICompilationUnit cu : p.getCompilationUnits()) { scanImports(cu, imports); } for (IClassFile cf : p.getClassFiles()) { scanImports(cf, imports); } return imports.toArray(new String[imports.size()]); } /** * @param project * @param monitor * @return */ public static List<IPackageImport> findRequiredImports(ISigilProjectModel project, IProgressMonitor monitor) { LinkedList<IPackageImport> imports = new LinkedList<IPackageImport>(); Set<String> names = findJavaImports(project, monitor); if (!monitor.isCanceled()) { for (String packageName : names) { if (!ProfileManager.isBootDelegate(project, packageName)) { // these must come from boot classloader try { if (!project.isInClasspath(packageName, monitor)) { Collection<IPackageExport> exports = findExportsForPackage(project, packageName); if (!exports.isEmpty()) { imports.add(select(exports)); } } } catch (CoreException e) { SigilCore.error("Failed to check classpath", e); } } } } return imports; } /** * @param project * @param monitor * @return */ public static Collection<IModelElement> findUnusedReferences(final ISigilProjectModel project, final IProgressMonitor monitor) { final LinkedList<IModelElement> unused = new LinkedList<IModelElement>(); final Set<String> packages = findJavaImports(project, monitor); if (!monitor.isCanceled()) { project.visit(new IModelWalker() { public boolean visit(IModelElement element) { if (element instanceof IPackageImport) { IPackageImport pi = (IPackageImport) element; if (!packages.contains(pi.getPackageName())) { unused.add(pi); } } else if (element instanceof IRequiredBundle) { IRequiredBundle rb = (IRequiredBundle) element; IRepositoryManager manager = project.getRepositoryManager(); ResolutionConfig config = new ResolutionConfig( ResolutionConfig.INCLUDE_OPTIONAL | ResolutionConfig.IGNORE_ERRORS); try { IResolution r = manager.getBundleResolver().resolve(rb, config, new ResolutionMonitorAdapter(monitor)); ISigilBundle bundle = r.getProvider(rb); boolean found = false; for (IPackageExport pe : bundle.getBundleInfo().getExports()) { if (packages.contains(pe.getPackageName())) { found = true; break; } } if (!found) { unused.add(rb); } } catch (ResolutionException e) { SigilCore.error("Failed to resolve " + rb, e); } } return !monitor.isCanceled(); } }); } return unused; } public static Collection<IClasspathEntry> resolveClasspathEntrys(ISigilProjectModel sigil, IProgressMonitor monitor) throws CoreException { if (monitor == null) { monitor = Job.getJobManager().createProgressGroup(); monitor.beginTask("Resolving classpath for " + sigil.getSymbolicName(), 2); } ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(); ResolutionConfig config = new ResolutionConfig( ResolutionConfig.INCLUDE_OPTIONAL | ResolutionConfig.IGNORE_ERRORS | ResolutionConfig.INDEXED_ONLY | ResolutionConfig.LOCAL_ONLY | ResolutionConfig.COMPILE_TIME); IResolution resolution; try { resolution = sigil.getRepositoryManager().getBundleResolver().resolve(sigil, config, new ResolutionMonitorAdapter(monitor)); } catch (ResolutionException e) { throw SigilCore.newCoreException("Failed to resolve dependencies", e); } monitor.worked(1); Set<ISigilBundle> bundles = resolution.getBundles(); for (ISigilBundle bundle : bundles) { if (!sigil.getSymbolicName().equals(bundle.getBundleInfo().getSymbolicName())) { // discard self reference... List<IModelElement> matched = resolution.getMatchedRequirements(bundle); for (IClasspathEntry cpe : buildClassPathEntry(sigil, bundle, bundles, matched, monitor)) { entries.add(cpe); } } } Collections.sort(entries, new Comparator<IClasspathEntry>() { public int compare(IClasspathEntry o1, IClasspathEntry o2) { return o1.toString().compareTo(o2.toString()); } }); monitor.worked(1); monitor.done(); return entries; } private static Collection<IClasspathEntry> buildClassPathEntry(ISigilProjectModel project, ISigilBundle provider, Set<ISigilBundle> all, List<IModelElement> requirements, IProgressMonitor monitor) throws CoreException { IAccessRule[] rules = buildAccessRules(project, provider, all, requirements); IClasspathAttribute[] attrs = new IClasspathAttribute[0]; ISigilProjectModel other = provider.getAncestor(ISigilProjectModel.class); try { if (other == null) { provider.synchronize(new ProgressAdapter(monitor)); return newBundleEntry(provider, rules, attrs, false); } else { return newProjectEntry(other, rules, attrs, false); } } catch (IOException e) { throw SigilCore.newCoreException("Failed to synchronize " + provider, e); } } private static Collection<IClasspathEntry> newProjectEntry(ISigilProjectModel n, IAccessRule[] rules, IClasspathAttribute[] attributes, boolean export) throws CoreException { ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(); entries.add(JavaCore.newProjectEntry(n.getProject().getFullPath(), rules, false, attributes, export)); for (IClasspathEntry e : n.getJavaModel().getRawClasspath()) { String encoded = n.getJavaModel().encodeClasspathEntry(e); if (n.getBundle().getClasspathEntrys().contains(encoded)) { switch (e.getEntryKind()) { case IClasspathEntry.CPE_LIBRARY: entries.add(JavaCore.newLibraryEntry(e.getPath(), e.getSourceAttachmentPath(), e.getSourceAttachmentRootPath(), rules, attributes, export)); break; case IClasspathEntry.CPE_VARIABLE: IPath path = JavaCore.getResolvedVariablePath(e.getPath()); if (path != null) { IPath spath = e.getSourceAttachmentPath(); if (spath != null) { spath = JavaCore.getResolvedVariablePath(spath); } entries.add(JavaCore.newLibraryEntry(path, spath, e.getSourceAttachmentRootPath(), rules, attributes, export)); } break; } } } return entries; } private static Collection<IClasspathEntry> newBundleEntry(ISigilBundle bundle, IAccessRule[] rules, IClasspathAttribute[] attributes, boolean exported) throws CoreException { String name = bundle.getBundleInfo().getSymbolicName(); if (bundle.getBundleInfo().getVersion() != null) { name += "_version_" + bundle.getBundleInfo().getVersion(); } String cacheName = name + rules.toString(); Collection<IClasspathEntry> entries = null; synchronized (entryCache) { entries = entryCache.get(cacheName); if (entries == null) { IPath path = PathUtil.newPathIfExists(bundle.getLocation()); if (path == null) { SigilCore.error("Found null path for " + bundle.getSymbolicName()); entries = Collections.emptyList(); } else { entries = buildEntries(path, name, bundle, rules, attributes, exported); } entryCache.put(cacheName, entries); } } return entries; } private static IPath bundleCache = SigilCore.getDefault().getStateLocation().append("bundle-cache"); public static boolean isCachedBundle(String bp) { return bp.startsWith(bundleCache.toOSString()); } private static Collection<IClasspathEntry> buildEntries(IPath path, String name, ISigilBundle bundle, IAccessRule[] rules, IClasspathAttribute[] attributes, boolean exported) throws CoreException { if (path.toFile().isDirectory()) { throw SigilCore.newCoreException("Bundle location cannot be a directory", null); } else { // ok it's a jar could contain libs etc try { IPath cache = bundleCache.append(name); Collection<String> classpath = bundle.getBundleInfo().getClasspaths(); ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(classpath.size()); IPath source = PathUtil.newPathIfExists(bundle.getSourcePathLocation()); IPath rootPath = PathUtil.newPathIfNotNull(bundle.getSourceRootPath()); if (source != null && !source.toFile().exists()) { source = null; } if (!classpath.isEmpty()) { unpack(cache, bundle, classpath); for (String cp : classpath) { IPath p = ".".equals(cp) ? path : cache.append(cp); if (p.toFile().exists()) { IClasspathEntry e = JavaCore.newLibraryEntry(p, source, rootPath, rules, attributes, exported); entries.add(e); } } } else { // default classpath is . IClasspathEntry e = JavaCore.newLibraryEntry(path, source, rootPath, rules, attributes, exported); entries.add(e); } return entries; } catch (IOException e) { throw SigilCore.newCoreException("Failed to unpack bundle", e); } } } private static HashMap<IPath, Collection<String>> unpacked = new HashMap<IPath, Collection<String>>(); private static synchronized void unpack(IPath cache, ISigilBundle bundle, Collection<String> classpath) throws IOException { Collection<String> check = unpacked.get(cache); if (check == null || !check.equals(classpath)) { if (classpath.size() == 1 && classpath.contains(".")) { unpacked.put(cache, classpath); } else { // trim . from path to avoid check later in inClasspath check = new HashSet<String>(classpath); check.remove("."); File dir = createEmptyDir(cache); FileInputStream fin = null; try { fin = new FileInputStream(bundle.getLocation()); JarInputStream in = new JarInputStream(fin); JarEntry entry; while ((entry = in.getNextJarEntry()) != null) { if (inClasspath(check, entry)) { File f = new File(dir, entry.getName()); if (entry.isDirectory()) { createDir(f); } else { try { File p = f.getParentFile(); createDir(p); streamTo(in, f); } catch (RuntimeException e) { SigilCore.error("Failed to unpack " + entry, e); } } } } unpacked.put(cache, classpath); } finally { if (fin != null) { fin.close(); } } } } } /** * @param classpath * @param entry * @return */ private static boolean inClasspath(Collection<String> classpath, JarEntry entry) { for (String s : classpath) { if (entry.getName().startsWith(s)) { return true; } } return false; } private static void createDir(File p) throws IOException { if (!p.exists()) { if (!p.mkdirs()) throw new IOException("Failed to create directory " + p); } } private static void streamTo(InputStream in, File f) throws IOException { FileOutputStream fos = new FileOutputStream(f); try { byte[] buf = new byte[1024]; for (;;) { int r = in.read(buf); if (r == -1) break; fos.write(buf, 0, r); } fos.flush(); } finally { try { fos.close(); } catch (IOException e) { SigilCore.error("Failed to close stream", e); } } } private static File createEmptyDir(IPath cache) { File dir = cache.toFile(); if (dir.exists()) { deleteAll(dir); } dir.mkdirs(); return dir; } private static void deleteAll(File file) { File[] sub = file.listFiles(); if (sub != null) { for (File f : sub) { deleteAll(f); } } file.delete(); } private static IAccessRule[] buildAccessRules(ISigilProjectModel project, ISigilBundle bundle, Set<ISigilBundle> all, List<IModelElement> requirements) throws JavaModelException { ArrayList<IAccessRule> rules = new ArrayList<IAccessRule>(); for (IModelElement e : requirements) { if (e instanceof IRequiredBundle) { IRequiredBundle host = project.getBundle().getBundleInfo().getFragmentHost(); if (host != null) { if (host.equals(e)) { return new IAccessRule[] { ALLOW_ALL_RULE }; } else { return buildExportRules(bundle, all, requirements); } } else { return buildExportRules(bundle, all, requirements); } } else if (e instanceof IPackageImport) { IPackageImport pi = (IPackageImport) e; String pckg = pi.getPackageName(); HashSet<String> pckgs = new HashSet<String>(); pckgs.add(pckg); //findIndirectReferences(pckgs, pckg, project.getJavaModel(), project.getJavaModel()); for (String p : pckgs) { rules.add(newPackageAccess(p)); } } } rules.add(DENY_RULE); return rules.toArray(new IAccessRule[rules.size()]); } private static IAccessRule[] buildExportRules(ISigilBundle bundle, Set<ISigilBundle> all, List<IModelElement> requirements) { Set<IPackageExport> ex = mergeExports(bundle, all, requirements); IAccessRule[] rules = new IAccessRule[ex.size() + 1]; Iterator<IPackageExport> iter = ex.iterator(); for (int i = 0; i < rules.length - 1; i++) { IPackageExport p = iter.next(); rules[i] = JavaCore.newAccessRule(new Path(p.getPackageName().replace('.', '/')).append("*"), IAccessRule.K_ACCESSIBLE); } rules[rules.length - 1] = DENY_RULE; return rules; } private static Set<IPackageExport> mergeExports(ISigilBundle bundle, Set<ISigilBundle> all, List<IModelElement> requirements) { IBundleModelElement headers = bundle.getBundleInfo(); // FIXME treeset as PackageExport does not implement equals/hashCode TreeSet<IPackageExport> exports = new TreeSet<IPackageExport>(headers.getExports()); IRequiredBundle host = headers.getFragmentHost(); if (host != null) { for (ISigilBundle b : all) { if (host.accepts(b.getBundleCapability())) { exports.addAll(b.getBundleInfo().getExports()); break; } } } return exports; } /* * Searches for C (and D, E, etc) in case: * A extends B extends C where A, B and C are in different packages and A is in this bundle * and B and C are in one or more external bundles */ private static void findIndirectReferences(Set<String> indirect, String pckg, IParent parent, IJavaProject p) throws JavaModelException { for (IJavaElement e : parent.getChildren()) { boolean skip = false; switch (e.getElementType()) { case IJavaElement.PACKAGE_FRAGMENT_ROOT: IPackageFragmentRoot rt = (IPackageFragmentRoot) e; IClasspathEntry ce = rt.getRawClasspathEntry(); IPath path = ce.getPath(); skip = "org.eclipse.jdt.launching.JRE_CONTAINER".equals(path.toString()); break; case IJavaElement.CLASS_FILE: IClassFile cf = (IClassFile) e; if (cf.getElementName().startsWith(pckg)) { findIndirectReferences(indirect, findPackage(cf.getType().getSuperclassName()), p, p); } break; case IJavaElement.COMPILATION_UNIT: ICompilationUnit cu = (ICompilationUnit) e; break; } if (!skip && e instanceof IParent) { IParent newParent = (IParent) e; findIndirectReferences(indirect, pckg, newParent, p); } } } private static IAccessRule newPackageAccess(String packageName) { return JavaCore.newAccessRule(new Path(packageName.replace('.', '/')).append("*"), IAccessRule.K_ACCESSIBLE); } private static Set<String> findJavaImports(ISigilProjectModel project, IProgressMonitor monitor) { Set<String> imports = new HashSet<String>(); findJavaModelImports(project, imports, monitor); if (!monitor.isCanceled()) { findTextImports(project, imports, monitor); } return imports; } private static void findTextImports(ISigilProjectModel project, Set<String> imports, IProgressMonitor monitor) { IContentTypeManager contentTypeManager = Platform.getContentTypeManager(); IContentType txt = contentTypeManager.getContentType("org.eclipse.core.runtime.text"); for (Resource p : project.getBundle().getSourcePaths()) { IFile f = project.getProject().getFile(p.getLocalFile()); if (f.exists()) { try { IContentDescription desc = f.getContentDescription(); if (desc != null) { IContentType type = desc.getContentType(); if (type != null) { if (type.isKindOf(txt)) { parseText(f, imports); } } } } catch (CoreException e) { SigilCore.error("Failed to parse text file " + f, e); } } } } private static void findJavaModelImports(ISigilProjectModel project, Set<String> imports, IProgressMonitor monitor) { try { for (IPackageFragment root : project.getJavaModel().getPackageFragments()) { if (monitor.isCanceled()) { return; } IPackageFragmentRoot rt = (IPackageFragmentRoot) root .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); if (isInClassPath(project, rt)) { for (ICompilationUnit cu : root.getCompilationUnits()) { scanImports(cu, imports); } for (IClassFile cf : root.getClassFiles()) { scanImports(cf, imports); } } } } catch (JavaModelException e) { SigilCore.error("Failed to parse java model", e); } } // matches word.word.word.word.Word private static final Pattern JAVA_CLASS_PATTERN = Pattern.compile("((\\w*\\.\\w*)+?)\\.[A-Z]\\w*"); private static void parseText(IFile f, Set<String> imports) throws CoreException { for (String result : Grep.grep(JAVA_CLASS_PATTERN, f)) { findImport(result, imports); } } private static boolean isInClassPath(ISigilProjectModel project, IPackageFragmentRoot rt) throws JavaModelException { String path = encode(project, rt.getRawClasspathEntry()); return project.getBundle().getClasspathEntrys().contains(path); } private static String encode(ISigilProjectModel project, IClasspathEntry cp) { return project.getJavaModel().encodeClasspathEntry(cp).trim(); } private static void scanImports(IParent parent, Set<String> imports) throws JavaModelException { for (IJavaElement e : parent.getChildren()) { switch (e.getElementType()) { case IJavaElement.TYPE: handleType((IType) e, imports); break; case IJavaElement.IMPORT_DECLARATION: handleImport((IImportDeclaration) e, imports); break; case IJavaElement.FIELD: handleField((IField) e, imports); break; case IJavaElement.LOCAL_VARIABLE: handleLocalVariable((ILocalVariable) e, imports); break; case IJavaElement.ANNOTATION: handleAnnotation((IAnnotation) e, imports); break; case IJavaElement.METHOD: handleMethod((IMethod) e, imports); break; default: // no action break; } if (e instanceof IParent) { scanImports((IParent) e, imports); } } } private static void handleType(IType e, Set<String> imports) throws JavaModelException { findImportFromType(e.getSuperclassTypeSignature(), imports); for (String sig : e.getSuperInterfaceTypeSignatures()) { findImportFromType(sig, imports); } //findImportsForSuperTypes(e, imports); } /*private static void findImportsForSuperTypes(IType e, Set<String> imports) throws JavaModelException { IJavaProject project = (IJavaProject) e.getAncestor(IJavaModel.JAVA_PROJECT); LinkedList<String> types = new LinkedList<String>(); types.add( decodeSignature(e.getSuperclassTypeSignature()) ); for ( String sig : e.getSuperInterfaceTypeSignatures() ) { types.add( decodeSignature(sig) ); } for ( IPackageFragmentRoot root : project.getPackageFragmentRoots() ) { // only need to search binary files for inheritance as source will automatically be searched if ( root.getKind() == IPackageFragmentRoot.K_BINARY ) { for ( String t : types ) { String pac = findPackage(t); if ( pac != null ) { IPackageFragment fragment = root.getPackageFragment(pac); if ( fragment != null ) { IClassFile c = fragment.getClassFile(findClass(t)); if ( c != null ) { findImportsForSuperTypes(c.getType(), imports); } } } } } } } */ private static void handleMethod(IMethod e, Set<String> imports) throws JavaModelException { findImportFromType(e.getReturnType(), imports); for (String param : e.getParameterTypes()) { findImportFromType(param, imports); } for (String ex : e.getExceptionTypes()) { findImportFromType(ex, imports); } } private static void handleAnnotation(IAnnotation e, Set<String> imports) { findImport(e.getElementName(), imports); } private static void handleLocalVariable(ILocalVariable e, Set<String> imports) { findImportFromType(e.getTypeSignature(), imports); } private static void handleField(IField e, Set<String> imports) throws IllegalArgumentException, JavaModelException { findImportFromType(Signature.getElementType(e.getTypeSignature()), imports); } private static void handleImport(IImportDeclaration id, Set<String> imports) { findImport(id.getElementName(), imports); } private static void findImportFromType(String type, Set<String> imports) { String element = decodeSignature(type); findImport(element, imports); } private static String decodeSignature(String type) { return decodeSignature(type, false); } private static String decodeSignature(String type, boolean resolve) { if (type == null) { return null; } if (type.length() > 0) { switch (type.charAt(0)) { case Signature.C_ARRAY: return decodeSignature(type.substring(1)); case Signature.C_UNRESOLVED: return resolve ? resolve(type.substring(1, type.length() - 1)) : null; case Signature.C_RESOLVED: return type.substring(1); } } return type; } private static String resolve(String substring) { // TODO Auto-generated method stub return null; } private static void findImport(String clazz, Set<String> imports) { String packageName = findPackage(clazz); if (packageName != null) { imports.add(packageName); } } private static String findPackage(String clazz) { if (clazz == null) return null; int pos = clazz.lastIndexOf('.'); return pos == -1 ? null : clazz.substring(0, pos); } private static String findClass(String clazz) { if (clazz == null) return null; int pos = clazz.lastIndexOf('.'); return pos == -1 ? null : clazz.substring(pos + 1); } private static IPackageImport select(Collection<IPackageExport> proposals) { IPackageExport pe = null; for (IPackageExport check : proposals) { if (pe == null || check.getVersion().compareTo(pe.getVersion()) > 0) { pe = check; } } String packageName = pe.getPackageName(); Version version = pe.getVersion(); VersionRange versions = ModelHelper.getDefaultRange(version); IPackageImport pi = ModelElementFactory.getInstance().newModelElement(IPackageImport.class); pi.setPackageName(packageName); pi.setVersions(versions); return pi; } public static Iterable<IJavaElement> findTypes(IParent parent, int... type) throws JavaModelException { LinkedList<IJavaElement> found = new LinkedList<IJavaElement>(); scanForElement(parent, type, found, false); return found; } public static IJavaElement findType(IParent parent, int... type) throws JavaModelException { LinkedList<IJavaElement> found = new LinkedList<IJavaElement>(); scanForElement(parent, type, found, true); return found.isEmpty() ? null : found.getFirst(); } private static void scanForElement(IParent parent, int[] type, List<IJavaElement> roots, boolean thereCanBeOnlyOne) throws JavaModelException { for (IJavaElement e : parent.getChildren()) { if (isType(type, e)) { roots.add(e); if (thereCanBeOnlyOne) { break; } } else if (e instanceof IParent) { scanForElement((IParent) e, type, roots, thereCanBeOnlyOne); } } } private static boolean isType(int[] type, IJavaElement e) { for (int i : type) { if (i == e.getElementType()) { return true; } } return false; } public static boolean isAssignableTo(String ifaceOrParentClass, IType type) throws JavaModelException { if (ifaceOrParentClass == null) return true; ITypeHierarchy h = type.newSupertypeHierarchy(null); for (IType superType : h.getAllClasses()) { String name = superType.getFullyQualifiedName(); if (name.equals(ifaceOrParentClass)) { return true; } } for (IType ifaceType : h.getAllInterfaces()) { String name = ifaceType.getFullyQualifiedName(); if (name.equals(ifaceOrParentClass)) { return true; } } return false; } private static IType findType(ITypeRoot root) throws JavaModelException { // TODO Auto-generated method stub for (IJavaElement child : root.getChildren()) { if (child.getElementType() == IJavaElement.TYPE) { return (IType) child; } } throw new JavaModelException(new IllegalStateException("Missing type for " + root), IStatus.ERROR); } public static Set<String> findLocalPackageDependencies(ISigilProjectModel project, String packageName, IProgressMonitor monitor) throws JavaModelException { Set<String> imports = findJavaImports(project, monitor); imports.remove(packageName); return imports; } public static Set<String> findLocalPackageUsers(ISigilProjectModel project, String packageName, IProgressMonitor monitor) throws JavaModelException { Set<String> imports = new HashSet<String>(); Set<String> check = new HashSet<String>(); for (IPackageFragment root : project.getJavaModel().getPackageFragments()) { IPackageFragmentRoot rt = (IPackageFragmentRoot) root.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); if (isInClassPath(project, rt)) { for (ICompilationUnit cu : root.getCompilationUnits()) { IPackageFragment pack = (IPackageFragment) cu.getAncestor(IJavaModel.PACKAGE_FRAGMENT); if (!pack.getElementName().equals(packageName)) { scanImports(cu, check); if (check.contains(packageName)) { imports.add(pack.getElementName()); } } check.clear(); } for (IClassFile cf : root.getClassFiles()) { IPackageFragment pack = (IPackageFragment) cf.getAncestor(IJavaModel.PACKAGE_FRAGMENT); if (!pack.getElementName().equals(packageName)) { scanImports(cf, check); if (check.contains(packageName)) { imports.add(pack.getElementName()); } } check.clear(); } } } return imports; } }