1 /*
2 * Entreri, an entity-component framework in Java
3 *
4 * Copyright (c) 2013, Michael Ludwig
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without modification,
8 * are permitted provided that the following conditions are met:
9 *
10 * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 package com.lhkbob.entreri.impl;
28
29 import com.lhkbob.entreri.Component;
30 import com.lhkbob.entreri.IllegalComponentDefinitionException;
31
32 import javax.annotation.processing.AbstractProcessor;
33 import javax.annotation.processing.RoundEnvironment;
34 import javax.annotation.processing.SupportedAnnotationTypes;
35 import javax.annotation.processing.SupportedSourceVersion;
36 import javax.lang.model.SourceVersion;
37 import javax.lang.model.element.Element;
38 import javax.lang.model.element.ElementKind;
39 import javax.lang.model.element.TypeElement;
40 import javax.lang.model.util.Elements;
41 import javax.lang.model.util.Types;
42 import javax.tools.Diagnostic;
43 import java.io.IOException;
44 import java.io.Writer;
45 import java.util.Set;
46
47 /**
48 * ComponentImplementationProcessor is an annotation processor to use with Java 6
49 * compilers or APT to generate component proxy implementations for all component
50 * sub-interfaces encountered in the build class path. These will then be dynamically
51 * loaded at runtime instead of using something such as Janino to generate classes from
52 * scratch.
53 *
54 * @author Michael Ludwig
55 */
56 @SupportedAnnotationTypes("*")
57 @SupportedSourceVersion(SourceVersion.RELEASE_7)
58 public class ComponentImplementationProcessor extends AbstractProcessor {
59 @Override
60 public boolean process(Set<? extends TypeElement> annotations,
61 RoundEnvironment roundEnv) {
62 Types tutil = processingEnv.getTypeUtils();
63 Elements eutil = processingEnv.getElementUtils();
64 for (Element e : roundEnv.getRootElements()) {
65 if (e.getKind().equals(ElementKind.INTERFACE)) {
66 // we have an interface
67 TypeElement t = (TypeElement) e;
68 if (tutil.isAssignable(t.asType(), eutil.getTypeElement(
69 Component.class.getCanonicalName()).asType())) {
70
71 try {
72 ComponentSpecification spec = ComponentSpecification.Factory
73 .fromTypeElement(
74 t,
75 processingEnv);
76 String name = ComponentFactoryProvider
77 .getImplementationClassName(spec, true);
78 String code = ComponentFactoryProvider
79 .generateJavaCode(spec, processingEnv.getSourceVersion());
80 try {
81 Writer w = processingEnv.getFiler().createSourceFile(name, t)
82 .openWriter();
83 w.write(code);
84 w.flush();
85 w.close();
86 } catch (IOException ioe) {
87 processingEnv.getMessager()
88 .printMessage(Diagnostic.Kind.ERROR,
89 ioe.getMessage(), t);
90 }
91 } catch (IllegalComponentDefinitionException ec) {
92 String typePrefix = t.asType().toString();
93 String msg = ec.getMessage();
94 if (msg.startsWith(typePrefix)) {
95 msg = msg.substring(typePrefix.length());
96 }
97 processingEnv.getMessager()
98 .printMessage(Diagnostic.Kind.ERROR, msg, t);
99 }
100 }
101 }
102 }
103
104 return false;
105 }
106 }