jaroslav@468: /** jaroslav@468: * Back 2 Browser Bytecode Translator jaroslav@468: * Copyright (C) 2012 Jaroslav Tulach jaroslav@468: * jaroslav@468: * This program is free software: you can redistribute it and/or modify jaroslav@468: * it under the terms of the GNU General Public License as published by jaroslav@468: * the Free Software Foundation, version 2 of the License. jaroslav@468: * jaroslav@468: * This program is distributed in the hope that it will be useful, jaroslav@468: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@468: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@468: * GNU General Public License for more details. jaroslav@468: * jaroslav@468: * You should have received a copy of the GNU General Public License jaroslav@468: * along with this program. Look for COPYING file in the top folder. jaroslav@468: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@468: */ jaroslav@462: package org.apidesign.bck2brwsr.dew; jaroslav@462: jaroslav@463: import java.io.ByteArrayInputStream; jaroslav@463: import java.io.ByteArrayOutputStream; jaroslav@462: import java.io.IOException; jaroslav@463: import java.io.InputStream; jaroslav@463: import java.io.OutputStream; jaroslav@463: import java.net.URI; jaroslav@463: import java.net.URISyntaxException; jaroslav@462: import java.util.ArrayList; jaroslav@463: import java.util.Arrays; jaroslav@463: import java.util.HashMap; jaroslav@462: import java.util.List; jaroslav@462: import java.util.Map; jaroslav@462: import java.util.regex.Matcher; jaroslav@462: import java.util.regex.Pattern; jaroslav@462: import javax.tools.Diagnostic; jaroslav@462: import javax.tools.DiagnosticListener; jaroslav@462: import javax.tools.FileObject; jaroslav@463: import javax.tools.ForwardingJavaFileManager; jaroslav@462: import javax.tools.JavaFileManager; jaroslav@462: import javax.tools.JavaFileObject; jaroslav@462: import javax.tools.JavaFileObject.Kind; jaroslav@463: import javax.tools.SimpleJavaFileObject; jaroslav@462: import javax.tools.StandardJavaFileManager; jaroslav@462: import javax.tools.StandardLocation; jaroslav@463: import javax.tools.ToolProvider; jaroslav@462: jaroslav@462: /** jaroslav@462: * jaroslav@462: * @author Jaroslav Tulach jaroslav@462: */ jaroslav@464: final class Compile implements DiagnosticListener { jaroslav@464: private final List> errors = new ArrayList<>(); jaroslav@464: private final Map classes; jaroslav@462: private final String pkg; jaroslav@464: private final String cls; jaroslav@579: private final String html; jaroslav@462: jaroslav@464: private Compile(String html, String code) throws IOException { jaroslav@464: this.pkg = findPkg(code); jaroslav@464: this.cls = findCls(code); jaroslav@579: this.html = html; jaroslav@464: classes = compile(html, code); jaroslav@464: } jaroslav@464: jaroslav@464: /** Performs compilation of given HTML page and associated Java code jaroslav@464: */ jaroslav@464: public static Compile create(String html, String code) throws IOException { jaroslav@464: return new Compile(html, code); jaroslav@462: } jaroslav@462: jaroslav@464: /** Checks for given class among compiled resources */ jaroslav@464: public byte[] get(String res) { jaroslav@464: return classes.get(res); jaroslav@464: } jaroslav@464: jaroslav@464: /** Obtains errors created during compilation. jaroslav@464: */ jaroslav@464: public List> getErrors() { jaroslav@464: List> err = new ArrayList<>(); jaroslav@464: for (Diagnostic diagnostic : errors) { jaroslav@464: if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { jaroslav@464: err.add(diagnostic); jaroslav@464: } jaroslav@462: } jaroslav@464: return err; jaroslav@462: } jaroslav@464: jaroslav@464: private Map compile(final String html, final String code) throws IOException { tzezula@1324: final ClassLoaderFileManager clfm = new ClassLoaderFileManager(); tzezula@1324: final JavaFileObject file = clfm.createMemoryFileObject( tzezula@1324: ClassLoaderFileManager.convertFQNToResource(pkg.isEmpty() ? cls : pkg + "." + cls) + Kind.SOURCE.extension, tzezula@1324: Kind.SOURCE, tzezula@1324: code.getBytes()); tzezula@1324: final JavaFileObject htmlFile = clfm.createMemoryFileObject( tzezula@1324: ClassLoaderFileManager.convertFQNToResource(pkg), tzezula@1324: Kind.OTHER, tzezula@1324: html.getBytes()); jaroslav@463: tzezula@1324: JavaFileManager jfm = new ForwardingJavaFileManager(clfm) { jaroslav@463: @Override jaroslav@463: public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { jaroslav@463: if (location == StandardLocation.SOURCE_PATH) { jaroslav@463: if (packageName.equals(pkg)) { jaroslav@463: return htmlFile; jaroslav@463: } tzezula@1324: } jaroslav@463: return null; jaroslav@463: } jaroslav@463: }; jaroslav@463: tzezula@1324: final Boolean res = ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call(); tzezula@1324: jaroslav@463: jaroslav@464: Map result = new HashMap<>(); tzezula@1324: for (MemoryFileObject generated : clfm.getGeneratedFiles(Kind.CLASS)) { tzezula@1324: result.put(generated.infer(), generated.getContent()); jaroslav@463: } jaroslav@463: return result; jaroslav@463: } jaroslav@462: jaroslav@462: jaroslav@462: @Override jaroslav@462: public void report(Diagnostic diagnostic) { jaroslav@462: errors.add(diagnostic); jaroslav@462: } jaroslav@462: private static String findPkg(String java) throws IOException { jaroslav@462: Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE); jaroslav@462: Matcher m = p.matcher(java); jaroslav@462: if (!m.find()) { jaroslav@462: throw new IOException("Can't find package declaration in the java file"); jaroslav@462: } jaroslav@462: String pkg = m.group(1); jaroslav@462: return pkg; jaroslav@462: } jaroslav@462: private static String findCls(String java) throws IOException { jaroslav@462: Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE); jaroslav@462: Matcher m = p.matcher(java); jaroslav@462: if (!m.find()) { jaroslav@462: throw new IOException("Can't find package declaration in the java file"); jaroslav@462: } jaroslav@462: String cls = m.group(1); jaroslav@462: return cls; jaroslav@462: } jaroslav@579: jaroslav@579: String getHtml() { jaroslav@579: String fqn = "'" + pkg + '.' + cls + "'"; jaroslav@579: return html.replace("'${fqn}'", fqn); jaroslav@579: } jaroslav@462: }