/groovy-eclipse/org.codehaus.groovy.eclipse.core/src/org/codehaus/groovy/eclipse/core/model/GroovyProject.java
Java | 1249 lines | 1164 code | 8 blank | 77 comment | 31 complexity | 10397917b7e3cae305ec81e836049c36 MD5 | raw file
Possible License(s): Apache-2.0
Large files files are truncated, but you can click here to view the full file
- /*
- * Created on 21-Jan-2004
- *
- * To change the template for this generated file go to Window - Preferences -
- * Java - Code Generation - Code and Comments
- */
- package org.codehaus.groovy.eclipse.core.model;
- import static org.apache.commons.io.FileUtils.forceDelete;
- import static org.apache.commons.io.IOUtils.closeQuietly;
- import static org.apache.commons.lang.StringUtils.defaultString;
- import static org.apache.commons.lang.StringUtils.isBlank;
- import static org.apache.commons.lang.StringUtils.isNotBlank;
- import static org.apache.commons.lang.StringUtils.removeStart;
- import static org.codehaus.groovy.eclipse.collections.ListUtil.newEmptyList;
- import static org.codehaus.groovy.eclipse.collections.ListUtil.newList;
- import static org.codehaus.groovy.eclipse.collections.MapUtil.newEmptyLinkedMap;
- import static org.codehaus.groovy.eclipse.collections.SetUtil.linkedSet;
- import static org.codehaus.groovy.eclipse.core.GroovyCore.logException;
- import static org.codehaus.groovy.eclipse.core.GroovyCore.trace;
- import static org.codehaus.groovy.eclipse.core.model.GroovyProjectModel.getClassesForModules;
- import static org.codehaus.groovy.eclipse.core.model.GroovyProjectModel.getSourceFileKey;
- import static org.codehaus.groovy.eclipse.core.preferences.PreferenceConstants.GROOVY_DONT_CHECK_PACKAGE_VS_SRC_PATH;
- import static org.codehaus.groovy.eclipse.core.preferences.PreferenceConstants.GROOVY_DONT_GENERATE_CLASS_FILES;
- import static org.codehaus.groovy.eclipse.core.util.CoreUtils.createLineToOffsetMapping;
- import static org.eclipse.core.resources.IResource.DEPTH_INFINITE;
- import static org.eclipse.core.resources.IncrementalProjectBuilder.CLEAN_BUILD;
- import static org.eclipse.core.resources.IncrementalProjectBuilder.FULL_BUILD;
- import static org.eclipse.core.resources.IncrementalProjectBuilder.INCREMENTAL_BUILD;
- import static org.eclipse.core.resources.ResourcesPlugin.getWorkspace;
- import static org.eclipse.swt.widgets.Display.getDefault;
- import java.io.BufferedReader;
- import java.io.ByteArrayInputStream;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.net.URLClassLoader;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import org.apache.commons.lang.StringUtils;
- import org.codehaus.groovy.antlr.GroovySourceAST;
- import org.codehaus.groovy.ast.ClassNode;
- import org.codehaus.groovy.ast.ModuleNode;
- import org.codehaus.groovy.eclipse.core.GroovyCore;
- import org.codehaus.groovy.eclipse.core.builder.GroovyNature;
- import org.codehaus.groovy.eclipse.core.compiler.GroovyCompiler;
- import org.codehaus.groovy.eclipse.core.compiler.GroovyCompilerConfigurationBuilder;
- import org.codehaus.groovy.eclipse.core.compiler.IGroovyCompilationReporter;
- import org.codehaus.groovy.eclipse.core.compiler.IGroovyCompiler;
- import org.codehaus.groovy.eclipse.core.compiler.IGroovyCompilerConfiguration;
- import org.codehaus.groovy.eclipse.core.preferences.PreferenceConstants;
- import org.codehaus.groovy.eclipse.core.preferences.PropertyChangeListener;
- import org.codehaus.groovy.syntax.SyntaxException;
- import org.eclipse.core.resources.IContainer;
- import org.eclipse.core.resources.IFile;
- import org.eclipse.core.resources.IFolder;
- import org.eclipse.core.resources.IMarker;
- import org.eclipse.core.resources.IProject;
- import org.eclipse.core.resources.IResource;
- import org.eclipse.core.resources.IResourceDelta;
- import org.eclipse.core.resources.IWorkspaceRoot;
- import org.eclipse.core.resources.IWorkspaceRunnable;
- import org.eclipse.core.resources.ProjectScope;
- import org.eclipse.core.resources.WorkspaceJob;
- import org.eclipse.core.runtime.CoreException;
- import org.eclipse.core.runtime.IPath;
- import org.eclipse.core.runtime.IProgressMonitor;
- import org.eclipse.core.runtime.IStatus;
- import org.eclipse.core.runtime.NullProgressMonitor;
- import org.eclipse.core.runtime.Path;
- import org.eclipse.core.runtime.Status;
- import org.eclipse.core.runtime.jobs.ILock;
- import org.eclipse.core.runtime.jobs.Job;
- import org.eclipse.jdt.core.IClasspathEntry;
- 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.jface.preference.IPersistentPreferenceStore;
- import org.eclipse.ui.preferences.ScopedPreferenceStore;
- /**
- * The main groovy project class used to configure the project settings, and do
- * the compiling.
- *
- * @author MelamedZ
- * @author Hein Meling
- * @author empovazan - many changes extracting actual building into a
- * GroovyCompiler class and updating AST from changed by unsaved source
- * files.
- */
- public class GroovyProject
- {
- // Tries to get Groovy output path
- public static String getProjectOutputPath( final IJavaProject javaProject )
- {
- final String projectPreference = preferenceStore( javaProject.getProject() ).getString( PreferenceConstants.GROOVY_COMPILER_OUTPUT_PATH );
- if( isNotBlank( projectPreference ) )
- {
- if( !javaProject.getProject().getFolder( projectPreference ).exists() )
- {
- trace( "Trying to set Groovy output path inside of GroovyProject.getProjectOutputPath()" );
- // TODO: emp - again, redundant? vs:
- // GroovyModel.getModel().getGroovyProject(javaProject).
- // setOutputPath(projectPreference,
- // projectPreference);
- try
- {
- GroovyModel.getModel().getGroovyProject( javaProject ).setOutputPath( projectPreference, projectPreference );
- }
- catch( final Exception e )
- {
- logException( "Error while retrieving the output path of the project " + javaProject.getElementName(), e );
- return null;
- }
- }
- return projectPreference;
- }
- return "";
- }
- /**
- * Returns the Eclipse project output path
- *
- * @param project
- * @return
- * @throws JavaModelException
- */
- public static String getOutputPath( final IJavaProject project )
- throws JavaModelException
- {
- if( project == null || !project.exists() || project.getProject().getLocation() == null )
- return null;
- return project.getProject().getLocation().toString() + "/" + getProjectOutputPath( project );
- }
- public static String getOutputOSPath( final IJavaProject project ) throws JavaModelException
- {
- if( project == null || !project.exists() || project.getProject().getLocation() == null )
- return null;
- final String outputPath = project.getProject().getLocation().toOSString()
- + File.separator
- + getProjectOutputPath( project ).replace( '/', File.separatorChar );
- return outputPath;
- }
- /**
- * called when setting the Eclipse Project preference for compiled groovy
- * output - create the new folder if it exists - delete the old folder - add
- * the new folder to the Project classpath - rebuild the project
- *
- * @param oldPath
- * @param newPath
- */
- public void setOutputPath( final String oldPath,
- final String newPath )
- {
- trace("in GroovyProject.setOutputPath() - attempting to change output path from " + oldPath + " to " + newPath);
- final IWorkspaceRoot root = getWorkspace().getRoot();
- final IProject project = javaProject.getProject();
- // if the old equals the new and it already exists, nothing to do
- if( StringUtils.equals( newPath, oldPath ) && isNotBlank( newPath ) )
- {
- final IFolder folder = root.getFolder( new Path( project.getFullPath() + "/" + newPath ) );
- if( folder.exists() )
- return;
- }
- final IWorkspaceRunnable runnable = new IWorkspaceRunnable()
- {
- public void run( final IProgressMonitor monitor )
- throws CoreException
- {
- final String savedWorkspacePath = project.getFullPath() + "/" + oldPath;
- final IFolder savedFolder = isNotBlank( oldPath )
- ? root.getFolder( new Path( savedWorkspacePath ) )
- : null;
- // delete the old Groovy output folder
- if( savedFolder != null && savedFolder.exists() )
- {
- if( !javaProject.getOutputLocation().equals( savedFolder.getFullPath() ) )
- savedFolder.delete( true, monitor );
- }
- // user folder typed in
- if( isNotBlank( newPath ) )
- {
- final IFolder folder = project.getFolder( newPath );
- trace( "new output folder equals:" + folder );
- if( !javaProject.getOutputLocation().equals( folder.getFullPath() ) && !folder.exists() )
- {
- folder.create( true, false, monitor );
- folder.setDerived( true );
- }
- }
- return;
- }
- };
- new WorkspaceJob( "Updating Groovy output location for project: " + project.getName() )
- {
- @Override
- public IStatus runInWorkspace( final IProgressMonitor monitor )
- throws CoreException
- {
- getWorkspace().run( runnable, monitor );
- return Status.OK_STATUS;
- }
- }.schedule();
- }
- class CompilationReporter
- implements IGroovyCompilationReporter
- {
- private final Map< String, IFile > mapFileNamesToIFile;
- private final IProgressMonitor monitor;
- String erroredFileName = "";
- List lineToOffsetsMapping;
- public CompilationReporter( final Map< String, IFile > mapFileNamesToIFile,
- final IProgressMonitor monitor )
- {
- this.mapFileNamesToIFile = mapFileNamesToIFile;
- this.monitor = monitor;
- }
- public void beginReporting()
- {
- monitor.worked( 1 );
- }
- public void endReporting()
- {
- // TODO: emp - tentative location for this method call. The thing
- // is, generated*() notifications are sent
- // before this method is called. In addition, it seems only the
- // output folders should be refreshed.
- // The line:
- // javaProject.getProject().refreshLocal(IResource.DEPTH_INFINITE,
- // new NullProgressMonitor());
- // seems to imply otherwise. Am I missing something?
- refreshOutput();
- }
- public void compilationError( final String fileName,
- final int line,
- final int startCol,
- final int endCol,
- final String message,
- final String stackTrace )
- {
- final IFile file = mapFileNamesToIFile.get( fileName );
- try
- {
- // Cache the line to offsets mapping.
- if( !fileName.equals( erroredFileName ) )
- {
- erroredFileName = fileName;
- lineToOffsetsMapping = createLineToOffsetMapping( file );
- }
- }
- catch( final IOException e )
- {
- logException( "Internal error reporting error, please report" + file.getName(), e );
- return;
- }
- catch( final CoreException e )
- {
- logException( "Internal error reporting error, please report" + file.getName(), e );
- }
- try
- {
- getWorkspace().run( new AddErrorMarkerTask( file,
- lineToOffsetsMapping,
- line,
- startCol,
- endCol,
- message,
- stackTrace),
- null );
- }
- catch( final CoreException ce )
- {
- logException("error compiling " + file.getName(), ce);
- }
- }
- public void generatedAST( final String fileName,
- final ModuleNode moduleNode )
- {
- // TODO: emp - every single artifact must be reported - this only
- // stores the module node for the file and
- // not all the other dependencies.
- // Some refactoring is needed.
- model.updateClassNameModuleNodeMap( newList( moduleNode ) );
- }
- public void generatedClasses( final String fileName,
- final String[] classNames,
- final String[] classFilePaths )
- {
- final IProject project = getJavaProject().getProject();
- final IPath projectPath = project.getLocation();
- try
- {
- final IFolder outputFolder = project.getFolder( getProjectOutputPath( javaProject ) );
- outputFolder.refreshLocal( DEPTH_INFINITE, new NullProgressMonitor() );
- for( final String path : classFilePaths )
- {
- final IPath classFilePath = new Path( path );
- final int count = classFilePath.matchingFirstSegments( projectPath );
- final IFile classFile = project.getFile( classFilePath.removeFirstSegments( count ) );
- try
- {
- classFile.setDerived( true );
- }
- catch( final CoreException e )
- {
- logException( e.getMessage(), e );
- }
- }
- }
- catch( final CoreException e )
- {
- logException( e.getMessage(), e );
- }
- final IFile file = mapFileNamesToIFile.get( fileName );
- fireGroovyFileBuilt( file );
- }
- public void beginReporting( final String fileName ) {}
- public void endReporting( final String fileName ) {}
- public void generatedCST( final String fileName, final GroovySourceAST cst ) {}
- }
- /**
- * Compilation reporter when rebuilding a specific AST from an input stream.
- */
- class InputStreamCompileReporter
- implements IGroovyCompilationReporter
- {
- private final IFile file;
- private final String sourceCode;
- private List lineToOffsetsMapping;
- InputStreamCompileReporter( final IFile file,
- final String sourceCode )
- {
- this.file = file;
- this.sourceCode = sourceCode;
- }
- public void beginReporting( final String fileName )
- {
- deleteErrorMarkers( file );
- }
- public void compilationError( final String fileName,
- final int line,
- final int startCol,
- final int endCol,
- final String message,
- final String stackTrace )
- {
- if( lineToOffsetsMapping == null )
- lineToOffsetsMapping = createLineToOffsetMapping( sourceCode );
- try
- {
- getWorkspace().run( new AddErrorMarkerTask( file, lineToOffsetsMapping, line, startCol, endCol, message, stackTrace ), null );
- }
- catch( final CoreException ce )
- {
- logException( "error compiling " + file.getName(), ce );
- }
- }
- public void generatedAST( final String fileName,
- final ModuleNode moduleNode )
- {
- // TODO: emp - fix this with a new API once I figure out what is
- // happening in
- // GroovyProjectModel.
- model.updateClassNameModuleNodeMap( newList( moduleNode ) );
- // TODO: emp - Hack! GroovyBuildListener needs a fuller API to
- // report building of ASTs
- // and class files.
- // Many listeners care only about the AST.
- fireGroovyFileBuilt( file );
- }
- public void beginReporting() {}
- public void endReporting() {}
- public void endReporting( final String fileName) {}
- public void generatedCST( final String fileName, final GroovySourceAST cst ) {}
- public void generatedClasses( final String fileName, final String[] classNames, final String[] classFilePaths) {}
- }
- private final IJavaProject javaProject;
- private final IPersistentPreferenceStore preferenceStore;
- private final GroovyProjectModel model = new GroovyProjectModel(this);
- public static final String GROOVY_ERROR_MARKER = "org.codehaus.groovy.eclipse.groovyFailure";
- private final ILock listenersLock = Job.getJobManager().newLock();
- private final List< GroovyBuildListener > listeners = newList();
- private final IGroovyCompiler compiler = new GroovyCompiler();
- // TODO: We need to keep track if a full build has occurred without errors
- // or not.
- // If it hasn't, methods that do things like return all runnable classes
- // with a main
- // won't work correctly unless a full build occurrs to create Module Nodes
- // for all the
- // source files in the project.
- // private boolean hasFullBuildHappened = false;
- /**
- * Construct new groovy project.
- *
- * @param javaProject
- */
- public GroovyProject( final IJavaProject javaProject )
- {
- this.javaProject = javaProject;
- preferenceStore = preferenceStore( javaProject.getProject() );
- preferenceStore.addPropertyChangeListener( new PropertyChangeListener( javaProject.getProject() ) );
- GroovyCore.getPreferenceStore()
- .addPropertyChangeListener( new PropertyChangeListener( javaProject.getProject() ) );
- trace( "constructing Groovy Project " + javaProject.getElementName() );
- // Note that enabling debug will disable class generation
- // compilerConfiguration.setDebug(true);
- }
- public GroovyProjectModel getModel()
- {
- return model;
- }
- public GroovyProjectModel model()
- {
- return getModel();
- }
- public IContainer getGroovyOutputFolder()
- {
- final String outputPath = defaultString( getProjectOutputPath( getJavaProject() ) ).trim();
- if( isBlank( outputPath ) || StringUtils.equals( "/", outputPath ) || StringUtils.equals( "\\", outputPath ) )
- return getJavaProject().getProject();
- return getJavaProject().getProject().getFolder( outputPath );
- }
- public IPersistentPreferenceStore getPreferenceStore()
- {
- return preferenceStore;
- }
- public GroovyProject rebuild( final IProgressMonitor monitor )
- {
- buildGroovyContent( monitor, FULL_BUILD, filesForFullBuild() );
- return this;
- }
- public boolean isGeneratingClassFiles()
- {
- return !preferenceStore.getBoolean( GROOVY_DONT_GENERATE_CLASS_FILES );
- }
- /**
- * Overloaded method used by builders to compile groovy files that defaults
- * to the variable for generating .class files to what's set in the Groovy
- * prefs page
- *
- * @param monitor
- * @param kind
- */
- public void buildGroovyContent( final IProgressMonitor monitor,
- final int kind,
- final ChangeSet changeSet)
- {
- if( monitor.isCanceled() )
- return;
- buildGroovyContent( monitor, kind, changeSet, isGeneratingClassFiles() );
- }
- /**
- * Used by builders to compile Groovy source
- *
- * @param monitor
- * @param kind
- * @param changeSet
- * @param generateClassFiles
- */
- public void buildGroovyContent( final IProgressMonitor progressMonitor,
- final int kind,
- final ChangeSet changeSet,
- final boolean generateClassFiles )
- {
- final IProgressMonitor monitor = progressMonitor != null ? progressMonitor : new NullProgressMonitor();
- try
- {
- if( monitor.isCanceled() )
- return;
- final String outputPath = getOutputPath( javaProject );
- if( kind == FULL_BUILD )
- {
- trace("beginning FULL BUILD - GroovyProject.buildGroovyContent()");
- // Removing all .class files that we are aware of.
- // Making a defensive copy since removeClassFiles() will modify
- // the overlying map.
- final Set< String > keySet = linkedSet( model.scriptPaths() );
- for( final Iterator< String > iterator = keySet.iterator(); iterator.hasNext(); )
- {
- if( monitor.isCanceled() )
- return;
- removeClassFiles( iterator.next(), true );
- }
- model.clear();
- }
- else
- {
- trace( "beginning INCREMENTAL BUILD - GroovyProject.buildGroovyContent()" );
- // Removing .class files associated with changeSet.filesToRemove
- removeClassFiles( changeSet.filesToRemove(), true );
- }
- for( final Iterator< IFile > it = changeSet.getFilesToBuild().iterator(); it.hasNext(); )
- {
- if( monitor.isCanceled() )
- return;
- deleteErrorMarkers( it.next() );
- }
- trace( "filesToBuild:" + changeSet );
- compile( changeSet.filesToBuild(), monitor, outputPath, generateClassFiles );
- }
- catch( final Exception e )
- {
- monitor.worked( 1 );
- logException( "error building groovy files", e );
- }
- }
- private void compile( final IFile[] files,
- final IProgressMonitor monitor,
- final String outputPath,
- final boolean generateClassFiles )
- {
- if( monitor.isCanceled() )
- return;
- final Map< String, IFile > mapFileNamesToIFile = newEmptyLinkedMap();
- for( final IFile file : files )
- mapFileNamesToIFile.put( file.getLocation().toOSString(), file );
- final GroovyCompilerConfigurationBuilder builder = generateClassFiles
- ? new GroovyCompilerConfigurationBuilder().buildAST().buildClasses()
- : new GroovyCompilerConfigurationBuilder().buildAST();
- if( monitor.isCanceled() )
- return;
- final IGroovyCompilerConfiguration config;
- try
- {
- config = builder.classLoader( getProjectClassLoader() ).outputPath( outputPath ).done();
- if( monitor.isCanceled() )
- return;
- compiler.compile( mapFileNamesToIFile.keySet().toArray( new String[ 0 ] ),
- config,
- new CompilationReporter( mapFileNamesToIFile, monitor ) );
- }
- catch( final CoreException e )
- {
- logException( "Internal Error - please report: project = " + getJavaProject().getProject().getName() + ". " + e.getMessage(), e );
- }
- catch( final NoClassDefFoundError e )
- {
- logException( "Internal Error - please report: project = " + getJavaProject().getProject().getName(), e );
- }
- }
- /**
- * This method assumes the collection of files are pointing to the groovy
- * source code files that have been removed. It extracts the package name by
- * querying the scriptPathModuleNodeMap attribute and then looks in the java
- * project default output location for files that have the class names given
- * by the scriptPathModuleNodeMap attribute.
- *
- * @param files
- */
- private void removeClassFiles( final IFile[] files,
- final boolean refreshOutput )
- {
- if( files == null || files.length == 0 )
- return;
- for( final IFile file : files )
- removeClassFiles( getSourceFileKey( file ), refreshOutput );
- }
- private void removeClassFiles( final String filePath,
- final boolean refreshOutput )
- {
- if( isBlank( filePath ) )
- return;
- removeClassFiles( model.removeModuleNodes( filePath ), refreshOutput );
- }
- private void removeClassFiles( final List< ModuleNode > modules,
- final boolean refreshOutput )
- {
- if( modules == null || modules.size() == 0 )
- return;
- final List< ClassNode > classes = getClassesForModules( modules );
- for( final Iterator< ClassNode > iterator = classes.iterator(); iterator.hasNext(); )
- removeClassFiles( iterator.next(), refreshOutput );
- }
- @SuppressWarnings("unchecked")
- public void removeClassFiles( final ModuleNode module,
- final boolean refreshOutput )
- {
- if( module == null )
- return;
- final List< ClassNode > classes = module.getClasses();
- for( final Iterator< ClassNode > iterator = classes.iterator(); iterator.hasNext(); )
- removeClassFiles( iterator.next(), refreshOutput );
- }
- public void removeClassFiles( final ClassNode clase,
- final boolean refreshOutput )
- {
- if( clase == null )
- return;
- try
- {
- final String output = getOutputOSPath( javaProject );
- final String packageLocation = clase.hasPackageName()
- ? output + File.separator + clase.getPackageName().replace( '.', File.separatorChar )
- : output;
- final File directory = new File( packageLocation );
- if( !directory.exists() || !directory.isDirectory() )
- return;
- final File[] directoryFiles = directory.listFiles();
- removeClassFiles( clase.getNameWithoutPackage(), directoryFiles, refreshOutput );
- }
- catch( final JavaModelException e )
- {
- logException( "Error getting java output location for " + javaProject.getElementName(), e );
- }
- }
- private void removeClassFiles( final String className,
- final File[] directoryFiles,
- final boolean refreshOutput )
- {
- if( className == null || className.trim().equals( "" ) || directoryFiles == null )
- return;
- for( final File directoryFile : directoryFiles )
- {
- try
- {
- if( directoryFile.getName().equals( className + ".class" ) )
- {
- forceDelete( directoryFile );
- continue;
- }
- if( directoryFile.getName().startsWith( className + "$" ) && directoryFile.getName().endsWith( ".class" ) )
- {
- forceDelete( directoryFile );
- continue;
- }
- }
- catch( final IOException ioe )
- {
- logException( "Error deleting " + directoryFile.getName(), ioe );
- }
- }
- if( refreshOutput )
- refreshOutput();
- }
- /**
- * Recompile a source file without creating a .class file. This method is
- * useful for recreating the ModuleNode from the groovy compiler if the
- * ModuleNode has yet to be created during the current working session.
- *
- * @param file
- */
- public void compileGroovyFile( final IFile file )
- {
- compileGroovyFile( file, false );
- }
- /**
- * Compiles a Groovy file that is represented by the given input stream.
- * This method is useful for tooling that contains an copy of the file that
- * is in the process of being modified and wants to update the AST to
- * reflect the updated content. Class files will <em>not</em> be created.
- * The input stream is closed by this method.
- *
- * @param file
- * @param inputStream
- */
- public void compileGroovyFile( final IFile file,
- final InputStream input )
- {
- try
- {
- final String sourceCode = readSourceCode( input );
- final InputStream inputStream = new ByteArrayInputStream( sourceCode.getBytes( file.getCharset() ) );
- final String fullFileName = file.getLocation().toOSString();
- final IGroovyCompilerConfiguration config
- = new GroovyCompilerConfigurationBuilder().buildAST()
- .errorRecovery()
- .resolveAST()
- .classLoader( getProjectClassLoader() )
- .outputPath( getOutputOSPath( javaProject ) )
- .done();
- compiler.compile( fullFileName, inputStream, config, new InputStreamCompileReporter( file, sourceCode ) );
- }
- catch( final JavaModelException e )
- {
- logException( e.getMessage(), e );
- }
- catch( final CoreException e )
- {
- logException( e.getMessage(), e );
- }
- catch( final IOException e )
- {
- logException( e.getMessage(), e );
- }
- }
- private String readSourceCode( final InputStream inputStream )
- throws IOException
- {
- final BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
- try
- {
- final StringBuffer buffer = new StringBuffer();
- final char[] cbuffer = new char[ 1024 ];
- int count;
- while( ( count = reader.read( cbuffer ) ) != -1 )
- buffer.append( cbuffer, 0, count );
- return buffer.toString();
- }
- finally
- {
- closeQuietly( reader );
- closeQuietly( inputStream );
- }
- }
- /**
- * Recompile a source file and specify the creation of a .class file.
- */
- public void compileGroovyFile( final IFile file,
- final boolean generateClassFiles )
- {
- final ChangeSet changeSet = new ChangeSet().addFileToBuild(file);
- buildGroovyContent( new NullProgressMonitor(), INCREMENTAL_BUILD, changeSet, generateClassFiles );
- }
- public static IPersistentPreferenceStore preferenceStore( final IProject project )
- {
- return new ScopedPreferenceStore( new ProjectScope( project ),
- "org.codehaus.groovy.eclipse.preferences" );
- }
- /**
- * @param excludeGroovyRuntime If true, the class path will not contain the
- * Groovy runtime.
- * @return The class path of this project.
- * @throws CoreException
- */
- public Set< String > getClassPath()
- throws CoreException
- {
- return getClasspath( getJavaProject(), newList( new IJavaProject[ 0 ] ) );
- }
- /**
- * Get class path string specified using the OS specific path separator.
- *
- * @return The class path or an empty string if no class path is defined.
- * @param excludeGroovyRuntime Flag to exclude the runtime. The runtime
- * should be excuded for IDE code, e.g. completion and building, but
- * included for launchers etc.
- * @throws CoreException
- */
- public String getOSClassPath()
- throws CoreException
- {
- final Set< String > setOfClassPath = getClasspath( javaProject, newList( new IJavaProject[ 0 ] ) );
- if( setOfClassPath.size() == 0 )
- return "";
- final StringBuffer classPath = new StringBuffer();
- final Iterator< String > iter = setOfClassPath.iterator();
- while( iter.hasNext() )
- classPath.append( iter.next().toString() ).append( File.pathSeparator );
- return classPath.substring( 0, classPath.length() - 1 );
- }
- /**
- * @return The class loader used by the project for compiling, or null if
- * one is not available.
- * @throws CoreException
- */
- public ClassLoader getProjectClassLoader()
- throws CoreException
- {
- // if( projectClassLoader == null )
- // projectClassLoader = newProjectClassLoader();
- return newProjectClassLoader();
- // return projectClassLoader;
- }
- /**
- * @return A new class loader for the project.
- * @throws CoreException
- */
- public ClassLoader newProjectClassLoader()
- throws CoreException
- {
- // set the parent classloader to the org.codehaus.groovy BundleLoader
- // so we know ANTLR always comes from the same known classloader and thus
- // avoid ClassCastExceptions that come from class being loaded from different
- // classloaders
- return new URLClassLoader( getClassPathAsUrls(), org.codehaus.groovy.plugin.Activator.class.getClassLoader() );
- }
- /**
- * @return The class path as URLs, useful for creating class loaders.
- * @param excludeGroovyRuntime Flag to exclude the runtime. The runtime
- * should be excuded for IDE code, e.g. completion and building, but
- * included for launchers etc.
- * @throws CoreException
- */
- public URL[] getClassPathAsUrls()
- throws CoreException
- {
- final List< String > classPath = newList( getOSClassPath().split( File.pathSeparator ) );
- final List< URL > classpathUrls = newEmptyList();
- for( final Iterator< String > iter = classPath.iterator(); iter.hasNext(); )
- {
- try
- {
- classpathUrls.add( new File( iter.next() ).toURI().toURL() );
- }
- catch( final MalformedURLException e )
- {
- logException( "Error converting File to URL", e );
- throw new RuntimeException( e );
- }
- }
- return classpathUrls.toArray( new URL[ classpathUrls.size() ] );
- }
- public static Set< String > getClasspath( final IJavaProject project,
- final List< IJavaProject > visited )
- throws CoreException
- {
- final Set< String > set = linkedSet();
- if( project == null || !project.exists() )
- return set;
- if( visited.contains( project ) )
- return set;
- visited.add( project );
- collectPackageFragmentRootPaths( set, project, visited );
- collectClassPathEntryPaths( set, project, visited );
- if( !project.getProject().hasNature( GroovyNature.GROOVY_NATURE ) )
- return set;
- final String outputPath = getOutputPath( project );
- if( !outputPath.trim().equals( "" ) )
- set.add( outputPath );
- return set;
- }
- private static void collectPackageFragmentRootPaths( final Set< String > results,
- final IJavaProject project,
- final List visited )
- throws JavaModelException
- {
- final IPackageFragmentRoot[] fragRoots = project.getPackageFragmentRoots();
- for( final IPackageFragmentRoot fragRoot : fragRoots )
- {
- final IResource resource = fragRoot.getCorrespondingResource();
- // Fix for: GROOVY-1825 - emp
- // The first project visited is the source or the compile request.
- // Its source folder is placed on the
- // class path.
- // External project source folders must not be placed on the class
- // path as the source code will be compiled,
- // however their classes will appear in this projects output folder
- // which is incorrect behaviour.
- // So check visit count == 1 to prevent other source paths from
- // being added to the class path.
- if( resource != null && visited.size() == 1 )
- results.add( resource.getLocation().toString() );
- else
- results.add( fragRoot.getPath().toString() );
- }
- }
- private static void collectClassPathEntryPaths( final Set< String > results,
- final IJavaProject project,
- final List< IJavaProject > visited )
- throws CoreException, JavaModelException
- {
- final IWorkspaceRoot root = getWorkspace().getRoot();
- for( final IClasspathEntry entry : project.getResolvedClasspath( false ) )
- {
- final IResource resource = root.findMember( entry.getPath() );
- switch( entry.getEntryKind() )
- {
- case IClasspathEntry.CPE_LIBRARY:
- collectLibraryPaths( results, entry, resource );
- break;
- case IClasspathEntry.CPE_PROJECT:
- collectDependentProjectPaths( results, resource, visited );
- break;
- case IClasspathEntry.CPE_SOURCE:
- collectOutputLocations( results, project, root, entry );
- break;
- }
- }
- }
- private static void collectOutputLocations( final Set< String > results,
- final IJavaProject project,
- final IWorkspaceRoot root,
- final IClasspathEntry entry )
- throws JavaModelException
- {
- if( entry.getOutputLocation() != null )
- {
- results.add( root.getFolder( entry.getOutputLocation() ).getRawLocation().toString() );
- return;
- }
- if( project.exists() )
- {
- final IPath projectOutputLocation = project.getOutputLocation();
- final IResource member = root.findMember( projectOutputLocation );
- if( member != null && member.exists() )
- {
- final IPath location = member.getLocation();
- results.add( location.toString() );
- }
- }
- }
- private static void collectDependentProjectPaths( final Set< String > results,
- final IResource resource,
- final List< IJavaProject > visited )
- throws CoreException
- {
- final IJavaProject referencedProject = JavaCore.create( ( IProject )resource );
- if( referencedProject != null && referencedProject.getProject().exists() )
- results.addAll( getClasspath( referencedProject, visited ) );
- }
- private static void collectLibraryPaths( final Set< String > results,
- final IClasspathEntry entry,
- final IResource resource )
- {
- if( resource != null )
- results.add( resource.getLocation().toString() );
- else
- results.add( entry.getPath().toString() );
- }
- /**
- * Processing the exception that is thrown when there are compiler errors
- * and creates errors markers for the files that have errors.
- *
- * @param file - list of IFiles to compile for a full build
- * @param e
- */
- private void handleCompilationError( final List< IFile > fileList,
- final Exception e )
- {
- // GroovyCore.trace("compilation error : " + e.getMessage());
- final IFile file = fileList.get( 0 );
- try
- {
- getWorkspace().run( new AddErrorMarker( fileList, e ), null );
- }
- catch( final CoreException ce )
- {
- logException( "error compiling " + file.getName(), ce );
- }
- }
- /**
- * @param listener
- */
- public void addBuildListener( final GroovyBuildListener listener )
- {
- try
- {
- listenersLock.acquire();
- listeners.add( listener );
- }
- finally
- {
- listenersLock.release();
- }
- }
- /**
- * @param listener
- */
- public void removeBuildListener( final GroovyBuildListener listener )
- {
- try
- {
- listenersLock.acquire();
- listeners.remove( listener );
- }
- finally
- {
- listenersLock.release();
- }
- }
- class FireFileBuiltAction
- implements Runnable
- {
- private final IFile file;
- public void run()
- {
- try
- {
- listenersLock.acquire();
- for( final Iterator< GroovyBuildListener > iter = listeners.iterator(); iter.hasNext();)
- {
- final GroovyBuildListener buildListener = iter.next();
- try
- {
- buildListener.fileBuilt( file );
- }
- catch( final Exception e )
- {
- logException( "Exception in GroovyBuildListener", e );
- }
- }
- }
- finally
- {
- listenersLock.release();
- }
- }
- public FireFileBuiltAction( final IFile file )
- {
- this.file = file;
- }
- }
- private void fireGroovyFileBuilt( final IFile file )
- {
- getDefault().asyncExec( new FireFileBuiltAction( file ) );
- }
- /**
- * @return Returns the javaProject.
- */
- public IJavaProject getJavaProject()
- {
- return javaProject;
- }
- /**
- * This method looks for any scripts ( ModuleNodes ) that declare themselves
- * to be in a package where their location in the source folder hierarchy
- * says otherwise. So if you have a Script that has a class A where the
- * fully qualified type name for A is pack1.A, then the script had better
- * been in a source folder under the subdirectory pack1. This is to resolve
- * JIRA Issue: GROOVY-1361
- */
- private IFile[] checkForInvalidPackageDeclarations()
- {
- if( preferenceStore.getBoolean( GROOVY_DONT_CHECK_PACKAGE_VS_SRC_PATH ) )
- return new IFile[ 0 ];
- final List< IFile > invalidList = newList();
- for( final Iterator< String > keyIterator = model.scriptPaths().iterator(); keyIterator.hasNext(); )
- {
- final String key = keyIterator.next();
- final List< ModuleNode > moduleList = model.getModuleNodes( key );
- if( moduleList.isEmpty() )
- continue;
- for( final Iterator< ModuleNode > moduleIterator = moduleList.iterator(); moduleIterator.hasNext(); )
- {
- final ModuleNode module = moduleIterator.next();
- final String packageNameString = module.getPackageName() != null ? module.getPackageName() : "";
- final File moduleFile = new File( module.getDescription() );
- final String packageLocation = moduleFile.getParent();
- if( packageLocation == null )
- continue;
- final IPath[] entries = getSourceDirectories();
- boolean found = false;
- final Path packagePathObj = new Path( packageLocation );
- // We are checking here that the script path actually lies in a
- // source directory for this project.
- // If it does not, the error message does not make alot of
- // sense.
- for( final IPath entry : entries )
- {
- if( !entry.isPrefixOf( packagePathObj ) )
- continue;
- found = true;
- break;
- }
- if( !found )
- continue;
- final String packageName = packageNameString.endsWith( "." )
- ? packageNameString.substring( 0, packageNameString.length() - 1 )
- : packageNameString;
- final String packagePath = packageName.replace( '.', File.separatorChar );
- if( isBlank( packagePath ) )
- {
- // This is for the default package... why doesn't java just
- // make it illegal??
- found = false;
- for( final IPath entry : entries )
- {
- if( !entry.toOSString().equals( packageLocation ) )
- continue;
- found = true;
- break;
- }
- if( found )
- continue;
- }
- if( !packagePath.equals( "" ) && packageLocation.endsWith( packagePath ) )
- continue;
- final IProject project = javaProject.getProject();
- final String scriptPathString = removeStart( module.getDescription(), project.getLocation().toOSString() );
- final IPath scriptPath = new Path( scriptPathString );
- final IFile scriptFile = project.getFile( scriptPath );
- if( !scriptFile.exists() )
- continue;
- final List< IFile > fileList = newList();
- fileList.add( scriptFile );
- final String prefix = "Invalid Package declaration in script: ";
- final String message = prefix + module.getDescription() + " is not in a source folder matching the package declaration: " + packageName;
- removeDuplicateMarker( module, scriptFile, prefix );
- final SyntaxException se = new SyntaxException(message,1,1);
- handleCompilationError( fileList, se);
- invalidList.add( scriptFile );
- }
- }
- return invalidList.toArray( new IFile[ 0 ] );
- }
- public IPath[] getSourceDirectories()
- {
- final List< IPath > list = newList();
- try
- {
- for( final IClasspathEntry entry : javaProject.getResolvedClasspath( false ) )
- {
- if( entry.getEntryKind() != IClasspathEntry.CPE_SOURCE )
- continue;
- final IResource resource = javaProject.getProject().findMember( entry.getPath().removeFirstSegments( 1 ) );
- if( resource == null || !resource.exists() )
- continue;
- list.add( resource.getLocation() );
- }
- }
- catch( final JavaModelException e )
- {
- logException( "Error getting the classpath: " + e, e );
- return new IPath[ 0 ];
- }
- return list.toArray( new IPath[ 0 ] );
- }
- private void removeDuplicateMarker( final ModuleNode module,
- final IFile scriptFile,
- final String prefix )
- {
- try
- {
- final IMarker[] markers = scriptFile.findMarkers( GROOVY_ERROR_MARKER, false, DEPTH_INFINITE );
- if( markers == null || markers.length == 0 )
- return;
- for( final IMarker marker : markers )
- {
- if( !marker.getAttribute( "message", "" ).startsWith( prefix ) )
- continue;
- marker.delete();
- }
- }
- catch( final CoreException e )
- {
- logException( "Error getting markers: " + GROOVY_ERROR_MARKER + " for script: " + module.getDescription() + ". " + e, e );
- }
- return;
- }
- public GroovyProject refreshOutput()
- {
- final IFile[] invalidScripts = checkForInvalidPackageDeclarations();
- removeClassFiles( invalidScripts, false );
- try
- {
- javaProject.getProject().refreshLocal( DEPTH_INFINITE, new NullProgressMonitor() );
- }
- catch( final CoreException e )
- {
- logException( "Error refreshing output location, the navigator view could be out of sync: " + e, e );
- }
- return this;
- }
- /**
- * Remove the GROOOVY error markers from a groovy file (IFile) in the
- * project
- *
- * @param file
- */
- public static void deleteErrorMarkers( final IFile file )
- {
- try
- {
- // HACK: emp - This check is done before deleting markers, as
- // without it a deadlock between the workspace
- // thread and the reconciler thread occurs when renaming a Groovy
- // file.
- // if(file.exists()) {
- final IMarker[] markers = file.findMarkers( G…
Large files files are truncated, but you can click here to view the full file