| /******************************************************************************* |
| * Copyright (c) 2005 The Regents of the University of California. |
| * This material was produced under U.S. Government contract W-7405-ENG-36 |
| * for Los Alamos National Laboratory, which is operated by the University |
| * of California for the U.S. Department of Energy. The U.S. Government has |
| * rights to use, reproduce, and distribute this software. NEITHER THE |
| * GOVERNMENT NOR THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR |
| * ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified |
| * to produce derivative works, such modified software should be clearly marked, |
| * so as not to confuse it with the version available from LANL. |
| * |
| * Additionally, 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 |
| * |
| * LA-CC 04-115 |
| *******************************************************************************/ |
| package org.eclipse.ptp.debug.internal.core.sourcelookup; |
| |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.transform.TransformerException; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceChangeEvent; |
| import org.eclipse.core.resources.IResourceChangeListener; |
| import org.eclipse.core.resources.IResourceDelta; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.debug.core.model.IPersistableSourceLocator; |
| import org.eclipse.debug.core.model.IStackFrame; |
| import org.eclipse.ptp.debug.core.PDebugUtils; |
| import org.eclipse.ptp.debug.core.PTPDebugCorePlugin; |
| import org.eclipse.ptp.debug.core.model.IPStackFrame; |
| import org.eclipse.ptp.debug.core.sourcelookup.IPSourceLocation; |
| import org.eclipse.ptp.debug.core.sourcelookup.IPSourceLocator; |
| import org.eclipse.ptp.debug.core.sourcelookup.IProjectSourceLocation; |
| import org.eclipse.ptp.debug.core.sourcelookup.SourceLookupFactory; |
| import org.osgi.framework.Bundle; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * @author Clement chu |
| * |
| */ |
| public class PSourceLocator implements IPSourceLocator, IPersistableSourceLocator, IResourceChangeListener { |
| private static final String SOURCE_LOCATOR_NAME = "pSourceLocator"; |
| private static final String DISABLED_GENERIC_PROJECT_NAME = "disabledGenericProject"; |
| private static final String ADDITIONAL_SOURCE_LOCATION_NAME = "additionalSourceLocation"; |
| private static final String SOURCE_LOCATION_NAME = "cSourceLocation"; |
| private static final String ATTR_CLASS = "class"; |
| private static final String ATTR_MEMENTO = "memento"; |
| private static final String ATTR_PROJECT_NAME = "projectName"; |
| private static final String ATTR_DUPLICATE_FILES = "duplicateFiles"; |
| private IProject fProject = null; |
| private IPSourceLocation[] fSourceLocations; |
| private List<IProject> fReferencedProjects = new ArrayList<IProject>(10); |
| private boolean fDuplicateFiles = false; |
| |
| public PSourceLocator(IProject project) { |
| setProject(project); |
| setReferencedProjects(); |
| setSourceLocations(getDefaultSourceLocations()); |
| } |
| public Object getSourceElement(IStackFrame stackFrame) { |
| return getInput(stackFrame); |
| } |
| public int getLineNumber(IStackFrame frame) { |
| return (frame instanceof IPStackFrame) ? ((IPStackFrame) frame).getFrameLineNumber() : 0; |
| } |
| protected Object getInput(IStackFrame f) { |
| if (f instanceof IPStackFrame) { |
| IPStackFrame frame = (IPStackFrame) f; |
| LinkedList<Object> list = new LinkedList<Object>(); |
| if (frame != null) { |
| Object result = null; |
| String fileName = frame.getFile(); |
| if (fileName != null && fileName.length() > 0) { |
| IPSourceLocation[] locations = getSourceLocations(); |
| for (int i = 0; i < locations.length; ++i) { |
| try { |
| result = locations[i].findSourceElement(fileName); |
| } catch (CoreException e) { |
| // do nothing |
| } |
| if (result != null) { |
| if (result instanceof List) |
| list.addAll((List<?>) result); |
| else |
| list.add(result); |
| if (!searchForDuplicateFiles()) |
| break; |
| } |
| } |
| } |
| } |
| return (list.size() > 0) ? ((list.size() == 1) ? list.getFirst() : list) : null; |
| } |
| return null; |
| } |
| public boolean contains(IResource resource) { |
| IPSourceLocation[] locations = getSourceLocations(); |
| for (int i = 0; i < locations.length; ++i) { |
| if (resource instanceof IProject) { |
| if (locations[i] instanceof PProjectSourceLocation && ((PProjectSourceLocation) locations[i]).getProject().equals(resource)) { |
| return true; |
| } |
| } |
| if (resource instanceof IFile) { |
| try { |
| Object result = locations[i].findSourceElement(resource.getLocation().toOSString()); |
| if (result instanceof IFile && ((IFile) result).equals(resource)) |
| return true; |
| if (result instanceof List && ((List<?>) result).contains(resource)) |
| return true; |
| } catch (CoreException e) { |
| } |
| } |
| } |
| return false; |
| } |
| public IPSourceLocation[] getSourceLocations() { |
| return fSourceLocations; |
| } |
| public void setSourceLocations(IPSourceLocation[] locations) { |
| fSourceLocations = locations; |
| } |
| public static IPSourceLocation[] getDefaultSourceLocations(IProject project) { |
| ArrayList<IProjectSourceLocation> list = new ArrayList<IProjectSourceLocation>(); |
| if (project != null && project.exists()) { |
| list.add(SourceLookupFactory.createProjectSourceLocation(project)); |
| addReferencedSourceLocations(list, project); |
| } |
| return (IPSourceLocation[]) list.toArray(new IPSourceLocation[list.size()]); |
| } |
| private static void addReferencedSourceLocations(List<IProjectSourceLocation> list, IProject project) { |
| if (project != null) { |
| try { |
| IProject[] projects = project.getReferencedProjects(); |
| for (int i = 0; i < projects.length; i++) { |
| if (projects[i].exists() && !containsProject(list, projects[i])) { |
| list.add(SourceLookupFactory.createProjectSourceLocation(projects[i])); |
| addReferencedSourceLocations(list, projects[i]); |
| } |
| } |
| } catch (CoreException e) { |
| // do nothing |
| } |
| } |
| } |
| private static boolean containsProject(List<IProjectSourceLocation> list, IProject project) { |
| Iterator<IProjectSourceLocation> it = list.iterator(); |
| while (it.hasNext()) { |
| IProjectSourceLocation location = (IProjectSourceLocation) it.next(); |
| if (project.equals(location.getProject())) |
| return true; |
| } |
| return false; |
| } |
| public Object findSourceElement(String fileName) { |
| Object result = null; |
| if (fileName != null && fileName.length() > 0) { |
| IPSourceLocation[] locations = getSourceLocations(); |
| for (int i = 0; i < locations.length; ++i) { |
| try { |
| result = locations[i].findSourceElement(fileName); |
| } catch (CoreException e) { |
| // do nothing |
| } |
| if (result != null) |
| break; |
| } |
| } |
| return result; |
| } |
| public String getMemento() throws CoreException { |
| Document document = null; |
| Throwable ex = null; |
| try { |
| document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); |
| Element node = document.createElement(SOURCE_LOCATOR_NAME); |
| document.appendChild(node); |
| IPSourceLocation[] locations = getSourceLocations(); |
| saveDisabledGenericSourceLocations(locations, document, node); |
| saveAdditionalSourceLocations(locations, document, node); |
| node.setAttribute(ATTR_DUPLICATE_FILES, new Boolean(searchForDuplicateFiles()).toString()); |
| return PDebugUtils.serializeDocument(document); |
| } catch (ParserConfigurationException e) { |
| ex = e; |
| } catch (IOException e) { |
| ex = e; |
| } catch (TransformerException e) { |
| ex = e; |
| } |
| abort(InternalSourceLookupMessages.getString("PSourceLocator.0"), ex); |
| // execution will not reach here |
| return null; |
| } |
| public void initializeDefaults(ILaunchConfiguration configuration) throws CoreException { |
| setSourceLocations(getDefaultSourceLocations()); |
| } |
| public void initializeFromMemento(String memento) throws CoreException { |
| Exception ex = null; |
| try { |
| Element root = null; |
| DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); |
| StringReader reader = new StringReader(memento); |
| InputSource source = new InputSource(reader); |
| root = parser.parse(source).getDocumentElement(); |
| if (!root.getNodeName().equalsIgnoreCase(SOURCE_LOCATOR_NAME)) { |
| abort(InternalSourceLookupMessages.getString("PSourceLocator.1"), null); |
| } |
| List<IPSourceLocation> sourceLocations = new ArrayList<IPSourceLocation>(); |
| // Add locations based on referenced projects |
| IProject project = getProject(); |
| if (project != null && project.exists() && project.isOpen()) |
| sourceLocations.addAll(Arrays.asList(getDefaultSourceLocations())); |
| removeDisabledLocations(root, sourceLocations); |
| addAdditionalLocations(root, sourceLocations); |
| // To support old launch configuration |
| addOldLocations(root, sourceLocations); |
| setSourceLocations((IPSourceLocation[]) sourceLocations.toArray(new IPSourceLocation[sourceLocations.size()])); |
| setSearchForDuplicateFiles(Boolean.valueOf(root.getAttribute(ATTR_DUPLICATE_FILES)).booleanValue()); |
| return; |
| } catch (ParserConfigurationException e) { |
| ex = e; |
| } catch (SAXException e) { |
| ex = e; |
| } catch (IOException e) { |
| ex = e; |
| } |
| abort(InternalSourceLookupMessages.getString("PSourceLocator.2"), ex); |
| } |
| private void removeDisabledLocations(Element root, List<IPSourceLocation> sourceLocations) { |
| NodeList list = root.getChildNodes(); |
| int length = list.getLength(); |
| HashSet<String> disabledProjects = new HashSet<String>(length); |
| 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(DISABLED_GENERIC_PROJECT_NAME)) { |
| String projectName = entry.getAttribute(ATTR_PROJECT_NAME); |
| if (isEmpty(projectName)) { |
| PTPDebugCorePlugin.log("Unable to restore C/C++ source locator - invalid format."); |
| } |
| disabledProjects.add(projectName.trim()); |
| } |
| } |
| } |
| Iterator<IPSourceLocation> it = sourceLocations.iterator(); |
| while (it.hasNext()) { |
| IPSourceLocation location = (IPSourceLocation) it.next(); |
| if (location instanceof IProjectSourceLocation && disabledProjects.contains(((IProjectSourceLocation) location).getProject().getName())) |
| it.remove(); |
| } |
| } |
| private void addAdditionalLocations(Element root, List<IPSourceLocation> sourceLocations) throws CoreException { |
| Bundle bundle = PTPDebugCorePlugin.getDefault().getBundle(); |
| MultiStatus status = new MultiStatus(PTPDebugCorePlugin.getUniqueIdentifier(), PTPDebugCorePlugin.INTERNAL_ERROR, InternalSourceLookupMessages.getString("PSourceLocator.3"), null); |
| 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(ADDITIONAL_SOURCE_LOCATION_NAME)) { |
| String className = entry.getAttribute(ATTR_CLASS); |
| String data = entry.getAttribute(ATTR_MEMENTO); |
| if (isEmpty(className)) { |
| PTPDebugCorePlugin.log("Unable to restore C/C++ source locator - invalid format."); |
| continue; |
| } |
| Class clazz = null; |
| try { |
| clazz = bundle.loadClass(className); |
| } catch (ClassNotFoundException e) { |
| PTPDebugCorePlugin.log(MessageFormat.format("Unable to restore source location - class not found {0}", new Object[] { className })); |
| continue; |
| } |
| IPSourceLocation location = null; |
| try { |
| location = (IPSourceLocation) clazz.newInstance(); |
| } catch (IllegalAccessException e) { |
| PTPDebugCorePlugin.log("Unable to restore source location."); |
| continue; |
| } catch (InstantiationException e) { |
| PTPDebugCorePlugin.log("Unable to restore source location."); |
| continue; |
| } |
| try { |
| location.initializeFrom(data); |
| sourceLocations.add(location); |
| } catch (CoreException e) { |
| status.addAll(e.getStatus()); |
| } |
| } |
| } |
| } |
| if (status.getSeverity() > IStatus.OK) |
| throw new CoreException(status); |
| } |
| private void addOldLocations(Element root, List<IPSourceLocation> sourceLocations) throws CoreException { |
| Bundle bundle = PTPDebugCorePlugin.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(SOURCE_LOCATION_NAME)) { |
| String className = entry.getAttribute(ATTR_CLASS); |
| String data = entry.getAttribute(ATTR_MEMENTO); |
| if (isEmpty(className)) { |
| PTPDebugCorePlugin.log("Unable to restore C/C++ source locator - invalid format."); |
| continue; |
| } |
| Class clazz = null; |
| try { |
| clazz = bundle.loadClass(className); |
| } catch (ClassNotFoundException e) { |
| PTPDebugCorePlugin.log(MessageFormat.format("Unable to restore source location - class not found {0}", new Object[] { className })); |
| continue; |
| } |
| IPSourceLocation location = null; |
| try { |
| location = (IPSourceLocation) clazz.newInstance(); |
| } catch (IllegalAccessException e) { |
| PTPDebugCorePlugin.log("Unable to restore source location."); |
| continue; |
| } catch (InstantiationException e) { |
| PTPDebugCorePlugin.log("Unable to restore source location."); |
| continue; |
| } |
| location.initializeFrom(data); |
| if (!sourceLocations.contains(location)) { |
| if (location instanceof PProjectSourceLocation) |
| ((PProjectSourceLocation) location).setGenerated(isReferencedProject(((PProjectSourceLocation) location).getProject())); |
| sourceLocations.add(location); |
| } |
| } |
| } |
| } |
| } |
| private void abort(String message, Throwable e) throws CoreException { |
| IStatus s = new Status(IStatus.ERROR, PTPDebugCorePlugin.getUniqueIdentifier(), PTPDebugCorePlugin.INTERNAL_ERROR, message, e); |
| throw new CoreException(s); |
| } |
| private boolean isEmpty(String string) { |
| return string == null || string.trim().length() == 0; |
| } |
| public void resourceChanged(IResourceChangeEvent event) { |
| if (event.getSource() instanceof IWorkspace && event.getDelta() != null) { |
| IResourceDelta[] deltas = event.getDelta().getAffectedChildren(); |
| if (deltas != null) { |
| ArrayList<IResource> list = new ArrayList<IResource>(deltas.length); |
| for (int i = 0; i < deltas.length; ++i) |
| if (deltas[i].getResource() instanceof IProject) |
| list.add(deltas[i].getResource()); |
| resetSourceLocations(list); |
| } |
| } |
| } |
| private void saveDisabledGenericSourceLocations(IPSourceLocation[] locations, Document doc, Element node) { |
| IProject project = getProject(); |
| if (project != null && project.exists() && project.isOpen()) { |
| List<IProject> list = PDebugUtils.getReferencedProjects(project); |
| HashSet<String> names = new HashSet<String>(list.size() + 1); |
| names.add(project.getName()); |
| Iterator<?> it = list.iterator(); |
| while (it.hasNext()) { |
| names.add(((IProject) it.next()).getName()); |
| } |
| for (int i = 0; i < locations.length; ++i) |
| if (locations[i] instanceof IProjectSourceLocation && ((IProjectSourceLocation) locations[i]).isGeneric()) |
| names.remove(((IProjectSourceLocation) locations[i]).getProject().getName()); |
| |
| it = names.iterator(); |
| while (it.hasNext()) { |
| Element child = doc.createElement(DISABLED_GENERIC_PROJECT_NAME); |
| child.setAttribute(ATTR_PROJECT_NAME, (String) it.next()); |
| node.appendChild(child); |
| } |
| } |
| } |
| private void saveAdditionalSourceLocations(IPSourceLocation[] locations, Document doc, Element node) { |
| for (int i = 0; i < locations.length; i++) { |
| if (locations[i] instanceof IProjectSourceLocation && ((IProjectSourceLocation) locations[i]).isGeneric()) |
| continue; |
| Element child = doc.createElement(ADDITIONAL_SOURCE_LOCATION_NAME); |
| child.setAttribute(ATTR_CLASS, locations[i].getClass().getName()); |
| try { |
| child.setAttribute(ATTR_MEMENTO, locations[i].getMemento()); |
| } catch (CoreException e) { |
| PTPDebugCorePlugin.log(e); |
| continue; |
| } |
| node.appendChild(child); |
| } |
| } |
| public IProject getProject() { |
| return fProject; |
| } |
| protected void setProject(IProject project) { |
| fProject = project; |
| } |
| private boolean isReferencedProject(IProject ref) { |
| if (getProject() != null) { |
| try { |
| return Arrays.asList(getProject().getReferencedProjects()).contains(ref); |
| } catch (CoreException e) { |
| PTPDebugCorePlugin.log(e); |
| } |
| } |
| return false; |
| } |
| private void setReferencedProjects() { |
| fReferencedProjects.clear(); |
| fReferencedProjects = PDebugUtils.getReferencedProjects(getProject()); |
| } |
| protected IPSourceLocation[] getDefaultSourceLocations() { |
| Iterator<IProject> it = fReferencedProjects.iterator(); |
| ArrayList<IProjectSourceLocation> list = new ArrayList<IProjectSourceLocation>(fReferencedProjects.size()); |
| if (getProject() != null && getProject().exists() && getProject().isOpen()) |
| list.add(SourceLookupFactory.createProjectSourceLocation(getProject())); |
| while (it.hasNext()) { |
| IProject project = (IProject) it.next(); |
| if (project != null && project.exists() && project.isOpen()) |
| list.add(SourceLookupFactory.createProjectSourceLocation(project)); |
| } |
| return (IPSourceLocation[]) list.toArray(new IPSourceLocation[list.size()]); |
| } |
| private void resetSourceLocations(List<IResource> affectedProjects) { |
| if (affectedProjects.size() != 0 && getProject() != null) { |
| if (!getProject().exists() || !getProject().isOpen()) { |
| removeGenericSourceLocations(); |
| } else { |
| updateGenericSourceLocations(affectedProjects); |
| } |
| } |
| } |
| private void removeGenericSourceLocations() { |
| fReferencedProjects.clear(); |
| IPSourceLocation[] locations = getSourceLocations(); |
| ArrayList<IPSourceLocation> newLocations = new ArrayList<IPSourceLocation>(locations.length); |
| for (int i = 0; i < locations.length; ++i) |
| if (!(locations[i] instanceof IProjectSourceLocation) || !((IProjectSourceLocation) locations[i]).isGeneric()) |
| newLocations.add(locations[i]); |
| setSourceLocations((IPSourceLocation[]) newLocations.toArray(new IPSourceLocation[newLocations.size()])); |
| } |
| private void updateGenericSourceLocations(List<IResource> affectedProjects) { |
| List<IProject> newRefs = PDebugUtils.getReferencedProjects(getProject()); |
| IPSourceLocation[] locations = getSourceLocations(); |
| ArrayList<IPSourceLocation> newLocations = new ArrayList<IPSourceLocation>(locations.length); |
| for (int i = 0; i < locations.length; ++i) { |
| if (!(locations[i] instanceof IProjectSourceLocation) || !((IProjectSourceLocation) locations[i]).isGeneric()) { |
| newLocations.add(locations[i]); |
| } else { |
| IProject project = ((IProjectSourceLocation) locations[i]).getProject(); |
| if (project.exists() && project.isOpen()) { |
| if (newRefs.contains(project) || project.equals(getProject())) { |
| newLocations.add(locations[i]); |
| newRefs.remove(project); |
| } |
| } |
| } |
| } |
| Iterator<IProject> it = newRefs.iterator(); |
| while (it.hasNext()) { |
| IProject project = (IProject) it.next(); |
| if (!fReferencedProjects.contains(project)) |
| newLocations.add(SourceLookupFactory.createProjectSourceLocation(project)); |
| } |
| fReferencedProjects = newRefs; |
| setSourceLocations((IPSourceLocation[]) newLocations.toArray(new IPSourceLocation[newLocations.size()])); |
| } |
| public boolean searchForDuplicateFiles() { |
| return fDuplicateFiles; |
| } |
| public void setSearchForDuplicateFiles(boolean search) { |
| fDuplicateFiles = search; |
| IPSourceLocation[] locations = getSourceLocations(); |
| for (int i = 0; i < locations.length; ++i) |
| locations[i].setSearchForDuplicateFiles(search); |
| } |
| } |