2 * Back 2 Browser Bytecode Translator
3 * Copyright (C) 2012-2015 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
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.
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.
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.
18 package org.apidesign.bck2brwsr.htmlpage;
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;
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;
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 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
49 * @author Jaroslav Tulach <jtulach@netbeans.org>
51 @ExtraJavaScript(processByteCode = false, resource = "")
52 final class Compile implements DiagnosticListener<JavaFileObject> {
53 private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<>();
54 private final Map<String, byte[]> classes;
55 private final String pkg;
56 private final String cls;
57 private final String html;
59 private Compile(String html, String code) throws IOException {
60 this.pkg = findPkg(code);
61 this.cls = findCls(code);
63 classes = compile(html, code);
66 /** Performs compilation of given HTML page and associated Java code
68 public static Compile create(String html, String code) throws IOException {
69 return new Compile(html, code);
72 /** Checks for given class among compiled resources */
73 public byte[] get(String res) {
74 return classes.get(res);
77 /** Obtains errors created during compilation.
79 public List<Diagnostic<? extends JavaFileObject>> getErrors() {
80 List<Diagnostic<? extends JavaFileObject>> err = new ArrayList<>();
81 for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
82 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
89 private Map<String, byte[]> compile(final String html, final String code) throws IOException {
90 StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
92 final Map<String, ByteArrayOutputStream> class2BAOS = new HashMap<>();
94 JavaFileObject file = new Mem(URI.create("mem://mem"), Kind.SOURCE, code);
95 final JavaFileObject htmlFile = new Mem2(URI.create("mem://mem2"), Kind.OTHER, html);
99 scratch = new URI("mem://mem3");
100 } catch (URISyntaxException ex) {
101 throw new IOException(ex);
104 JavaFileManager jfm = new ForwardingJavaFileManagerImpl(sjfm, class2BAOS, scratch, htmlFile);
106 ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call();
108 Map<String, byte[]> result = new HashMap<>();
110 for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
111 result.put(e.getKey(), e.getValue().toByteArray());
119 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
120 errors.add(diagnostic);
122 private static String findPkg(String java) throws IOException {
123 Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
124 Matcher m = p.matcher(java);
126 throw new IOException("Can't find package declaration in the java file");
128 String pkg = m.group(1);
131 private static String findCls(String java) throws IOException {
132 Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
133 Matcher m = p.matcher(java);
135 throw new IOException("Can't find package declaration in the java file");
137 String cls = m.group(1);
142 String fqn = "'" + pkg + '.' + cls + "'";
143 return html.replace("'${fqn}'", fqn);
146 @ExtraJavaScript(processByteCode = false, resource = "")
147 private class ForwardingJavaFileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {
149 private final Map<String, ByteArrayOutputStream> class2BAOS;
150 private final URI scratch;
151 private final JavaFileObject htmlFile;
153 public ForwardingJavaFileManagerImpl(JavaFileManager fileManager, Map<String, ByteArrayOutputStream> class2BAOS, URI scratch, JavaFileObject htmlFile) {
155 this.class2BAOS = class2BAOS;
156 this.scratch = scratch;
157 this.htmlFile = htmlFile;
161 public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
162 if (kind == Kind.CLASS) {
163 final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
165 class2BAOS.put(className.replace('.', '/') + ".class", buffer);
166 return new Sibling(sibling.toUri(), kind, buffer);
169 if (kind == Kind.SOURCE) {
170 return new Source(scratch/*sibling.toUri()*/, kind);
173 throw new IllegalStateException();
177 public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
178 if (location == StandardLocation.SOURCE_PATH) {
179 if (packageName.equals(pkg)) {
187 @ExtraJavaScript(processByteCode = false, resource = "")
188 private class Sibling extends SimpleJavaFileObject {
189 private final ByteArrayOutputStream buffer;
191 public Sibling(URI uri, Kind kind, ByteArrayOutputStream buffer) {
193 this.buffer = buffer;
197 public OutputStream openOutputStream() throws IOException {
202 @ExtraJavaScript(processByteCode = false, resource = "")
203 private class Source extends SimpleJavaFileObject {
204 public Source(URI uri, Kind kind) {
207 private final ByteArrayOutputStream data = new ByteArrayOutputStream();
210 public OutputStream openOutputStream() throws IOException {
215 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
217 return new String(data.toByteArray());
222 @ExtraJavaScript(processByteCode = false, resource = "")
223 private static class Mem extends SimpleJavaFileObject {
225 private final String code;
227 public Mem(URI uri, Kind kind, String code) {
233 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
238 @ExtraJavaScript(processByteCode = false, resource = "")
239 private static class Mem2 extends SimpleJavaFileObject {
241 private final String html;
243 public Mem2(URI uri, Kind kind, String html) {
249 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
254 public InputStream openInputStream() throws IOException {
255 return new ByteArrayInputStream(html.getBytes());