blob: 0f7c9328cc9a2a39c6f296038b7ddf00c63baaf7 [file] [log] [blame]
/*
*(c) Copyright QNX Software Systems Ltd. 2002.
* All Rights Reserved.
*
*/
package org.eclipse.cdt.debug.internal.core.sourcelookup;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.xerces.dom.DocumentImpl;
import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.cdt.debug.core.CDebugUtils;
import org.eclipse.cdt.debug.core.sourcelookup.ICSourceLocation;
import org.eclipse.cdt.debug.core.sourcelookup.IProjectSourceLocation;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
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.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
*
* Locates source elements in a Java project. Returns instances of <code>IFile</code>.
*
* @since Sep 23, 2002
*/
public class CProjectSourceLocation implements IProjectSourceLocation
{
private static final String ELEMENT_NAME = "cProjectSourceLocation";
private static final String ATTR_PROJECT = "project";
private static final String ATTR_GENERIC = "generic";
/**
* The project associated with this source location
*/
private IProject fProject;
private IResource[] fFolders;
private HashMap fCache = new HashMap( 20 );
private HashSet fNotFoundCache = new HashSet( 20 );
private boolean fGenerated = true;
private boolean fSearchForDuplicateFiles = false;
/**
* Constructor for CProjectSourceLocation.
*/
public CProjectSourceLocation()
{
}
/**
* Constructor for CProjectSourceLocation.
*/
public CProjectSourceLocation( IProject project )
{
setProject( project );
fGenerated = true;
}
/**
* Constructor for CProjectSourceLocation.
*/
public CProjectSourceLocation( IProject project, boolean generated )
{
setProject( project );
fGenerated = generated;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.sourcelookup.ICSourceLocation#findSourceElement(String)
*/
public Object findSourceElement( String name ) throws CoreException
{
Object result = null;
if ( !isEmpty( name ) && getProject() != null && !notFoundCacheLookup( name ) )
{
result = cacheLookup( name );
if ( result == null )
{
result = doFindSourceElement( name );
if ( result != null )
{
cacheSourceElement( name, result );
}
}
if ( result == null )
{
cacheNotFound( name );
}
}
return result;
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(Class)
*/
public Object getAdapter( Class adapter )
{
if ( adapter.equals( ICSourceLocation.class ) )
return this;
if ( adapter.equals( CProjectSourceLocation.class ) )
return this;
if ( adapter.equals( IProject.class ) )
return getProject();
return null;
}
/**
* Sets the project in which source elements will be searched for.
*
* @param project the project
*/
private void setProject( IProject project )
{
fProject = project;
}
/**
* Returns the project associated with this source location.
*
* @return project
*/
public IProject getProject()
{
return fProject;
}
private Object doFindSourceElement( String name )
{
File file = new File( name );
return ( file.isAbsolute() ) ? findFileByAbsolutePath( file ) : findFileByRelativePath( name );
}
private Object findFileByAbsolutePath( File file )
{
LinkedList list = new LinkedList();
if ( file.exists() )
{
IPath path = new Path( file.getAbsolutePath() );
IFile[] wsFiles = CDebugCorePlugin.getWorkspace().getRoot().findFilesForLocation( path );
for ( int i = 0; i < wsFiles.length; ++i )
if ( wsFiles[i].getProject().equals( getProject() ) && wsFiles[i].exists() )
if ( !searchForDuplicateFiles() )
return wsFiles[i];
else
list.add( wsFiles[i] );
}
return ( list.size() > 0 ) ? ( ( list.size() == 1 ) ? list.getFirst() : list ) : null;
}
private Object findFileByRelativePath( String fileName )
{
IResource[] folders = getFolders();
LinkedList list = new LinkedList();
for ( int i = 0; i < folders.length; ++i )
{
if ( list.size() > 0 && !searchForDuplicateFiles() )
break;
IPath path = folders[i].getLocation().append( fileName );
File file = new File( path.toOSString() );
if ( file.exists() )
{
IFile[] wsFiles = CDebugCorePlugin.getWorkspace().getRoot().findFilesForLocation( path );
for ( int j = 0; j < wsFiles.length; ++j )
if ( wsFiles[j].exists() )
if ( !searchForDuplicateFiles() )
return wsFiles[j];
else
list.add( wsFiles[j] );
}
}
return ( list.size() > 0 ) ? ( ( list.size() == 1 ) ? list.getFirst() : list ) : null;
}
private Object cacheLookup( String name )
{
return fCache.get( name );
}
private boolean notFoundCacheLookup( String name )
{
return fNotFoundCache.contains( name );
}
private void cacheSourceElement( String name, Object element )
{
fCache.put( name, element );
}
private void cacheNotFound( String name )
{
fNotFoundCache.add( name );
}
public void dispose()
{
fCache.clear();
fNotFoundCache.clear();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.sourcelookup.ICSourceLocation#getMemento()
*/
public String getMemento() throws CoreException
{
Document doc = new DocumentImpl();
Element node = doc.createElement( ELEMENT_NAME );
doc.appendChild( node );
node.setAttribute( ATTR_PROJECT, getProject().getName() );
node.setAttribute( ATTR_GENERIC, new Boolean( isGeneric() ).toString() );
try
{
return CDebugUtils.serializeDocument( doc, " " );
}
catch( IOException e )
{
abort( MessageFormat.format( "Unable to create memento for C/C++ project source location {0}.", new String[] { getProject().getName() } ), e );
}
// execution will not reach here
return null;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.sourcelookup.ICSourceLocation#initializeFrom(java.lang.String)
*/
public void initializeFrom( 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();
String name = root.getAttribute( ATTR_PROJECT );
if ( isEmpty( name ) )
{
abort( "Unable to initialize source location - missing project name", null );
}
else
{
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject( name );
setProject( project );
}
String isGeneric = root.getAttribute( ATTR_GENERIC );
if ( isGeneric == null || isGeneric.trim().length() == 0 )
isGeneric = Boolean.FALSE.toString();
setGenerated( isGeneric.equals( Boolean.TRUE.toString() ) );
return;
}
catch( ParserConfigurationException e )
{
ex = e;
}
catch( SAXException e )
{
ex = e;
}
catch( IOException e )
{
ex = e;
}
abort( "Exception occurred initializing source location.", ex );
}
/**
* Throws an internal error exception
*/
private void abort( String message, Throwable e ) throws CoreException
{
IStatus s = new Status( IStatus.ERROR,
CDebugCorePlugin.getUniqueIdentifier(),
CDebugCorePlugin.INTERNAL_ERROR,
message,
e );
throw new CoreException( s );
}
private boolean isEmpty( String string )
{
return string == null || string.length() == 0;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.sourcelookup.IProjectSourceLocation#isGenerated()
*/
public boolean isGeneric()
{
return fGenerated;
}
public void setGenerated( boolean b )
{
fGenerated = b;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals( Object obj )
{
if ( obj instanceof IProjectSourceLocation && getProject() != null )
return getProject().equals( ((IProjectSourceLocation)obj).getProject() );
return false;
}
private void initializeFolders()
{
final LinkedList list = new LinkedList();
if ( getProject() != null )
{
list.add( getProject() );
try
{
getProject().accept(
new IResourceProxyVisitor()
{
public boolean visit( IResourceProxy proxy ) throws CoreException
{
switch( proxy.getType() )
{
case IResource.FILE:
return false;
case IResource.FOLDER:
list.addLast( proxy.requestResource() );
return true;
}
return true;
}
},
IResource.NONE );
}
catch( CoreException e )
{
}
}
fFolders = (IResource[])list.toArray( new IResource[list.size()] );
}
protected IResource[] getFolders()
{
if ( fFolders == null )
initializeFolders();
return fFolders;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.sourcelookup.ICSourceLocation#searchForDuplicateFiles()
*/
public boolean searchForDuplicateFiles()
{
return fSearchForDuplicateFiles;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.sourcelookup.ICSourceLocation#setSearchForDuplicateFiles(boolean)
*/
public void setSearchForDuplicateFiles( boolean search )
{
fCache.clear();
fNotFoundCache.clear();
fSearchForDuplicateFiles = search;
}
public String toString()
{
return ( getProject() != null ) ? fProject.toString() : "";
}
}