launcher/src/main/java/org/apidesign/bck2brwsr/dew/Compile.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 16 Jan 2013 11:07:28 +0100
branchdew
changeset 464 9823859d253a
parent 463 3641fd0663d3
child 468 a7ff47e054f3
permissions -rw-r--r--
Polishing the compilation APIs
     1 package org.apidesign.bck2brwsr.dew;
     2 
     3 import java.io.ByteArrayInputStream;
     4 import java.io.ByteArrayOutputStream;
     5 import java.io.IOException;
     6 import java.io.InputStream;
     7 import java.io.OutputStream;
     8 import java.net.URI;
     9 import java.net.URISyntaxException;
    10 import java.util.ArrayList;
    11 import java.util.Arrays;
    12 import java.util.HashMap;
    13 import java.util.List;
    14 import java.util.Map;
    15 import java.util.regex.Matcher;
    16 import java.util.regex.Pattern;
    17 import javax.tools.Diagnostic;
    18 import javax.tools.DiagnosticListener;
    19 import javax.tools.FileObject;
    20 import javax.tools.ForwardingJavaFileManager;
    21 import javax.tools.JavaFileManager;
    22 import javax.tools.JavaFileObject;
    23 import javax.tools.JavaFileObject.Kind;
    24 import javax.tools.SimpleJavaFileObject;
    25 import javax.tools.StandardJavaFileManager;
    26 import javax.tools.StandardLocation;
    27 import javax.tools.ToolProvider;
    28 
    29 /**
    30  *
    31  * @author Jaroslav Tulach <jtulach@netbeans.org>
    32  */
    33 final class Compile implements DiagnosticListener<JavaFileObject> {
    34     private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<>();
    35     private final Map<String, byte[]> classes;
    36     private final String pkg;
    37     private final String cls;
    38 
    39     private Compile(String html, String code) throws IOException {
    40         this.pkg = findPkg(code);
    41         this.cls = findCls(code);
    42         classes = compile(html, code);
    43     }
    44 
    45     /** Performs compilation of given HTML page and associated Java code
    46      */
    47     public static Compile create(String html, String code) throws IOException {
    48         return new Compile(html, code);
    49     }
    50     
    51     /** Checks for given class among compiled resources */
    52     public byte[] get(String res) {
    53         return classes.get(res);
    54     }
    55     
    56     /** Obtains errors created during compilation.
    57      */
    58     public List<Diagnostic<? extends JavaFileObject>> getErrors() {
    59         List<Diagnostic<? extends JavaFileObject>> err = new ArrayList<>();
    60         for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
    61             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
    62                 err.add(diagnostic);
    63             }
    64         }
    65         return err;
    66     }
    67     
    68     private Map<String, byte[]> compile(final String html, final String code) throws IOException {
    69         StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
    70 
    71         final Map<String, ByteArrayOutputStream> class2BAOS = new HashMap<>();
    72 
    73         JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
    74             @Override
    75             public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
    76                 return code;
    77             }
    78         };
    79         final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
    80             @Override
    81             public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
    82                 return html;
    83             }
    84 
    85             @Override
    86             public InputStream openInputStream() throws IOException {
    87                 return new ByteArrayInputStream(html.getBytes());
    88             }
    89         };
    90         
    91         final URI scratch;
    92         try {
    93             scratch = new URI("mem://mem3");
    94         } catch (URISyntaxException ex) {
    95             throw new IOException(ex);
    96         }
    97         
    98         JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
    99             @Override
   100             public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
   101                 if (kind  == Kind.CLASS) {
   102                     final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
   103 
   104                     class2BAOS.put(className.replace('.', '/') + ".class", buffer);
   105                     return new SimpleJavaFileObject(sibling.toUri(), kind) {
   106                         @Override
   107                         public OutputStream openOutputStream() throws IOException {
   108                             return buffer;
   109                         }
   110                     };
   111                 }
   112                 
   113                 if (kind == Kind.SOURCE) {
   114                     return new SimpleJavaFileObject(scratch/*sibling.toUri()*/, kind) {
   115                         private final ByteArrayOutputStream data = new ByteArrayOutputStream();
   116                         @Override
   117                         public OutputStream openOutputStream() throws IOException {
   118                             return data;
   119                         }
   120 
   121                         @Override
   122                         public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   123                             data.close();
   124                             return new String(data.toByteArray());
   125                         }
   126                     };
   127                 }
   128                 
   129                 throw new IllegalStateException();
   130             }
   131 
   132             @Override
   133             public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
   134                 if (location == StandardLocation.SOURCE_PATH) {
   135                     if (packageName.equals(pkg)) {
   136                         return htmlFile;
   137                     }
   138                 }
   139                 
   140                 return null;
   141             }
   142             
   143         };
   144 
   145         ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call();
   146 
   147         Map<String, byte[]> result = new HashMap<>();
   148 
   149         for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
   150             result.put(e.getKey(), e.getValue().toByteArray());
   151         }
   152 
   153         return result;
   154     }
   155 
   156 
   157     @Override
   158     public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   159         errors.add(diagnostic);
   160     }
   161     private static String findPkg(String java) throws IOException {
   162         Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
   163         Matcher m = p.matcher(java);
   164         if (!m.find()) {
   165             throw new IOException("Can't find package declaration in the java file");
   166         }
   167         String pkg = m.group(1);
   168         return pkg;
   169     }
   170     private static String findCls(String java) throws IOException {
   171         Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
   172         Matcher m = p.matcher(java);
   173         if (!m.find()) {
   174             throw new IOException("Can't find package declaration in the java file");
   175         }
   176         String cls = m.group(1);
   177         return cls;
   178     }
   179 }