swingx-master/swingx-mavensupport/src/main/java/org/jdesktop/beans/JavaBeanProcessor.java
package org.jdesktop.beans;

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.util.Collections;
import java.util.Set;
import java.util.TreeSet;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.StandardLocation;

import org.kohsuke.MetaInfServices;

/**
 * An annotation processor that creates or updates a manifest with Java-Bean information.
 * 
 * @author kschaefer
 */
@SuppressWarnings("nls")
@MetaInfServices(Processor.class)
public class JavaBeanProcessor extends AbstractProcessor {
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Collections.singleton(JavaBean.class.getName());
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (roundEnv.processingOver()) {
            return false;
        }

        Set<String> beans = new TreeSet<String>();

        //JavaBean is a type only annotation, so cast to TypeElement is safe
        for (TypeElement type : (Set<TypeElement>) roundEnv.getElementsAnnotatedWith(JavaBean.class)) {
            beans.add(type.getQualifiedName().toString());
        }
        
        // remove any existing values; we append to the file
        Filer filer = processingEnv.getFiler();
        
        FileObject manifest = null;
        
        try {
            processingEnv.getMessager().printMessage(Kind.NOTE, "Attempting to open manifest...");
            
            manifest = filer.getResource(StandardLocation.SOURCE_PATH, "", "META-INF/MANIFEST.MF");
            
            if (manifest != null) {
                processingEnv.getMessager().printMessage(Kind.NOTE, "Succeeded: " + manifest.getName());
                
                BufferedReader r = null;
                
                try {
                    processingEnv.getMessager().printMessage(Kind.NOTE, "Attempting to find previously defined Java beans");
                    
                    r = new BufferedReader(new InputStreamReader(manifest.openInputStream(), "UTF-8"));
                    
                    String possibleBean = null;
                    
                    for (String line = r.readLine(); line != null; line = r.readLine()) {
                        if (possibleBean == null) {
                            if (line.startsWith("Name: ") && line.endsWith(".class")) {
                                possibleBean = line.substring("Name: ".length(), line.length() - ".class".length()).replace('/', '.');
                                
                                try {
                                    Class.forName(possibleBean);
                                } catch (ClassNotFoundException notABean) {
                                    possibleBean = null;
                                }
                            }
                        } else {
                            if (line.equals("Java-Bean: True")) {
                                processingEnv.getMessager().printMessage(Kind.NOTE,  possibleBean + " already defined");
                                beans.remove(possibleBean);
                            }
                            
                            possibleBean = null;
                        }
                    }
                    
                    r.close();
                    
                } catch (FileNotFoundException ignore) {
                    processingEnv.getMessager().printMessage(Kind.NOTE, "Manifest not found");
                } catch (IOException e) {
                    throw new RuntimeException("Failed to read current Java-Bean information", e);
                } finally {
                    if (r != null) {
                        try {
                            r.close();
                        } catch (IOException ignore) { }
                    }
                }
            }
        } catch (FileNotFoundException ignore) {
            // no file to process
            processingEnv.getMessager().printMessage(Kind.NOTE, "Manifest does not exist...");
        } catch (IOException e) {
            processingEnv.getMessager().printMessage(Kind.ERROR, "Failed to load existing manifest for Java-Bean processing:\n" + e);
            
            return false;
        }
        
        try {
            processingEnv.getMessager().printMessage(Kind.NOTE, "Attempting to create output manifest...");
            
            manifest = filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "META-INF/MANIFEST.MF");
            
            processingEnv.getMessager().printMessage(Kind.NOTE, "Succeeded: " + manifest.getName());
        } catch (IOException e) {
            processingEnv.getMessager().printMessage(Kind.ERROR, "Cannot create manifest for Java-Bean processing:\n" + e);
            
            return false;
        }

        processingEnv.getMessager().printMessage(Kind.NOTE, "Appending Java-Beans to MANIFEST.MF");
        processingEnv.getMessager().printMessage(Kind.NOTE, beans.toString());
        
        PrintWriter pw = null;
        
        try {
            pw = new PrintWriter(new OutputStreamWriter(manifest.openOutputStream(), "UTF-8"));
            
            pw.println();
            
            for (String value : beans) {
                pw.println("Name: " + value + ".class");
                pw.println("Java-Bean: True");
                pw.println();
            }
        } catch (IOException e) {
            throw new RuntimeException("Failed to write Java-Bean information", e);
        } finally {
            if (pw != null) {
                pw.close();
            }
        }
        
        return false;
    }
}
