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