1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/Compile.java Wed Feb 20 18:14:59 2013 +0100
1.3 @@ -0,0 +1,203 @@
1.4 +/**
1.5 + * Back 2 Browser Bytecode Translator
1.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
1.7 + *
1.8 + * This program is free software: you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation, version 2 of the License.
1.11 + *
1.12 + * This program is distributed in the hope that it will be useful,
1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.15 + * GNU General Public License for more details.
1.16 + *
1.17 + * You should have received a copy of the GNU General Public License
1.18 + * along with this program. Look for COPYING file in the top folder.
1.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
1.20 + */
1.21 +package org.apidesign.bck2brwsr.htmlpage;
1.22 +
1.23 +import java.io.ByteArrayInputStream;
1.24 +import java.io.ByteArrayOutputStream;
1.25 +import java.io.IOException;
1.26 +import java.io.InputStream;
1.27 +import java.io.OutputStream;
1.28 +import java.net.URI;
1.29 +import java.net.URISyntaxException;
1.30 +import java.util.ArrayList;
1.31 +import java.util.Arrays;
1.32 +import java.util.HashMap;
1.33 +import java.util.List;
1.34 +import java.util.Map;
1.35 +import java.util.regex.Matcher;
1.36 +import java.util.regex.Pattern;
1.37 +import javax.tools.Diagnostic;
1.38 +import javax.tools.DiagnosticListener;
1.39 +import javax.tools.FileObject;
1.40 +import javax.tools.ForwardingJavaFileManager;
1.41 +import javax.tools.JavaFileManager;
1.42 +import javax.tools.JavaFileObject;
1.43 +import javax.tools.JavaFileObject.Kind;
1.44 +import javax.tools.SimpleJavaFileObject;
1.45 +import javax.tools.StandardJavaFileManager;
1.46 +import javax.tools.StandardLocation;
1.47 +import javax.tools.ToolProvider;
1.48 +
1.49 +/**
1.50 + *
1.51 + * @author Jaroslav Tulach <jtulach@netbeans.org>
1.52 + */
1.53 +final class Compile implements DiagnosticListener<JavaFileObject> {
1.54 + private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<>();
1.55 + private final Map<String, byte[]> classes;
1.56 + private final String pkg;
1.57 + private final String cls;
1.58 + private final String html;
1.59 +
1.60 + private Compile(String html, String code) throws IOException {
1.61 + this.pkg = findPkg(code);
1.62 + this.cls = findCls(code);
1.63 + this.html = html;
1.64 + classes = compile(html, code);
1.65 + }
1.66 +
1.67 + /** Performs compilation of given HTML page and associated Java code
1.68 + */
1.69 + public static Compile create(String html, String code) throws IOException {
1.70 + return new Compile(html, code);
1.71 + }
1.72 +
1.73 + /** Checks for given class among compiled resources */
1.74 + public byte[] get(String res) {
1.75 + return classes.get(res);
1.76 + }
1.77 +
1.78 + /** Obtains errors created during compilation.
1.79 + */
1.80 + public List<Diagnostic<? extends JavaFileObject>> getErrors() {
1.81 + List<Diagnostic<? extends JavaFileObject>> err = new ArrayList<>();
1.82 + for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
1.83 + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
1.84 + err.add(diagnostic);
1.85 + }
1.86 + }
1.87 + return err;
1.88 + }
1.89 +
1.90 + private Map<String, byte[]> compile(final String html, final String code) throws IOException {
1.91 + StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
1.92 +
1.93 + final Map<String, ByteArrayOutputStream> class2BAOS = new HashMap<>();
1.94 +
1.95 + JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
1.96 + @Override
1.97 + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
1.98 + return code;
1.99 + }
1.100 + };
1.101 + final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
1.102 + @Override
1.103 + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
1.104 + return html;
1.105 + }
1.106 +
1.107 + @Override
1.108 + public InputStream openInputStream() throws IOException {
1.109 + return new ByteArrayInputStream(html.getBytes());
1.110 + }
1.111 + };
1.112 +
1.113 + final URI scratch;
1.114 + try {
1.115 + scratch = new URI("mem://mem3");
1.116 + } catch (URISyntaxException ex) {
1.117 + throw new IOException(ex);
1.118 + }
1.119 +
1.120 + JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
1.121 + @Override
1.122 + public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
1.123 + if (kind == Kind.CLASS) {
1.124 + final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
1.125 +
1.126 + class2BAOS.put(className.replace('.', '/') + ".class", buffer);
1.127 + return new SimpleJavaFileObject(sibling.toUri(), kind) {
1.128 + @Override
1.129 + public OutputStream openOutputStream() throws IOException {
1.130 + return buffer;
1.131 + }
1.132 + };
1.133 + }
1.134 +
1.135 + if (kind == Kind.SOURCE) {
1.136 + return new SimpleJavaFileObject(scratch/*sibling.toUri()*/, kind) {
1.137 + private final ByteArrayOutputStream data = new ByteArrayOutputStream();
1.138 + @Override
1.139 + public OutputStream openOutputStream() throws IOException {
1.140 + return data;
1.141 + }
1.142 +
1.143 + @Override
1.144 + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
1.145 + data.close();
1.146 + return new String(data.toByteArray());
1.147 + }
1.148 + };
1.149 + }
1.150 +
1.151 + throw new IllegalStateException();
1.152 + }
1.153 +
1.154 + @Override
1.155 + public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
1.156 + if (location == StandardLocation.SOURCE_PATH) {
1.157 + if (packageName.equals(pkg)) {
1.158 + return htmlFile;
1.159 + }
1.160 + }
1.161 +
1.162 + return null;
1.163 + }
1.164 +
1.165 + };
1.166 +
1.167 + ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call();
1.168 +
1.169 + Map<String, byte[]> result = new HashMap<>();
1.170 +
1.171 + for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
1.172 + result.put(e.getKey(), e.getValue().toByteArray());
1.173 + }
1.174 +
1.175 + return result;
1.176 + }
1.177 +
1.178 +
1.179 + @Override
1.180 + public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
1.181 + errors.add(diagnostic);
1.182 + }
1.183 + private static String findPkg(String java) throws IOException {
1.184 + Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
1.185 + Matcher m = p.matcher(java);
1.186 + if (!m.find()) {
1.187 + throw new IOException("Can't find package declaration in the java file");
1.188 + }
1.189 + String pkg = m.group(1);
1.190 + return pkg;
1.191 + }
1.192 + private static String findCls(String java) throws IOException {
1.193 + Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
1.194 + Matcher m = p.matcher(java);
1.195 + if (!m.find()) {
1.196 + throw new IOException("Can't find package declaration in the java file");
1.197 + }
1.198 + String cls = m.group(1);
1.199 + return cls;
1.200 + }
1.201 +
1.202 + String getHtml() {
1.203 + String fqn = "'" + pkg + '.' + cls + "'";
1.204 + return html.replace("'${fqn}'", fqn);
1.205 + }
1.206 +}