http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java ---------------------------------------------------------------------- diff --git a/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java b/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java new file mode 100644 index 0000000..c6deffb --- /dev/null +++ b/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java @@ -0,0 +1,388 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.html.boot.spi; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; +import net.java.html.js.JavaScriptBody; +import org.netbeans.html.boot.impl.FnContext; + +/** Represents single JavaScript function that can be invoked. + * Created via {@link Presenter#defineFn(java.lang.String, java.lang.String...)}. + * + * @author Jaroslav Tulach + */ +public abstract class Fn { + private final Presenter presenter; + + /** + * @deprecated Ineffective as of 0.6. + * Provide a presenter via {@link #Fn(org.netbeans.html.boot.spi.Fn.Presenter)} + * constructor + */ + @Deprecated + protected Fn() { + this(null); + } + + /** Creates new function object and associates it with given presenter. + * + * @param presenter the browser presenter associated with this function + * @since 0.6 + */ + protected Fn(Presenter presenter) { + this.presenter = presenter; + } + + /** True, if currently active presenter is the same as presenter this + * function has been created for via {@link #Fn(org.netbeans.html.boot.spi.Fn.Presenter)}. + * + * @return true, if proper presenter is used + */ + public final boolean isValid() { + return presenter != null && FnContext.currentPresenter(false) == presenter; + } + + /** Helper method to check if the provided instance is valid function. + * Checks if the parameter is non-null and if so, does {@link #isValid()} + * check. + * + * @param fnOrNull function or <code>null</code> + * @return true if the parameter is non-null and valid + * @since 0.7 + */ + public static boolean isValid(Fn fnOrNull) { + return fnOrNull != null && fnOrNull.isValid(); + } + + /** Helper method to find current presenter and ask it to define new + * function by calling {@link Presenter#defineFn(java.lang.String, java.lang.String...)}. + * + * @param caller the class who wishes to define the function + * @param code the body of the function (can reference <code>this</code> and <code>names</code> variables) + * @param names names of individual parameters + * @return the function object that can be {@link Fn#invoke(java.lang.Object, java.lang.Object...) invoked} + * - can return <code>null</code> if there is {@link #activePresenter() no presenter} + * @since 0.7 + */ + public static Fn define(Class<?> caller, String code, String... names) { + return define(caller, false, code, names); + } + + /** Helper method to find current presenter and ask it to define new + * function. + * + * @param caller the class who wishes to define the function + * @param keepParametersAlive whether Java parameters should survive in JavaScript + * after the method invocation is over + * @param code the body of the function (can reference <code>this</code> and <code>names</code> variables) + * @param names names of individual parameters + * @return the function object that can be {@link Fn#invoke(java.lang.Object, java.lang.Object...) invoked} + * - can return <code>null</code> if there is {@link #activePresenter() no presenter} + * @since 1.1 + */ + public static Fn define(Class<?> caller, boolean keepParametersAlive, String code, String... names) { + final Presenter p = FnContext.currentPresenter(false); + if (p == null) { + return null; + } + if (p instanceof KeepAlive) { + boolean[] arr; + if (!keepParametersAlive && names.length > 0) { + arr = new boolean[names.length]; + for (int i = 0; i < arr.length; i++) { + arr[i] = false; + } + } else { + arr = null; + } + return ((KeepAlive)p).defineFn(code, names, arr); + } + return p.defineFn(code, names); + } + + private static final Map<String,Set<Presenter>> LOADED = new HashMap<String, Set<Presenter>>(); + + /** Wraps function to ensure that the script represented by <code>resource</code> + * gets loaded into the browser environment before the function <code>fn</code> + * is executed. + * + * @param fn original function to call (if <code>null</code> returns <code>null</code>) + * @param caller the class who wishes to define/call the function + * @param resource resources (accessible via {@link ClassLoader#getResource(java.lang.String)}) + * with a <em>JavaScript</em> that is supposed to loaded into the browser + * environment + * @return function that ensures the script is loaded and then delegates + * to <code>fn</code>. Returns <code>null</code> if the input <code>fn</code> is null + * @since 0.7 + */ + public static Fn preload(final Fn fn, final Class<?> caller, final String resource) { + if (fn == null) { + return null; + } + return new Fn(fn.presenter()) { + @Override + public Object invoke(Object thiz, Object... args) throws Exception { + loadResource(); + return fn.invoke(thiz, args); + } + + @Override + public void invokeLater(Object thiz, Object... args) throws Exception { + loadResource(); + fn.invokeLater(thiz, args); + } + + private void loadResource() throws Exception { + Presenter p = presenter(); + if (p == null) { + p = FnContext.currentPresenter(false); + } + if (p != null) { + Set<Presenter> there = LOADED.get(resource); + if (there == null) { + there = new HashSet<Presenter>(); + LOADED.put(resource, there); + } + if (there.add(p)) { + final ClassLoader l = caller.getClassLoader(); + InputStream is = l.getResourceAsStream(resource); + if (is == null && resource.startsWith("/")) { + is = l.getResourceAsStream(resource.substring(1)); + } + if (is == null) { + throw new IOException("Cannot find " + resource + " in " + l); + } + try { + InputStreamReader r = new InputStreamReader(is, "UTF-8"); + p.loadScript(r); + } finally { + is.close(); + } + } + } + } + }; + } + + + /** The currently active presenter. + * + * @return the currently active presenter or <code>null</code> + * @since 0.7 + */ + public static Presenter activePresenter() { + return FnContext.currentPresenter(false); + } + + /** Activates given presenter. Used to associate the native + * JavaScript code specified by + * {@link JavaScriptBody} annotation with certain presenter: + * <pre> + * try ({@link Closeable} c = Fn.activate(presenter)) { + * doCallsInPresenterContext(); + * } + * </pre> + * + * @param p the presenter that should be active until closable is closed + * @return the closable to close + * @since 0.7 + */ + public static Closeable activate(Presenter p) { + return FnContext.activate(p); + } + + /** Invokes the defined function with specified <code>this</code> and + * appropriate arguments. + * + * @param thiz the meaning of <code>this</code> inside of the JavaScript + * function - can be <code>null</code> + * @param args arguments for the function + * @return return value from the function + * @throws Exception if something goes wrong, as exception may be thrown + */ + public abstract Object invoke(Object thiz, Object... args) throws Exception; + + /** Invokes the defined function with specified <code>this</code> and + * appropriate arguments asynchronously. The invocation may be + * happen <em>"later"</em>. + * + * @param thiz the meaning of <code>this</code> inside of the JavaScript + * function - can be <code>null</code> + * @param args arguments for the function + * @throws Exception if something goes wrong, as exception may be thrown + * @since 0.7.6 + */ + public void invokeLater(Object thiz, Object... args) throws Exception { + invoke(thiz, args); + } + + /** Provides the function implementation access to the presenter provided + * in {@link #Fn(org.netbeans.html.boot.spi.Fn.Presenter) the constructor}. + * + * @return presenter passed in the constructor (may be, but should not be <code>null</code>) + * @since 0.7 + */ + protected final Presenter presenter() { + return presenter; + } + + /** The representation of a <em>presenter</em> - usually a browser window. + * Should be provided by a library included in the application and registered + * in <code>META-INF/services</code>, for example with + * <code>@ServiceProvider(service = Fn.Presenter.class)</code> annotation. + * <p> + * Since 0.7 a presenter may implement {@link Executor} interface, in case + * it supports single threaded execution environment. The executor's + * {@link Executor#execute(java.lang.Runnable)} method is then supposed + * to invoke the runnable immediately (in case we are on the right thread + * already) or return and asynchronously invoke the runnable later on the + * right thread (if we are on wrong thread). + */ + public interface Presenter { + /** Creates new function with given parameter names and provided body. + * + * @param code the body of the function. Can refer to variables named + * as <code>names</code> + * @param names names of parameters of the function - these will be + * available when the <code>code</code> body executes + * + * @return function that can be later invoked + */ + public Fn defineFn(String code, String... names); + + /** Opens the browser, loads provided page and when the + * page is ready, it calls back to the provider runnable. + * + * @param page the URL for the page to display + * @param onPageLoad callback when the page is ready + */ + public void displayPage(URL page, Runnable onPageLoad); + + /** Loads a script into the browser JavaScript interpreter and + * executes it. + * @param code the script to execute + * @throws Exception if something goes wrong, throw an exception + */ + public void loadScript(Reader code) throws Exception; + } + + /** Additional interface to be implemented by {@link Presenter}s that + * wish to control what objects are passed into the JavaScript virtual + * machine. + * <p> + * If a JavaScript engine makes callback to Java method that returns + * a value, the {@link #toJavaScript(java.lang.Object)} method is + * consulted to convert the Java value to something reasonable inside + * JavaScript VM. + * <p> + * <em>Note:</em> The implementation based on <em>JavaFX</em> <code>WebView</code> + * uses this interface to convert Java arrays to JavaScript ones. + * + * @see Presenter + * @since 0.7 + */ + public interface ToJavaScript { + /** Convert a Java return value into some object suitable for + * JavaScript virtual machine. + * + * @param toReturn the Java object to be returned + * @return the replacement value to return instead + */ + public Object toJavaScript(Object toReturn); + } + + /** Additional interface to be implemented by {@link Presenter}s that + * need to convert JavaScript object (usually array) to Java object + * when calling back from JavaScript to Java. + * <p> + * <em>Note:</em> The implementation based on <em>JavaFX</em> + * <code>WebView</code> uses this interface to convert JavaScript arrays to + * Java ones. + * + * @since 0.7 + */ + public interface FromJavaScript { + /** Convert a JavaScript object into suitable Java representation + * before a Java method is called with this object as an argument. + * + * @param js the JavaScript object + * @return replacement object for + */ + public Object toJava(Object js); + } + + /** Additional interface to {@link Presenter} to control more precisely + * garbage collection behavior of individual parameters. See + * {@link JavaScriptBody#keepAlive()} attribute for description of the + * actual behavior of the interface. + * + * @since 1.1 + */ + public interface KeepAlive { + /** Creates new function with given parameter names and provided body. + * + * @param code the body of the function. Can refer to variables named + * as <code>names</code> + * @param names names of parameters of the function - these will be + * available when the <code>code</code> body executes + * @param keepAlive array of booleans describing for each parameter + * whether it should be kept alive or not. Length of the array + * must be the same as length of <code>names</code> array. The + * array may be <code>null</code> to signal that all parameters + * should be <em>kept alive</em>. + * + * @return function that can be later invoked + */ + public Fn defineFn(String code, String[] names, boolean[] keepAlive); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/spi/package.html ---------------------------------------------------------------------- diff --git a/boot/src/main/java/org/netbeans/html/boot/spi/package.html b/boot/src/main/java/org/netbeans/html/boot/spi/package.html new file mode 100644 index 0000000..d4ef66e --- /dev/null +++ b/boot/src/main/java/org/netbeans/html/boot/spi/package.html @@ -0,0 +1,54 @@ +<!-- + + DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + + Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + + Oracle and Java are registered trademarks of Oracle and/or its affiliates. + Other names may be trademarks of their respective owners. + + The contents of this file are subject to the terms of either the GNU + General Public License Version 2 only ("GPL") or the Common + Development and Distribution License("CDDL") (collectively, the + "License"). You may not use this file except in compliance with the + License. You can obtain a copy of the License at + http://www.netbeans.org/cddl-gplv2.html + or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + specific language governing permissions and limitations under the + License. When distributing the software, include this License Header + Notice in each file and include the License file at + nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + particular file as subject to the "Classpath" exception as provided + by Oracle in the GPL Version 2 section of the License file that + accompanied this code. If applicable, add the following below the + License Header, with the fields enclosed by brackets [] replaced by + your own identifying information: + "Portions Copyrighted [year] [name of copyright owner]" + + Contributor(s): + + The Original Software is NetBeans. The Initial Developer of the Original + Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + + If you wish your version of this file to be governed by only the CDDL + or only the GPL Version 2, indicate your decision by adding + "[Contributor] elects to include this software in this distribution + under the [CDDL or GPL Version 2] license." If you do not indicate a + single choice of license, a recipient has the option to distribute + your version of this file under either the CDDL, the GPL Version 2 or + to extend the choice of license to its licensees as provided above. + However, if you add GPL Version 2 code and therefore, elected the GPL + Version 2 license, then the option applies only if the new code is + made subject to such option by the copyright holder. + +--> +<!DOCTYPE html> +<html> + <body> + <div>Interfaces for integrators of various execution environments.</div> + Not really interesting for clients. The clients should rather use + {@link net.java.html.boot.BrowserBuilder} to launch their applications, + or (if they need to do some JavaScript calls themselves) look at + {@link net.java.html.js.JavaScriptBody} annotation and its usage. + </body> +</html> http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/resources/net/java/html/boot/html4j.txt ---------------------------------------------------------------------- diff --git a/boot/src/main/resources/net/java/html/boot/html4j.txt b/boot/src/main/resources/net/java/html/boot/html4j.txt new file mode 100644 index 0000000..0552164 --- /dev/null +++ b/boot/src/main/resources/net/java/html/boot/html4j.txt @@ -0,0 +1,43 @@ +==== + DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + + Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + + Oracle and Java are registered trademarks of Oracle and/or its affiliates. + Other names may be trademarks of their respective owners. + + The contents of this file are subject to the terms of either the GNU + General Public License Version 2 only ("GPL") or the Common + Development and Distribution License("CDDL") (collectively, the + "License"). You may not use this file except in compliance with the + License. You can obtain a copy of the License at + http://www.netbeans.org/cddl-gplv2.html + or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + specific language governing permissions and limitations under the + License. When distributing the software, include this License Header + Notice in each file and include the License file at + nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + particular file as subject to the "Classpath" exception as provided + by Oracle in the GPL Version 2 section of the License file that + accompanied this code. If applicable, add the following below the + License Header, with the fields enclosed by brackets [] replaced by + your own identifying information: + "Portions Copyrighted [year] [name of copyright owner]" + + Contributor(s): + + The Original Software is NetBeans. The Initial Developer of the Original + Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + + If you wish your version of this file to be governed by only the CDDL + or only the GPL Version 2, indicate your decision by adding + "[Contributor] elects to include this software in this distribution + under the [CDDL or GPL Version 2] license." If you do not indicate a + single choice of license, a recipient has the option to distribute + your version of this file under either the CDDL, the GPL Version 2 or + to extend the choice of license to its licensees as provided above. + However, if you add GPL Version 2 code and therefore, elected the GPL + Version 2 license, then the option applies only if the new code is + made subject to such option by the copyright holder. +==== + http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/net/java/html/boot/BrowserBuilderTest.java ---------------------------------------------------------------------- diff --git a/boot/src/test/java/net/java/html/boot/BrowserBuilderTest.java b/boot/src/test/java/net/java/html/boot/BrowserBuilderTest.java new file mode 100644 index 0000000..c4644fa --- /dev/null +++ b/boot/src/test/java/net/java/html/boot/BrowserBuilderTest.java @@ -0,0 +1,134 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package net.java.html.boot; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Locale; +import static org.testng.Assert.*; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class BrowserBuilderTest { + private File dir; + private File index; + + public BrowserBuilderTest() { + } + + @BeforeMethod public void prepareFiles() throws IOException { + dir = File.createTempFile("test", ".dir"); + dir.delete(); + assertTrue(dir.mkdirs(), "Dir successfully created: " + dir); + + index = new File(dir, "index.html"); + index.createNewFile(); + + System.setProperty("browser.rootdir", dir.getPath()); + } + + @AfterMethod public void clearFiles() throws IOException { + Files.walkFileTree(dir.toPath(), new FileVisitor<Path>() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } + + + @Test public void findsZhCN() throws IOException { + File zh = new File(dir, "index_zh.html"); zh.createNewFile(); + File zhCN = new File(dir, "index_zh_CN.html"); zhCN.createNewFile(); + + IOException[] mal = { null }; + URL url = BrowserBuilder.findLocalizedResourceURL("index.html", Locale.SIMPLIFIED_CHINESE, mal, BrowserBuilder.class); + + assertEquals(url, zhCN.toURI().toURL(), "Found both suffixes"); + } + + @Test public void findsZh() throws IOException { + File zh = new File(dir, "index_zh.html"); zh.createNewFile(); + + IOException[] mal = { null }; + URL url = BrowserBuilder.findLocalizedResourceURL("index.html", Locale.SIMPLIFIED_CHINESE, mal, BrowserBuilder.class); + + assertEquals(url, zh.toURI().toURL(), "Found one suffix"); + } + + @Test public void findsIndex() throws IOException { + IOException[] mal = { null }; + URL url = BrowserBuilder.findLocalizedResourceURL("index.html", Locale.SIMPLIFIED_CHINESE, mal, BrowserBuilder.class); + + assertEquals(url, index.toURI().toURL(), "Found root file"); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java ---------------------------------------------------------------------- diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java b/boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java new file mode 100644 index 0000000..c4a3cd3 --- /dev/null +++ b/boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java @@ -0,0 +1,53 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.html.boot.impl; + +/** + * + * @author Jaroslav Tulach + */ +public class Arithm { + public int sumTwo(int a, int b) { + return a + b; + } +} http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java ---------------------------------------------------------------------- diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java b/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java new file mode 100644 index 0000000..6862e6a --- /dev/null +++ b/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java @@ -0,0 +1,307 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.html.boot.impl; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.fail; + +/** + * + * @author Jaroslav Tulach + */ +final class Compile implements DiagnosticListener<JavaFileObject> { + private final List<Diagnostic<? extends JavaFileObject>> errors = + new ArrayList<Diagnostic<? extends JavaFileObject>>(); + private final Map<String, byte[]> classes; + private final String pkg; + private final String cls; + private final String html; + private final String sourceLevel; + + private Compile(String html, String code, String sl) throws IOException { + this.pkg = findPkg(code); + this.cls = findCls(code); + this.html = html; + this.sourceLevel = sl; + classes = compile(html, code); + } + + /** Performs compilation of given HTML page and associated Java code + */ + public static Compile create(String html, String code) throws IOException { + return create(html, code, "1.7"); + } + static Compile create(String html, String code, String sourceLevel) throws IOException { + return new Compile(html, code, sourceLevel); + } + + /** Checks for given class among compiled resources */ + public byte[] get(String res) { + return classes.get(res); + } + + /** Obtains errors created during compilation. + */ + public List<Diagnostic<? extends JavaFileObject>> getErrors() { + return getDiagnostics(Diagnostic.Kind.ERROR); + } + public List<Diagnostic<? extends JavaFileObject>> getDiagnostics(Diagnostic.Kind kind) { + List<Diagnostic<? extends JavaFileObject>> err; + err = new ArrayList<Diagnostic<? extends JavaFileObject>>(); + for (Diagnostic<? extends JavaFileObject> diagnostic : errors) { + if (diagnostic.getKind() == kind) { + err.add(diagnostic); + } + } + return err; + } + + private Map<String, byte[]> compile(final String html, final String code) throws IOException { + StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null); + + final Map<String, ByteArrayOutputStream> class2BAOS; + class2BAOS = new HashMap<String, ByteArrayOutputStream>(); + + JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return code; + } + }; + final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return html; + } + + @Override + public InputStream openInputStream() throws IOException { + return new ByteArrayInputStream(html.getBytes()); + } + }; + + final URI scratch; + try { + scratch = new URI("mem://mem3"); + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + + JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) { + @Override + public FileObject getFileForOutput(JavaFileManager.Location location, String packageName, String relativeName, FileObject sibling) throws IOException { + try { + return new VirtFO(new URI("mem://resource/" + relativeName), Kind.OTHER, relativeName); + } catch (URISyntaxException ex) { + throw new IllegalStateException(ex); + } + } + + + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { + if (kind == Kind.CLASS) { + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + class2BAOS.put(className.replace('.', '/') + ".class", buffer); + return new SimpleJavaFileObject(sibling.toUri(), kind) { + @Override + public OutputStream openOutputStream() throws IOException { + return buffer; + } + }; + } + + if (kind == Kind.SOURCE) { + final String n = className.replace('.', '/') + ".java"; + final URI un; + try { + un = new URI("mem://" + n); + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + return new VirtFO(un/*sibling.toUri()*/, kind, n); + } + + throw new IllegalStateException(); + } + + @Override + public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { + if (location == StandardLocation.SOURCE_PATH) { + if (packageName.equals(pkg)) { + return htmlFile; + } + if (packageName.isEmpty() && relativeName.startsWith(pkg.replace('.', '/'))) { + return htmlFile; + } + } + + return null; + } + + @Override + public boolean isSameFile(FileObject a, FileObject b) { + if (a instanceof VirtFO && b instanceof VirtFO) { + return ((VirtFO)a).getName().equals(((VirtFO)b).getName()); + } + + return super.isSameFile(a, b); + } + + class VirtFO extends SimpleJavaFileObject { + + private final String n; + + public VirtFO(URI uri, Kind kind, String n) { + super(uri, kind); + this.n = n; + } + private final ByteArrayOutputStream data = new ByteArrayOutputStream(); + + @Override + public OutputStream openOutputStream() throws IOException { + return data; + } + + @Override + public String getName() { + return n; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + data.close(); + return new String(data.toByteArray()); + } + } + }; + + ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", sourceLevel, "-target", "1.7"), null, Arrays.asList(file)).call(); + + Map<String, byte[]> result = new HashMap<String, byte[]>(); + + for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) { + result.put(e.getKey(), e.getValue().toByteArray()); + } + + return result; + } + + + @Override + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { + errors.add(diagnostic); + } + private static String findPkg(String java) throws IOException { + Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE); + Matcher m = p.matcher(java); + if (!m.find()) { + throw new IOException("Can't find package declaration in the java file"); + } + String pkg = m.group(1); + return pkg; + } + private static String findCls(String java) throws IOException { + Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE); + Matcher m = p.matcher(java); + if (!m.find()) { + throw new IOException("Can't find package declaration in the java file"); + } + String cls = m.group(1); + return cls; + } + + String getHtml() { + String fqn = "'" + pkg + '.' + cls + "'"; + return html.replace("'${fqn}'", fqn); + } + void assertErrors() { + assertFalse(getErrors().isEmpty(), "There are supposed to be some errors"); + } + + void assertError(String expMsg) { + StringBuilder sb = new StringBuilder(); + sb.append("Can't find ").append(expMsg).append(" among:"); + for (Diagnostic<? extends JavaFileObject> e : errors) { + String msg = e.getMessage(Locale.US); + if (msg.contains(expMsg)) { + return; + } + sb.append("\n"); + sb.append(msg); + } + fail(sb.toString()); + } + + void assertNoErrors() { + assertTrue(getErrors().isEmpty(), "No errors expected: " + getErrors()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/CountFnCreationTest.java ---------------------------------------------------------------------- diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/CountFnCreationTest.java b/boot/src/test/java/org/netbeans/html/boot/impl/CountFnCreationTest.java new file mode 100644 index 0000000..8e3f0e2 --- /dev/null +++ b/boot/src/test/java/org/netbeans/html/boot/impl/CountFnCreationTest.java @@ -0,0 +1,123 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.html.boot.impl; + +import java.io.Closeable; +import java.io.IOException; +import java.io.Reader; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.Collection; +import java.util.Enumeration; +import net.java.html.js.JavaScriptBody; +import net.java.html.js.JavaScriptResource; +import org.netbeans.html.boot.spi.Fn; +import static org.testng.Assert.assertEquals; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +@JavaScriptResource("empty.js") +public class CountFnCreationTest implements Fn.Presenter { + private int cnt; + + @JavaScriptBody(args = {}, body = "return;") + public static native void body(); + + @Test public void countManyTimes() throws Exception { + class Res implements FindResources { + @Override + public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough) { + try { + ClassLoader l = CountFnCreationTest.class.getClassLoader(); + Enumeration<URL> en = l.getResources(path); + while (en.hasMoreElements()) { + results.add(en.nextElement()); + } + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + } + ClassLoader l = FnUtils.newLoader(new Res(), this, CountFnCreationTest.class.getClassLoader().getParent()); + Method m = l.loadClass(CountFnCreationTest.class.getName()).getMethod("body"); + Closeable c = Fn.activate(this); + try { + assertEquals(cnt, 0, "No functions yet"); + m.invoke(null); + assertEquals(cnt, 1, "One function defined"); + m.invoke(null); + assertEquals(cnt, 1, "Still one function"); + } finally { + c.close(); + } + } + + @Override + public Fn defineFn(String code, String... names) { + cnt++; + return new MyFn(this); + } + + @Override + public void displayPage(URL page, Runnable onPageLoad) { + } + + @Override + public void loadScript(Reader code) throws Exception { + } + + private static final class MyFn extends Fn { + + public MyFn(Presenter presenter) { + super(presenter); + } + + @Override + public java.lang.Object invoke(java.lang.Object thiz, java.lang.Object... args) throws Exception { + return null; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java ---------------------------------------------------------------------- diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java b/boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java new file mode 100644 index 0000000..d7c55ab --- /dev/null +++ b/boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java @@ -0,0 +1,186 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.html.boot.impl; + +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; +import java.io.Reader; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import org.netbeans.html.boot.spi.Fn; +import static org.testng.Assert.assertEquals; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class FnTest extends JsClassLoaderBase { + private static Fn.Presenter presenter; + + public FnTest() { + } + + @BeforeClass + public static void createClassLoader() throws Exception { + ScriptEngineManager sem = new ScriptEngineManager(); + final ScriptEngine eng = sem.getEngineByMimeType("text/javascript"); + + final URL my = FnTest.class.getProtectionDomain().getCodeSource().getLocation(); + ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent(); + final URLClassLoader ul = new URLClassLoader(new URL[] { my }, parent); + + class Impl implements FindResources, Fn.Presenter { + @Override + public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough) { + URL u = ul.findResource(path); + if (u != null) { + results.add(u); + } + } + + @Override + public Fn defineFn(String code, String... names) { + StringBuilder sb = new StringBuilder(); + sb.append("(function() {"); + sb.append("return function("); + String sep = ""; + for (String n : names) { + sb.append(sep); + sb.append(n); + sep = ", "; + } + sb.append(") {"); + sb.append(code); + sb.append("};"); + sb.append("})()"); + try { + final java.lang.Object val = eng.eval(sb.toString()); + return new Fn(this) { + @Override + public java.lang.Object invoke(java.lang.Object thiz, java.lang.Object... args) throws Exception { + List<java.lang.Object> all = new ArrayList<java.lang.Object>(args.length + 1); + all.add(thiz == null ? val : thiz); + all.addAll(Arrays.asList(args)); + Invocable inv = (Invocable)eng; + try { + java.lang.Object ret = inv.invokeMethod(val, "call", all.toArray()); + return val.equals(ret) ? null : ret; + } catch (ScriptException ex) { + throw ex; + } + } + }; + } catch (ScriptException ex) { + throw new LinkageError("Can't parse: " + sb, ex); + } + } + + @Override + public void displayPage(URL resource, Runnable r) { + throw new UnsupportedOperationException(); + } + + @Override + public void loadScript(Reader code) throws Exception { + eng.eval(code); + } + } + Impl impl = new Impl(); + ClassLoader loader = FnUtils.newLoader(impl, impl, parent); + presenter = impl; + + Closeable close = FnContext.activate(impl); + methodClass = loader.loadClass(JsMethods.class.getName()); + close.close(); + } + + @Test public void flushingPresenter() throws IOException { + class FP implements Fn.Presenter, Flushable { + int flush; + + @Override + public Fn defineFn(String code, String... names) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void displayPage(URL page, Runnable onPageLoad) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void loadScript(Reader code) throws Exception { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void flush() throws IOException { + flush++; + } + } + + FP p = new FP(); + Closeable c1 = Fn.activate(p); + Closeable c2 = Fn.activate(p); + c2.close(); + assertEquals(p.flush, 0, "No flush yet"); + c1.close(); + assertEquals(p.flush, 1, "Now flushed"); + } + + @BeforeMethod public void initPresenter() { + FnContext.currentPresenter(presenter); + } +} http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java ---------------------------------------------------------------------- diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java b/boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java new file mode 100644 index 0000000..1ef07b5 --- /dev/null +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java @@ -0,0 +1,167 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.html.boot.impl; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Locale; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class JavaScriptProcesorTest { + + @Test public void detectCallbackToNonExistingClass() throws IOException { + String code = "package x.y.z;\n" + + "import net.java.html.js.JavaScriptBody;\n" + + "class X {\n" + + " @JavaScriptBody(args={\"r\"}, javacall=true, body =\n" + + " \"[email protected]::run()();\"\n" // typo + + " )\n" + + " private static native void callback(Runnable r);\n" + + "}\n"; + + Compile c = Compile.create("", code); + c.assertErrors(); + c.assertError("java.lang.Runable"); // typo + } + + @Test public void detectCallbackToNonExistingMethod() throws IOException { + String code = "package x.y.z;\n" + + "import net.java.html.js.JavaScriptBody;\n" + + "class X {\n" + + " @JavaScriptBody(args={\"r\"}, javacall=true, body =\n" + + " \"[email protected]::cancel()();\"\n" + + " )\n" + + " private static native void callback(Runnable r);\n" + + "}\n"; + + Compile c = Compile.create("", code); + c.assertErrors(); + c.assertError("method cancel"); + } + + @Test public void detectCallbackToNonExistingParams() throws IOException { + String code = "package x.y.z;\n" + + "import net.java.html.js.JavaScriptBody;\n" + + "class X {\n" + + " @JavaScriptBody(args={\"r\"}, javacall=true, body =\n" + + " \"[email protected]::run(I)(10);\"\n" + + " )\n" + + " private static native void callback(Runnable r);\n" + + "}\n"; + + Compile c = Compile.create("", code); + c.assertErrors(); + c.assertError("wrong parameters: (I)"); + } + + @Test public void objectTypeParamsAreOK() throws IOException { + String code = "package x.y.z;\n" + + "import net.java.html.js.JavaScriptBody;\n" + + "class X {\n" + + " @JavaScriptBody(args={\"r\"}, javacall=true, body =\n" + + " \"[email protected]::equals(Ljava/lang/Object;)(null);\"\n" + + " )\n" + + " private static native void testEqual(Object r);\n" + + "}\n"; + + Compile c = Compile.create("", code); + c.assertNoErrors(); + } + + @Test public void misorderNotified() throws IOException { + String code = "package x.y.z;\n" + + "import net.java.html.js.JavaScriptBody;\n" + + "class X {\n" + + " @JavaScriptBody(args={\"r\", \"a\", \"b\"}, body =\"\"\n" + + " )\n" + + " private static native void testEqual(Object p, String q, int r);\n" + + "}\n"; + + Compile c = Compile.create("", code); + List<Diagnostic<? extends JavaFileObject>> warnings = c.getDiagnostics(Diagnostic.Kind.WARNING); + assertTrue(warnings.size() >= 1, "There are warnings: " + warnings); + for (Diagnostic<? extends JavaFileObject> w : warnings) { + if (w.getMessage(Locale.US).contains("Actual method parameter names and args")) { + return; + } + } + fail("Expecting order warning: " + warnings); + } + + @Test public void needJavaScriptBodyToUseResource() throws IOException { + String code = "package x.y.z;\n" + + "import net.java.html.js.JavaScriptResource;\n" + + "@JavaScriptResource(\"x.html\")\n" + + "class X {\n" + + " private static native void callback(Runnable r);\n" + + "}\n"; + + Compile c = Compile.create("", code); + c.assertErrors(); + c.assertError("needs @JavaScriptBody"); + } + + @Test public void generatesCallbacksThatReturnObject() throws Exception { + Class<?> callbacksForTestPkg = Class.forName("org.netbeans.html.boot.impl.$JsCallbacks$"); + Method m = callbacksForTestPkg.getDeclaredMethod("java_lang_Runnable$run$", Runnable.class); + assertEquals(m.getReturnType(), java.lang.Object.class, "All methods always return object"); + } + + @Test public void hasInstanceField() throws Exception { + Class<?> callbacksForTestPkg = Class.forName("org.netbeans.html.boot.impl.$JsCallbacks$"); + Field f = callbacksForTestPkg.getDeclaredField("VM"); + f.setAccessible(true); + assertTrue(callbacksForTestPkg.isInstance(f.get(null)), "Singleton field VM"); + } +} http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/JsCallbackTest.java ---------------------------------------------------------------------- diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/JsCallbackTest.java b/boot/src/test/java/org/netbeans/html/boot/impl/JsCallbackTest.java new file mode 100644 index 0000000..5b68349 --- /dev/null +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsCallbackTest.java @@ -0,0 +1,86 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.html.boot.impl; + +import static org.testng.Assert.*; +import org.testng.annotations.Test; + +/** Verify behavior of the callback parser. + * + * @author Jaroslav Tulach + */ +public class JsCallbackTest { + + public JsCallbackTest() { + } + @Test public void missingTypeSpecification() { + String body = "console[attr] = function(msg) {\n" + + " @org.netbeans.html.charts.Main::log(msg);\n" + + "};\n"; + JsCallback instance = new JsCallbackImpl(); + try { + String result = instance.parse(body); + fail("The parsing should fail!"); + } catch (IllegalStateException ex) { + // OK + } + } + + + public class JsCallbackImpl extends JsCallback { + private String ident; + private String fqn; + private String method; + private String params; + + @Override + public CharSequence callMethod(String ident, String fqn, String method, String params) { + this.ident = ident; + this.fqn = fqn; + this.method = method; + this.params = params; + return "call"; + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java ---------------------------------------------------------------------- diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java new file mode 100644 index 0000000..9b458d2 --- /dev/null +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java @@ -0,0 +1,285 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.html.boot.impl; + +import java.io.Closeable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; +import org.netbeans.html.boot.spi.Fn; +import org.testng.Assert; +import static org.testng.Assert.*; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class JsClassLoaderBase { + protected static Class<?> methodClass; + + public JsClassLoaderBase() { + } + + @BeforeMethod + public void assertClassDefined() { + assertNotNull(methodClass, "BeforeClass set up code should provide methodClass"); + } + + @Test public void noParamMethod() throws Throwable { + Method plus = methodClass.getMethod("fortyTwo"); + try { + final java.lang.Object val = plus.invoke(null); + assertTrue(val instanceof Number, "A number returned " + val); + assertEquals(((Number)val).intValue(), 42); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + @Test public void testExecuteScript() throws Throwable { + Method plus = methodClass.getMethod("plus", int.class, int.class); + try { + assertEquals(plus.invoke(null, 10, 20), 30); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + @Test public void overloadedMethod() throws Throwable { + Method plus = methodClass.getMethod("plus", int.class); + try { + assertEquals(plus.invoke(null, 10), 10); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + @Test public void instanceMethod() throws Throwable { + Method plus = methodClass.getMethod("plusInst", int.class); + java.lang.Object inst = methodClass.newInstance(); + try { + assertEquals(plus.invoke(inst, 10), 10); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + @Test public void staticThis() throws Throwable { + Method st = methodClass.getMethod("staticThis"); + try { + assertNull(st.invoke(null)); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + @Test public void getThis() throws Throwable { + java.lang.Object th = methodClass.newInstance(); + Method st = methodClass.getMethod("getThis"); + try { + assertEquals(st.invoke(th), th); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + @Test public void primitiveArrayReturn() throws Throwable { + Method st = methodClass.getMethod("both", double.class, double.class); + Throwable ex; + try { + java.lang.Object arr = st.invoke(null, 2, 5); + ex = null; + } catch (InvocationTargetException invoke) { + ex = invoke.getTargetException(); + } + assertTrue(ex instanceof ClassCastException, "Primitive arrays aren't returned from JavaScript: " + ex); + } + + @Test public void truth() throws Throwable { + Method st = methodClass.getMethod("truth"); + assertTrue((st.getModifiers() & Modifier.STATIC) != 0, "Is static"); + assertEquals(st.invoke(null), Boolean.TRUE, "Can return boolean"); + } + + @Test public void callback() throws Throwable { + class R implements Runnable { + int cnt; + + @Override + public void run() { + cnt++; + } + } + R r = new R(); + + Method inc = methodClass.getMethod("callback", Runnable.class); + inc.invoke(null, r); + + assertEquals(r.cnt, 1, "Callback happened"); + } + + @Test public void sumArray() throws Throwable { + Method st = methodClass.getMethod("sumArr", int[].class); + assertEquals(st.invoke(null, new int[] { 1, 2, 3 }), 6, "1+2+3 is six"); + } + + @Test public void javaScriptResource() throws Throwable { + try { + Method st = methodClass.getMethod("useExternalMul", int.class, int.class); + assertEquals(st.invoke(null, 6, 7), 42, "Meaning of JavaScript?"); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + @Test public void callJavaScriptMethodOnOwnClass() throws Throwable { + try { + java.lang.Object thiz = methodClass.newInstance(); + Method st = methodClass.getMethod("returnYourSelf", methodClass); + assertEquals(st.invoke(null, thiz), thiz, "Returns this"); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + @Test public void callStaticJavaMethod() throws Throwable { + Method st = methodClass.getMethod("staticCallback", int.class, int.class); + assertEquals(st.invoke(null, 6, 7), 42, "Meaning of JavaScript?"); + } + + @Test public void callStaticStringParamMethod() throws Throwable { + Method st = methodClass.getMethod("parseInt", String.class); + assertEquals(st.invoke(null, "42"), 42, "Meaning of JavaScript?"); + } + + @Test public void passEnum() throws Throwable { + Class<?> enmClazz = methodClass.getDeclaredClasses()[0]; + assertTrue(Enum.class.isAssignableFrom(enmClazz), "It is an enum: " + enmClazz); + Class<? extends Enum> enmClazz2 = enmClazz.asSubclass(Enum.class); + Method st = methodClass.getMethod("fromEnum", enmClazz); + + java.lang.Object valueB = Enum.valueOf(enmClazz2, "B"); + assertEquals(st.invoke(null, valueB), "B", "Converts to string"); + } + + @Test public void firstLong() throws Throwable { + Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class); + assertEquals(st.invoke(null, true, false, 10, 20), 10L, "Take first value"); + } + + @Test public void secondLong() throws Throwable { + Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class); + assertEquals(st.invoke(null, false, true, 10, 20), 20L, "Take 2nd value"); + } + + @Test public void bothLong() throws Throwable { + Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class); + assertEquals(st.invoke(null, true, true, 10, 20), 30L, "Take both values"); + } + + @Test public void recordError() throws Throwable { + Method st = methodClass.getMethod("recordError", java.lang.Object.class); + assertEquals(st.invoke(methodClass.newInstance(), "Hello"), "Hello", "The same parameter returned"); + } + + @Test public void plusOrMul() throws Throwable { + Method st = methodClass.getMethod("plusOrMul", int.class, int.class); + assertNotNull(Fn.activePresenter(), "Is there a presenter?"); + Closeable c = Fn.activate(null); + try { + assertNull(Fn.activePresenter(), "No presenter now"); + assertEquals(st.invoke(null, 6, 7), 42, "Mul in Java"); + } finally { + c.close(); + } + assertNotNull(Fn.activePresenter(), "Is there a presenter again"); + assertEquals(st.invoke(null, 6, 7), 13, "Plus in JavaScript"); + c = Fn.activate(null); + try { + assertNull(Fn.activePresenter(), "No presenter again"); + assertEquals(st.invoke(null, 6, 7), 42, "Mul in Java"); + } finally { + c.close(); + } + assertNotNull(Fn.activePresenter(), "Is there a presenter again"); + assertEquals(st.invoke(null, 6, 7), 13, "Plus in JavaScript again"); + } + + @Test public void arrayInOut() throws Throwable { + String[] arr = { "Ahoj" }; + Method st = methodClass.getMethod("arr", java.lang.Object[].class); + java.lang.Object ret = st.invoke(null, (java.lang.Object) arr); + assertTrue(ret instanceof java.lang.Object[], "Expecting array: " + ret); + java.lang.Object[] res = (java.lang.Object[]) ret; + assertEquals(res.length, 1, "One element"); + assertEquals(res[0], "Ahoj", "The right string"); + } + + @Test public void parametricCallback() throws Throwable { + Map<String,Number> map = new HashMap<String, Number>(); + Method st = methodClass.getMethod("callParamTypes", Map.class, int.class); + st.invoke(null, map, 42); + assertEquals(map.get("key").intValue(), 42, "The right value"); + } + + @Test public void checkTheTypeOfThrownException() throws Throwable { + FnContext.currentPresenter(null); + assertNull(Fn.activePresenter(), "No presenter is activer right now"); + java.lang.Object res = null; + try { + Method st = methodClass.getMethod("plus", int.class, int.class); + try { + res = st.invoke(null, 40, 2); + Assert.fail("Native method should throw IllegalStateException. Was: " + res); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } catch (IllegalStateException ex) { + assertEquals(ex.getMessage(), "No presenter active. Use BrwsrCtx.execute!"); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java ---------------------------------------------------------------------- diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java new file mode 100644 index 0000000..d69a761 --- /dev/null +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java @@ -0,0 +1,161 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.html.boot.impl; + +import java.io.Closeable; +import java.io.Reader; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import org.netbeans.html.boot.spi.Fn; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; + +/** + * + * @author Jaroslav Tulach + */ +public class JsClassLoaderTest extends JsClassLoaderBase{ + private static Fn.Presenter loader; + + @BeforeClass + public static void setUpClass() throws Exception { + ScriptEngineManager sem = new ScriptEngineManager(); + final ScriptEngine eng = sem.getEngineByMimeType("text/javascript"); + + final URL my = JsClassLoaderTest.class.getProtectionDomain().getCodeSource().getLocation(); + ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent(); + final URLClassLoader ul = new URLClassLoader(new URL[] { my }, parent); + class MyCL extends FnUtils.JsClassLoaderImpl implements Fn.Presenter { + + public MyCL(ClassLoader parent) { + super(parent, null, null); + } + + @Override + protected URL findResource(String name) { + return ul.getResource(name); + } + @Override + public Fn defineFn(String code, String... names) { + StringBuilder sb = new StringBuilder(); + sb.append("(function() {"); + sb.append("return function("); + String sep = ""; + for (String n : names) { + sb.append(sep); + sb.append(n); + sep = ", "; + } + sb.append(") {"); + sb.append(code); + sb.append("};"); + sb.append("})()"); + try { + final java.lang.Object val = eng.eval(sb.toString()); + return new Fn(this) { + @Override + public java.lang.Object invoke(java.lang.Object thiz, java.lang.Object... args) throws Exception { + List<java.lang.Object> all = new ArrayList<java.lang.Object>(args.length + 1); + all.add(thiz == null ? val : thiz); + all.addAll(Arrays.asList(args)); + Invocable inv = (Invocable)eng; + try { + java.lang.Object ret = inv.invokeMethod(val, "call", all.toArray()); + return val.equals(ret) ? null : ret; + } catch (Exception ex) { + throw ex; + } + } + }; + } catch (ScriptException ex) { + throw new LinkageError("Can't parse: " + sb, ex); + } + } + + @Override + protected Enumeration<URL> findResources(String name) { + URL u = findResource(name); + List<URL> arr = new ArrayList<URL>(); + if (u != null) { + arr.add(u); + } + return Collections.enumeration(arr); + } + + @Override + public void loadScript(Reader code) throws ScriptException { + eng.eval(code); + } + + @Override + public void displayPage(URL page, Runnable onPageLoad) { + throw new UnsupportedOperationException(); + } + }; + + MyCL l = new MyCL(parent); + Closeable close = FnContext.activate(l); + methodClass = l.loadClass(JsMethods.class.getName()); + close.close(); + loader = l; + } + + @BeforeMethod public void initPresenter() { + FnContext.currentPresenter(loader); + } + + @AfterClass + public static void cleanUp() { + methodClass = null; + } +} \ No newline at end of file
