Copyright (c) 2000, 2015 IBM Corporation and others.
This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0
which accompanies this distribution, and is available at
https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
Contributors:
IBM Corporation - initial API and implementation
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.launching.sourcelookup;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.model.IPersistableSourceLocator;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.internal.launching.LaunchingMessages;
import org.eclipse.jdt.internal.launching.LaunchingPlugin;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.osgi.util.NLS;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.osgi.framework.Bundle;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
Locates source for a Java debug session by searching
a configurable set of source locations.
This class may be instantiated.
See Also: - ISourceLocator
Since: 2.0 Deprecated: In 3.0, the debug platform provides source lookup facilities that
should be used in place of the Java source lookup support provided in 2.0.
The new facilities provide a source lookup director that coordinates source
lookup among a set of participants, searching a set of source containers.
See the following packages: org.eclipse.debug.core.sourcelookup
and org.eclipse.debug.core.sourcelookup.containers
. This class
has been replaced by a Java source lookup director and Java source lookup
participant. To migrate to the new source lookup support clients should
add two new attributes to their launch configuration type extensions:
- sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"
- sourcePathComputerId="org.eclipse.jdt.launching.sourceLookup.javaSourcePathComputer"
The source locator id attribute specifies to use the Java source lookup director
for launch configurations of the associated type, and the source path computer id
attribute specifies the class to use when computing a default source lookup
path for a launch configuration. The path computer referenced/provided (by the
above id), computes a default source lookup path based on the support provided in
the 2.0 release - i.e. a configuration's ATTR_SOURCE_PATH_PROVIDER
attribute (if present), or a default source lookup path based on a configuration's
runtime classpath. This class has been replaced by the Java source lookup
director which is an internal class, but can be used via the
sourceLocatorId
attribute on a launch configuration type extension. @noextend This class is not intended to be sub-classed by clients.
/**
* Locates source for a Java debug session by searching
* a configurable set of source locations.
* <p>
* This class may be instantiated.
* </p>
* @see org.eclipse.debug.core.model.ISourceLocator
* @since 2.0
* @deprecated In 3.0, the debug platform provides source lookup facilities that
* should be used in place of the Java source lookup support provided in 2.0.
* The new facilities provide a source lookup director that coordinates source
* lookup among a set of participants, searching a set of source containers.
* See the following packages: <code>org.eclipse.debug.core.sourcelookup</code>
* and <code>org.eclipse.debug.core.sourcelookup.containers</code>. This class
* has been replaced by a Java source lookup director and Java source lookup
* participant. To migrate to the new source lookup support clients should
* add two new attributes to their launch configuration type extensions:<ul>
* <li>sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"</li>
* <li>sourcePathComputerId="org.eclipse.jdt.launching.sourceLookup.javaSourcePathComputer"</li>
* </ul>
* The source locator id attribute specifies to use the Java source lookup director
* for launch configurations of the associated type, and the source path computer id
* attribute specifies the class to use when computing a default source lookup
* path for a launch configuration. The path computer referenced/provided (by the
* above id), computes a default source lookup path based on the support provided in
* the 2.0 release - i.e. a configuration's <code>ATTR_SOURCE_PATH_PROVIDER</code>
* attribute (if present), or a default source lookup path based on a configuration's
* runtime classpath. This class has been replaced by the Java source lookup
* director which is an internal class, but can be used via the
* <code>sourceLocatorId</code> attribute on a launch configuration type extension.
* @noextend This class is not intended to be sub-classed by clients.
*/
@Deprecated
public class JavaSourceLocator implements IPersistableSourceLocator {
Identifier for the 'Java Source Locator' extension
(value "org.eclipse.jdt.launching.javaSourceLocator"
).
/**
* Identifier for the 'Java Source Locator' extension
* (value <code>"org.eclipse.jdt.launching.javaSourceLocator"</code>).
*/
public static final String ID_JAVA_SOURCE_LOCATOR = LaunchingPlugin.getUniqueIdentifier() + ".javaSourceLocator"; //$NON-NLS-1$
A collection of the source locations to search
/**
* A collection of the source locations to search
*/
private IJavaSourceLocation[] fLocations;
Constructs a new empty JavaSourceLocator.
/**
* Constructs a new empty JavaSourceLocator.
*/
public JavaSourceLocator() {
setSourceLocations(new IJavaSourceLocation[0]);
}
Constructs a new Java source locator that looks in the
specified project for source, and required projects, if
includeRequired
is true
.
Params: - projects – the projects in which to look for source
- includeRequired – whether to look in required projects
as well
Throws: - CoreException – if a new locator fails to be created
/**
* Constructs a new Java source locator that looks in the
* specified project for source, and required projects, if
* <code>includeRequired</code> is <code>true</code>.
*
* @param projects the projects in which to look for source
* @param includeRequired whether to look in required projects
* as well
* @throws CoreException if a new locator fails to be created
*/
public JavaSourceLocator(IJavaProject[] projects, boolean includeRequired) throws CoreException {
ArrayList<IJavaProject> requiredProjects = new ArrayList<>();
for (int i= 0; i < projects.length; i++) {
if (includeRequired) {
collectRequiredProjects(projects[i], requiredProjects);
} else {
if (!requiredProjects.contains(projects[i])) {
requiredProjects.add(projects[i]);
}
}
}
// only add external entries with the same location once
HashMap<IPath, IPath> external = new HashMap<>();
ArrayList<PackageFragmentRootSourceLocation> list = new ArrayList<>();
// compute the default locations for each project, and add unique ones
Iterator<IJavaProject> iter = requiredProjects.iterator();
while (iter.hasNext()) {
IJavaProject p = iter.next();
IPackageFragmentRoot[] roots = p.getPackageFragmentRoots();
for (int i = 0; i < roots.length; i++) {
if (roots[i].isExternal()) {
IPath location = roots[i].getPath();
if (external.get(location) == null) {
external.put(location, location);
list.add(new PackageFragmentRootSourceLocation(roots[i]));
}
} else {
list.add(new PackageFragmentRootSourceLocation(roots[i]));
}
}
}
IJavaSourceLocation[] locations = list.toArray(new IJavaSourceLocation[list.size()]);
setSourceLocations(locations);
}
Constructs a new JavaSourceLocator that searches the
specified set of source locations for source elements.
Params: - locations – the source locations to search for
source, in the order they should be searched
/**
* Constructs a new JavaSourceLocator that searches the
* specified set of source locations for source elements.
*
* @param locations the source locations to search for
* source, in the order they should be searched
*/
public JavaSourceLocator(IJavaSourceLocation[] locations) {
setSourceLocations(locations);
}
Constructs a new JavaSourceLocator that searches the
default set of source locations for the given Java project.
Params: - project – Java project
Throws: - CoreException – if an exception occurs reading
the classpath of the given or any required project
/**
* Constructs a new JavaSourceLocator that searches the
* default set of source locations for the given Java project.
*
* @param project Java project
* @exception CoreException if an exception occurs reading
* the classpath of the given or any required project
*/
public JavaSourceLocator(IJavaProject project) throws CoreException {
setSourceLocations(getDefaultSourceLocations(project));
}
Sets the locations that will be searched, in the order
to be searched.
Params: - locations – the locations that will be searched, in the order
to be searched
/**
* Sets the locations that will be searched, in the order
* to be searched.
*
* @param locations the locations that will be searched, in the order
* to be searched
*/
public void setSourceLocations(IJavaSourceLocation[] locations) {
fLocations = locations;
}
Returns the locations that this source locator is currently
searching, in the order that they are searched.
Returns: the locations that this source locator is currently
searching, in the order that they are searched
/**
* Returns the locations that this source locator is currently
* searching, in the order that they are searched.
*
* @return the locations that this source locator is currently
* searching, in the order that they are searched
*/
public IJavaSourceLocation[] getSourceLocations() {
return fLocations;
}
Returns all source elements that correspond to the type associated with
the given stack frame, or null
if none.
Params: - stackFrame – stack frame
Returns: all source elements that correspond to the type associated with
the given stack frame, or null
if none Since: 2.1
/**
* Returns all source elements that correspond to the type associated with
* the given stack frame, or <code>null</code> if none.
*
* @param stackFrame stack frame
* @return all source elements that correspond to the type associated with
* the given stack frame, or <code>null</code> if none
* @since 2.1
*/
public Object[] getSourceElements(IStackFrame stackFrame) {
if (stackFrame instanceof IJavaStackFrame) {
IJavaStackFrame frame = (IJavaStackFrame)stackFrame;
String name = null;
try {
name = getFullyQualfiedName(frame);
if (name == null) {
return null;
}
} catch (CoreException e) {
// if the thread has since resumed, return null
if (e.getStatus().getCode() != IJavaThread.ERR_THREAD_NOT_SUSPENDED) {
LaunchingPlugin.log(e);
}
return null;
}
List<Object> list = new ArrayList<>();
IJavaSourceLocation[] locations = getSourceLocations();
for (int i = 0; i < locations.length; i++) {
try {
Object sourceElement = locations[i].findSourceElement(name);
if (sourceElement != null) {
list.add(sourceElement);
}
} catch (CoreException e) {
// log the error and try the next source location
LaunchingPlugin.log(e);
}
}
return list.toArray();
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.ISourceLocator#getSourceElement(org.eclipse.debug.core.model.IStackFrame)
*/
@Override
public Object getSourceElement(IStackFrame stackFrame) {
if (stackFrame instanceof IJavaStackFrame) {
IJavaStackFrame frame = (IJavaStackFrame)stackFrame;
String name = null;
try {
name = getFullyQualfiedName(frame);
if (name == null) {
return null;
}
} catch (CoreException e) {
// if the thread has since resumed, return null
if (e.getStatus().getCode() != IJavaThread.ERR_THREAD_NOT_SUSPENDED) {
LaunchingPlugin.log(e);
}
return null;
}
IJavaSourceLocation[] locations = getSourceLocations();
for (int i = 0; i < locations.length; i++) {
try {
Object sourceElement = locations[i].findSourceElement(name);
if (sourceElement != null) {
return sourceElement;
}
} catch (CoreException e) {
// log the error and try the next source location
LaunchingPlugin.log(e);
}
}
}
return null;
}
private String getFullyQualfiedName(IJavaStackFrame frame) throws CoreException {
String name = null;
if (frame.isObsolete()) {
return null;
}
String sourceName = frame.getSourceName();
if (sourceName == null) {
// no debug attributes, guess at source name
name = frame.getDeclaringTypeName();
} else {
// build source name from debug attributes using
// the source file name and the package of the declaring
// type
// @see bug# 21518 - remove absolute path prefix
int index = sourceName.lastIndexOf('\\');
if (index == -1) {
index = sourceName.lastIndexOf('/');
}
if (index >= 0) {
sourceName = sourceName.substring(index + 1);
}
String declName= frame.getDeclaringTypeName();
index = declName.lastIndexOf('.');
if (index >= 0) {
name = declName.substring(0, index + 1);
} else {
name = ""; //$NON-NLS-1$
}
index = sourceName.lastIndexOf('.');
if (index >= 0) {
name += sourceName.substring(0, index) ;
}
}
return name;
}
Adds all projects required by proj
to the list
res
Params: - proj – the project for which to compute required
projects
- res – the list to add all required projects too
Throws: - JavaModelException – if there is a problem with the backing Java model
/**
* Adds all projects required by <code>proj</code> to the list
* <code>res</code>
*
* @param proj the project for which to compute required
* projects
* @param res the list to add all required projects too
* @throws JavaModelException if there is a problem with the backing Java model
*/
protected static void collectRequiredProjects(IJavaProject proj, ArrayList<IJavaProject> res) throws JavaModelException {
if (!res.contains(proj)) {
res.add(proj);
IJavaModel model= proj.getJavaModel();
IClasspathEntry[] entries= proj.getRawClasspath();
for (int i= 0; i < entries.length; i++) {
IClasspathEntry curr= entries[i];
if (curr.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
IJavaProject ref= model.getJavaProject(curr.getPath().segment(0));
if (ref.exists()) {
collectRequiredProjects(ref, res);
}
}
}
}
}
Returns a default collection of source locations for
the given Java project. Default source locations consist
of the given project and all of its required projects .
Params: - project – Java project
Throws: - CoreException – if an exception occurs reading
computing the default locations
Returns: a collection of source locations for all required
projects
/**
* Returns a default collection of source locations for
* the given Java project. Default source locations consist
* of the given project and all of its required projects .
*
* @param project Java project
* @return a collection of source locations for all required
* projects
* @exception CoreException if an exception occurs reading
* computing the default locations
*/
public static IJavaSourceLocation[] getDefaultSourceLocations(IJavaProject project) throws CoreException {
// create a temporary launch config
ILaunchConfigurationType type = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationType(IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION);
ILaunchConfigurationWorkingCopy config = type.newInstance(null, project.getElementName());
config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, project.getElementName());
JavaSourceLocator locator = new JavaSourceLocator();
locator.initializeDefaults(config);
return locator.getSourceLocations();
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IPersistableSourceLocator#getMemento()
*/
@Override
public String getMemento() throws CoreException {
Document doc = DebugPlugin.newDocument();
Element node = doc.createElement("javaSourceLocator"); //$NON-NLS-1$
doc.appendChild(node);
IJavaSourceLocation[] locations = getSourceLocations();
for (int i = 0; i < locations.length; i++) {
Element child = doc.createElement("javaSourceLocation"); //$NON-NLS-1$
child.setAttribute("class", locations[i].getClass().getName()); //$NON-NLS-1$
child.setAttribute("memento", locations[i].getMemento()); //$NON-NLS-1$
node.appendChild(child);
}
return DebugPlugin.serializeDocument(doc);
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IPersistableSourceLocator#initializeDefaults(org.eclipse.debug.core.ILaunchConfiguration)
*/
@Override
public void initializeDefaults(ILaunchConfiguration configuration) throws CoreException {
IRuntimeClasspathEntry[] entries = JavaRuntime.computeUnresolvedSourceLookupPath(configuration);
IRuntimeClasspathEntry[] resolved = JavaRuntime.resolveSourceLookupPath(entries, configuration);
setSourceLocations(getSourceLocations(resolved));
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IPersistableSourceLocator#initializeFromMemento(java.lang.String)
*/
@Override
public void initializeFromMemento(String memento) throws CoreException {
Exception ex = null;
try {
Element root = null;
DocumentBuilder parser =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
parser.setErrorHandler(new DefaultHandler());
StringReader reader = new StringReader(memento);
InputSource source = new InputSource(reader);
root = parser.parse(source).getDocumentElement();
if (!root.getNodeName().equalsIgnoreCase("javaSourceLocator")) { //$NON-NLS-1$
abort(LaunchingMessages.JavaSourceLocator_Unable_to_restore_Java_source_locator___invalid_format__6, null);
}
List<IJavaSourceLocation> sourceLocations = new ArrayList<>();
Bundle bundle = LaunchingPlugin.getDefault().getBundle();
NodeList list = root.getChildNodes();
int length = list.getLength();
for (int i = 0; i < length; ++i) {
Node node = list.item(i);
short type = node.getNodeType();
if (type == Node.ELEMENT_NODE) {
Element entry = (Element) node;
if (entry.getNodeName().equalsIgnoreCase("javaSourceLocation")) { //$NON-NLS-1$
String className = entry.getAttribute("class"); //$NON-NLS-1$
String data = entry.getAttribute("memento"); //$NON-NLS-1$
if (isEmpty(className)) {
abort(LaunchingMessages.JavaSourceLocator_Unable_to_restore_Java_source_locator___invalid_format__10, null);
}
Class<?> clazz = null;
try {
clazz = bundle.loadClass(className);
} catch (ClassNotFoundException e) {
abort(NLS.bind(LaunchingMessages.JavaSourceLocator_Unable_to_restore_source_location___class_not_found___0__11, new String[] {className}), e);
}
IJavaSourceLocation location = null;
try {
location = (IJavaSourceLocation)clazz.newInstance();
} catch (IllegalAccessException e) {
abort(LaunchingMessages.JavaSourceLocator_Unable_to_restore_source_location__12, e);
} catch (InstantiationException e) {
abort(LaunchingMessages.JavaSourceLocator_Unable_to_restore_source_location__12, e);
}
location.initializeFrom(data);
sourceLocations.add(location);
} else {
abort(LaunchingMessages.JavaSourceLocator_Unable_to_restore_Java_source_locator___invalid_format__14, null);
}
}
}
setSourceLocations(sourceLocations.toArray(new IJavaSourceLocation[sourceLocations.size()]));
return;
} catch (ParserConfigurationException e) {
ex = e;
} catch (SAXException e) {
ex = e;
} catch (IOException e) {
ex = e;
}
abort(LaunchingMessages.JavaSourceLocator_Exception_occurred_initializing_source_locator__15, ex);
}
Returns source locations that are associated with the given runtime classpath
entries.
Params: - entries – the entries to compute source locations for
Returns: the array of IJavaSourceLocation
/**
* Returns source locations that are associated with the given runtime classpath
* entries.
* @param entries the entries to compute source locations for
* @return the array of {@link IJavaSourceLocation}
*/
private static IJavaSourceLocation[] getSourceLocations(IRuntimeClasspathEntry[] entries) {
List<IJavaSourceLocation> locations = new ArrayList<>(entries.length);
for (int i = 0; i < entries.length; i++) {
IRuntimeClasspathEntry entry = entries[i];
IJavaSourceLocation location = null;
switch (entry.getType()) {
case IRuntimeClasspathEntry.PROJECT:
IProject project = (IProject)entry.getResource();
if (project != null && project.exists() && project.isOpen()) {
location = new JavaProjectSourceLocation(JavaCore.create(project));
}
break;
case IRuntimeClasspathEntry.ARCHIVE:
// check if the archive is in the workspace as a package fragment root
location = getArchiveSourceLocation(entry);
if (location == null) {
String path = entry.getSourceAttachmentLocation();
if (path == null) {
// if there is no source attachment, look in the archive itself
path = entry.getLocation();
}
if (path != null) {
File file = new File(path);
if (file.exists()) {
if (file.isDirectory()) {
location = new DirectorySourceLocation(file);
} else {
location = new ArchiveSourceLocation(path, entry.getSourceAttachmentRootLocation());
}
}
}
}
break;
case IRuntimeClasspathEntry.VARIABLE:
String source = entry.getSourceAttachmentLocation();
if (source != null) {
location = new ArchiveSourceLocation(source, entry.getSourceAttachmentRootLocation());
}
break;
case IRuntimeClasspathEntry.CONTAINER:
throw new IllegalArgumentException(LaunchingMessages.JavaSourceLocator_Illegal_to_have_a_container_resolved_to_a_container_1);
}
if (location != null) {
locations.add(location);
}
}
return locations.toArray(new IJavaSourceLocation[locations.size()]);
}
private boolean isEmpty(String string) {
return string == null || string.length() == 0;
}
Throws an internal error exception
Params: - message – the message
- e – the error
Throws: - CoreException – the new
CoreException
/**
* Throws an internal error exception
* @param message the message
* @param e the error
* @throws CoreException the new {@link CoreException}
*/
private void abort(String message, Throwable e) throws CoreException {
IStatus s = new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), IJavaLaunchConfigurationConstants.ERR_INTERNAL_ERROR, message, e);
throw new CoreException(s);
}
Returns whether the given objects are equal, allowing
for null
.
Params: - a – the first item
- b – the item to compare
Returns: whether the given objects are equal, allowing
for null
/**
* Returns whether the given objects are equal, allowing
* for <code>null</code>.
*
* @param a the first item
* @param b the item to compare
* @return whether the given objects are equal, allowing
* for <code>null</code>
*/
private static boolean equalOrNull(Object a, Object b) {
if (a == null) {
return b == null;
}
if (b == null) {
return false;
}
return a.equals(b);
}
Returns whether the source attachments of the given package fragment
root and runtime classpath entry are equal.
Params: - root – package fragment root
- entry – runtime classpath entry
Throws: - JavaModelException – if there is a problem with the backing Java model
Returns: whether the source attachments of the given package fragment
root and runtime classpath entry are equal
/**
* Returns whether the source attachments of the given package fragment
* root and runtime classpath entry are equal.
*
* @param root package fragment root
* @param entry runtime classpath entry
* @return whether the source attachments of the given package fragment
* root and runtime classpath entry are equal
* @throws JavaModelException if there is a problem with the backing Java model
*/
private static boolean isSourceAttachmentEqual(IPackageFragmentRoot root, IRuntimeClasspathEntry entry) throws JavaModelException {
return equalOrNull(root.getSourceAttachmentPath(), entry.getSourceAttachmentPath());
}
Determines if the given archive runtime classpath entry exists
in the workspace as a package fragment root. Returns the associated
package fragment root source location if possible, otherwise
null
.
Params: - entry – archive runtime classpath entry
Returns: IJavaSourceLocation or null
/**
* Determines if the given archive runtime classpath entry exists
* in the workspace as a package fragment root. Returns the associated
* package fragment root source location if possible, otherwise
* <code>null</code>.
*
* @param entry archive runtime classpath entry
* @return IJavaSourceLocation or <code>null</code>
*/
private static IJavaSourceLocation getArchiveSourceLocation(IRuntimeClasspathEntry entry) {
IResource resource = entry.getResource();
if (resource == null) {
// Check all package fragment roots for case of external archive.
// External jars are shared, so it does not matter which project it
// originates from
IJavaModel model = JavaCore.create(ResourcesPlugin.getWorkspace().getRoot());
try {
IJavaProject[] jps = model.getJavaProjects();
for (int i = 0; i < jps.length; i++) {
IPackageFragmentRoot[] allRoots = jps[i].getPackageFragmentRoots();
for (int j = 0; j < allRoots.length; j++) {
IPackageFragmentRoot root = allRoots[j];
if (root.isExternal() && root.getPath().equals(new Path(entry.getLocation()))) {
if (isSourceAttachmentEqual(root, entry)) {
// use package fragment root
return new PackageFragmentRootSourceLocation(root);
}
}
}
}
} catch (JavaModelException e) {
LaunchingPlugin.log(e);
}
} else {
// check if the archive is a package fragment root
IProject project = resource.getProject();
IJavaProject jp = JavaCore.create(project);
try {
if (jp != null && jp.exists()) {
IPackageFragmentRoot root = jp.getPackageFragmentRoot(resource);
IPackageFragmentRoot[] allRoots = jp.getPackageFragmentRoots();
for (int j = 0; j < allRoots.length; j++) {
if (allRoots[j].equals(root)) {
// ensure source attachment paths match
if (isSourceAttachmentEqual(root, entry)) {
// use package fragment root
return new PackageFragmentRootSourceLocation(root);
}
}
}
}
// check all other java projects to see if another project references
// the archive
IJavaModel model = JavaCore.create(ResourcesPlugin.getWorkspace().getRoot());
IJavaProject[] jps = model.getJavaProjects();
for (int i = 0; i < jps.length; i++) {
IPackageFragmentRoot[] allRoots = jps[i].getPackageFragmentRoots();
for (int j = 0; j < allRoots.length; j++) {
IPackageFragmentRoot root = allRoots[j];
if (!root.isExternal() && root.getPath().equals(entry.getPath())) {
if (isSourceAttachmentEqual(root, entry)) {
// use package fragment root
return new PackageFragmentRootSourceLocation(root);
}
}
}
}
} catch (JavaModelException e) {
LaunchingPlugin.log(e);
}
}
return null;
}
}