提交 0ab13ede 编写于 作者: J jjg

7093891: support multiple task listeners

Reviewed-by: darcy, mcimadamore
上级 56de3b8a
/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -25,9 +25,9 @@
package com.sun.source.util;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Tree;
import java.io.IOException;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
......@@ -35,6 +35,12 @@ import javax.lang.model.util.Types;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.api.BasicJavacTask;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.util.Context;
/**
* Provides access to functionality specific to the JDK Java Compiler, javac.
*
......@@ -44,11 +50,30 @@ import javax.tools.JavaFileObject;
*/
public abstract class JavacTask implements CompilationTask {
/**
* Get the {@code JavacTask} for a {@code ProcessingEnvironment}.
* If the compiler is being invoked using a
* {@link javax.tools.JavaCompiler.CompilationTask CompilationTask},
* then that task will be returned.
* @param processingEnvironment
* @return the {@code JavacTask} for a {@code ProcessingEnvironment}
* @since 1.8
*/
public static JavacTask instance(ProcessingEnvironment processingEnvironment) {
if (!processingEnvironment.getClass().getName().equals(
"com.sun.tools.javac.processing.JavacProcessingEnvironment"))
throw new IllegalArgumentException();
Context c = ((JavacProcessingEnvironment) processingEnvironment).getContext();
JavacTask t = c.get(JavacTask.class);
return (t != null) ? t : new BasicJavacTask(c, true);
}
/**
* Parse the specified files returning a list of abstract syntax trees.
*
* @return a list of abstract syntax trees
* @throws IOException if an unhandled I/O error occurred in the compiler.
* @throws IllegalStateException if the operation cannot be performed at this time.
*/
public abstract Iterable<? extends CompilationUnitTree> parse()
throws IOException;
......@@ -58,6 +83,7 @@ public abstract class JavacTask implements CompilationTask {
*
* @return a list of elements that were analyzed
* @throws IOException if an unhandled I/O error occurred in the compiler.
* @throws IllegalStateException if the operation cannot be performed at this time.
*/
public abstract Iterable<? extends Element> analyze() throws IOException;
......@@ -66,17 +92,51 @@ public abstract class JavacTask implements CompilationTask {
*
* @return a list of files that were generated
* @throws IOException if an unhandled I/O error occurred in the compiler.
* @throws IllegalStateException if the operation cannot be performed at this time.
*/
public abstract Iterable<? extends JavaFileObject> generate() throws IOException;
/**
* The specified listener will receive events describing the progress of
* this compilation task.
* The specified listener will receive notification of events
* describing the progress of this compilation task.
*
* If another listener is receiving notifications as a result of a prior
* call of this method, then that listener will no longer receive notifications.
*
* Informally, this method is equivalent to calling {@code removeTaskListener} for
* any listener that has been previously set, followed by {@code addTaskListener}
* for the new listener.
*
* @throws IllegalStateException if the specified listener has already been added.
*/
public abstract void setTaskListener(TaskListener taskListener);
/**
* The specified listener will receive notification of events
* describing the progress of this compilation task.
*
* This method may be called at any time before or during the compilation.
*
* @throws IllegalStateException if the specified listener has already been added.
* @since 1.8
*/
public abstract void addTaskListener(TaskListener taskListener);
/**
* The specified listener will no longer receive notification of events
* describing the progress of this compilation task.
*
* This method may be called at any time before or during the compilation.
*
* @since 1.8
*/
public abstract void removeTaskListener(TaskListener taskListener);
/**
* Get a type mirror of the tree node determined by the specified path.
* This method has been superceded by methods on
* {@link com.sun.source.util.Trees Trees}.
* @see com.sun.source.util.Trees#getTypeMirror
*/
public abstract TypeMirror getTypeMirror(Iterable<? extends Tree> path);
/**
......
/*
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.api;
import java.io.IOException;
import java.util.Locale;
import javax.annotation.processing.Processor;
import javax.lang.model.element.Element;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.JavaFileObject;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.model.JavacTypes;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Context;
import java.util.Collection;
/**
* Provides basic functionality for implementations of JavacTask.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own
* risk. This code and its internal interfaces are subject to change
* or deletion without notice.</b></p>
*/
public class BasicJavacTask extends JavacTask {
protected Context context;
private TaskListener taskListener;
public BasicJavacTask(Context c, boolean register) {
context = c;
if (register)
context.put(JavacTask.class, this);
}
@Override
public Iterable<? extends CompilationUnitTree> parse() throws IOException {
throw new IllegalStateException();
}
@Override
public Iterable<? extends Element> analyze() throws IOException {
throw new IllegalStateException();
}
@Override
public Iterable<? extends JavaFileObject> generate() throws IOException {
throw new IllegalStateException();
}
@Override
public void setTaskListener(TaskListener tl) {
MultiTaskListener mtl = MultiTaskListener.instance(context);
if (taskListener != null)
mtl.remove(taskListener);
if (tl != null)
mtl.add(tl);
taskListener = tl;
}
@Override
public void addTaskListener(TaskListener taskListener) {
MultiTaskListener mtl = MultiTaskListener.instance(context);
mtl.add(taskListener);
}
@Override
public void removeTaskListener(TaskListener taskListener) {
MultiTaskListener mtl = MultiTaskListener.instance(context);
mtl.remove(taskListener);
}
public Collection<TaskListener> getTaskListeners() {
MultiTaskListener mtl = MultiTaskListener.instance(context);
return mtl.getTaskListeners();
}
@Override
public TypeMirror getTypeMirror(Iterable<? extends Tree> path) {
// TODO: Should complete attribution if necessary
Tree last = null;
for (Tree node : path)
last = node;
return ((JCTree)last).type;
}
@Override
public Elements getElements() {
return JavacElements.instance(context);
}
@Override
public Types getTypes() {
return JavacTypes.instance(context);
}
public void setProcessors(Iterable<? extends Processor> processors) {
throw new IllegalStateException();
}
public void setLocale(Locale locale) {
throw new IllegalStateException();
}
public Boolean call() {
throw new IllegalStateException();
}
}
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -31,8 +31,13 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
......@@ -41,25 +46,21 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.FileObject;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.util.ClientCodeException;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JCDiagnostic;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.lang.model.element.Modifier;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject.Kind;
/**
* Wrap objects to enable unchecked exceptions to be caught and handled.
......@@ -160,6 +161,20 @@ public class ClientCodeWrapper {
return new WrappedTaskListener(tl);
}
TaskListener unwrap(TaskListener l) {
if (l instanceof WrappedTaskListener)
return ((WrappedTaskListener) l).clientTaskListener;
else
return l;
}
Collection<TaskListener> unwrap(Collection<? extends TaskListener> listeners) {
Collection<TaskListener> c = new ArrayList<TaskListener>(listeners.size());
for (TaskListener l: listeners)
c.add(unwrap(l));
return c;
}
@SuppressWarnings("unchecked")
private <T> Diagnostic<T> unwrap(final Diagnostic<T> diagnostic) {
if (diagnostic instanceof JCDiagnostic) {
......@@ -181,6 +196,10 @@ public class ClientCodeWrapper {
return trusted;
}
private String wrappedToString(Class<?> wrapperClass, Object wrapped) {
return wrapperClass.getSimpleName() + "[" + wrapped + "]";
}
// <editor-fold defaultstate="collapsed" desc="Wrapper classes">
// FIXME: all these classes should be converted to use multi-catch when
......@@ -361,6 +380,11 @@ public class ClientCodeWrapper {
throw new ClientCodeException(e);
}
}
@Override
public String toString() {
return wrappedToString(getClass(), clientJavaFileManager);
}
}
protected class WrappedFileObject implements FileObject {
......@@ -486,6 +510,11 @@ public class ClientCodeWrapper {
throw new ClientCodeException(e);
}
}
@Override
public String toString() {
return wrappedToString(getClass(), clientFileObject);
}
}
protected class WrappedJavaFileObject extends WrappedFileObject implements JavaFileObject {
......@@ -544,6 +573,11 @@ public class ClientCodeWrapper {
throw new ClientCodeException(e);
}
}
@Override
public String toString() {
return wrappedToString(getClass(), clientFileObject);
}
}
protected class WrappedDiagnosticListener<T /*super JavaFileObject*/> implements DiagnosticListener<T> {
......@@ -565,6 +599,11 @@ public class ClientCodeWrapper {
throw new ClientCodeException(e);
}
}
@Override
public String toString() {
return wrappedToString(getClass(), clientDiagnosticListener);
}
}
public class DiagnosticSourceUnwrapper implements Diagnostic<JavaFileObject> {
......@@ -610,6 +649,7 @@ public class ClientCodeWrapper {
return d.getMessage(locale);
}
@Override
public String toString() {
return d.toString();
}
......@@ -647,6 +687,11 @@ public class ClientCodeWrapper {
throw new ClientCodeException(e);
}
}
@Override
public String toString() {
return wrappedToString(getClass(), clientTaskListener);
}
}
// </editor-fold>
......
/*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -44,6 +44,7 @@ import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.comp.*;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.main.*;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.model.*;
import com.sun.tools.javac.parser.Parser;
import com.sun.tools.javac.parser.ParserFactory;
......@@ -51,7 +52,6 @@ import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.main.JavaCompiler;
/**
* Provides access to functionality specific to the JDK Java Compiler, javac.
......@@ -64,18 +64,16 @@ import com.sun.tools.javac.main.JavaCompiler;
* @author Peter von der Ah&eacute;
* @author Jonathan Gibbons
*/
public class JavacTaskImpl extends JavacTask {
public class JavacTaskImpl extends BasicJavacTask {
private ClientCodeWrapper ccw;
private Main compilerMain;
private JavaCompiler compiler;
private Locale locale;
private String[] args;
private String[] classNames;
private Context context;
private List<JavaFileObject> fileObjects;
private Map<JavaFileObject, JCCompilationUnit> notYetEntered;
private ListBuffer<Env<AttrContext>> genList;
private TaskListener taskListener;
private AtomicBoolean used = new AtomicBoolean();
private Iterable<? extends Processor> processors;
......@@ -86,6 +84,7 @@ public class JavacTaskImpl extends JavacTask {
String[] classNames,
Context context,
List<JavaFileObject> fileObjects) {
super(null, false);
this.ccw = ClientCodeWrapper.instance(context);
this.compilerMain = compilerMain;
this.args = args;
......@@ -190,11 +189,7 @@ public class JavacTaskImpl extends JavacTask {
}
private void initContext() {
context.put(JavacTaskImpl.class, this);
if (context.get(TaskListener.class) != null)
context.put(TaskListener.class, (TaskListener)null);
if (taskListener != null)
context.put(TaskListener.class, ccw.wrap(taskListener));
context.put(JavacTask.class, this);
//initialize compiler's default locale
context.put(Locale.class, locale);
}
......@@ -224,10 +219,6 @@ public class JavacTaskImpl extends JavacTask {
return fm.getRegularFile(file);
}
public void setTaskListener(TaskListener taskListener) {
this.taskListener = taskListener;
}
/**
* Parse the specified files returning a list of abstract syntax trees.
*
......
/*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -26,7 +26,7 @@
package com.sun.tools.javac.api;
import java.io.IOException;
import java.util.Map;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
......@@ -44,13 +44,14 @@ import com.sun.source.tree.CatchTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Scope;
import com.sun.source.tree.Tree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.SourcePositions;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type.UnionClassType;
import com.sun.tools.javac.comp.Attr;
import com.sun.tools.javac.comp.AttrContext;
......@@ -61,8 +62,8 @@ import com.sun.tools.javac.comp.Resolve;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.parser.EndPosTable;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.TreeCopier;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.tree.TreeMaker;
......@@ -95,12 +96,14 @@ public class JavacTrees extends Trees {
private JavacElements elements;
private JavacTaskImpl javacTaskImpl;
// called reflectively from Trees.instance(CompilationTask task)
public static JavacTrees instance(JavaCompiler.CompilationTask task) {
if (!(task instanceof JavacTaskImpl))
throw new IllegalArgumentException();
return instance(((JavacTaskImpl)task).getContext());
}
// called reflectively from Trees.instance(ProcessingEnvironment env)
public static JavacTrees instance(ProcessingEnvironment env) {
if (!(env instanceof JavacProcessingEnvironment))
throw new IllegalArgumentException();
......@@ -131,7 +134,10 @@ public class JavacTrees extends Trees {
resolve = Resolve.instance(context);
treeMaker = TreeMaker.instance(context);
memberEnter = MemberEnter.instance(context);
javacTaskImpl = context.get(JavacTaskImpl.class);
JavacTask t = context.get(JavacTask.class);
if (t instanceof JavacTaskImpl)
javacTaskImpl = (JavacTaskImpl) t;
}
public SourcePositions getSourcePositions() {
......
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.api;
import java.util.Arrays;
import java.util.Collection;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.util.Context;
/**
* TODO.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class MultiTaskListener implements TaskListener {
/** The context key for the MultiTaskListener. */
public static final Context.Key<MultiTaskListener> taskListenerKey =
new Context.Key<MultiTaskListener>();
/** Get the MultiTaskListener instance for this context. */
public static MultiTaskListener instance(Context context) {
MultiTaskListener instance = context.get(taskListenerKey);
if (instance == null)
instance = new MultiTaskListener(context);
return instance;
}
protected MultiTaskListener(Context context) {
context.put(taskListenerKey, this);
ccw = ClientCodeWrapper.instance(context);
}
/**
* The current set of registered listeners.
* This is a mutable reference to an immutable array.
*/
TaskListener[] listeners = { };
ClientCodeWrapper ccw;
public Collection<TaskListener> getTaskListeners() {
return Arrays.asList(listeners);
}
public boolean isEmpty() {
return (listeners.length == 0);
}
public void add(TaskListener listener) {
for (TaskListener l: listeners) {
if (ccw.unwrap(l) == listener)
throw new IllegalStateException();
}
TaskListener[] newListeners = new TaskListener[listeners.length + 1];
System.arraycopy(listeners, 0, newListeners, 0, listeners.length);
newListeners[newListeners.length - 1] = ccw.wrap(listener);
listeners = newListeners;
}
public void remove(TaskListener listener) {
for (int i = 0; i < listeners.length; i++) {
if (ccw.unwrap(listeners[i]) == listener) {
TaskListener[] newListeners = new TaskListener[listeners.length - 1];
System.arraycopy(listeners, 0, newListeners, 0, i);
System.arraycopy(listeners, i + 1, newListeners, i, newListeners.length - i);
listeners = newListeners;
break;
}
}
}
@Override
public void started(TaskEvent e) {
// guard against listeners being updated by a listener
TaskListener[] ll = this.listeners;
for (TaskListener l: ll)
l.started(e);
}
@Override
public void finished(TaskEvent e) {
// guard against listeners being updated by a listener
TaskListener[] ll = this.listeners;
for (TaskListener l: ll)
l.finished(e);
}
@Override
public String toString() {
return Arrays.toString(listeners);
}
}
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -28,8 +28,8 @@ package com.sun.tools.javac.main;
import java.io.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Queue;
......@@ -41,13 +41,13 @@ import java.util.logging.Logger;
import javax.annotation.processing.Processor;
import javax.lang.model.SourceVersion;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.DiagnosticListener;
import static javax.tools.StandardLocation.CLASS_OUTPUT;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.api.MultiTaskListener;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Symbol.*;
......@@ -60,8 +60,6 @@ import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.Log.WriterKind;
import static javax.tools.StandardLocation.CLASS_OUTPUT;
import static com.sun.tools.javac.main.Option.*;
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
import static com.sun.tools.javac.util.ListBuffer.lb;
......@@ -289,9 +287,9 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
*/
protected ParserFactory parserFactory;
/** Optional listener for progress events
/** Broadcasting listener for progress events
*/
protected TaskListener taskListener;
protected MultiTaskListener taskListener;
/**
* Annotation processing may require and provide a new instance
......@@ -356,7 +354,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
lower = Lower.instance(context);
annotate = Annotate.instance(context);
types = Types.instance(context);
taskListener = context.get(TaskListener.class);
taskListener = MultiTaskListener.instance(context);
reader.sourceCompleter = this;
......@@ -592,7 +590,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
if (verbose) {
log.printVerbose("parsing.started", filename);
}
if (taskListener != null) {
if (!taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, filename);
taskListener.started(e);
}
......@@ -605,7 +603,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
tree.sourcefile = filename;
if (content != null && taskListener != null) {
if (content != null && !taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree);
taskListener.finished(e);
}
......@@ -751,14 +749,14 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
log.useSource(prev);
}
if (taskListener != null) {
if (!taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
taskListener.started(e);
}
enter.complete(List.of(tree), c);
if (taskListener != null) {
if (!taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, tree);
taskListener.finished(e);
}
......@@ -924,7 +922,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
*/
public List<JCCompilationUnit> enterTrees(List<JCCompilationUnit> roots) {
//enter symbols for all files
if (taskListener != null) {
if (!taskListener.isEmpty()) {
for (JCCompilationUnit unit: roots) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
taskListener.started(e);
......@@ -933,7 +931,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
enter.main(roots);
if (taskListener != null) {
if (!taskListener.isEmpty()) {
for (JCCompilationUnit unit: roots) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.ENTER, unit);
taskListener.finished(e);
......@@ -1002,7 +1000,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
reader.saveParameterNames = true;
keepComments = true;
genEndPos = true;
if (taskListener != null)
if (!taskListener.isEmpty())
taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
log.deferDiagnostics = true;
} else { // free resources
......@@ -1017,7 +1015,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
}
/**
* Process any anotations found in the specifed compilation units.
* Process any annotations found in the specified compilation units.
* @param roots a list of compilation units
* @return an instance of the compiler in which to complete the compilation
*/
......@@ -1176,7 +1174,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
if (verbose)
log.printVerbose("checking.attribution", env.enclClass.sym);
if (taskListener != null) {
if (!taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym);
taskListener.started(e);
}
......@@ -1259,7 +1257,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
}
}
finally {
if (taskListener != null) {
if (!taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym);
taskListener.finished(e);
}
......@@ -1440,7 +1438,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
+ " " + cdef.sym + "]");
}
if (taskListener != null) {
if (!taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
taskListener.started(e);
}
......@@ -1464,7 +1462,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
log.useSource(prev);
}
if (taskListener != null) {
if (!taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.GENERATE, env.toplevel, cdef.sym);
taskListener.finished(e);
}
......
/*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -25,34 +25,33 @@
package com.sun.tools.javac.processing;
import java.lang.reflect.*;
import java.util.*;
import java.util.regex.*;
import java.net.URL;
import java.io.Closeable;
import java.io.File;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.regex.*;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.*;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileManager;
import javax.tools.StandardJavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.DiagnosticListener;
import javax.tools.StandardJavaFileManager;
import static javax.tools.StandardLocation.*;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.api.MultiTaskListener;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.file.FSInfo;
......@@ -71,19 +70,16 @@ import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.ClientCodeException;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Convert;
import com.sun.tools.javac.util.FatalError;
import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.JavacMessages;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.JavacMessages;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import com.sun.tools.javac.util.Options;
import static javax.tools.StandardLocation.*;
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
import static com.sun.tools.javac.main.Option.*;
import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING;
import static com.sun.tools.javac.main.Option.*;
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
/**
* Objects of this class hold and manage the state needed to support
......@@ -157,6 +153,8 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
*/
private JavacMessages messages;
private MultiTaskListener taskListener;
private Context context;
public JavacProcessingEnvironment(Context context, Iterable<? extends Processor> processors) {
......@@ -185,6 +183,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
processorOptions = initProcessorOptions(context);
unmatchedProcessorOptions = initUnmatchedProcessorOptions();
messages = JavacMessages.instance(context);
taskListener = MultiTaskListener.instance(context);
initProcessorIterator(context, processors);
}
......@@ -976,8 +975,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
void run(boolean lastRound, boolean errorStatus) {
printRoundInfo(lastRound);
TaskListener taskListener = context.get(TaskListener.class);
if (taskListener != null)
if (!taskListener.isEmpty())
taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
try {
......@@ -993,7 +991,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
discoverAndRunProcs(context, annotationsPresent, topLevelClasses, packageInfoFiles);
}
} finally {
if (taskListener != null)
if (!taskListener.isEmpty())
taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
}
......@@ -1051,9 +1049,9 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
if (dl != null)
next.put(DiagnosticListener.class, dl);
TaskListener tl = context.get(TaskListener.class);
if (tl != null)
next.put(TaskListener.class, tl);
MultiTaskListener mtl = context.get(MultiTaskListener.taskListenerKey);
if (mtl != null)
next.put(MultiTaskListener.taskListenerKey, mtl);
FSInfo fsInfo = context.get(FSInfo.class);
if (fsInfo != null)
......@@ -1086,9 +1084,9 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
elementUtils.setContext(next);
typeUtils.setContext(next);
JavacTaskImpl task = context.get(JavacTaskImpl.class);
JavacTaskImpl task = (JavacTaskImpl) context.get(JavacTask.class);
if (task != null) {
next.put(JavacTaskImpl.class, task);
next.put(JavacTask.class, task);
task.updateContext(next);
}
......@@ -1110,8 +1108,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
List<JCCompilationUnit> roots,
List<ClassSymbol> classSymbols,
Iterable<? extends PackageSymbol> pckSymbols) {
TaskListener taskListener = context.get(TaskListener.class);
log = Log.instance(context);
Set<PackageSymbol> specifiedPackages = new LinkedHashSet<PackageSymbol>();
......@@ -1182,7 +1178,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
// Free resources
this.close();
if (taskListener != null)
if (!taskListener.isEmpty())
taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING));
if (errorStatus) {
......
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7093891
* @summary support multiple task listeners
*/
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.api.JavacTool;
public class TestSimpleAddRemove {
enum AddKind {
SET_IN_TASK,
ADD_IN_TASK,
ADD_IN_PROCESSOR,
ADD_IN_LISTENER;
}
enum RemoveKind {
REMOVE_IN_TASK,
REMOVE_IN_PROCESSOR,
REMOVE_IN_LISTENER,
}
enum CompileKind {
CALL {
void run(JavacTask t) {
if (!t.call()) throw new Error("compilation failed");
}
},
GENERATE {
void run(JavacTask t) throws IOException {
t.generate();
}
};
abstract void run(JavacTask t) throws IOException;
}
static class EventKindCounter extends EnumMap<TaskEvent.Kind, EventKindCounter.Count> {
static class Count {
int started;
int finished;
@Override
public String toString() {
return started + ":" + finished;
}
}
EventKindCounter() {
super(TaskEvent.Kind.class);
}
void inc(TaskEvent.Kind k, boolean started) {
Count c = get(k);
if (c == null)
put(k, c = new Count());
if (started)
c.started++;
else
c.finished++;
}
}
static class TestListener implements TaskListener {
EventKindCounter counter;
TestListener(EventKindCounter c) {
counter = c;
}
public void started(TaskEvent e) {
counter.inc(e.getKind(), true);
}
public void finished(TaskEvent e) {
counter.inc(e.getKind(), false);
}
}
static void addInListener(final JavacTask task, final TaskEvent.Kind kind, final TaskListener listener) {
task.addTaskListener(new TaskListener() {
public void started(TaskEvent e) {
if (e.getKind() == kind) {
task.addTaskListener(listener);
task.removeTaskListener(this);
}
}
public void finished(TaskEvent e) { }
});
}
static void removeInListener(final JavacTask task, final TaskEvent.Kind kind, final TaskListener listener) {
task.addTaskListener(new TaskListener() {
public void started(TaskEvent e) {
if (e.getKind() == kind) {
task.removeTaskListener(listener);
task.removeTaskListener(this);
}
}
public void finished(TaskEvent e) { }
});
}
@SupportedAnnotationTypes("*")
class TestProcessor extends AbstractProcessor {
AddKind ak;
RemoveKind rk;
TaskListener listener;
TestProcessor(AddKind ak, RemoveKind rk, TaskListener listener) {
this.ak = ak;
this.rk = rk;
this.listener = listener;
}
int round = 0;
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// System.err.println("TestProcessor.process " + roundEnv);
JavacTask task = JavacTask.instance(processingEnv);
if (++round == 1) {
switch (ak) {
case ADD_IN_PROCESSOR:
task.addTaskListener(listener);
break;
case ADD_IN_LISTENER:
addInListener(task, TaskEvent.Kind.ANALYZE, listener);
break;
}
} else if (roundEnv.processingOver()) {
switch (rk) {
case REMOVE_IN_PROCESSOR:
task.removeTaskListener(listener);
break;
case REMOVE_IN_LISTENER:
removeInListener(task, TaskEvent.Kind.GENERATE, listener);
break;
}
}
return true;
}
}
static class TestSource extends SimpleJavaFileObject {
public TestSource() {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return "class Test { }";
}
}
public static void main(String... args) throws Exception {
new TestSimpleAddRemove().run();
}
JavacTool tool = (JavacTool) ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null);
void run() throws Exception {
for (CompileKind ck: CompileKind.values()) {
for (AddKind ak: AddKind.values()) {
for (RemoveKind rk: RemoveKind.values()) {
test(ck, ak, rk);
}
}
}
if (errors > 0)
throw new Exception(errors + " errors occurred");
}
void test(CompileKind ck, AddKind ak, RemoveKind rk) throws IOException {
System.err.println("Test: " + ck + " " + ak + " " + rk);
File tmpDir = new File(ck + "-" + ak + "-" + rk);
tmpDir.mkdirs();
fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(tmpDir));
List<String> options = new ArrayList<String>();
Iterable<? extends JavaFileObject> files = Arrays.asList(new TestSource());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
JavacTask task = tool.getTask(pw, fm, null, options, null, files);
EventKindCounter ec = new EventKindCounter();
TaskListener listener = new TestListener(ec);
boolean needProcessor = false;
switch (ak) {
case SET_IN_TASK:
task.setTaskListener(listener);
break;
case ADD_IN_TASK:
task.addTaskListener(listener);
break;
case ADD_IN_PROCESSOR:
case ADD_IN_LISTENER:
needProcessor = true;
}
switch (rk) {
case REMOVE_IN_TASK:
task.removeTaskListener(listener);
break;
case REMOVE_IN_PROCESSOR:
case REMOVE_IN_LISTENER:
needProcessor = true;
}
if (needProcessor)
task.setProcessors(Arrays.asList(new TestProcessor(ak, rk, listener)));
ck.run(task);
System.err.println(ec);
check(ck, ak, rk, ec);
System.err.println();
}
void check(CompileKind ck, AddKind ak, RemoveKind rk, EventKindCounter ec) {
// All results should be independent of ck, so we can ignore that
// Quick way to compare expected values of ec, by comparing ec.toString()
String expect = ec.toString();
String found;
switch (ak) {
// Add/set in task should record all events until the listener is removed
case SET_IN_TASK:
case ADD_IN_TASK:
switch (rk) {
case REMOVE_IN_TASK:
// Remove will succeed, meaning no events will be recorded
found = "{}";
break;
case REMOVE_IN_PROCESSOR:
found = "{PARSE=1:1, ENTER=2:2, ANNOTATION_PROCESSING=1:0, ANNOTATION_PROCESSING_ROUND=2:1}";
break;
case REMOVE_IN_LISTENER:
found = "{PARSE=1:1, ENTER=3:3, ANALYZE=1:1, GENERATE=1:0, ANNOTATION_PROCESSING=1:1, ANNOTATION_PROCESSING_ROUND=2:2}";
break;
default:
throw new IllegalStateException();
}
break;
// "Add in processor" should skip initial PARSE/ENTER events
case ADD_IN_PROCESSOR:
switch (rk) {
// Remove will fail (too early), so events to end will be recorded
case REMOVE_IN_TASK:
found = "{ENTER=2:2, ANALYZE=1:1, GENERATE=1:1, ANNOTATION_PROCESSING=0:1, ANNOTATION_PROCESSING_ROUND=1:2}";
break;
case REMOVE_IN_PROCESSOR:
found = "{ENTER=1:1, ANNOTATION_PROCESSING_ROUND=1:1}";
break;
case REMOVE_IN_LISTENER:
found = "{ENTER=2:2, ANALYZE=1:1, GENERATE=1:0, ANNOTATION_PROCESSING=0:1, ANNOTATION_PROCESSING_ROUND=1:2}";
break;
default:
throw new IllegalStateException();
}
break;
// "Add in listener" will occur during "ANALYSE.started" event
case ADD_IN_LISTENER:
switch (rk) {
// Remove will fail (too early, so events to end will be recorded
case REMOVE_IN_TASK:
case REMOVE_IN_PROCESSOR:
found = "{ANALYZE=0:1, GENERATE=1:1}";
break;
// Remove will succeed during "GENERATE.finished" event
case REMOVE_IN_LISTENER:
found = "{ANALYZE=0:1, GENERATE=1:0}";
break;
default:
throw new IllegalStateException();
}
break;
default:
throw new IllegalStateException();
}
if (!found.equals(expect)) {
System.err.println("Expected: " + expect);
System.err.println(" Found: " + found);
error("unexpected value found");
}
}
int errors;
void error(String message) {
System.err.println("Error: " + message);
errors++;
}
}
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -31,6 +31,7 @@ import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.api.ClientCodeWrapper.Trusted;
import com.sun.tools.javac.api.BasicJavacTask;
import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.util.Context;
......@@ -89,10 +90,10 @@ public class TestClose implements TaskListener {
" public void run() {\n" +
" System.out.println(getClass().getName() + \": run()\");\n" +
" try {\n" +
" cl.loadClass(\"Callback\")\n" +
" .asSubclass(Runnable.class)\n" +
" .newInstance()\n" +
" .run();\n" +
" cl.loadClass(\"Callback\")\n" +
" .asSubclass(Runnable.class)\n" +
" .newInstance()\n" +
" .run();\n" +
" } catch (ReflectiveOperationException e) {\n" +
" throw new Error(e);\n" +
" }\n" +
......@@ -184,25 +185,24 @@ public class TestClose implements TaskListener {
throw new AssertionError();
}
public static void add(ProcessingEnvironment env, Runnable r) {
try {
Context c = ((JavacProcessingEnvironment) env).getContext();
Object o = c.get(TaskListener.class);
JavacTask task = JavacTask.instance(env);
TaskListener l = ((BasicJavacTask) task).getTaskListeners().iterator().next();
// The TaskListener is an instanceof TestClose, but when using the
// default class loaders. the taskListener uses a different
// instance of Class<TestClose> than the anno processor.
// If you try to evaluate
// TestClose tc = (TestClose) (o).
// TestClose tc = (TestClose) (l).
// you get the following somewhat confusing error:
// java.lang.ClassCastException: TestClose cannot be cast to TestClose
// The workaround is to access the fields of TestClose with reflection.
Field f = o.getClass().getField("runnables");
Field f = l.getClass().getField("runnables");
@SuppressWarnings("unchecked")
List<Runnable> runnables = (List<Runnable>) f.get(o);
List<Runnable> runnables = (List<Runnable>) f.get(l);
runnables.add(r);
} catch (Throwable t) {
System.err.println(t);
t.printStackTrace();
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册