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