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