blob: c0daec27cb379c100f2ca08d26f904787b7aac0d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 BEA Systems, Inc.
* All rights reserved. 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
*
* Contributors:
* mkaufman@bea.com - initial API and implementation
*
*******************************************************************************/
package org.eclipse.jdt.apt.core.internal;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.apt.core.AptPlugin;
import org.eclipse.jdt.apt.core.internal.generatedfile.GeneratedFileManager;
import org.eclipse.jdt.apt.core.internal.util.FactoryPath;
import org.eclipse.jdt.apt.core.util.AptConfig;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.CompilationParticipant;
import org.eclipse.jdt.core.compiler.ICompilationParticipantResult;
import org.eclipse.jdt.core.compiler.ReconcileContext;
import com.sun.mirror.apt.AnnotationProcessorFactory;
/**
* A singleton object, created by callback through the
* org.eclipse.jdt.core.compilationParticipants extension point.
*/
public class AptCompilationParticipant extends CompilationParticipant
{
/**
* Batch factories that claimed some annotation in a previous round of APT processing.
* This currently only apply to the build case since are only generating types during build
* and hence cause APT rounding.
* The set is an order preserving. The order is determined by their first invocation.
*/
private Set<AnnotationProcessorFactory> _previousRoundsBatchFactories = new LinkedHashSet<AnnotationProcessorFactory>();
private int _buildRound = 0;
private static AptCompilationParticipant INSTANCE;
public static AptCompilationParticipant getInstance() {
return INSTANCE;
}
/**
* This class is constructed indirectly, by registering an extension to the
* org.eclipse.jdt.core.compilationParticipants extension point. Other
* clients should NOT construct this object.
*/
public AptCompilationParticipant()
{
INSTANCE = this;
}
public boolean isAnnotationProcessor(){
return true;
}
public void processAnnotations(ICompilationParticipantResult[] filesWithAnnotations, boolean isBatchBuild) {
if( filesWithAnnotations == null || filesWithAnnotations.length == 0 )
return;
final IProject project = filesWithAnnotations[0].getFile().getProject();
final IJavaProject javaProject = JavaCore.create(project);
// Don't dispatch on pre-1.5 project. They cannot legally have annotations
String javaVersion = javaProject.getOption("org.eclipse.jdt.core.compiler.source", true); //$NON-NLS-1$
// Check for 1.3 or 1.4, as we don't want this to break in the future when 1.6
// is a possibility
if ("1.3".equals(javaVersion) || "1.4".equals(javaVersion)) { //$NON-NLS-1$ //$NON-NLS-2$
return;
}
try {
if (isBatchBuild && _buildRound == 0 ) {
AnnotationProcessorFactoryLoader.getLoader().resetBatchProcessors(javaProject);
_previousRoundsBatchFactories.clear();
}
Map<AnnotationProcessorFactory, FactoryPath.Attributes> factories =
AnnotationProcessorFactoryLoader.getLoader().getFactoriesAndAttributesForProject(javaProject);
AptProject aptProject = AptPlugin.getAptProject(javaProject);
Set<AnnotationProcessorFactory> dispatchedBatchFactories =
APTDispatchRunnable.runAPTDuringBuild(filesWithAnnotations, aptProject, factories, _previousRoundsBatchFactories, isBatchBuild);
_previousRoundsBatchFactories.addAll(dispatchedBatchFactories);
}
finally {
if (isBatchBuild) {
// In order to keep from locking jars, we explicitly close any batch-based
// classloaders we opened
AnnotationProcessorFactoryLoader.getLoader().closeBatchClassLoader();
}
_buildRound ++;
}
}
/**
* Given a Map which maps from a key to a value, where key is an arbitrary
* type, and where value is a Collection, mergeMaps will ensure that for a key
* k with value v in source, all of the elements in the Collection v will be
* moved into the Collection v' corresponding to key k in the destination Map.
*
* @param source - The source map from some key to a Collection.
* @param destination - The destination map from some key to a Collection
*/
private static void mergeMaps( Map source, Map destination ) {
if( source == null || destination == null ) return;
Iterator keys = source.keySet().iterator();
while( keys.hasNext() ) {
Object key = keys.next();
Object val = destination.get( key );
if ( val != null ) {
Collection c = (Collection) val;
c.addAll( (Collection)source.get( key ) );
}
else {
destination.put( key, source.get( key ) );
}
}
}
public void reconcile(ReconcileContext context){
try
{
final ICompilationUnit workingCopy = context.getWorkingCopy();
if( workingCopy == null )
return;
IJavaProject javaProject = workingCopy.getJavaProject();
if( javaProject == null )
return;
AptProject aptProject = AptPlugin.getAptProject(javaProject);
Map<AnnotationProcessorFactory, FactoryPath.Attributes> factories =
AnnotationProcessorFactoryLoader.getLoader().getFactoriesAndAttributesForProject( javaProject );
APTDispatchRunnable.runAPTDuringReconcile(context, aptProject, factories);
}
catch ( Throwable t )
{
AptPlugin.log(t, "Failure processing"); //$NON-NLS-1$
}
}
public void cleanStarting(IJavaProject javaProject){
IProject p = javaProject.getProject();
AptPlugin.getAptProject(javaProject).projectClean( true );
try{
// clear out all markers during a clean.
IMarker[] markers = p.findMarkers(AptPlugin.APT_BATCH_PROCESSOR_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
if( markers != null ){
for( IMarker marker : markers )
marker.delete();
}
}
catch(CoreException e){
AptPlugin.log(e, "Unable to delete batch annotation processor markers"); //$NON-NLS-1$
}
}
/**
* Does APT have anything to do for this project?
* Even if there are no processors on the factory path, apt may still
* be involved during a clean.
*/
public boolean isActive(IJavaProject project){
return AptConfig.isEnabled(project);
}
public int aboutToBuild(IJavaProject project) {
if (AptConfig.isEnabled(project)) {
// setup the classpath and make sure the generated source folder is on disk.
AptPlugin.getAptProject(project).compilationStarted();
}
_buildRound = 0; // reset
// TODO: (wharley) if the factory path is different we need a full build
return CompilationParticipant.READY_FOR_BUILD;
}
private final static String DOT_JAVA = ".java"; //$NON-NLS-1$
}