View Javadoc

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 }