dew/src/main/java/org/apidesign/bck2brwsr/dew/Compile.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 23 Sep 2013 00:59:14 +0200
branchjavac
changeset 1295 5b3ae17babdf
parent 579 942deef87200
child 1327 217ca48c5b80
permissions -rw-r--r--
Can we run Javac in the bck2brwsr VM?
jaroslav@468
     1
/**
jaroslav@468
     2
 * Back 2 Browser Bytecode Translator
jaroslav@468
     3
 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
jaroslav@468
     4
 *
jaroslav@468
     5
 * This program is free software: you can redistribute it and/or modify
jaroslav@468
     6
 * it under the terms of the GNU General Public License as published by
jaroslav@468
     7
 * the Free Software Foundation, version 2 of the License.
jaroslav@468
     8
 *
jaroslav@468
     9
 * This program is distributed in the hope that it will be useful,
jaroslav@468
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
jaroslav@468
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
jaroslav@468
    12
 * GNU General Public License for more details.
jaroslav@468
    13
 *
jaroslav@468
    14
 * You should have received a copy of the GNU General Public License
jaroslav@468
    15
 * along with this program. Look for COPYING file in the top folder.
jaroslav@468
    16
 * If not, see http://opensource.org/licenses/GPL-2.0.
jaroslav@468
    17
 */
jaroslav@462
    18
package org.apidesign.bck2brwsr.dew;
jaroslav@462
    19
jaroslav@463
    20
import java.io.ByteArrayInputStream;
jaroslav@463
    21
import java.io.ByteArrayOutputStream;
jaroslav@462
    22
import java.io.IOException;
jaroslav@463
    23
import java.io.InputStream;
jaroslav@463
    24
import java.io.OutputStream;
jaroslav@463
    25
import java.net.URI;
jaroslav@463
    26
import java.net.URISyntaxException;
jaroslav@462
    27
import java.util.ArrayList;
jaroslav@463
    28
import java.util.Arrays;
jaroslav@463
    29
import java.util.HashMap;
jaroslav@462
    30
import java.util.List;
jaroslav@462
    31
import java.util.Map;
jaroslav@462
    32
import javax.tools.Diagnostic;
jaroslav@462
    33
import javax.tools.DiagnosticListener;
jaroslav@462
    34
import javax.tools.FileObject;
jaroslav@463
    35
import javax.tools.ForwardingJavaFileManager;
jaroslav@462
    36
import javax.tools.JavaFileManager;
jaroslav@462
    37
import javax.tools.JavaFileObject;
jaroslav@462
    38
import javax.tools.JavaFileObject.Kind;
jaroslav@463
    39
import javax.tools.SimpleJavaFileObject;
jaroslav@462
    40
import javax.tools.StandardJavaFileManager;
jaroslav@462
    41
import javax.tools.StandardLocation;
jaroslav@463
    42
import javax.tools.ToolProvider;
jaroslav@462
    43
jaroslav@462
    44
/**
jaroslav@462
    45
 *
jaroslav@462
    46
 * @author Jaroslav Tulach <jtulach@netbeans.org>
jaroslav@462
    47
 */
jaroslav@464
    48
final class Compile implements DiagnosticListener<JavaFileObject> {
jaroslav@464
    49
    private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<>();
jaroslav@464
    50
    private final Map<String, byte[]> classes;
jaroslav@462
    51
    private final String pkg;
jaroslav@464
    52
    private final String cls;
jaroslav@579
    53
    private final String html;
jaroslav@462
    54
jaroslav@464
    55
    private Compile(String html, String code) throws IOException {
jaroslav@1295
    56
        this.pkg = find("package", ';', code);
jaroslav@1295
    57
        this.cls = find("class", ' ', code);
jaroslav@579
    58
        this.html = html;
jaroslav@464
    59
        classes = compile(html, code);
jaroslav@464
    60
    }
jaroslav@464
    61
jaroslav@464
    62
    /** Performs compilation of given HTML page and associated Java code
jaroslav@464
    63
     */
jaroslav@464
    64
    public static Compile create(String html, String code) throws IOException {
jaroslav@464
    65
        return new Compile(html, code);
jaroslav@462
    66
    }
jaroslav@462
    67
    
jaroslav@464
    68
    /** Checks for given class among compiled resources */
jaroslav@464
    69
    public byte[] get(String res) {
jaroslav@464
    70
        return classes.get(res);
jaroslav@464
    71
    }
jaroslav@464
    72
    
jaroslav@464
    73
    /** Obtains errors created during compilation.
jaroslav@464
    74
     */
jaroslav@464
    75
    public List<Diagnostic<? extends JavaFileObject>> getErrors() {
jaroslav@464
    76
        List<Diagnostic<? extends JavaFileObject>> err = new ArrayList<>();
jaroslav@464
    77
        for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
jaroslav@464
    78
            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
jaroslav@464
    79
                err.add(diagnostic);
jaroslav@464
    80
            }
jaroslav@462
    81
        }
jaroslav@464
    82
        return err;
jaroslav@462
    83
    }
jaroslav@464
    84
    
jaroslav@464
    85
    private Map<String, byte[]> compile(final String html, final String code) throws IOException {
jaroslav@464
    86
        StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
jaroslav@463
    87
jaroslav@464
    88
        final Map<String, ByteArrayOutputStream> class2BAOS = new HashMap<>();
jaroslav@463
    89
jaroslav@463
    90
        JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
jaroslav@463
    91
            @Override
jaroslav@463
    92
            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
jaroslav@463
    93
                return code;
jaroslav@463
    94
            }
jaroslav@463
    95
        };
jaroslav@463
    96
        final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
jaroslav@463
    97
            @Override
jaroslav@463
    98
            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
jaroslav@463
    99
                return html;
jaroslav@463
   100
            }
jaroslav@463
   101
jaroslav@463
   102
            @Override
jaroslav@463
   103
            public InputStream openInputStream() throws IOException {
jaroslav@463
   104
                return new ByteArrayInputStream(html.getBytes());
jaroslav@463
   105
            }
jaroslav@463
   106
        };
jaroslav@463
   107
        
jaroslav@463
   108
        final URI scratch;
jaroslav@463
   109
        try {
jaroslav@463
   110
            scratch = new URI("mem://mem3");
jaroslav@463
   111
        } catch (URISyntaxException ex) {
jaroslav@463
   112
            throw new IOException(ex);
jaroslav@463
   113
        }
jaroslav@463
   114
        
jaroslav@463
   115
        JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
jaroslav@463
   116
            @Override
jaroslav@463
   117
            public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
jaroslav@463
   118
                if (kind  == Kind.CLASS) {
jaroslav@463
   119
                    final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
jaroslav@463
   120
jaroslav@463
   121
                    class2BAOS.put(className.replace('.', '/') + ".class", buffer);
jaroslav@463
   122
                    return new SimpleJavaFileObject(sibling.toUri(), kind) {
jaroslav@463
   123
                        @Override
jaroslav@463
   124
                        public OutputStream openOutputStream() throws IOException {
jaroslav@463
   125
                            return buffer;
jaroslav@463
   126
                        }
jaroslav@463
   127
                    };
jaroslav@463
   128
                }
jaroslav@463
   129
                
jaroslav@463
   130
                if (kind == Kind.SOURCE) {
jaroslav@463
   131
                    return new SimpleJavaFileObject(scratch/*sibling.toUri()*/, kind) {
jaroslav@463
   132
                        private final ByteArrayOutputStream data = new ByteArrayOutputStream();
jaroslav@463
   133
                        @Override
jaroslav@463
   134
                        public OutputStream openOutputStream() throws IOException {
jaroslav@463
   135
                            return data;
jaroslav@463
   136
                        }
jaroslav@463
   137
jaroslav@463
   138
                        @Override
jaroslav@463
   139
                        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
jaroslav@463
   140
                            data.close();
jaroslav@463
   141
                            return new String(data.toByteArray());
jaroslav@463
   142
                        }
jaroslav@463
   143
                    };
jaroslav@463
   144
                }
jaroslav@463
   145
                
jaroslav@463
   146
                throw new IllegalStateException();
jaroslav@463
   147
            }
jaroslav@463
   148
jaroslav@463
   149
            @Override
jaroslav@463
   150
            public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
jaroslav@463
   151
                if (location == StandardLocation.SOURCE_PATH) {
jaroslav@463
   152
                    if (packageName.equals(pkg)) {
jaroslav@463
   153
                        return htmlFile;
jaroslav@463
   154
                    }
jaroslav@463
   155
                }
jaroslav@463
   156
                
jaroslav@463
   157
                return null;
jaroslav@463
   158
            }
jaroslav@463
   159
            
jaroslav@463
   160
        };
jaroslav@463
   161
jaroslav@464
   162
        ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call();
jaroslav@463
   163
jaroslav@464
   164
        Map<String, byte[]> result = new HashMap<>();
jaroslav@463
   165
jaroslav@463
   166
        for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
jaroslav@463
   167
            result.put(e.getKey(), e.getValue().toByteArray());
jaroslav@463
   168
        }
jaroslav@463
   169
jaroslav@463
   170
        return result;
jaroslav@463
   171
    }
jaroslav@462
   172
jaroslav@462
   173
jaroslav@462
   174
    @Override
jaroslav@462
   175
    public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
jaroslav@462
   176
        errors.add(diagnostic);
jaroslav@462
   177
    }
jaroslav@1295
   178
    private static String find(String pref, char term, String java) throws IOException {
jaroslav@1295
   179
        int pkg = java.indexOf(pref);
jaroslav@1295
   180
        if (pkg != -1) {
jaroslav@1295
   181
            pkg += pref.length();
jaroslav@1295
   182
            while (Character.isWhitespace(java.charAt(pkg))) {
jaroslav@1295
   183
                pkg++;
jaroslav@1295
   184
            }
jaroslav@1295
   185
            int semicolon = java.indexOf(term, pkg);
jaroslav@1295
   186
            if (semicolon != -1) {
jaroslav@1295
   187
                String pkgName = java.substring(pkg, semicolon).trim();
jaroslav@1295
   188
                return pkgName;
jaroslav@1295
   189
            }
jaroslav@462
   190
        }
jaroslav@1295
   191
        throw new IOException("Can't find " + pref + " declaration in the java file");
jaroslav@462
   192
    }
jaroslav@579
   193
jaroslav@579
   194
    String getHtml() {
jaroslav@579
   195
        String fqn = "'" + pkg + '.' + cls + "'";
jaroslav@579
   196
        return html.replace("'${fqn}'", fqn);
jaroslav@579
   197
    }
jaroslav@462
   198
}