/*
* 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;
}
}