blob: c1e232b7d6c0ac023a184b0fa7a97245af97adbe [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.apt.dispatch;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import javax.annotation.processing.Processor;
import javax.tools.StandardLocation;
import org.eclipse.jdt.internal.compiler.batch.Main;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
/**
* Java 6 annotation processor manager used when compiling from the command line
* or via the javax.tools.JavaCompiler interface.
* @see org.eclipse.jdt.internal.compiler.apt.ide.dispatch.IdeAnnotationProcessorManager
*/
public class BatchAnnotationProcessorManager extends BaseAnnotationProcessorManager
{
/**
* Processors that have been set by calling CompilationTask.setProcessors().
*/
private List<Processor> _setProcessors = null;
private Iterator<Processor> _setProcessorIter = null;
/**
* Processors named with the -processor option on the command line.
*/
private List<String> _commandLineProcessors;
private Iterator<String> _commandLineProcessorIter = null;
private ServiceLoader<Processor> _serviceLoader = null;
private Iterator<Processor> _serviceLoaderIter;
private ClassLoader _procLoader;
/**
* Zero-arg constructor so this object can be easily created via reflection.
* A BatchAnnotationProcessorManager cannot be used until its
* {@link #configure(Main, String[])} method has been called.
*/
public BatchAnnotationProcessorManager()
{
}
@Override
public void configure(Object batchCompiler, String[] commandLineArguments) {
if (null != _processingEnv) {
throw new IllegalStateException(
"Calling configure() more than once on an AnnotationProcessorManager is not supported"); //$NON-NLS-1$
}
BatchProcessingEnvImpl processingEnv = new BatchProcessingEnvImpl(this, (Main) batchCompiler, commandLineArguments);
_processingEnv = processingEnv;
_procLoader = processingEnv.getFileManager().getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH);
_commandLineProcessors = parseCommandLineProcessors(commandLineArguments);
if (null != _commandLineProcessors) {
_commandLineProcessorIter = _commandLineProcessors.iterator();
}
}
/**
* If a -processor option was specified in command line arguments,
* parse it into a list of qualified classnames.
* @param commandLineArguments contains one string for every space-delimited token on the command line
* @return a list of qualified classnames, or null if there was no -processor option.
*/
private List<String> parseCommandLineProcessors(String[] commandLineArguments) {
List<String> result = null;
for (int i = 0; i < commandLineArguments.length; ++i) {
String option = commandLineArguments[i];
if ("-processor".equals(option)) { //$NON-NLS-1$
result = new ArrayList<String>();
String procs = commandLineArguments[++i];
for (String proc : procs.split(",")) { //$NON-NLS-1$
result.add(proc);
}
break;
}
}
return result;
}
@Override
public ProcessorInfo discoverNextProcessor() {
if (null != _setProcessors) {
// If setProcessors() was called, use that list until it's empty and then stop.
if (_setProcessorIter.hasNext()) {
Processor p = _setProcessorIter.next();
p.init(_processingEnv);
ProcessorInfo pi = new ProcessorInfo(p);
_processors.add(pi);
return pi;
}
return null;
}
if (null != _commandLineProcessors) {
// If there was a -processor option, iterate over processor names,
// creating and initializing processors, until no more names are found, then stop.
if (_commandLineProcessorIter.hasNext()) {
String proc = _commandLineProcessorIter.next();
try {
Class<?> clazz = _procLoader.loadClass(proc);
Object o = clazz.newInstance();
Processor p = (Processor) o;
p.init(_processingEnv);
ProcessorInfo pi = new ProcessorInfo(p);
_processors.add(pi);
return pi;
} catch (Exception e) {
// TODO: better error handling
throw new AbortCompilation(null, e);
}
}
return null;
}
// if no processors were explicitly specified with setProcessors()
// or the command line, search the processor path with ServiceLoader.
if (null == _serviceLoader ) {
_serviceLoader = ServiceLoader.load(Processor.class, _procLoader);
_serviceLoaderIter = _serviceLoader.iterator();
}
try {
if (_serviceLoaderIter.hasNext()) {
Processor p = _serviceLoaderIter.next();
p.init(_processingEnv);
ProcessorInfo pi = new ProcessorInfo(p);
_processors.add(pi);
return pi;
}
} catch (ServiceConfigurationError e) {
// TODO: better error handling
throw new AbortCompilation(null, e);
}
return null;
}
@Override
public void reportProcessorException(Processor p, Exception e) {
// TODO: if (verbose) report the processor
throw new AbortCompilation(null, e);
}
@Override
public void setProcessors(Object[] processors) {
if (!_isFirstRound) {
throw new IllegalStateException("setProcessors() cannot be called after processing has begun"); //$NON-NLS-1$
}
// Cast all the processors here, rather than failing later.
// But don't call init() until the processor is actually needed.
_setProcessors = new ArrayList<Processor>(processors.length);
for (Object o : processors) {
Processor p = (Processor)o;
_setProcessors.add(p);
}
_setProcessorIter = _setProcessors.iterator();
// processors set this way take precedence over anything on the command line
_commandLineProcessors = null;
_commandLineProcessorIter = null;
}
}