Speeding up start of applications by listing the classes that need post processing and analysing/processing only those
1.1 --- a/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java Sun Jan 12 14:57:18 2014 +0100
1.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java Sun Jan 12 19:23:58 2014 +0100
1.3 @@ -43,6 +43,9 @@
1.4 package org.netbeans.html.boot.impl;
1.5
1.6 import java.io.IOException;
1.7 +import java.io.OutputStream;
1.8 +import java.io.OutputStreamWriter;
1.9 +import java.io.PrintWriter;
1.10 import java.io.Writer;
1.11 import java.util.Collections;
1.12 import java.util.HashMap;
1.13 @@ -85,6 +88,8 @@
1.14 public final class JavaScriptProcesor extends AbstractProcessor {
1.15 private final Map<String,Map<String,ExecutableElement>> javacalls =
1.16 new HashMap<String,Map<String,ExecutableElement>>();
1.17 + private final Map<String,Set<TypeElement>> bodies =
1.18 + new HashMap<String, Set<TypeElement>>();
1.19
1.20 @Override
1.21 public Set<String> getSupportedAnnotationTypes() {
1.22 @@ -107,6 +112,17 @@
1.23 JavaScriptBody jsb = e.getAnnotation(JavaScriptBody.class);
1.24 if (jsb == null) {
1.25 continue;
1.26 + } else {
1.27 + Set<TypeElement> classes = this.bodies.get(findPkg(e));
1.28 + if (classes == null) {
1.29 + classes = new HashSet<TypeElement>();
1.30 + bodies.put(findPkg(e), classes);
1.31 + }
1.32 + Element t = e.getEnclosingElement();
1.33 + while (!t.getKind().isClass() && !t.getKind().isInterface()) {
1.34 + t = t.getEnclosingElement();
1.35 + }
1.36 + classes.add((TypeElement)t);
1.37 }
1.38 String[] arr = jsb.args();
1.39 if (params.size() != arr.length) {
1.40 @@ -151,6 +167,7 @@
1.41
1.42 if (roundEnv.processingOver()) {
1.43 generateCallbackClass(javacalls);
1.44 + generateJavaScriptBodyList(bodies);
1.45 javacalls.clear();
1.46 }
1.47 return true;
1.48 @@ -262,6 +279,33 @@
1.49 }
1.50 }
1.51
1.52 + private void generateJavaScriptBodyList(Map<String,Set<TypeElement>> bodies) {
1.53 + for (Map.Entry<String, Set<TypeElement>> entry : bodies.entrySet()) {
1.54 + String pkg = entry.getKey();
1.55 + Set<TypeElement> classes = entry.getValue();
1.56 +
1.57 + try {
1.58 + FileObject out = processingEnv.getFiler().createResource(
1.59 + StandardLocation.CLASS_OUTPUT, pkg, "net.java.html.js.classes",
1.60 + classes.iterator().next()
1.61 + );
1.62 + OutputStream os = out.openOutputStream();
1.63 + try {
1.64 + PrintWriter w = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
1.65 + for (TypeElement type : classes) {
1.66 + w.println(processingEnv.getElementUtils().getBinaryName(type));
1.67 + }
1.68 + w.flush();
1.69 + w.close();
1.70 + } finally {
1.71 + os.close();
1.72 + }
1.73 + } catch (IOException x) {
1.74 + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Failed to write to " + entry.getKey() + ": " + x.toString());
1.75 + }
1.76 + }
1.77 + }
1.78 +
1.79 private void generateCallbackClass(Map<String,Map<String, ExecutableElement>> process) {
1.80 for (Map.Entry<String, Map<String, ExecutableElement>> pkgEn : process.entrySet()) {
1.81 String pkgName = pkgEn.getKey();
2.1 --- a/boot/src/main/java/org/netbeans/html/boot/impl/JsAgent.java Sun Jan 12 14:57:18 2014 +0100
2.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsAgent.java Sun Jan 12 19:23:58 2014 +0100
2.3 @@ -59,7 +59,11 @@
2.4 @Override
2.5 public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
2.6 try {
2.7 - return FnUtils.transform(classfileBuffer, loader);
2.8 + if (JsPkgCache.process(loader, className)) {
2.9 + return FnUtils.transform(classfileBuffer, loader);
2.10 + } else {
2.11 + return classfileBuffer;
2.12 + }
2.13 } catch (Exception ex) {
2.14 return classfileBuffer;
2.15 }
3.1 --- a/boot/src/main/java/org/netbeans/html/boot/impl/JsClassLoader.java Sun Jan 12 14:57:18 2014 +0100
3.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsClassLoader.java Sun Jan 12 19:23:58 2014 +0100
3.3 @@ -117,10 +117,10 @@
3.4 }
3.5 is.close();
3.6 is = null;
3.7 - arr = FnUtils.transform(arr, JsClassLoader.this);
3.8 - if (arr != null) {
3.9 - return defineClass(name, arr, 0, arr.length);
3.10 + if (JsPkgCache.process(this, name)) {
3.11 + arr = FnUtils.transform(arr, JsClassLoader.this);
3.12 }
3.13 + return defineClass(name, arr, 0, arr.length);
3.14 } catch (IOException ex) {
3.15 throw new ClassNotFoundException("Can't load " + name, ex);
3.16 } finally {
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsPkgCache.java Sun Jan 12 19:23:58 2014 +0100
4.3 @@ -0,0 +1,132 @@
4.4 +/**
4.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4.6 + *
4.7 + * Copyright 2013-2013 Oracle and/or its affiliates. All rights reserved.
4.8 + *
4.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
4.10 + * Other names may be trademarks of their respective owners.
4.11 + *
4.12 + * The contents of this file are subject to the terms of either the GNU
4.13 + * General Public License Version 2 only ("GPL") or the Common
4.14 + * Development and Distribution License("CDDL") (collectively, the
4.15 + * "License"). You may not use this file except in compliance with the
4.16 + * License. You can obtain a copy of the License at
4.17 + * http://www.netbeans.org/cddl-gplv2.html
4.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
4.19 + * specific language governing permissions and limitations under the
4.20 + * License. When distributing the software, include this License Header
4.21 + * Notice in each file and include the License file at
4.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
4.23 + * particular file as subject to the "Classpath" exception as provided
4.24 + * by Oracle in the GPL Version 2 section of the License file that
4.25 + * accompanied this code. If applicable, add the following below the
4.26 + * License Header, with the fields enclosed by brackets [] replaced by
4.27 + * your own identifying information:
4.28 + * "Portions Copyrighted [year] [name of copyright owner]"
4.29 + *
4.30 + * Contributor(s):
4.31 + *
4.32 + * The Original Software is NetBeans. The Initial Developer of the Original
4.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
4.34 + *
4.35 + * If you wish your version of this file to be governed by only the CDDL
4.36 + * or only the GPL Version 2, indicate your decision by adding
4.37 + * "[Contributor] elects to include this software in this distribution
4.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
4.39 + * single choice of license, a recipient has the option to distribute
4.40 + * your version of this file under either the CDDL, the GPL Version 2 or
4.41 + * to extend the choice of license to its licensees as provided above.
4.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
4.43 + * Version 2 license, then the option applies only if the new code is
4.44 + * made subject to such option by the copyright holder.
4.45 + */
4.46 +package org.netbeans.html.boot.impl;
4.47 +
4.48 +import java.io.BufferedReader;
4.49 +import java.io.IOException;
4.50 +import java.io.InputStream;
4.51 +import java.io.InputStreamReader;
4.52 +import java.net.URL;
4.53 +import java.util.Collections;
4.54 +import java.util.Enumeration;
4.55 +import java.util.Map;
4.56 +import java.util.Set;
4.57 +import java.util.TreeSet;
4.58 +import java.util.WeakHashMap;
4.59 +import java.util.logging.Level;
4.60 +import java.util.logging.Logger;
4.61 +
4.62 +/**
4.63 + *
4.64 + * @author Jaroslav Tulach <jtulach@netbeans.org>
4.65 + */
4.66 +final class JsPkgCache {
4.67 + private final Map<String,Set<String>> props = new WeakHashMap<String, Set<String>>();
4.68 + private static final Map<ClassLoader, JsPkgCache> CACHE = new WeakHashMap<ClassLoader, JsPkgCache>();
4.69 + private static final Set<String> NONE = Collections.emptySet();
4.70 +
4.71 + public static boolean process(ClassLoader l, String className) {
4.72 + if (className.equals("org.netbeans.html.boot.impl.Test")) {
4.73 + return true;
4.74 + }
4.75 + Set<String> p;
4.76 + JsPkgCache c;
4.77 + String pkgName;
4.78 + synchronized (CACHE) {
4.79 + c = CACHE.get(l);
4.80 + if (c == null) {
4.81 + c = new JsPkgCache();
4.82 + CACHE.put(l, c);
4.83 + }
4.84 + int lastDot = className.lastIndexOf('.');
4.85 + pkgName = className.substring(0, lastDot + 1).replace('.', '/');
4.86 + p = c.props.get(pkgName);
4.87 + if (p == NONE) {
4.88 + return false;
4.89 + } else if (p != null) {
4.90 + return p.contains(className);
4.91 + }
4.92 + }
4.93 + final String res = pkgName + "net.java.html.js.classes";
4.94 +
4.95 + Enumeration<URL> en;
4.96 + try {
4.97 + en = l.getResources(res);
4.98 + } catch (IOException ex) {
4.99 + en = null;
4.100 + }
4.101 + if (en == null || !en.hasMoreElements()) synchronized (CACHE) {
4.102 + c.props.put(pkgName, NONE);
4.103 + return false;
4.104 + }
4.105 +
4.106 + try {
4.107 + Set<String> arr = new TreeSet<String>();
4.108 + while (en.hasMoreElements()) {
4.109 + URL u = en.nextElement();
4.110 + BufferedReader r = new BufferedReader(
4.111 + new InputStreamReader(u.openStream(), "UTF-8")
4.112 + );
4.113 + for (;;) {
4.114 + String line = r.readLine();
4.115 + if (line == null) {
4.116 + break;
4.117 + }
4.118 + arr.add(line);
4.119 + }
4.120 + r.close();
4.121 + }
4.122 + p = arr;
4.123 + } catch (IOException ex) {
4.124 + LOG.log(Level.WARNING, "Can't read " + res, ex);
4.125 + p = NONE;
4.126 + }
4.127 +
4.128 + synchronized (CACHE) {
4.129 + c.props.put(pkgName, p);
4.130 + return p.contains(className);
4.131 + }
4.132 +
4.133 + }
4.134 + private static final Logger LOG = Logger.getLogger(JsPkgCache.class.getName());
4.135 +}
5.1 --- a/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java Sun Jan 12 14:57:18 2014 +0100
5.2 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java Sun Jan 12 19:23:58 2014 +0100
5.3 @@ -55,6 +55,8 @@
5.4 import java.util.List;
5.5 import java.util.Locale;
5.6 import java.util.Map;
5.7 +import java.util.logging.Level;
5.8 +import java.util.logging.Logger;
5.9 import java.util.regex.Matcher;
5.10 import java.util.regex.Pattern;
5.11 import javax.tools.Diagnostic;
5.12 @@ -153,6 +155,16 @@
5.13
5.14 JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
5.15 @Override
5.16 + public FileObject getFileForOutput(JavaFileManager.Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
5.17 + try {
5.18 + return new VirtFO(new URI("mem://resource/" + relativeName), Kind.OTHER, relativeName);
5.19 + } catch (URISyntaxException ex) {
5.20 + throw new IllegalStateException(ex);
5.21 + }
5.22 + }
5.23 +
5.24 +
5.25 + @Override
5.26 public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
5.27 if (kind == Kind.CLASS) {
5.28 final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
6.1 --- a/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java Sun Jan 12 14:57:18 2014 +0100
6.2 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java Sun Jan 12 19:23:58 2014 +0100
6.3 @@ -49,6 +49,7 @@
6.4 import java.net.URLClassLoader;
6.5 import java.util.ArrayList;
6.6 import java.util.Arrays;
6.7 +import java.util.Collections;
6.8 import java.util.Enumeration;
6.9 import java.util.List;
6.10 import javax.script.Invocable;
6.11 @@ -123,7 +124,12 @@
6.12
6.13 @Override
6.14 protected Enumeration<URL> findResources(String name) {
6.15 - throw new UnsupportedOperationException();
6.16 + URL u = findResource(name);
6.17 + List<URL> arr = new ArrayList<URL>();
6.18 + if (u != null) {
6.19 + arr.add(u);
6.20 + }
6.21 + return Collections.enumeration(arr);
6.22 }
6.23
6.24 @Override