/* * Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved. * * This program and the accompanying materials are made available * under the terms of the Eclipse Public License, Version 1.0, * which accompanies this distribution and is available at * * http://www.eclipse.org/legal/epl-v10.html * */ package net.rim.ejde.internal.sourcelookup; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import net.rim.ejde.internal.core.ContextManager; import net.rim.ejde.internal.ui.launchers.LaunchUtils; import net.rim.ejde.internal.util.NatureUtils; import org.apache.log4j.Logger; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.jdt.core.IClasspathContainer; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; import org.eclipse.jdt.launching.IRuntimeClasspathEntry; import org.eclipse.jdt.launching.IRuntimeClasspathEntry2; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.StandardSourcePathProvider; public class RIMSourcePathProvider extends StandardSourcePathProvider { private static Logger log = Logger.getLogger( RIMSourcePathProvider.class ); public final static String RIM_SOURCEPATH_PROVIDER_ID = "net.rim.ejde.sourcelookup.RIMSourcePathProvider"; public static final String DEFAIULT_TYPE_ID = "org.eclipse.jdt.launching.classpathentry.defaultClasspath"; //$NON-NLS-1$ public static final String STRING_VARIABLE_TYPE_ID = "org.eclipse.jdt.launching.classpathentry.variableClasspathEntry"; /* * (non-Javadoc) * * @seeorg.eclipse.jdt.launching.IRuntimeClasspathProvider# * computeUnresolvedClasspath(org.eclipse.debug.core.ILaunchConfiguration) */ public IRuntimeClasspathEntry[] computeUnresolvedClasspath( ILaunchConfiguration configuration ) throws CoreException { boolean useDefault = configuration.getAttribute( IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH, true ); IRuntimeClasspathEntry[] entries = null; if( useDefault ) { IJavaProject[] projects = getJavaProjects( configuration ); entries = new IRuntimeClasspathEntry[ 0 ]; for( int j = 0; j < projects.length; j++ ) { IJavaProject proj = projects[ j ]; IRuntimeClasspathEntry[] subEntries = JavaRuntime.computeUnresolvedRuntimeClasspath( proj ); IRuntimeClasspathEntry[] newEntries = new IRuntimeClasspathEntry[ entries.length + subEntries.length ]; System.arraycopy( entries, 0, newEntries, 0, entries.length ); System.arraycopy( subEntries, 0, newEntries, entries.length, subEntries.length ); entries = newEntries; } } else { // recover persisted source path entries = recoverRuntimePath( configuration, IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH ); } return entries; } /** * Computes and returns the default unresolved runtime classpath for the given project. * * @return runtime classpath entries * @exception CoreException * if unable to compute the runtime classpath * @see IRuntimeClasspathEntry */ public static IRuntimeClasspathEntry[] computeUnresolvedRuntimeClasspath( IJavaProject project ) throws CoreException { IClasspathEntry[] entries = project.getRawClasspath(); List< IRuntimeClasspathEntry > classpathEntries = new ArrayList< IRuntimeClasspathEntry >(); for( int i = 0; i < entries.length; i++ ) { IClasspathEntry entry = entries[ i ]; switch( entry.getEntryKind() ) { case IClasspathEntry.CPE_CONTAINER: IClasspathContainer container = JavaCore.getClasspathContainer( entry.getPath(), project ); if( container != null ) { switch( container.getKind() ) { case IClasspathContainer.K_APPLICATION: // don't look at application entries break; case IClasspathContainer.K_DEFAULT_SYSTEM: classpathEntries.add( JavaRuntime.newRuntimeContainerClasspathEntry( container.getPath(), IRuntimeClasspathEntry.STANDARD_CLASSES, project ) ); break; case IClasspathContainer.K_SYSTEM: classpathEntries.add( JavaRuntime.newRuntimeContainerClasspathEntry( container.getPath(), IRuntimeClasspathEntry.BOOTSTRAP_CLASSES, project ) ); break; } } break; case IClasspathEntry.CPE_VARIABLE: if( JavaRuntime.JRELIB_VARIABLE.equals( entry.getPath().segment( 0 ) ) ) { IRuntimeClasspathEntry jre = JavaRuntime.newVariableRuntimeClasspathEntry( entry.getPath() ); jre.setClasspathProperty( IRuntimeClasspathEntry.STANDARD_CLASSES ); classpathEntries.add( jre ); } break; default: break; } } classpathEntries.add( JavaRuntime.newDefaultProjectClasspathEntry( project ) ); return classpathEntries.toArray( new IRuntimeClasspathEntry[ classpathEntries.size() ] ); } /* * (non-Javadoc) * * @see org.eclipse.jdt.launching.IRuntimeClasspathProvider#resolveClasspath( * org.eclipse.jdt.launching.IRuntimeClasspathEntry[], org.eclipse.debug.core.ILaunchConfiguration) */ public IRuntimeClasspathEntry[] resolveClasspath( IRuntimeClasspathEntry[] entries, ILaunchConfiguration configuration ) throws CoreException { List< IRuntimeClasspathEntry > all = new UniqueList( entries.length ); for( int i = 0; i < entries.length; i++ ) { try { switch( entries[ i ].getType() ) { case IRuntimeClasspathEntry.PROJECT: // a project resolves to itself for source lookup // (rather // than the class file output locations) all.add( entries[ i ] ); break; case IRuntimeClasspathEntry.OTHER: IRuntimeClasspathEntry2 entry = (IRuntimeClasspathEntry2) entries[ i ]; String typeId = entry.getTypeId(); IRuntimeClasspathEntry[] res = null; if( typeId.equals( DEFAIULT_TYPE_ID ) ) { // add the resolved children of the project IRuntimeClasspathEntry[] children = entry.getRuntimeClasspathEntries( configuration ); res = JavaRuntime.resolveSourceLookupPath( children, configuration ); } else { res = JavaRuntime.resolveRuntimeClasspathEntry( entry, configuration ); } if( res != null ) { for( int j = 0; j < res.length; j++ ) { all.add( res[ j ] ); addManifestReferences( res[ j ], all ); } } break; default: IRuntimeClasspathEntry[] resolved = JavaRuntime .resolveRuntimeClasspathEntry( entries[ i ], configuration ); for( int j = 0; j < resolved.length; j++ ) { all.add( resolved[ j ] ); addManifestReferences( resolved[ j ], all ); } break; } } catch( CoreException e ) { // if an exception is caught, we will still try to resolve the // rest classpathes // TODO: should we pop-up a dialog to display the error // messages? or display the // exceptions in problem view? log.error( e ); } } return all.toArray( new IRuntimeClasspathEntry[ all.size() ] ); } /** * Return the <code>IJavaProject</code> referenced in the specified configuration or <code>null</code> if none. * * @exception CoreException * if the referenced Java project does not exist */ private IJavaProject[] getJavaProjects( ILaunchConfiguration configuration ) throws CoreException { Set< IProject > iProjects = LaunchUtils.getProjectsFromConfiguration( configuration ); List< IJavaProject > javaProjects = new ArrayList< IJavaProject >(); for( Iterator< IProject > iterator = iProjects.iterator(); iterator.hasNext(); ) { IProject project = iterator.next(); if( NatureUtils.hasBBNature( project ) ) { IJavaProject javaProject = JavaCore.create( project ); javaProjects.add( javaProject ); if( javaProject != null && javaProject.getProject().exists() && !javaProject.getProject().isOpen() ) { handldError( "Project is closed.", IJavaLaunchConfigurationConstants.ERR_PROJECT_CLOSED, null ); } if( ( javaProject == null ) || !javaProject.exists() ) { handldError( "Project was not found.", IJavaLaunchConfigurationConstants.ERR_NOT_A_JAVA_PROJECT, null ); } } } return javaProjects.toArray( new IJavaProject[ 0 ] ); } /** * Throws a core exception. * * @param message * the error message * @param code * severity code * @param exception */ private static void handldError( String message, int code, Throwable exception ) throws CoreException { throw new CoreException( new Status( IStatus.ERROR, ContextManager.PLUGIN_ID, code, message, exception ) ); } /* * An ArrayList that acts like a set -i.e. does not allow duplicate items. */ class UniqueList extends ArrayList { public UniqueList( int length ) { super( length ); } public UniqueList() { super(); } public boolean add( Object o ) { if( !super.contains( o ) ) return super.add( o ); return false; } } }