0351f7565e765c3375517d2aebcc206dfc409434
[jglob.git] / src / dolda / jglob / Collector.java
1 package dolda.jglob;
2
3 import java.util.*;
4 import java.io.*;
5 import javax.annotation.processing.*;
6 import javax.tools.*;
7 import javax.lang.model.*;
8 import javax.lang.model.element.*;
9 import javax.lang.model.util.*;
10
11 @SupportedAnnotationTypes({"*"})
12 public class Collector extends AbstractProcessor {
13     private ProcessingEnvironment cfg;
14     private Elements eu;
15     private boolean verbose = false;
16
17     public void init(ProcessingEnvironment cfg) {
18         this.cfg = cfg;
19         eu = cfg.getElementUtils();
20     }
21
22     private String tn(TypeElement el) {
23         return(eu.getBinaryName(el).toString());
24     }
25
26     private Set<String> getprev(TypeElement annotation) {
27         Set<String> prev = new HashSet<String>();
28         try {
29             FileObject lf = cfg.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/glob/" + tn(annotation));
30             InputStream in;
31             try {
32                 in = lf.openInputStream();
33             } catch(FileNotFoundException e) {
34                 return(prev);
35             }
36             try {
37                 BufferedReader r = new BufferedReader(new InputStreamReader(in, "utf-8"));
38                 String ln;
39                 while((ln = r.readLine()) != null)
40                     prev.add(ln);
41                 return(prev);
42             } finally {
43                 in.close();
44             }
45         } catch(IOException e) {
46             cfg.getMessager().printMessage(Diagnostic.Kind.ERROR, "could not read previous globlist for " + tn(annotation) + ": " + e);
47             return(Collections.emptySet());
48         }
49     }
50
51     private void writenew(TypeElement annotation, Collection<String> names) {
52         try {
53             FileObject lf = cfg.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/glob/" + tn(annotation));
54             OutputStream out = lf.openOutputStream();
55             try {
56                 Writer w = new BufferedWriter(new OutputStreamWriter(out, "utf-8"));
57                 for(String nm : names)
58                     w.write(nm + "\n");
59                 w.flush();
60             } finally {
61                 out.close();
62             }
63         } catch(IOException e) {
64             cfg.getMessager().printMessage(Diagnostic.Kind.ERROR, "could not write new globlist for " + tn(annotation) + ": " + e);
65         }
66     }
67
68     private void process(TypeElement annotation, RoundEnvironment round, TypeMap types) {
69         Set<String> prev = getprev(annotation);
70         Set<String> carry = new HashSet<String>(prev);
71         Set<String> found = new HashSet<String>();
72         for(Element e : round.getElementsAnnotatedWith(annotation)) {
73             if(!(e instanceof TypeElement)) {
74                 cfg.getMessager().printMessage(Diagnostic.Kind.ERROR, tn(annotation) + " must annotate types", e);
75                 continue;
76             }
77             TypeElement type = (TypeElement)e;
78             String nm = tn(type);
79             if(!prev.contains(nm) && verbose)
80                 cfg.getMessager().printMessage(Diagnostic.Kind.NOTE, "added " + nm, type);
81             found.add(nm);
82             carry.remove(nm);
83         }
84         for(Iterator<String> i = carry.iterator(); i.hasNext();) {
85             String nm = i.next();
86             TypeElement el = types.get(nm);
87             if(el != null) {
88                 i.remove();
89                 if(verbose)
90                     cfg.getMessager().printMessage(Diagnostic.Kind.NOTE, "removed " + nm, el);
91             }
92         }
93         List<String> all = new ArrayList<String>();
94         all.addAll(carry);
95         all.addAll(found);
96         Collections.sort(all);
97         writenew(annotation, all);
98     }
99
100     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment round) {
101         for(TypeElement a : annotations) {
102             if(a.getAnnotation(Discoverable.class) != null)
103                 process(a, round, new TypeMap(round.getRootElements(), eu));
104         }
105         return(false);
106     }
107
108     public SourceVersion getSupportedSourceVersion() {
109         return(SourceVersion.latest());
110     }
111 }