htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 16 Oct 2012 12:49:59 +0200
changeset 107 0195ef3415ba
parent 106 346633cd13d6
child 108 7e3f72897a83
permissions -rw-r--r--
mvn clean install on root project succeeds
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.bck2brwsr.htmlpage;
    19 
    20 import java.io.IOException;
    21 import java.io.InputStream;
    22 import java.io.OutputStreamWriter;
    23 import java.io.Writer;
    24 import java.util.Locale;
    25 import java.util.Set;
    26 import javax.annotation.processing.AbstractProcessor;
    27 import javax.annotation.processing.Processor;
    28 import javax.annotation.processing.RoundEnvironment;
    29 import javax.annotation.processing.SupportedAnnotationTypes;
    30 import javax.lang.model.element.Element;
    31 import javax.lang.model.element.ElementKind;
    32 import javax.lang.model.element.ExecutableElement;
    33 import javax.lang.model.element.Modifier;
    34 import javax.lang.model.element.PackageElement;
    35 import javax.lang.model.element.TypeElement;
    36 import javax.tools.Diagnostic;
    37 import javax.tools.FileObject;
    38 import javax.tools.StandardLocation;
    39 import org.apidesign.bck2brwsr.htmlpage.api.OnClick;
    40 import org.apidesign.bck2brwsr.htmlpage.api.Page;
    41 import org.openide.util.lookup.ServiceProvider;
    42 
    43 /** Annotation processor to process an XHTML page and generate appropriate 
    44  * "id" file.
    45  *
    46  * @author Jaroslav Tulach <jtulach@netbeans.org>
    47  */
    48 @ServiceProvider(service=Processor.class)
    49 @SupportedAnnotationTypes({
    50     "org.apidesign.bck2brwsr.htmlpage.api.Page",
    51     "org.apidesign.bck2brwsr.htmlpage.api.OnClick"
    52 })
    53 public final class PageProcessor extends AbstractProcessor {
    54     @Override
    55     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    56         for (Element e : roundEnv.getElementsAnnotatedWith(Page.class)) {
    57             Page p = e.getAnnotation(Page.class);
    58             PackageElement pe = (PackageElement)e.getEnclosingElement();
    59             String pkg = pe.getQualifiedName().toString();
    60             
    61             ProcessPage pp;
    62             try {
    63                 InputStream is = openStream(pkg, p.xhtml());
    64                 pp = ProcessPage.readPage(is);
    65                 is.close();
    66             } catch (IOException iOException) {
    67                 processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Can't read " + p.xhtml(), e);
    68                 return false;
    69             }
    70             Writer w;
    71             try {
    72                 FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + p.name(), e);
    73                 w = new OutputStreamWriter(java.openOutputStream());
    74                 try {
    75                     w.append("package " + pkg + ";\n");
    76                     w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n");
    77                     w.append("class ").append(p.name()).append(" {\n");
    78                     for (String id : pp.ids()) {
    79                         String tag = pp.tagNameForId(id);
    80                         String type = type(tag);
    81                         w.append("  ").append("public static final ").
    82                             append(type).append(' ').append(cnstnt(id)).append(" = new ").
    83                             append(type).append("(\"").append(id).append("\");\n");
    84                     }
    85                     w.append("  static {\n");
    86                     if (!initializeOnClick(pe, w, pp)) {
    87                         return false;
    88                     }
    89                     w.append("  }\n");
    90                     w.append("}\n");
    91                 } finally {
    92                     w.close();
    93                 }
    94             } catch (IOException ex) {
    95                 processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Can't create " + p.name() + ".java", e);
    96                 return false;
    97             }
    98         }
    99         return true;
   100     }
   101 
   102     private InputStream openStream(String pkg, String name) throws IOException {
   103         try {
   104             FileObject fo = processingEnv.getFiler().getResource(
   105                 StandardLocation.SOURCE_PATH, pkg, name);
   106             return fo.openInputStream();
   107         } catch (IOException ex) {
   108             return processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, pkg, name).openInputStream();
   109         }
   110     }
   111 
   112     private static String type(String tag) {
   113         if (tag.equals("title")) {
   114             return "Title";
   115         }
   116         if (tag.equals("button")) {
   117             return "Button";
   118         }
   119         if (tag.equals("input")) {
   120             return "Input";
   121         }
   122         return "Element";
   123     }
   124 
   125     private static String cnstnt(String id) {
   126         return id.toUpperCase(Locale.ENGLISH).replace('.', '_');
   127     }
   128 
   129     private boolean initializeOnClick(PackageElement pe, Writer w, ProcessPage pp) throws IOException {
   130         for (Element clazz : pe.getEnclosedElements()) {
   131             if (clazz.getKind() != ElementKind.CLASS) {
   132                 continue;
   133             }
   134             TypeElement type = (TypeElement)clazz;
   135             for (Element method : clazz.getEnclosedElements()) {
   136                 OnClick oc = method.getAnnotation(OnClick.class);
   137                 if (oc != null) {
   138                     if (pp.tagNameForId(oc.id()) == null) {
   139                         processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "id = " + oc.id() + " does not exist in the HTML page. Found only " + pp.ids(), method);
   140                         return false;
   141                     }
   142                     ExecutableElement ee = (ExecutableElement)method;
   143                     if (!ee.getParameters().isEmpty()) {
   144                         processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@OnClose method can't take arguments", ee);
   145                         return false;
   146                     }
   147                     if (!ee.getModifiers().contains(Modifier.STATIC)) {
   148                         processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@OnClose method has to be static", ee);
   149                         return false;
   150                     }
   151                     if (ee.getModifiers().contains(Modifier.PRIVATE)) {
   152                         processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@OnClose method can't be private", ee);
   153                         return false;
   154                     }
   155                     w.append("  ").append(cnstnt(oc.id())).
   156                         append(".addOnClick(new Runnable() { public void run() {\n");
   157                     w.append("    ").append(type.getSimpleName().toString()).
   158                         append('.').append(ee.getSimpleName()).append("();\n");
   159                     w.append("  }});\n");
   160                 }
   161             }
   162         }
   163         return true;
   164     }
   165 }