javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/Compile.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Fri, 02 May 2014 09:06:57 +0200
branchclosure
changeset 1518 8261c59be151
parent 1505 706b66d8c481
child 1787 ea12a3bb4b33
permissions -rw-r--r--
More classes to not process into JavaScript
     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.ByteArrayInputStream;
    21 import java.io.ByteArrayOutputStream;
    22 import java.io.IOException;
    23 import java.io.InputStream;
    24 import java.io.OutputStream;
    25 import java.net.URI;
    26 import java.net.URISyntaxException;
    27 import java.util.ArrayList;
    28 import java.util.Arrays;
    29 import java.util.HashMap;
    30 import java.util.List;
    31 import java.util.Map;
    32 import java.util.regex.Matcher;
    33 import java.util.regex.Pattern;
    34 import javax.tools.Diagnostic;
    35 import javax.tools.DiagnosticListener;
    36 import javax.tools.FileObject;
    37 import javax.tools.ForwardingJavaFileManager;
    38 import javax.tools.JavaFileManager;
    39 import javax.tools.JavaFileObject;
    40 import javax.tools.JavaFileObject.Kind;
    41 import javax.tools.SimpleJavaFileObject;
    42 import javax.tools.StandardJavaFileManager;
    43 import javax.tools.StandardLocation;
    44 import javax.tools.ToolProvider;
    45 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
    46 
    47 /**
    48  *
    49  * @author Jaroslav Tulach <jtulach@netbeans.org>
    50  */
    51 @ExtraJavaScript(processByteCode = false, resource = "")
    52 final class Compile implements DiagnosticListener<JavaFileObject> {
    53     private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<>();
    54     private final Map<String, byte[]> classes;
    55     private final String pkg;
    56     private final String cls;
    57     private final String html;
    58 
    59     private Compile(String html, String code) throws IOException {
    60         this.pkg = findPkg(code);
    61         this.cls = findCls(code);
    62         this.html = html;
    63         classes = compile(html, code);
    64     }
    65 
    66     /** Performs compilation of given HTML page and associated Java code
    67      */
    68     public static Compile create(String html, String code) throws IOException {
    69         return new Compile(html, code);
    70     }
    71     
    72     /** Checks for given class among compiled resources */
    73     public byte[] get(String res) {
    74         return classes.get(res);
    75     }
    76     
    77     /** Obtains errors created during compilation.
    78      */
    79     public List<Diagnostic<? extends JavaFileObject>> getErrors() {
    80         List<Diagnostic<? extends JavaFileObject>> err = new ArrayList<>();
    81         for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
    82             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
    83                 err.add(diagnostic);
    84             }
    85         }
    86         return err;
    87     }
    88     
    89     private Map<String, byte[]> compile(final String html, final String code) throws IOException {
    90         StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
    91 
    92         final Map<String, ByteArrayOutputStream> class2BAOS = new HashMap<>();
    93 
    94         JavaFileObject file = new Mem(URI.create("mem://mem"), Kind.SOURCE, code);
    95         final JavaFileObject htmlFile = new Mem2(URI.create("mem://mem2"), Kind.OTHER, html);
    96         
    97         final URI scratch;
    98         try {
    99             scratch = new URI("mem://mem3");
   100         } catch (URISyntaxException ex) {
   101             throw new IOException(ex);
   102         }
   103         
   104         JavaFileManager jfm = new ForwardingJavaFileManagerImpl(sjfm, class2BAOS, scratch, htmlFile);
   105 
   106         ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call();
   107 
   108         Map<String, byte[]> result = new HashMap<>();
   109 
   110         for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
   111             result.put(e.getKey(), e.getValue().toByteArray());
   112         }
   113 
   114         return result;
   115     }
   116 
   117 
   118     @Override
   119     public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   120         errors.add(diagnostic);
   121     }
   122     private static String findPkg(String java) throws IOException {
   123         Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
   124         Matcher m = p.matcher(java);
   125         if (!m.find()) {
   126             throw new IOException("Can't find package declaration in the java file");
   127         }
   128         String pkg = m.group(1);
   129         return pkg;
   130     }
   131     private static String findCls(String java) throws IOException {
   132         Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
   133         Matcher m = p.matcher(java);
   134         if (!m.find()) {
   135             throw new IOException("Can't find package declaration in the java file");
   136         }
   137         String cls = m.group(1);
   138         return cls;
   139     }
   140 
   141     String getHtml() {
   142         String fqn = "'" + pkg + '.' + cls + "'";
   143         return html.replace("'${fqn}'", fqn);
   144     }
   145 
   146     @ExtraJavaScript(processByteCode = false, resource = "")
   147     private class ForwardingJavaFileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {
   148 
   149         private final Map<String, ByteArrayOutputStream> class2BAOS;
   150         private final URI scratch;
   151         private final JavaFileObject htmlFile;
   152 
   153         public ForwardingJavaFileManagerImpl(JavaFileManager fileManager, Map<String, ByteArrayOutputStream> class2BAOS, URI scratch, JavaFileObject htmlFile) {
   154             super(fileManager);
   155             this.class2BAOS = class2BAOS;
   156             this.scratch = scratch;
   157             this.htmlFile = htmlFile;
   158         }
   159 
   160         @Override
   161         public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
   162             if (kind  == Kind.CLASS) {
   163                 final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
   164                 
   165                 class2BAOS.put(className.replace('.', '/') + ".class", buffer);
   166                 return new Sibling(sibling.toUri(), kind, buffer);
   167             }
   168             
   169             if (kind == Kind.SOURCE) {
   170                 return new Source(scratch/*sibling.toUri()*/, kind);
   171             }
   172             
   173             throw new IllegalStateException();
   174         }
   175 
   176             @Override
   177             public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
   178                 if (location == StandardLocation.SOURCE_PATH) {
   179                     if (packageName.equals(pkg)) {
   180                         return htmlFile;
   181                     }
   182                 }
   183                 
   184                 return null;
   185             }
   186 
   187       @ExtraJavaScript(processByteCode = false, resource = "")
   188       private class Sibling extends SimpleJavaFileObject {
   189             private final ByteArrayOutputStream buffer;
   190 
   191             public Sibling(URI uri, Kind kind, ByteArrayOutputStream buffer) {
   192                 super(uri, kind);
   193                 this.buffer = buffer;
   194             }
   195 
   196             @Override
   197             public OutputStream openOutputStream() throws IOException {
   198                 return buffer;
   199             }
   200         }
   201 
   202       @ExtraJavaScript(processByteCode = false, resource = "")
   203       private class Source extends SimpleJavaFileObject {
   204             public Source(URI uri, Kind kind) {
   205                 super(uri, kind);
   206             }
   207             private final ByteArrayOutputStream data = new ByteArrayOutputStream();
   208 
   209             @Override
   210             public OutputStream openOutputStream() throws IOException {
   211                 return data;
   212             }
   213 
   214             @Override
   215             public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   216                 data.close();
   217                 return new String(data.toByteArray());
   218             }
   219         }
   220     }
   221 
   222     @ExtraJavaScript(processByteCode = false, resource = "")
   223     private static class Mem extends SimpleJavaFileObject {
   224 
   225         private final String code;
   226 
   227         public Mem(URI uri, Kind kind, String code) {
   228             super(uri, kind);
   229             this.code = code;
   230         }
   231 
   232         @Override
   233         public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   234             return code;
   235         }
   236     }
   237 
   238     @ExtraJavaScript(processByteCode = false, resource = "")
   239     private static class Mem2 extends SimpleJavaFileObject {
   240 
   241         private final String html;
   242 
   243         public Mem2(URI uri, Kind kind, String html) {
   244             super(uri, kind);
   245             this.html = html;
   246         }
   247 
   248         @Override
   249         public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   250             return html;
   251         }
   252 
   253         @Override
   254         public InputStream openInputStream() throws IOException {
   255             return new ByteArrayInputStream(html.getBytes());
   256         }
   257     }
   258 }