javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/Compile.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 29 Apr 2014 14:59:40 +0200
branchclosure
changeset 1505 706b66d8c481
parent 769 0c0fe97fe0c7
child 1518 8261c59be151
permissions -rw-r--r--
javaquery api works on JDK8
     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 SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
    95             @Override
    96             public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
    97                 return code;
    98             }
    99         };
   100         final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
   101             @Override
   102             public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   103                 return html;
   104             }
   105 
   106             @Override
   107             public InputStream openInputStream() throws IOException {
   108                 return new ByteArrayInputStream(html.getBytes());
   109             }
   110         };
   111         
   112         final URI scratch;
   113         try {
   114             scratch = new URI("mem://mem3");
   115         } catch (URISyntaxException ex) {
   116             throw new IOException(ex);
   117         }
   118         
   119         JavaFileManager jfm = new ForwardingJavaFileManagerImpl(sjfm, class2BAOS, scratch, htmlFile);
   120 
   121         ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call();
   122 
   123         Map<String, byte[]> result = new HashMap<>();
   124 
   125         for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
   126             result.put(e.getKey(), e.getValue().toByteArray());
   127         }
   128 
   129         return result;
   130     }
   131 
   132 
   133     @Override
   134     public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   135         errors.add(diagnostic);
   136     }
   137     private static String findPkg(String java) throws IOException {
   138         Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
   139         Matcher m = p.matcher(java);
   140         if (!m.find()) {
   141             throw new IOException("Can't find package declaration in the java file");
   142         }
   143         String pkg = m.group(1);
   144         return pkg;
   145     }
   146     private static String findCls(String java) throws IOException {
   147         Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
   148         Matcher m = p.matcher(java);
   149         if (!m.find()) {
   150             throw new IOException("Can't find package declaration in the java file");
   151         }
   152         String cls = m.group(1);
   153         return cls;
   154     }
   155 
   156     String getHtml() {
   157         String fqn = "'" + pkg + '.' + cls + "'";
   158         return html.replace("'${fqn}'", fqn);
   159     }
   160 
   161     @ExtraJavaScript(processByteCode = false, resource = "")
   162     private class ForwardingJavaFileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {
   163 
   164         private final Map<String, ByteArrayOutputStream> class2BAOS;
   165         private final URI scratch;
   166         private final JavaFileObject htmlFile;
   167 
   168         public ForwardingJavaFileManagerImpl(JavaFileManager fileManager, Map<String, ByteArrayOutputStream> class2BAOS, URI scratch, JavaFileObject htmlFile) {
   169             super(fileManager);
   170             this.class2BAOS = class2BAOS;
   171             this.scratch = scratch;
   172             this.htmlFile = htmlFile;
   173         }
   174 
   175         @Override
   176         public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
   177             if (kind  == Kind.CLASS) {
   178                 final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
   179                 
   180                 class2BAOS.put(className.replace('.', '/') + ".class", buffer);
   181                 return new SimpleJavaFileObject(sibling.toUri(), kind) {
   182                     @Override
   183                     public OutputStream openOutputStream() throws IOException {
   184                         return buffer;
   185                     }
   186                 };
   187             }
   188             
   189             if (kind == Kind.SOURCE) {
   190                 return new SimpleJavaFileObject(scratch/*sibling.toUri()*/, kind) {
   191                     private final ByteArrayOutputStream data = new ByteArrayOutputStream();
   192                     @Override
   193                     public OutputStream openOutputStream() throws IOException {
   194                         return data;
   195                     }
   196                     
   197                     @Override
   198                     public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   199                         data.close();
   200                         return new String(data.toByteArray());
   201                     }
   202                 };
   203             }
   204             
   205             throw new IllegalStateException();
   206         }
   207 
   208             @Override
   209             public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
   210                 if (location == StandardLocation.SOURCE_PATH) {
   211                     if (packageName.equals(pkg)) {
   212                         return htmlFile;
   213                     }
   214                 }
   215                 
   216                 return null;
   217             }
   218     }
   219 }