/******************************************************************************* * Copyright (c) 2003, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jst.j2ee.internal.dialogs; import java.util.ArrayList; import java.util.HashSet; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaModel; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IOpenable; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchScope; /** * This class was derived from JavaSearchScope as that class did not have a * provision to exclude classpath entries that are not exported A Java-specific * scope for searching relative to one or more java elements. */ public class TypeJavaSearchScope implements IJavaSearchScope { private boolean includeExportedClassPathEntriesOnly = true; private ArrayList elements; /* * The paths of the resources in this search scope (or the classpath * entries' paths if the resources are projects) */ private IPath[] paths; private boolean[] pathWithSubFolders; private int pathsCount; private IPath[] enclosingProjectsAndJars; public TypeJavaSearchScope() { this.initialize(); // disabled for now as this could be expensive // JavaModelManager.getJavaModelManager().rememberScope(this); } private void addEnclosingProjectOrJar(IPath path) { int length = this.enclosingProjectsAndJars.length; for (int i = 0; i < length; i++) { if (this.enclosingProjectsAndJars[i].equals(path)) return; } System.arraycopy(this.enclosingProjectsAndJars, 0, this.enclosingProjectsAndJars = new IPath[length + 1], 0, length); this.enclosingProjectsAndJars[length] = path; } /** * Method addProject. This method adds all the classpath entries for the * current project to the search scope. * * @param javaProject * @param includesPrereqProjects * @param visitedProjects * @throws JavaModelException */ public void addProject(IJavaProject javaProject, boolean includesPrereqProjects, HashSet visitedProjects) throws JavaModelException { IProject project = javaProject.getProject(); if (!project.isAccessible() || !visitedProjects.add(project)) return; this.addEnclosingProjectOrJar(project.getFullPath()); IClasspathEntry[] entries = javaProject.getResolvedClasspath(true); IJavaModel model = javaProject.getJavaModel(); for (int i = 0, length = entries.length; i < length; i++) { IClasspathEntry entry = entries[i]; switch (entry.getEntryKind()) { case IClasspathEntry.CPE_LIBRARY : IPath path = entry.getPath(); this.add(path, true); this.addEnclosingProjectOrJar(path); break; case IClasspathEntry.CPE_PROJECT : if (includesPrereqProjects) { this.add(model.getJavaProject(entry.getPath().lastSegment()), true, visitedProjects); } break; case IClasspathEntry.CPE_SOURCE : this.add(entry.getPath(), true); break; } } } /** * Method add. This method filters out all the classpath entries of the * project which are not exported. * * @param javaProject * @param includesPrereqProjects * @param visitedProjects * @throws JavaModelException */ public void add(IJavaProject javaProject, boolean includesPrereqProjects, HashSet visitedProjects) throws JavaModelException { IProject project = javaProject.getProject(); if (!project.isAccessible() || !visitedProjects.add(project)) return; this.addEnclosingProjectOrJar(project.getFullPath()); IClasspathEntry[] entries = javaProject.getResolvedClasspath(true); IJavaModel model = javaProject.getJavaModel(); for (int i = 0, length = entries.length; i < length; i++) { IClasspathEntry entry = entries[i]; if (includeExportedClassPathEntriesOnly()) { if (!entry.isExported() && entry.getEntryKind() != IClasspathEntry.CPE_SOURCE) continue; } switch (entry.getEntryKind()) { case IClasspathEntry.CPE_LIBRARY : IPath path = entry.getPath(); this.add(path, true); this.addEnclosingProjectOrJar(path); break; case IClasspathEntry.CPE_PROJECT : if (includesPrereqProjects) { this.add(model.getJavaProject(entry.getPath().lastSegment()), true, visitedProjects); } break; case IClasspathEntry.CPE_SOURCE : this.add(entry.getPath(), true); break; } } } public void add(IJavaElement element) throws JavaModelException { IPackageFragmentRoot root = null; switch (element.getElementType()) { case IJavaElement.JAVA_MODEL : // a workspace sope should be used break; case IJavaElement.JAVA_PROJECT : this.add((IJavaProject) element, true, new HashSet(2)); break; case IJavaElement.PACKAGE_FRAGMENT_ROOT : root = (IPackageFragmentRoot) element; this.add(root.getPath(), true); break; case IJavaElement.PACKAGE_FRAGMENT : root = (IPackageFragmentRoot) element.getParent(); if (root.isArchive()) { this.add(root.getPath().append(new Path(element.getElementName().replace('.', '/'))), false); } else { IResource resource = element.getUnderlyingResource(); if (resource != null && resource.isAccessible()) { this.add(resource.getFullPath(), false); } } break; default : // remember sub-cu (or sub-class file) java elements if (element instanceof IMember) { if (this.elements == null) { this.elements = new ArrayList(); } this.elements.add(element); } this.add(this.fullPath(element), true); // find package fragment root including this java element IJavaElement parent = element.getParent(); while (parent != null && !(parent instanceof IPackageFragmentRoot)) { parent = parent.getParent(); } if (parent instanceof IPackageFragmentRoot) { root = (IPackageFragmentRoot) parent; } } if (root != null) { if (root.getKind() == IPackageFragmentRoot.K_BINARY) { this.addEnclosingProjectOrJar(root.getPath()); } else { this.addEnclosingProjectOrJar(root.getJavaProject().getProject().getFullPath()); } } } /** * Adds the given path to this search scope. Remember if subfolders need to * be included as well. */ private void add(IPath path, boolean withSubFolders) { if (this.paths.length == this.pathsCount) { System.arraycopy(this.paths, 0, this.paths = new IPath[this.pathsCount * 2], 0, this.pathsCount); System.arraycopy(this.pathWithSubFolders, 0, this.pathWithSubFolders = new boolean[this.pathsCount * 2], 0, this.pathsCount); } this.paths[this.pathsCount] = path; this.pathWithSubFolders[this.pathsCount++] = withSubFolders; } /* * (non-Javadoc) * * @see IJavaSearchScope#encloses(String) */ public boolean encloses(String resourcePathString) { IPath resourcePath; int separatorIndex = resourcePathString.indexOf(JAR_FILE_ENTRY_SEPARATOR); if (separatorIndex != -1) { resourcePath = new Path(resourcePathString.substring(0, separatorIndex)).append(new Path(resourcePathString.substring(separatorIndex + 1))); } else { resourcePath = new Path(resourcePathString); } return this.encloses(resourcePath); } /** * Returns whether this search scope encloses the given path. */ private boolean encloses(IPath path) { for (int i = 0; i < this.pathsCount; i++) { if (this.pathWithSubFolders[i]) { if (this.paths[i].isPrefixOf(path)) { return true; } } else { IPath scopePath = this.paths[i]; if (scopePath.isPrefixOf(path) && (scopePath.segmentCount() == path.segmentCount() - 1)) { return true; } } } return false; } /* * (non-Javadoc) * * @see IJavaSearchScope#encloses(IJavaElement) */ public boolean encloses(IJavaElement element) { if (this.elements != null) { for (int i = 0, length = this.elements.size(); i < length; i++) { IJavaElement scopeElement = (IJavaElement) this.elements.get(i); IJavaElement searchedElement = element; while (searchedElement != null) { if (searchedElement.equals(scopeElement)) { return true; } searchedElement = searchedElement.getParent(); } } return false; } return this.encloses(this.fullPath(element)); } /* * (non-Javadoc) * * @see IJavaSearchScope#enclosingProjectsAndJars() */ public IPath[] enclosingProjectsAndJars() { return this.enclosingProjectsAndJars; } private IPath fullPath(IJavaElement element) { if (element instanceof IPackageFragmentRoot) { return ((IPackageFragmentRoot) element).getPath(); } IJavaElement parent = element.getParent(); IPath parentPath = parent == null ? null : this.fullPath(parent); IPath childPath; if (element instanceof IPackageFragment) { childPath = new Path(element.getElementName().replace('.', '/')); } else if (element instanceof IOpenable) { childPath = new Path(element.getElementName()); } else { return parentPath; } return parentPath == null ? childPath : parentPath.append(childPath); } protected void initialize() { this.paths = new IPath[1]; this.pathWithSubFolders = new boolean[1]; this.pathsCount = 0; this.enclosingProjectsAndJars = new IPath[0]; } /** * Gets the includeExportedClassPathEntriesOnly. * * @return Returns a boolean */ public boolean includeExportedClassPathEntriesOnly() { return includeExportedClassPathEntriesOnly; } /** * Sets the includeExportedClassPathEntriesOnly. * * @param includeExportedClassPathEntriesOnly * The includeExportedClassPathEntriesOnly to set */ public void setIncludeExportedClassPathEntriesOnly(boolean includeExportedClassPathEntriesOnly) { this.includeExportedClassPathEntriesOnly = includeExportedClassPathEntriesOnly; } /** * @see IJavaSearchScope#includesBinaries() * @deprecated */ public boolean includesBinaries() { return true; } /** * @see IJavaSearchScope#includesClasspaths() * @deprecated */ public boolean includesClasspaths() { return true; } /** * @see IJavaSearchScope#setIncludesBinaries(boolean) * @deprecated */ public void setIncludesBinaries(boolean includesBinaries) { //Default nothing } /** * @see IJavaSearchScope#setIncludesClasspaths(boolean) * @deprecated */ public void setIncludesClasspaths(boolean includesClasspaths) { //Default nothing } }