package org.rendersnake.annotation;
import java.io.IOException;
import java.io.Writer;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
/**
* PageAnnotationProcessor is used to process Page annotations for all classes
* for a project that uses renderSnake. It produces a new file named
* [rendersnake-uri-mappings.properties] as defined by a constant in
* URIMappingResolver in the META-INF folder of src/main/resources
* <p>
* Note: requires Java 1.6+
*
* @author ernestmicklei
*/
@SuppressWarnings("restriction")
@SupportedAnnotationTypes("org.rendersnake.annotation.Page")
public class PageAnnotationProcessor extends AbstractProcessor {
private static final Logger LOG = Logger.getLogger("org.rendersnake.annotation.PageAnnotationProcessor");
private static final String CONFIG_PROPERTIES = "rendersnake-uri-mappings.properties";
/**
* Each implementation of a Processor must provide a public no-argument
* constructor to be used by tools to instantiate the processor.
*/
public PageAnnotationProcessor() {
super();
}
@Override
public boolean process(Set<? extends TypeElement> elements, RoundEnvironment environment) {
// no more rounds needed
if (environment.processingOver()) return true;
// Messager allows the processor to output messages to the environment
// Messager messager = processingEnv.getMessager();
TreeMap<String, String> uriToClassName = new TreeMap<String, String>();
// Loop through the annotations that we are going to process
// In this case there should only be one: Option
for (TypeElement te : elements) {
for (Element e : environment.getElementsAnnotatedWith(te)) {
// Process the members. processAnnotation is our own method
this.processAnnotation(e, uriToClassName);
}
}
this.createMappingFile(uriToClassName);
// claim ownership
return true;
}
private void processAnnotation(Element anElement, Map<String, String> uriMap) {
Page annotation = anElement.getAnnotation(Page.class);
String className = anElement.getSimpleName().toString();
// compose the qualified name of the class
PackageElement pkgElement = (PackageElement)anElement.getEnclosingElement();
className = pkgElement.getQualifiedName().toString() + "." + className;
uriMap.put(annotation.uri(), className);
LOG.info("["+ annotation.uri() + "] => ["+className+"]");
}
private void createMappingFile(TreeMap<String, String> uriMap) {
try {
FileObject fo = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT,"",CONFIG_PROPERTIES);
Writer w = fo.openWriter();
for (String uri : uriMap.keySet()) {
w.append(uri);
w.append("=");
w.append(uriMap.get(uri));
w.append('\n');
}
w.close();
} catch (IOException ex) {
LOG.log(Level.WARNING, "Unable to create mapping file", ex);
}
}
// Perhaps not needed
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new HashSet<String>();
types.add("org.rendersnake.annotation.Page");
return types;
}
}