diff options
Diffstat (limited to 'parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson')
5 files changed, 486 insertions, 0 deletions
diff --git a/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/AnnotationProcessorImpl.java b/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/AnnotationProcessorImpl.java new file mode 100644 index 00000000000..3a7b6c2de62 --- /dev/null +++ b/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/AnnotationProcessorImpl.java @@ -0,0 +1,196 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.sun.com/cddl/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is SezPoz. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 2008 Sun + * Microsystems, Inc. All Rights Reserved. + */ +package org.jvnet.hudson.annotation_indexer; + +import org.kohsuke.MetaInfServices; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import static javax.lang.model.SourceVersion.RELEASE_6; +import static javax.lang.model.SourceVersion.RELEASE_7; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import javax.tools.Diagnostic.Kind; +import javax.tools.FileObject; +import static javax.tools.StandardLocation.CLASS_OUTPUT; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +/** + * Creates indices of {@link Indexed} annotations. + * + * @author Kohsuke Kawaguchi + */ +@SupportedSourceVersion(RELEASE_7) +@SupportedAnnotationTypes("*") +@SuppressWarnings({"Since15"}) +@MetaInfServices(Processor.class) +public class AnnotationProcessorImpl extends AbstractProcessor { + /** + * Use of an annotation. + */ + private final class Use { + /** + * FQCN of the annotation. + */ + final String annotationName; + /** + * Strings that designate FQCNs where annotations are used, either on a class or its members. + */ + final Set<String> classes = new TreeSet<String>(); + /** + * Keeps track of elements that has the annotation. + */ + final Set<Element> originatingElements = new HashSet<Element>(); + + private Use(String annotationName) { + this.annotationName = annotationName; + } + + void add(Element elt) { + originatingElements.add(elt); + + TypeElement t; + switch (elt.getKind()) { + case CLASS: + t = (TypeElement) elt; + break; + case METHOD: + case FIELD: + t = (TypeElement) elt.getEnclosingElement(); + break; + default: + throw new AssertionError(elt.getKind()); + } + classes.add(getElementUtils().getBinaryName(t).toString()); + } + + String getIndexFileName() { + return "META-INF/annotations/" + annotationName; + } + + /** + * Loads existing index, if it exists. + */ + List<String> loadExisting() throws IOException { + List<String> elements = new ArrayList<String>(); + try { + FileObject in = processingEnv.getFiler().getResource(CLASS_OUTPUT, "", getIndexFileName()); + // Read existing annotations, for incremental compilation. + BufferedReader is = new BufferedReader(new InputStreamReader(in.openInputStream(),"UTF-8")); + try { + String line; + while ((line=is.readLine())!=null) + elements.add(line); + } finally { + is.close(); + } + } catch (FileNotFoundException x) { + // OK, created for the first time + } + return elements; + } + + void write() { + try { + FileObject out = processingEnv.getFiler().createResource(CLASS_OUTPUT, + "", getIndexFileName(), + originatingElements.toArray(new Element[originatingElements.size()])); + + PrintWriter w = new PrintWriter(new OutputStreamWriter(out.openOutputStream(),"UTF-8")); + try { + for (String el : classes) + w.println(el); + } finally { + w.close(); + } + } catch (IOException x) { + processingEnv.getMessager().printMessage(Kind.ERROR, x.toString()); + } + } + } + + private Elements getElementUtils() { + return processingEnv.getElementUtils(); + } + + @Override + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) + return false; + + // map from indexable annotation names, to actual uses + Map<String,Use> output = new HashMap<String,Use>(); + scan(annotations, roundEnv, output); + for (Use u : output.values()) + u.write(); + return false; + } + + private AnnotationMirror findAnnotationOn(Element e, String name) { + for (AnnotationMirror a : getElementUtils().getAllAnnotationMirrors(e)) + if (getElementUtils().getBinaryName((TypeElement) a.getAnnotationType().asElement()).contentEquals(name)) + return a; + return null; + } + + private void scan(Set<? extends TypeElement> annotations, + RoundEnvironment roundEnv, Map<String,Use> output) { + for (TypeElement ann : annotations) { + AnnotationMirror indexed = findAnnotationOn(ann,Indexed.class.getName()); + if (indexed == null) + continue; // not indexed + + String annName = getElementUtils().getBinaryName(ann).toString(); + Use o = output.get(annName); + if (o==null) + output.put(annName,o=new Use(annName)); + + for (Element elt : roundEnv.getElementsAnnotatedWith(ann)) { + AnnotationMirror marked = findAnnotationOn(elt,annName); + assert marked != null; + + // TODO: validator support + + o.add(elt); + } + } + } + + +} diff --git a/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/FilterIterator.java b/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/FilterIterator.java new file mode 100644 index 00000000000..6e0035ddeb0 --- /dev/null +++ b/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/FilterIterator.java @@ -0,0 +1,74 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.sun.com/cddl/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is SezPoz. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 2008 Sun + * Microsystems, Inc. All Rights Reserved. + */package org.jvnet.hudson.annotation_indexer; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * @author Kohsuke Kawaguchi + */ +abstract class FilterIterator<T> implements Iterator<T> { + private final Iterator<? extends T> core; + private T next; + private boolean fetched; + + protected FilterIterator(Iterator<? extends T> core) { + this.core = core; + } + + protected FilterIterator(Iterable<? extends T> core) { + this(core.iterator()); + } + + private void fetch() { + while(!fetched && core.hasNext()) { + T n = core.next(); + if(filter(n)) { + next = n; + fetched = true; + } + } + } + + /** + * Filter out items in the original collection. + * + * @return + * true to leave this item and return this item from this iterator. + * false to hide this item. + */ + protected abstract boolean filter(T t); + + public boolean hasNext() { + fetch(); + return fetched; + } + + public T next() { + fetch(); + if(!fetched) throw new NoSuchElementException(); + fetched = false; + return next; + } + + public void remove() { + core.remove(); + } +} diff --git a/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/Index.java b/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/Index.java new file mode 100644 index 00000000000..b345f6b797d --- /dev/null +++ b/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/Index.java @@ -0,0 +1,140 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.sun.com/cddl/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is SezPoz. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 2008 Sun + * Microsystems, Inc. All Rights Reserved. + */package org.jvnet.hudson.annotation_indexer; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * @author Kohsuke Kawaguchi + */ +public class Index { + /** + * Lists up all the elements annotated by the given annotation and of the given {@link AnnotatedElement} subtype. + */ + public static <T extends AnnotatedElement> Iterable<T> list(Class<? extends Annotation> type, ClassLoader cl, final Class<T> subType) throws IOException { + final Iterable<AnnotatedElement> base = list(type,cl); + return new Iterable<T>() { + public Iterator<T> iterator() { + return new FilterIterator(base.iterator()) { + protected boolean filter(Object o) { + return subType.isInstance(o); + } + }; + } + }; + } + + /** + * Lists up all the elements annotated by the given annotation. + */ + public static Iterable<AnnotatedElement> list(final Class<? extends Annotation> type, final ClassLoader cl) throws IOException { + if (!type.isAnnotationPresent(Indexed.class)) + throw new IllegalArgumentException(type+" doesn't have @Indexed"); + + final Set<String> ids = new TreeSet<String>(); + + final Enumeration<URL> res = cl.getResources("META-INF/annotations/"+type.getName()); + while (res.hasMoreElements()) { + URL url = res.nextElement(); + BufferedReader r = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8")); + String line; + while ((line=r.readLine())!=null) + ids.add(line); + } + + return new Iterable<AnnotatedElement>() { + public Iterator<AnnotatedElement> iterator() { + return new Iterator<AnnotatedElement>() { + /** + * Next element to return. + */ + private AnnotatedElement next; + + private Iterator<String> iditr = ids.iterator(); + + private List<AnnotatedElement> lookaheads = new LinkedList<AnnotatedElement>(); + + public boolean hasNext() { + fetch(); + return next!=null; + } + + public AnnotatedElement next() { + fetch(); + AnnotatedElement r = next; + next = null; + return r; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + private void fetch() { + while (next==null) { + if (!lookaheads.isEmpty()) { + next = lookaheads.remove(0); + return; + } + + if (!iditr.hasNext()) return; + String name = iditr.next(); + + try { + Class<?> c = cl.loadClass(name); + + if (c.isAnnotationPresent(type)) + lookaheads.add(c); + listAnnotatedElements(c.getDeclaredMethods()); + listAnnotatedElements(c.getDeclaredFields()); + } catch (ClassNotFoundException e) { + LOGGER.log(Level.FINE, "Failed to load: "+name,e); + } + } + } + + private void listAnnotatedElements(AnnotatedElement[] elements) { + for (AnnotatedElement m : elements) { + // this means we don't correctly handle + if (m.isAnnotationPresent(type)) + lookaheads.add(m); + } + } + }; + } + }; + } + + private static final Logger LOGGER = Logger.getLogger(Index.class.getName()); +} diff --git a/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/Indexed.java b/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/Indexed.java new file mode 100644 index 00000000000..25be039f44c --- /dev/null +++ b/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/Indexed.java @@ -0,0 +1,38 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.sun.com/cddl/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is SezPoz. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 2008 Sun + * Microsystems, Inc. All Rights Reserved. + */ +package org.jvnet.hudson.annotation_indexer; + +import java.lang.annotation.Documented; +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import java.lang.annotation.Retention; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Target; + +/** + * Marks annotations that should be indexed during compilation. + * + * @author Kohsuke Kawaguchi + */ +@Documented +@Retention(RUNTIME) +@Target(ANNOTATION_TYPE) +public @interface Indexed { + Class<? extends Validator>[] validators() default {}; +} diff --git a/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/Validator.java b/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/Validator.java new file mode 100644 index 00000000000..4015d2588f8 --- /dev/null +++ b/parent/org.jvnet.hudson/src/main/java/org/jvnet/hudson/annotation_indexer/Validator.java @@ -0,0 +1,38 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.sun.com/cddl/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is SezPoz. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 2008 Sun + * Microsystems, Inc. All Rights Reserved. + */ +package org.jvnet.hudson.annotation_indexer; + +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; + +/** + * Checkes the usage of {@link Indexed} annotations at compile-time. + * + * @author Kohsuke Kawaguchi + * @see Indexed + */ +public interface Validator { + /** + * Checks the occurrence of the {@link Indexed} annotation + * and report any error. Useful for early error detection. + */ + void check(Element use, RoundEnvironment e, ProcessingEnvironment env); +} |