# HG changeset patch # User Jaroslav Tulach # Date 1387209583 -3600 # Node ID 92fb71afdc0e5d1b14a2b5121ee807cf6ebaf3e8 # Parent 700087d2a5d34dd7816acc42c0b4919800214900 Moving implementation classes into org.netbeans.html namespace diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java --- a/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java Mon Dec 16 15:48:09 2013 +0100 +++ b/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java Mon Dec 16 16:59:43 2013 +0100 @@ -49,7 +49,7 @@ import javafx.scene.web.WebView; import net.java.html.boot.BrowserBuilder; import net.java.html.js.JavaScriptBody; -import org.apidesign.html.boot.fx.AbstractFXPresenter; +import org.netbeans.html.boot.fx.AbstractFXPresenter; /** Utility methods for working with JavaFX WebViews. * diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/main/java/org/apidesign/html/boot/fx/AbstractFXPresenter.java --- a/boot-fx/src/main/java/org/apidesign/html/boot/fx/AbstractFXPresenter.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,190 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.fx; - -import java.io.BufferedReader; -import java.io.Reader; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import javafx.application.Platform; -import javafx.scene.web.WebEngine; -import javafx.scene.web.WebView; -import netscape.javascript.JSObject; -import org.apidesign.html.boot.spi.Fn; - -/** - * - * @author Jaroslav Tulach - */ -public abstract class AbstractFXPresenter implements Fn.Presenter { - static final Logger LOG = Logger.getLogger(FXPresenter.class.getName()); - protected static int cnt; - protected List scripts; - protected Runnable onLoad; - protected WebEngine engine; - - @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).append(n); - sep = ","; - } - sb.append(") {\n"); - sb.append(code); - sb.append("};"); - sb.append("})()"); - if (LOG.isLoggable(Level.FINE)) { - LOG.log(Level.FINE, - "defining function #{0}:\n{1}\n", - new Object[] { ++cnt, code } - ); - } - JSObject x = (JSObject) engine.executeScript(sb.toString()); - return new JSFn(this, x, cnt); - } - - @Override - public void loadScript(Reader code) throws Exception { - BufferedReader r = new BufferedReader(code); - StringBuilder sb = new StringBuilder(); - for (;;) { - String l = r.readLine(); - if (l == null) { - break; - } - sb.append(l).append('\n'); - } - final String script = sb.toString(); - if (scripts != null) { - scripts.add(script); - } - engine.executeScript(script); - } - - protected final void onPageLoad() { - if (scripts != null) { - for (String s : scripts) { - engine.executeScript(s); - } - } - onLoad.run(); - } - - @Override - public void displayPage(final URL resource, final Runnable onLoad) { - this.onLoad = onLoad; - final WebView view = findView(resource); - this.engine = view.getEngine(); - try { - if (FXInspect.initialize(engine)) { - scripts = new ArrayList(); - } - } catch (Throwable ex) { - ex.printStackTrace(); - } - - class Run implements Runnable { - - @Override - public void run() { - if (scripts != null) { - view.setContextMenuEnabled(true); - } - engine.load(resource.toExternalForm()); - } - } - Run run = new Run(); - if (Platform.isFxApplicationThread()) { - run.run(); - } else { - Platform.runLater(run); - } - waitFinished(); - } - - protected abstract void waitFinished(); - - protected abstract WebView findView(final URL resource); - - private static final class JSFn extends Fn { - - private final JSObject fn; - private static int call; - private final int id; - - public JSFn(AbstractFXPresenter p, JSObject fn, int id) { - super(p); - this.fn = fn; - this.id = id; - } - - @Override - public Object invoke(Object thiz, Object... args) throws Exception { - try { - if (LOG.isLoggable(Level.FINE)) { - LOG.log(Level.FINE, "calling {0} function #{1}", new Object[]{++call, id}); - } - List all = new ArrayList(args.length + 1); - all.add(thiz == null ? fn : thiz); - all.addAll(Arrays.asList(args)); - Object ret = fn.call("call", all.toArray()); // NOI18N - return ret == fn ? null : ret; - } catch (Error t) { - t.printStackTrace(); - throw t; - } catch (Exception t) { - t.printStackTrace(); - throw t; - } - } - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/main/java/org/apidesign/html/boot/fx/Dbgr.java --- a/boot-fx/src/main/java/org/apidesign/html/boot/fx/Dbgr.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.fx; - -import java.lang.reflect.Method; -import java.util.logging.Level; -import javafx.scene.web.WebEngine; -import javafx.util.Callback; -import static org.apidesign.html.boot.fx.AbstractFXPresenter.LOG; - -/** Debugger bridge to shield us from propriatory impl APIs. - * - * @author Jaroslav Tulach - */ -final class Dbgr { - final Object dbg; - final Method sendMsg; - - Dbgr(WebEngine eng, Callback callback) { - Object d; - Method m; - try { - d = eng.getClass().getMethod("impl_getDebugger").invoke(eng); // NOI18N - Class debugger = eng.getClass().getClassLoader().loadClass("com.sun.javafx.scene.web.Debugger"); // NOI18N - debugger.getMethod("setEnabled", boolean.class).invoke(d, true); // NOI18N - debugger.getMethod("setMessageCallback", Callback.class).invoke(d, callback); // NOI18N - m = debugger.getMethod("sendMessage", String.class); // NOI18N - } catch (Exception ex) { - LOG.log(Level.INFO, null, ex); - d = null; - m = null; - } - dbg = d; - sendMsg = m; - } - - void sendMessage(String msg) { - try { - if (dbg != null) { - sendMsg.invoke(dbg, msg); - } - } catch (Exception ex) { - LOG.log(Level.INFO, null, ex); - } - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/main/java/org/apidesign/html/boot/fx/FXBrwsr.java --- a/boot-fx/src/main/java/org/apidesign/html/boot/fx/FXBrwsr.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,193 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.fx; - -import java.net.URL; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; -import java.util.logging.Level; -import java.util.logging.Logger; -import javafx.application.Application; -import javafx.application.Platform; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.concurrent.Worker; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.VBox; -import javafx.scene.text.Text; -import javafx.scene.web.WebEvent; -import javafx.scene.web.WebView; -import javafx.stage.Modality; -import javafx.stage.Stage; - -/** This is an implementation class, use {@link BrowserBuilder} API. Just - * include this JAR on classpath and the {@link BrowserBuilder} API will find - * this implementation automatically. - */ -public class FXBrwsr extends Application { - private static final Logger LOG = Logger.getLogger(FXBrwsr.class.getName()); - private static FXBrwsr INSTANCE; - private static final CountDownLatch FINISHED = new CountDownLatch(1); - private BorderPane root; - - public static synchronized WebView findWebView(final URL url, final FXPresenter onLoad) { - if (INSTANCE == null) { - Executors.newFixedThreadPool(1).submit(new Runnable() { - @Override - public void run() { - try { - FXBrwsr.launch(FXBrwsr.class); - } catch (Throwable ex) { - ex.printStackTrace(); - } finally { - FINISHED.countDown(); - } - } - }); - } - while (INSTANCE == null) { - try { - FXBrwsr.class.wait(); - } catch (InterruptedException ex) { - // wait more - } - } - if (!Platform.isFxApplicationThread()) { - final WebView[] arr = {null}; - final CountDownLatch waitForResult = new CountDownLatch(1); - Platform.runLater(new Runnable() { - @Override - public void run() { - arr[0] = INSTANCE.newView(url, onLoad); - waitForResult.countDown(); - } - }); - for (;;) { - try { - waitForResult.await(); - break; - } catch (InterruptedException ex) { - LOG.log(Level.INFO, null, ex); - } - } - return arr[0]; - } else { - return INSTANCE.newView(url, onLoad); - } - } - - @Override - public void start(Stage primaryStage) throws Exception { - synchronized (FXBrwsr.class) { - INSTANCE = this; - FXBrwsr.class.notifyAll(); - } - BorderPane r = new BorderPane(); - Scene scene = new Scene(r, 800, 600); - primaryStage.setScene(scene); - primaryStage.show(); - this.root = r; - } - - private WebView newView(final URL url, final FXPresenter onLoad) { - final WebView view = new WebView(); - view.setContextMenuEnabled(false); - view.getEngine().setOnAlert(new EventHandler>() { - @Override - public void handle(WebEvent t) { - final Stage dialogStage = new Stage(); - dialogStage.initModality(Modality.WINDOW_MODAL); - dialogStage.setTitle("Warning"); - final Button button = new Button("Close"); - final Text text = new Text(t.getData()); - VBox box = new VBox(); - box.setAlignment(Pos.CENTER); - box.setSpacing(10); - box.setPadding(new Insets(10)); - box.getChildren().addAll(text, button); - dialogStage.setScene(new Scene(box)); - button.setCancelButton(true); - button.setOnAction(new EventHandler() { - @Override - public void handle(ActionEvent t) { - dialogStage.close(); - } - }); - dialogStage.centerOnScreen(); - dialogStage.showAndWait(); - } - }); - root.setCenter(view); - final Worker w = view.getEngine().getLoadWorker(); - w.stateProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue ov, Worker.State t, Worker.State newState) { - if (newState.equals(Worker.State.SUCCEEDED)) { - onLoad.onPageLoad(); - } - if (newState.equals(Worker.State.FAILED)) { - throw new IllegalStateException("Failed to load " + url); - } - } - }); - return view; - } - - static void waitFinished() { - for (;;) { - try { - FINISHED.await(); - break; - } catch (InterruptedException ex) { - LOG.log(Level.INFO, null, ex); - } - } - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/main/java/org/apidesign/html/boot/fx/FXInspect.java --- a/boot-fx/src/main/java/org/apidesign/html/boot/fx/FXInspect.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.fx; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.net.InetAddress; -import java.net.Socket; -import java.nio.charset.StandardCharsets; -import java.util.logging.Level; -import java.util.logging.Logger; -import javafx.application.Platform; -import javafx.scene.web.WebEngine; -import javafx.util.Callback; - -/** - * - * @author Jaroslav Tulach - */ -final class FXInspect implements Runnable { - private static final Logger LOG = Logger.getLogger(FXInspect.class.getName()); - - - private final WebEngine engine; - private final ObjectInputStream input; - private Dbgr dbg; - - private FXInspect(WebEngine engine, int port) throws IOException { - this.engine = engine; - - Socket socket = new Socket(InetAddress.getByName(null), port); - ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); - this.input = new ObjectInputStream(socket.getInputStream()); - initializeDebugger(output); - } - - static boolean initialize(WebEngine engine) { - final int inspectPort = Integer.getInteger("netbeans.inspect.port", -1); // NOI18N - if (inspectPort != -1) { - try { - FXInspect inspector = new FXInspect(engine, inspectPort); - Thread t = new Thread(inspector, "FX<->NetBeans Inspector"); - t.start(); - return true; - } catch (IOException ex) { - LOG.log(Level.INFO, "Cannot connect to NetBeans IDE to port " + inspectPort, ex); // NOI18N - } - } - return false; - } - - private void initializeDebugger(final ObjectOutputStream output) { - Platform.runLater(new Runnable() { - @Override - public void run() { - dbg = new Dbgr(engine, new Callback() { - @Override - public Void call(String message) { - try { - byte[] bytes = message.getBytes(StandardCharsets.UTF_8); - output.writeInt(bytes.length); - output.write(bytes); - output.flush(); - } catch (IOException ioex) { - ioex.printStackTrace(); - } - return null; - } - }); - } - }); - } - - @Override - public void run() { - try { - while (true) { - int length = input.readInt(); - byte[] bytes = new byte[length]; - input.readFully(bytes); - final String message = new String(bytes, StandardCharsets.UTF_8); - Platform.runLater(new Runnable() { - @Override - public void run() { - dbg.sendMessage(message); - } - }); - } - } catch (IOException ex) { - LOG.log(Level.WARNING, null, ex); - } - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/main/java/org/apidesign/html/boot/fx/FXPresenter.java --- a/boot-fx/src/main/java/org/apidesign/html/boot/fx/FXPresenter.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.fx; - -import java.io.BufferedReader; -import java.io.File; -import java.io.Reader; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import javafx.application.Platform; -import javafx.scene.web.WebEngine; -import javafx.scene.web.WebView; -import net.java.html.boot.BrowserBuilder; -import netscape.javascript.JSObject; -import org.apidesign.html.boot.spi.Fn; -import org.openide.util.lookup.ServiceProvider; - -/** This is an implementation class, use {@link BrowserBuilder} API. Just - * include this JAR on classpath and the {@link BrowserBuilder} API will find - * this implementation automatically. - * - * @author Jaroslav Tulach - */ -@ServiceProvider(service = Fn.Presenter.class) -public final class FXPresenter extends AbstractFXPresenter { - static { - try { - try { - Class c = Class.forName("javafx.application.Platform"); - // OK, on classpath - } catch (ClassNotFoundException classNotFoundException) { - Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); - m.setAccessible(true); - File f = new File(System.getProperty("java.home"), "lib/jfxrt.jar"); - if (f.exists()) { - URL l = f.toURI().toURL(); - m.invoke(ClassLoader.getSystemClassLoader(), l); - } - } - } catch (Exception ex) { - throw new LinkageError("Can't add jfxrt.jar on the classpath", ex); - } - } - - protected void waitFinished() { - FXBrwsr.waitFinished(); - } - - protected WebView findView(final URL resource) { - return FXBrwsr.findWebView(resource, this); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,190 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.fx; + +import java.io.BufferedReader; +import java.io.Reader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javafx.application.Platform; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebView; +import netscape.javascript.JSObject; +import org.apidesign.html.boot.spi.Fn; + +/** + * + * @author Jaroslav Tulach + */ +public abstract class AbstractFXPresenter implements Fn.Presenter { + static final Logger LOG = Logger.getLogger(FXPresenter.class.getName()); + protected static int cnt; + protected List scripts; + protected Runnable onLoad; + protected WebEngine engine; + + @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).append(n); + sep = ","; + } + sb.append(") {\n"); + sb.append(code); + sb.append("};"); + sb.append("})()"); + if (LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, + "defining function #{0}:\n{1}\n", + new Object[] { ++cnt, code } + ); + } + JSObject x = (JSObject) engine.executeScript(sb.toString()); + return new JSFn(this, x, cnt); + } + + @Override + public void loadScript(Reader code) throws Exception { + BufferedReader r = new BufferedReader(code); + StringBuilder sb = new StringBuilder(); + for (;;) { + String l = r.readLine(); + if (l == null) { + break; + } + sb.append(l).append('\n'); + } + final String script = sb.toString(); + if (scripts != null) { + scripts.add(script); + } + engine.executeScript(script); + } + + protected final void onPageLoad() { + if (scripts != null) { + for (String s : scripts) { + engine.executeScript(s); + } + } + onLoad.run(); + } + + @Override + public void displayPage(final URL resource, final Runnable onLoad) { + this.onLoad = onLoad; + final WebView view = findView(resource); + this.engine = view.getEngine(); + try { + if (FXInspect.initialize(engine)) { + scripts = new ArrayList(); + } + } catch (Throwable ex) { + ex.printStackTrace(); + } + + class Run implements Runnable { + + @Override + public void run() { + if (scripts != null) { + view.setContextMenuEnabled(true); + } + engine.load(resource.toExternalForm()); + } + } + Run run = new Run(); + if (Platform.isFxApplicationThread()) { + run.run(); + } else { + Platform.runLater(run); + } + waitFinished(); + } + + protected abstract void waitFinished(); + + protected abstract WebView findView(final URL resource); + + private static final class JSFn extends Fn { + + private final JSObject fn; + private static int call; + private final int id; + + public JSFn(AbstractFXPresenter p, JSObject fn, int id) { + super(p); + this.fn = fn; + this.id = id; + } + + @Override + public Object invoke(Object thiz, Object... args) throws Exception { + try { + if (LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "calling {0} function #{1}", new Object[]{++call, id}); + } + List all = new ArrayList(args.length + 1); + all.add(thiz == null ? fn : thiz); + all.addAll(Arrays.asList(args)); + Object ret = fn.call("call", all.toArray()); // NOI18N + return ret == fn ? null : ret; + } catch (Error t) { + t.printStackTrace(); + throw t; + } catch (Exception t) { + t.printStackTrace(); + throw t; + } + } + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/main/java/org/netbeans/html/boot/fx/Dbgr.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/Dbgr.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,87 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.fx; + +import java.lang.reflect.Method; +import java.util.logging.Level; +import javafx.scene.web.WebEngine; +import javafx.util.Callback; +import static org.netbeans.html.boot.fx.AbstractFXPresenter.LOG; + +/** Debugger bridge to shield us from propriatory impl APIs. + * + * @author Jaroslav Tulach + */ +final class Dbgr { + final Object dbg; + final Method sendMsg; + + Dbgr(WebEngine eng, Callback callback) { + Object d; + Method m; + try { + d = eng.getClass().getMethod("impl_getDebugger").invoke(eng); // NOI18N + Class debugger = eng.getClass().getClassLoader().loadClass("com.sun.javafx.scene.web.Debugger"); // NOI18N + debugger.getMethod("setEnabled", boolean.class).invoke(d, true); // NOI18N + debugger.getMethod("setMessageCallback", Callback.class).invoke(d, callback); // NOI18N + m = debugger.getMethod("sendMessage", String.class); // NOI18N + } catch (Exception ex) { + LOG.log(Level.INFO, null, ex); + d = null; + m = null; + } + dbg = d; + sendMsg = m; + } + + void sendMessage(String msg) { + try { + if (dbg != null) { + sendMsg.invoke(dbg, msg); + } + } catch (Exception ex) { + LOG.log(Level.INFO, null, ex); + } + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,193 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.fx; + +import java.net.URL; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.logging.Level; +import java.util.logging.Logger; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.concurrent.Worker; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; +import javafx.scene.web.WebEvent; +import javafx.scene.web.WebView; +import javafx.stage.Modality; +import javafx.stage.Stage; + +/** This is an implementation class, use {@link BrowserBuilder} API. Just + * include this JAR on classpath and the {@link BrowserBuilder} API will find + * this implementation automatically. + */ +public class FXBrwsr extends Application { + private static final Logger LOG = Logger.getLogger(FXBrwsr.class.getName()); + private static FXBrwsr INSTANCE; + private static final CountDownLatch FINISHED = new CountDownLatch(1); + private BorderPane root; + + public static synchronized WebView findWebView(final URL url, final FXPresenter onLoad) { + if (INSTANCE == null) { + Executors.newFixedThreadPool(1).submit(new Runnable() { + @Override + public void run() { + try { + FXBrwsr.launch(FXBrwsr.class); + } catch (Throwable ex) { + ex.printStackTrace(); + } finally { + FINISHED.countDown(); + } + } + }); + } + while (INSTANCE == null) { + try { + FXBrwsr.class.wait(); + } catch (InterruptedException ex) { + // wait more + } + } + if (!Platform.isFxApplicationThread()) { + final WebView[] arr = {null}; + final CountDownLatch waitForResult = new CountDownLatch(1); + Platform.runLater(new Runnable() { + @Override + public void run() { + arr[0] = INSTANCE.newView(url, onLoad); + waitForResult.countDown(); + } + }); + for (;;) { + try { + waitForResult.await(); + break; + } catch (InterruptedException ex) { + LOG.log(Level.INFO, null, ex); + } + } + return arr[0]; + } else { + return INSTANCE.newView(url, onLoad); + } + } + + @Override + public void start(Stage primaryStage) throws Exception { + synchronized (FXBrwsr.class) { + INSTANCE = this; + FXBrwsr.class.notifyAll(); + } + BorderPane r = new BorderPane(); + Scene scene = new Scene(r, 800, 600); + primaryStage.setScene(scene); + primaryStage.show(); + this.root = r; + } + + private WebView newView(final URL url, final FXPresenter onLoad) { + final WebView view = new WebView(); + view.setContextMenuEnabled(false); + view.getEngine().setOnAlert(new EventHandler>() { + @Override + public void handle(WebEvent t) { + final Stage dialogStage = new Stage(); + dialogStage.initModality(Modality.WINDOW_MODAL); + dialogStage.setTitle("Warning"); + final Button button = new Button("Close"); + final Text text = new Text(t.getData()); + VBox box = new VBox(); + box.setAlignment(Pos.CENTER); + box.setSpacing(10); + box.setPadding(new Insets(10)); + box.getChildren().addAll(text, button); + dialogStage.setScene(new Scene(box)); + button.setCancelButton(true); + button.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent t) { + dialogStage.close(); + } + }); + dialogStage.centerOnScreen(); + dialogStage.showAndWait(); + } + }); + root.setCenter(view); + final Worker w = view.getEngine().getLoadWorker(); + w.stateProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue ov, Worker.State t, Worker.State newState) { + if (newState.equals(Worker.State.SUCCEEDED)) { + onLoad.onPageLoad(); + } + if (newState.equals(Worker.State.FAILED)) { + throw new IllegalStateException("Failed to load " + url); + } + } + }); + return view; + } + + static void waitFinished() { + for (;;) { + try { + FINISHED.await(); + break; + } catch (InterruptedException ex) { + LOG.log(Level.INFO, null, ex); + } + } + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,134 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.fx; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.util.logging.Level; +import java.util.logging.Logger; +import javafx.application.Platform; +import javafx.scene.web.WebEngine; +import javafx.util.Callback; + +/** + * + * @author Jaroslav Tulach + */ +final class FXInspect implements Runnable { + private static final Logger LOG = Logger.getLogger(FXInspect.class.getName()); + + + private final WebEngine engine; + private final ObjectInputStream input; + private Dbgr dbg; + + private FXInspect(WebEngine engine, int port) throws IOException { + this.engine = engine; + + Socket socket = new Socket(InetAddress.getByName(null), port); + ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); + this.input = new ObjectInputStream(socket.getInputStream()); + initializeDebugger(output); + } + + static boolean initialize(WebEngine engine) { + final int inspectPort = Integer.getInteger("netbeans.inspect.port", -1); // NOI18N + if (inspectPort != -1) { + try { + FXInspect inspector = new FXInspect(engine, inspectPort); + Thread t = new Thread(inspector, "FX<->NetBeans Inspector"); + t.start(); + return true; + } catch (IOException ex) { + LOG.log(Level.INFO, "Cannot connect to NetBeans IDE to port " + inspectPort, ex); // NOI18N + } + } + return false; + } + + private void initializeDebugger(final ObjectOutputStream output) { + Platform.runLater(new Runnable() { + @Override + public void run() { + dbg = new Dbgr(engine, new Callback() { + @Override + public Void call(String message) { + try { + byte[] bytes = message.getBytes(StandardCharsets.UTF_8); + output.writeInt(bytes.length); + output.write(bytes); + output.flush(); + } catch (IOException ioex) { + ioex.printStackTrace(); + } + return null; + } + }); + } + }); + } + + @Override + public void run() { + try { + while (true) { + int length = input.readInt(); + byte[] bytes = new byte[length]; + input.readFully(bytes); + final String message = new String(bytes, StandardCharsets.UTF_8); + Platform.runLater(new Runnable() { + @Override + public void run() { + dbg.sendMessage(message); + } + }); + } + } catch (IOException ex) { + LOG.log(Level.WARNING, null, ex); + } + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,98 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.fx; + +import java.io.BufferedReader; +import java.io.File; +import java.io.Reader; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javafx.application.Platform; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebView; +import net.java.html.boot.BrowserBuilder; +import netscape.javascript.JSObject; +import org.apidesign.html.boot.spi.Fn; +import org.openide.util.lookup.ServiceProvider; + +/** This is an implementation class, use {@link BrowserBuilder} API. Just + * include this JAR on classpath and the {@link BrowserBuilder} API will find + * this implementation automatically. + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service = Fn.Presenter.class) +public final class FXPresenter extends AbstractFXPresenter { + static { + try { + try { + Class c = Class.forName("javafx.application.Platform"); + // OK, on classpath + } catch (ClassNotFoundException classNotFoundException) { + Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + m.setAccessible(true); + File f = new File(System.getProperty("java.home"), "lib/jfxrt.jar"); + if (f.exists()) { + URL l = f.toURI().toURL(); + m.invoke(ClassLoader.getSystemClassLoader(), l); + } + } + } catch (Exception ex) { + throw new LinkageError("Can't add jfxrt.jar on the classpath", ex); + } + } + + protected void waitFinished() { + FXBrwsr.waitFinished(); + } + + protected WebView findView(final URL resource) { + return FXBrwsr.findWebView(resource, this); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java --- a/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java Mon Dec 16 15:48:09 2013 +0100 +++ b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -95,7 +95,7 @@ } private void doTest() throws Throwable { - URL u = FXBrowsersOnResourceTest.class.getResource("/org/apidesign/html/boot/fx/empty.html"); + URL u = FXBrowsersOnResourceTest.class.getResource("/org/netbeans/html/boot/fx/empty.html"); assertNotNull(u, "URL found"); FXBrowsers.load(App.getV1(), u, OnPages.class, "first"); @@ -131,7 +131,7 @@ assertEquals(increment(), 1, "Now it is one"); - URL u = FXBrowsersOnResourceTest.class.getResource("/org/apidesign/html/boot/fx/empty.html"); + URL u = FXBrowsersOnResourceTest.class.getResource("/org/netbeans/html/boot/fx/empty.html"); assertNotNull(u, "URL found"); FXBrowsers.load(App.getV2(), u, OnPages.class, "second", "Hello"); diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java --- a/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java Mon Dec 16 15:48:09 2013 +0100 +++ b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -95,7 +95,7 @@ } private void doTest() throws Throwable { - URL u = FXBrowsersTest.class.getResource("/org/apidesign/html/boot/fx/empty.html"); + URL u = FXBrowsersTest.class.getResource("/org/netbeans/html/boot/fx/empty.html"); assertNotNull(u, "URL found"); FXBrowsers.load(App.getV1(), u, OnPages.class, "first"); @@ -130,7 +130,7 @@ assertEquals(increment(), 1, "Now it is one"); - URL u = FXBrowsersTest.class.getResource("/org/apidesign/html/boot/fx/empty.html"); + URL u = FXBrowsersTest.class.getResource("/org/netbeans/html/boot/fx/empty.html"); assertNotNull(u, "URL found"); FXBrowsers.load(App.getV2(), u, OnPages.class, "second", "Hello"); diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/test/java/org/apidesign/html/boot/fx/BootstrapTest.java --- a/boot-fx/src/test/java/org/apidesign/html/boot/fx/BootstrapTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.fx; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executors; -import net.java.html.boot.BrowserBuilder; -import org.apidesign.html.boot.impl.FnContext; -import org.apidesign.html.boot.spi.Fn; -import org.testng.annotations.Factory; -import org.testng.annotations.Test; - -/** - * - * @author Jaroslav Tulach - */ -public class BootstrapTest { - private static Class browserClass; - private static Fn.Presenter browserPresenter; - - public BootstrapTest() { - } - - @Factory public static Object[] compatibilityTests() throws Exception { - final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(BootstrapTest.class). - loadPage("empty.html"). - invoke("initialized"); - - Executors.newSingleThreadExecutor().submit(new Runnable() { - @Override - public void run() { - bb.showAndWait(); - } - }); - - List res = new ArrayList(); - Class test = - loadClass().getClassLoader().loadClass(Test.class.getName()). - asSubclass(Annotation.class); - for (Method m : loadClass().getMethods()) { - if (m.getAnnotation(test) != null) { - res.add(new KOFx(browserPresenter, m)); - } - } - return res.toArray(); - } - - static synchronized Class loadClass() throws InterruptedException { - while (browserClass == null) { - BootstrapTest.class.wait(); - } - return browserClass; - } - - public static synchronized void ready(Class browserCls) throws Exception { - browserClass = browserCls; - browserPresenter = FnContext.currentPresenter(); - BootstrapTest.class.notifyAll(); - } - - public static void initialized() throws Exception { - Class classpathClass = ClassLoader.getSystemClassLoader().loadClass(BootstrapTest.class.getName()); - Method m = classpathClass.getMethod("ready", Class.class); - m.invoke(null, FXPresenterTst.class); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/test/java/org/apidesign/html/boot/fx/FXPresenterTst.java --- a/boot-fx/src/test/java/org/apidesign/html/boot/fx/FXPresenterTst.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.fx; - -import net.java.html.js.JavaScriptBody; -import static org.testng.Assert.*; -import org.testng.annotations.Test; - -/** - * - * @author Jaroslav Tulach - */ -public class FXPresenterTst { - @Test public void showClassLoader() { - R run = new R(); - callback(run); - assertEquals(run.cnt, 1, "Can call even private implementation classes"); - } - - @JavaScriptBody(args = { "r" }, javacall = true, body = "r.@java.lang.Runnable::run()();") - private static native void callback(Runnable r); - - private static class R implements Runnable { - int cnt; - - @Override - public void run() { - cnt++; - } - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/test/java/org/apidesign/html/boot/fx/KOFx.java --- a/boot-fx/src/test/java/org/apidesign/html/boot/fx/KOFx.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.fx; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import javafx.application.Platform; -import org.apidesign.html.boot.impl.FnContext; -import org.apidesign.html.boot.spi.Fn; -import org.testng.IHookCallBack; -import org.testng.IHookable; -import org.testng.ITest; -import org.testng.ITestResult; -import org.testng.annotations.Test; - -/** - * - * @author Jaroslav Tulach - */ -public final class KOFx implements ITest, IHookable, Runnable { - private final Fn.Presenter p; - private final Method m; - private Object result; - private Object inst; - - KOFx(Fn.Presenter p, Method m) { - this.p = p; - this.m = m; - } - - @Override - public String getTestName() { - return m.getName(); - } - - @Test - public synchronized void executeTest() throws Exception { - if (result == null) { - Platform.runLater(this); - wait(); - } - if (result instanceof Exception) { - throw (Exception)result; - } - if (result instanceof Error) { - throw (Error)result; - } - } - - @Override - public synchronized void run() { - boolean notify = true; - try { - FnContext.currentPresenter(p); - if (inst == null) { - inst = m.getDeclaringClass().newInstance(); - } - result = m.invoke(inst); - if (result == null) { - result = this; - } - } catch (InvocationTargetException ex) { - Throwable r = ex.getTargetException(); - if (r instanceof InterruptedException) { - notify = false; - Platform.runLater(this); - return; - } - result = r; - } catch (Exception ex) { - result = ex; - } finally { - if (notify) { - notifyAll(); - } - FnContext.currentPresenter(null); - } - } - - @Override - public void run(IHookCallBack ihcb, ITestResult itr) { - ihcb.runTestMethod(itr); - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/test/java/org/netbeans/html/boot/fx/BootstrapTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/BootstrapTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,109 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.fx; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import net.java.html.boot.BrowserBuilder; +import org.netbeans.html.boot.impl.FnContext; +import org.apidesign.html.boot.spi.Fn; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class BootstrapTest { + private static Class browserClass; + private static Fn.Presenter browserPresenter; + + public BootstrapTest() { + } + + @Factory public static Object[] compatibilityTests() throws Exception { + final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(BootstrapTest.class). + loadPage("empty.html"). + invoke("initialized"); + + Executors.newSingleThreadExecutor().submit(new Runnable() { + @Override + public void run() { + bb.showAndWait(); + } + }); + + List res = new ArrayList(); + Class test = + loadClass().getClassLoader().loadClass(Test.class.getName()). + asSubclass(Annotation.class); + for (Method m : loadClass().getMethods()) { + if (m.getAnnotation(test) != null) { + res.add(new KOFx(browserPresenter, m)); + } + } + return res.toArray(); + } + + static synchronized Class loadClass() throws InterruptedException { + while (browserClass == null) { + BootstrapTest.class.wait(); + } + return browserClass; + } + + public static synchronized void ready(Class browserCls) throws Exception { + browserClass = browserCls; + browserPresenter = FnContext.currentPresenter(); + BootstrapTest.class.notifyAll(); + } + + public static void initialized() throws Exception { + Class classpathClass = ClassLoader.getSystemClassLoader().loadClass(BootstrapTest.class.getName()); + Method m = classpathClass.getMethod("ready", Class.class); + m.invoke(null, FXPresenterTst.class); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/test/java/org/netbeans/html/boot/fx/FXPresenterTst.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXPresenterTst.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,71 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.fx; + +import net.java.html.js.JavaScriptBody; +import static org.testng.Assert.*; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class FXPresenterTst { + @Test public void showClassLoader() { + R run = new R(); + callback(run); + assertEquals(run.cnt, 1, "Can call even private implementation classes"); + } + + @JavaScriptBody(args = { "r" }, javacall = true, body = "r.@java.lang.Runnable::run()();") + private static native void callback(Runnable r); + + private static class R implements Runnable { + int cnt; + + @Override + public void run() { + cnt++; + } + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/test/java/org/netbeans/html/boot/fx/KOFx.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/KOFx.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,125 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.fx; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import javafx.application.Platform; +import org.netbeans.html.boot.impl.FnContext; +import org.apidesign.html.boot.spi.Fn; +import org.testng.IHookCallBack; +import org.testng.IHookable; +import org.testng.ITest; +import org.testng.ITestResult; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public final class KOFx implements ITest, IHookable, Runnable { + private final Fn.Presenter p; + private final Method m; + private Object result; + private Object inst; + + KOFx(Fn.Presenter p, Method m) { + this.p = p; + this.m = m; + } + + @Override + public String getTestName() { + return m.getName(); + } + + @Test + public synchronized void executeTest() throws Exception { + if (result == null) { + Platform.runLater(this); + wait(); + } + if (result instanceof Exception) { + throw (Exception)result; + } + if (result instanceof Error) { + throw (Error)result; + } + } + + @Override + public synchronized void run() { + boolean notify = true; + try { + FnContext.currentPresenter(p); + if (inst == null) { + inst = m.getDeclaringClass().newInstance(); + } + result = m.invoke(inst); + if (result == null) { + result = this; + } + } catch (InvocationTargetException ex) { + Throwable r = ex.getTargetException(); + if (r instanceof InterruptedException) { + notify = false; + Platform.runLater(this); + return; + } + result = r; + } catch (Exception ex) { + result = ex; + } finally { + if (notify) { + notifyAll(); + } + FnContext.currentPresenter(null); + } + } + + @Override + public void run(IHookCallBack ihcb, ITestResult itr) { + ihcb.runTestMethod(itr); + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/test/resources/org/apidesign/html/boot/fx/empty.html --- a/boot-fx/src/test/resources/org/apidesign/html/boot/fx/empty.html Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ - - - - - FX Presenter Harness - - - - -
FX Presenter Harness
- - diff -r 700087d2a5d3 -r 92fb71afdc0e boot-fx/src/test/resources/org/netbeans/html/boot/fx/empty.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot-fx/src/test/resources/org/netbeans/html/boot/fx/empty.html Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,55 @@ + + + + + FX Presenter Harness + + + + +
FX Presenter Harness
+ + diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/net/java/html/boot/BrowserBuilder.java --- a/boot/src/main/java/net/java/html/boot/BrowserBuilder.java Mon Dec 16 15:48:09 2013 +0100 +++ b/boot/src/main/java/net/java/html/boot/BrowserBuilder.java Mon Dec 16 16:59:43 2013 +0100 @@ -54,10 +54,10 @@ import java.util.logging.Level; import java.util.logging.Logger; import net.java.html.js.JavaScriptBody; -import org.apidesign.html.boot.impl.FnUtils; +import org.netbeans.html.boot.impl.FnUtils; import org.apidesign.html.boot.spi.Fn; -import org.apidesign.html.boot.impl.FindResources; -import org.apidesign.html.boot.impl.FnContext; +import org.netbeans.html.boot.impl.FindResources; +import org.netbeans.html.boot.impl.FnContext; /** Use this builder to launch your Java/HTML based application. Typical * usage in a main method of your application looks like this: diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/apidesign/html/boot/impl/FindResources.java --- a/boot/src/main/java/org/apidesign/html/boot/impl/FindResources.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -import java.net.URL; -import java.util.Collection; - -/** - * - * @author Jaroslav Tulach - */ -public interface FindResources { - - public void findResources(String path, Collection results, boolean oneIsEnough); - -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/apidesign/html/boot/impl/FnContext.java --- a/boot/src/main/java/org/apidesign/html/boot/impl/FnContext.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -import java.io.Closeable; -import java.io.IOException; -import java.util.logging.Logger; -import org.apidesign.html.boot.spi.Fn; - -/** - * - * @author Jaroslav Tulach - */ -public final class FnContext implements Closeable { - private static final Logger LOG = Logger.getLogger(FnContext.class.getName()); - - private Object prev; - private FnContext(Fn.Presenter p) { - this.prev = p; - } - - @Override - public void close() throws IOException { - if (prev != this) { - currentPresenter((Fn.Presenter)prev); - prev = this; - } - } -/* - @Override - protected void finalize() throws Throwable { - if (prev != null) { - LOG.warning("Unclosed context!"); - } - } -*/ - public static Closeable activate(Fn.Presenter newP) { - return new FnContext(currentPresenter(newP)); - } - - - private static final ThreadLocal CURRENT = new ThreadLocal(); - - public static Fn.Presenter currentPresenter(Fn.Presenter p) { - Fn.Presenter prev = CURRENT.get(); - CURRENT.set(p); - return prev; - } - - public static Fn.Presenter currentPresenter() { - Fn.Presenter p = CURRENT.get(); - if (p == null) { - throw new IllegalStateException("No current WebView context around!"); - } - return p; - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java --- a/boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,597 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -import java.io.Closeable; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import java.util.concurrent.Callable; -import org.apidesign.html.boot.spi.Fn; -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.signature.SignatureReader; -import org.objectweb.asm.signature.SignatureVisitor; -import org.objectweb.asm.signature.SignatureWriter; - -/** - * - * @author Jaroslav Tulach - */ -public final class FnUtils implements Fn.Presenter { - - private FnUtils() { - } - - public static boolean isJavaScriptCapable(ClassLoader l) { - if (l instanceof JsClassLoader) { - return true; - } - Class clazz; - try (Closeable c = Fn.activate(new FnUtils())) { - clazz = Class.forName(Test.class.getName(), true, l); - final Object is = ((Callable)clazz.newInstance()).call(); - return Boolean.TRUE.equals(is); - } catch (Exception ex) { - return false; - } - } - - public static boolean isValid(Fn fn) { - return fn != null && fn.isValid(); - } - - public static ClassLoader newLoader(final FindResources f, final Fn.Presenter d, ClassLoader parent) { - return new JsClassLoader(parent) { - @Override - protected URL findResource(String name) { - List l = res(name, true); - return l.isEmpty() ? null : l.get(0); - } - - @Override - protected Enumeration findResources(String name) { - return Collections.enumeration(res(name, false)); - } - - private List res(String name, boolean oneIsEnough) { - List l = new ArrayList(); - f.findResources(name, l, oneIsEnough); - return l; - } - - @Override - protected Fn defineFn(String code, String... names) { - return d.defineFn(code, names); - } - - @Override - protected void loadScript(Reader code) throws Exception { - d.loadScript(code); - } - }; - } - - static String callback(final String body) { - return new JsCallback() { - @Override - protected CharSequence callMethod( - String ident, String fqn, String method, String params - ) { - StringBuilder sb = new StringBuilder(); - sb.append("vm.").append(mangle(fqn, method, params)); - sb.append("("); - if (ident != null) { - sb.append(ident); - } - return sb; - } - - }.parse(body); - } - - static void loadScript(ClassLoader jcl, String resource) { - final InputStream script = jcl.getResourceAsStream(resource); - if (script == null) { - throw new NullPointerException("Can't find " + resource); - } - try { - Reader isr = null; - try { - isr = new InputStreamReader(script, "UTF-8"); - FnContext.currentPresenter().loadScript(isr); - } finally { - if (isr != null) { - isr.close(); - } - } - } catch (Exception ex) { - throw new IllegalStateException("Can't execute " + resource, ex); - } - } - - @Override - public Fn defineFn(String code, String... names) { - return new TrueFn(); - } - - @Override - public void displayPage(URL page, Runnable onPageLoad) { - } - - @Override - public void loadScript(Reader code) throws Exception { - } - - private static final class FindInClass extends ClassVisitor { - private String name; - private int found; - private ClassLoader loader; - private String resource; - - public FindInClass(ClassLoader l, ClassVisitor cv) { - super(Opcodes.ASM4, cv); - this.loader = l; - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - this.name = name; - super.visit(version, access, name, signature, superName, interfaces); - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - if ("Lnet/java/html/js/JavaScriptResource;".equals(desc)) { - return new LoadResource(); - } - return super.visitAnnotation(desc, visible); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - return new FindInMethod(access, name, desc, - super.visitMethod(access & (~Opcodes.ACC_NATIVE), name, desc, signature, exceptions) - ); - } - - private final class FindInMethod extends MethodVisitor { - - private final String name; - private final String desc; - private final int access; - private List args; - private String body; - private boolean bodyGenerated; - - public FindInMethod(int access, String name, String desc, MethodVisitor mv) { - super(Opcodes.ASM4, mv); - this.access = access; - this.name = name; - this.desc = desc; - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - if ("Lnet/java/html/js/JavaScriptBody;".equals(desc) // NOI18N - || "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;".equals(desc) // NOI18N - ) { - found++; - return new FindInAnno(); - } - return super.visitAnnotation(desc, visible); - } - - private void generateJSBody(List args, String body) { - this.args = args; - this.body = body; - } - - @Override - public void visitCode() { - if (body == null) { - return; - } - generateBody(); - } - - private boolean generateBody() { - if (bodyGenerated) { - return false; - } - bodyGenerated = true; - - super.visitFieldInsn( - Opcodes.GETSTATIC, FindInClass.this.name, - "$$fn$$" + name + "_" + found, - "Lorg/apidesign/html/boot/spi/Fn;" - ); - super.visitInsn(Opcodes.DUP); - super.visitMethodInsn( - Opcodes.INVOKESTATIC, - "org/apidesign/html/boot/spi/Fn", "isValid", - "(Lorg/apidesign/html/boot/spi/Fn;)Z" - ); - Label ifNotNull = new Label(); - super.visitJumpInsn(Opcodes.IFNE, ifNotNull); - - // init Fn - super.visitInsn(Opcodes.POP); - super.visitLdcInsn(Type.getObjectType(FindInClass.this.name)); - super.visitLdcInsn(body); - super.visitIntInsn(Opcodes.SIPUSH, args.size()); - super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String"); - boolean needsVM = false; - for (int i = 0; i < args.size(); i++) { - assert !needsVM; - String argName = args.get(i); - needsVM = "vm".equals(argName); - super.visitInsn(Opcodes.DUP); - super.visitIntInsn(Opcodes.BIPUSH, i); - super.visitLdcInsn(argName); - super.visitInsn(Opcodes.AASTORE); - } - super.visitMethodInsn(Opcodes.INVOKESTATIC, - "org/apidesign/html/boot/spi/Fn", "define", - "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;" - ); - if (resource != null) { - super.visitLdcInsn(Type.getObjectType(FindInClass.this.name)); - super.visitLdcInsn(resource); - super.visitMethodInsn(Opcodes.INVOKESTATIC, - "org/apidesign/html/boot/spi/Fn", "preload", - "(Lorg/apidesign/html/boot/spi/Fn;Ljava/lang/Class;Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;" - ); - } - super.visitInsn(Opcodes.DUP); - super.visitFieldInsn( - Opcodes.PUTSTATIC, FindInClass.this.name, - "$$fn$$" + name + "_" + found, - "Lorg/apidesign/html/boot/spi/Fn;" - ); - // end of Fn init - - super.visitLabel(ifNotNull); - - final int offset; - if ((access & Opcodes.ACC_STATIC) == 0) { - offset = 1; - super.visitIntInsn(Opcodes.ALOAD, 0); - } else { - offset = 0; - super.visitInsn(Opcodes.ACONST_NULL); - } - - super.visitIntInsn(Opcodes.SIPUSH, args.size()); - super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); - - class SV extends SignatureVisitor { - - private boolean nowReturn; - private Type returnType; - private int index; - private int loadIndex = offset; - - public SV() { - super(Opcodes.ASM4); - } - - @Override - public void visitBaseType(char descriptor) { - final Type t = Type.getType("" + descriptor); - if (nowReturn) { - returnType = t; - return; - } - FindInMethod.super.visitInsn(Opcodes.DUP); - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++); - FindInMethod.super.visitVarInsn(t.getOpcode(Opcodes.ILOAD), loadIndex++); - String factory; - switch (descriptor) { - case 'I': - factory = "java/lang/Integer"; - break; - case 'J': - factory = "java/lang/Long"; - loadIndex++; - break; - case 'S': - factory = "java/lang/Short"; - break; - case 'F': - factory = "java/lang/Float"; - break; - case 'D': - factory = "java/lang/Double"; - loadIndex++; - break; - case 'Z': - factory = "java/lang/Boolean"; - break; - case 'C': - factory = "java/lang/Character"; - break; - case 'B': - factory = "java/lang/Byte"; - break; - default: - throw new IllegalStateException(t.toString()); - } - FindInMethod.super.visitMethodInsn(Opcodes.INVOKESTATIC, - factory, "valueOf", "(" + descriptor + ")L" + factory + ";" - ); - FindInMethod.super.visitInsn(Opcodes.AASTORE); - } - - @Override - public SignatureVisitor visitArrayType() { - if (nowReturn) { - throw new IllegalStateException("Not supported yet"); - } - loadObject(); - return new SignatureWriter(); - } - - @Override - public void visitClassType(String name) { - if (nowReturn) { - returnType = Type.getObjectType(name); - return; - } - loadObject(); - } - - @Override - public SignatureVisitor visitReturnType() { - nowReturn = true; - return this; - } - - private void loadObject() { - FindInMethod.super.visitInsn(Opcodes.DUP); - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++); - FindInMethod.super.visitVarInsn(Opcodes.ALOAD, loadIndex++); - FindInMethod.super.visitInsn(Opcodes.AASTORE); - } - - } - SV sv = new SV(); - SignatureReader sr = new SignatureReader(desc); - sr.accept(sv); - - if (needsVM) { - FindInMethod.super.visitInsn(Opcodes.DUP); - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, sv.index); - int lastSlash = FindInClass.this.name.lastIndexOf('/'); - String jsCallbacks = FindInClass.this.name.substring(0, lastSlash + 1) + "$JsCallbacks$"; - FindInMethod.super.visitFieldInsn(Opcodes.GETSTATIC, jsCallbacks, "VM", "L" + jsCallbacks + ";"); - FindInMethod.super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jsCallbacks, "current", "()L" + jsCallbacks + ";"); - FindInMethod.super.visitInsn(Opcodes.AASTORE); - } - - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, - "org/apidesign/html/boot/spi/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;" - ); - switch (sv.returnType.getSort()) { - case Type.VOID: - super.visitInsn(Opcodes.RETURN); - break; - case Type.ARRAY: - case Type.OBJECT: - super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName()); - super.visitInsn(Opcodes.ARETURN); - break; - case Type.BOOLEAN: - super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean"); - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, - "java/lang/Boolean", "booleanValue", "()Z" - ); - super.visitInsn(Opcodes.IRETURN); - break; - default: - super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number"); - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, - "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor() - ); - super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN)); - } - return true; - } - - @Override - public void visitEnd() { - super.visitEnd(); - if (body != null) { - if (generateBody()) { - // native method - super.visitMaxs(1, 0); - } - FindInClass.this.visitField( - Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, - "$$fn$$" + name + "_" + found, - "Lorg/apidesign/html/boot/spi/Fn;", - null, null - ); - } - } - - private final class FindInAnno extends AnnotationVisitor { - - private List args = new ArrayList(); - private String body; - private boolean javacall = false; - - public FindInAnno() { - super(Opcodes.ASM4); - } - - @Override - public void visit(String name, Object value) { - if (name == null) { - args.add((String) value); - return; - } - if (name.equals("javacall")) { // NOI18N - javacall = (Boolean) value; - return; - } - assert name.equals("body"); - body = (String) value; - } - - @Override - public AnnotationVisitor visitArray(String name) { - return this; - } - - @Override - public void visitEnd() { - if (body != null) { - if (javacall) { - body = callback(body); - args.add("vm"); - } - generateJSBody(args, body); - } - } - } - } - - private final class LoadResource extends AnnotationVisitor { - - public LoadResource() { - super(Opcodes.ASM4); - } - - @Override - public void visit(String attrName, Object value) { - String relPath = (String) value; - if (relPath.startsWith("/")) { - resource = relPath; - } else { - int last = name.lastIndexOf('/'); - String fullPath = name.substring(0, last + 1) + relPath; - resource = fullPath; - } - } - } - } - - private static class ClassWriterEx extends ClassWriter { - - private ClassLoader loader; - - public ClassWriterEx(ClassLoader l, ClassReader classReader, int flags) { - super(classReader, flags); - this.loader = l; - } - - @Override - protected String getCommonSuperClass(final String type1, final String type2) { - Class c, d; - try { - c = Class.forName(type1.replace('/', '.'), false, loader); - d = Class.forName(type2.replace('/', '.'), false, loader); - } catch (Exception e) { - throw new RuntimeException(e.toString()); - } - if (c.isAssignableFrom(d)) { - return type1; - } - if (d.isAssignableFrom(c)) { - return type2; - } - if (c.isInterface() || d.isInterface()) { - return "java/lang/Object"; - } else { - do { - c = c.getSuperclass(); - } while (!c.isAssignableFrom(d)); - return c.getName().replace('.', '/'); - } - } - } - - static byte[] transform(ClassLoader loader, byte[] arr) { - ClassReader cr = new ClassReader(arr) { - // to allow us to compile with -profile compact1 on - // JDK8 while processing the class as JDK7, the highest - // class format asm 4.1 understands to - @Override - public short readShort(int index) { - short s = super.readShort(index); - if (index == 6 && s > Opcodes.V1_7) { - return Opcodes.V1_7; - } - return s; - } - }; - FindInClass tst = new FindInClass(loader, null); - cr.accept(tst, 0); - if (tst.found > 0) { - ClassWriter w = new ClassWriterEx(loader, cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - FindInClass fic = new FindInClass(loader, w); - cr.accept(fic, 0); - arr = w.toByteArray(); - } - return arr; - } - - private static final class TrueFn extends Fn { - @Override - public Object invoke(Object thiz, Object... args) throws Exception { - return Boolean.TRUE; - } - } // end of TrueFn -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/apidesign/html/boot/impl/JavaScriptProcesor.java --- a/boot/src/main/java/org/apidesign/html/boot/impl/JavaScriptProcesor.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,369 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -import java.io.IOException; -import java.io.Writer; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.Completion; -import javax.annotation.processing.Completions; -import javax.annotation.processing.Messager; -import javax.annotation.processing.Processor; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.ExecutableType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.tools.Diagnostic; -import javax.tools.FileObject; -import javax.tools.StandardLocation; -import net.java.html.js.JavaScriptBody; -import net.java.html.js.JavaScriptResource; -import org.openide.util.lookup.ServiceProvider; - -/** - * - * @author Jaroslav Tulach - */ -@ServiceProvider(service = Processor.class) -public final class JavaScriptProcesor extends AbstractProcessor { - private final Map> javacalls = - new HashMap>(); - - @Override - public Set getSupportedAnnotationTypes() { - Set set = new HashSet(); - set.add(JavaScriptBody.class.getName()); - set.add(JavaScriptResource.class.getName()); - return set; - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - final Messager msg = processingEnv.getMessager(); - for (Element e : roundEnv.getElementsAnnotatedWith(JavaScriptBody.class)) { - if (e.getKind() != ElementKind.METHOD && e.getKind() != ElementKind.CONSTRUCTOR) { - continue; - } - ExecutableElement ee = (ExecutableElement)e; - List params = ee.getParameters(); - - JavaScriptBody jsb = e.getAnnotation(JavaScriptBody.class); - if (jsb == null) { - continue; - } - String[] arr = jsb.args(); - if (params.size() != arr.length) { - msg.printMessage(Diagnostic.Kind.ERROR, "Number of args arguments does not match real arguments!", e); - } - if (!jsb.javacall() && jsb.body().contains(".@")) { - msg.printMessage(Diagnostic.Kind.WARNING, "Usage of .@ usually requires javacall=true", e); - } - if (jsb.javacall()) { - JsCallback verify = new VerifyCallback(e); - try { - verify.parse(jsb.body()); - } catch (IllegalStateException ex) { - msg.printMessage(Diagnostic.Kind.ERROR, ex.getLocalizedMessage(), e); - } - } - } - for (Element e : roundEnv.getElementsAnnotatedWith(JavaScriptResource.class)) { - JavaScriptResource r = e.getAnnotation(JavaScriptResource.class); - if (r == null) { - continue; - } - final String res; - if (r.value().startsWith("/")) { - res = r.value(); - } else { - res = findPkg(e).replace('.', '/') + "/" + r.value(); - } - - try { - FileObject os = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", res); - os.openInputStream().close(); - } catch (IOException ex1) { - try { - FileObject os2 = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", res); - os2.openInputStream().close(); - } catch (IOException ex2) { - msg.printMessage(Diagnostic.Kind.ERROR, "Cannot find " + res + " in " + res + " package", e); - } - } - } - - if (roundEnv.processingOver()) { - generateCallbackClass(javacalls); - javacalls.clear(); - } - return true; - } - - @Override - public Iterable getCompletions(Element e, - AnnotationMirror annotation, ExecutableElement member, String userText - ) { - StringBuilder sb = new StringBuilder(); - if (e.getKind() == ElementKind.METHOD && member.getSimpleName().contentEquals("args")) { - ExecutableElement ee = (ExecutableElement) e; - String sep = ""; - sb.append("{ "); - for (VariableElement ve : ee.getParameters()) { - sb.append(sep).append('"').append(ve.getSimpleName()) - .append('"'); - sep = ", "; - } - sb.append(" }"); - return Collections.nCopies(1, Completions.of(sb.toString())); - } - return null; - } - - private class VerifyCallback extends JsCallback { - private final Element e; - public VerifyCallback(Element e) { - this.e = e; - } - - @Override - protected CharSequence callMethod(String ident, String fqn, String method, String params) { - final TypeElement type = processingEnv.getElementUtils().getTypeElement(fqn); - if (type == null) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Callback to non-existing class " + fqn, e - ); - return ""; - } - ExecutableElement found = null; - StringBuilder foundParams = new StringBuilder(); - for (Element m : type.getEnclosedElements()) { - if (m.getKind() != ElementKind.METHOD) { - continue; - } - if (m.getSimpleName().contentEquals(method)) { - String paramTypes = findParamTypes((ExecutableElement)m); - if (paramTypes.equals(params)) { - found = (ExecutableElement) m; - break; - } - foundParams.append(paramTypes).append("\n"); - } - } - if (found == null) { - if (foundParams.length() == 0) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Callback to class " + fqn + " with unknown method " + method, e - ); - } else { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Callback to " + fqn + "." + method + " with wrong parameters: " + - params + ". Only known parameters are " + foundParams, e - ); - } - } else { - Map mangledOnes = javacalls.get(findPkg(e)); - if (mangledOnes == null) { - mangledOnes = new TreeMap(); - javacalls.put(findPkg(e), mangledOnes); - } - String mangled = JsCallback.mangle(fqn, method, findParamTypes(found)); - mangledOnes.put(mangled, found); - } - return ""; - } - - private String findParamTypes(ExecutableElement method) { - ExecutableType t = (ExecutableType) method.asType(); - StringBuilder sb = new StringBuilder(); - sb.append('('); - for (TypeMirror tm : t.getParameterTypes()) { - if (tm.getKind().isPrimitive()) { - switch (tm.getKind()) { - case INT: sb.append('I'); break; - case BOOLEAN: sb.append('Z'); break; - case BYTE: sb.append('B'); break; - case CHAR: sb.append('C'); break; - case SHORT: sb.append('S'); break; - case DOUBLE: sb.append('D'); break; - case FLOAT: sb.append('F'); break; - case LONG: sb.append('J'); break; - default: - throw new IllegalStateException("Uknown " + tm.getKind()); - } - } else { - while (tm.getKind() == TypeKind.ARRAY) { - sb.append('['); - tm = ((ArrayType)tm).getComponentType(); - } - sb.append('L'); - sb.append(tm.toString().replace('.', '/')); - sb.append(';'); - } - } - sb.append(')'); - return sb.toString(); - } - } - - private void generateCallbackClass(Map> process) { - for (Map.Entry> pkgEn : process.entrySet()) { - String pkgName = pkgEn.getKey(); - Map map = pkgEn.getValue(); - StringBuilder source = new StringBuilder(); - source.append("package ").append(pkgName).append(";\n"); - source.append("public final class $JsCallbacks$ {\n"); - source.append(" static final $JsCallbacks$ VM = new $JsCallbacks$(null);\n"); - source.append(" private final org.apidesign.html.boot.spi.Fn.Presenter p;\n"); - source.append(" private $JsCallbacks$ last;\n"); - source.append(" private $JsCallbacks$(org.apidesign.html.boot.spi.Fn.Presenter p) {\n"); - source.append(" this.p = p;\n"); - source.append(" }\n"); - source.append(" final $JsCallbacks$ current() {\n"); - source.append(" org.apidesign.html.boot.spi.Fn.Presenter now = org.apidesign.html.boot.spi.Fn.activePresenter();\n"); - source.append(" if (now == p) return this;\n"); - source.append(" if (last != null && now == last.p) return last;\n"); - source.append(" return last = new $JsCallbacks$(now);\n"); - source.append(" }\n"); - for (Map.Entry entry : map.entrySet()) { - final String mangled = entry.getKey(); - final ExecutableElement m = entry.getValue(); - final boolean isStatic = m.getModifiers().contains(Modifier.STATIC); - - source.append("\n public java.lang.Object ") - .append(mangled) - .append("("); - - String sep = ""; - if (!isStatic) { - source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName()); - source.append(" self"); - sep = ", "; - } - - int cnt = 0; - for (VariableElement ve : m.getParameters()) { - source.append(sep); - source.append(ve.asType()); - source.append(" arg").append(++cnt); - sep = ", "; - } - source.append(") throws Throwable {\n"); - if (processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_7) >= 0) { - source.append(" try (java.io.Closeable a = org.apidesign.html.boot.spi.Fn.activate(p)) { \n"); - } else { - source.append(" java.io.Closeable a = org.apidesign.html.boot.spi.Fn.activate(p); try {\n"); - } - source.append(" "); - if (m.getReturnType().getKind() != TypeKind.VOID) { - source.append("return "); - } - if (isStatic) { - source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName()); - source.append('.'); - } else { - source.append("self."); - } - source.append(m.getSimpleName()); - source.append("("); - cnt = 0; - sep = ""; - for (VariableElement ve : m.getParameters()) { - source.append(sep); - source.append("arg").append(++cnt); - sep = ", "; - } - source.append(");\n"); - if (m.getReturnType().getKind() == TypeKind.VOID) { - source.append(" return null;\n"); - } - if (processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_7) >= 0) { - source.append(" }\n"); - } else { - - source.append(" } finally {\n"); - source.append(" a.close();\n"); - source.append(" }\n"); - } - source.append(" }\n"); - } - source.append("}\n"); - final String srcName = pkgName + ".$JsCallbacks$"; - try { - Writer w = processingEnv.getFiler().createSourceFile(srcName, - map.values().toArray(new Element[map.size()]) - ).openWriter(); - w.write(source.toString()); - w.close(); - } catch (IOException ex) { - processingEnv.getMessager().printMessage( - Diagnostic.Kind.ERROR, "Can't write " + srcName + ": " + ex.getMessage() - ); - } - } - } - - private static String findPkg(Element e) { - while (e.getKind() != ElementKind.PACKAGE) { - e = e.getEnclosingElement(); - } - return ((PackageElement)e).getQualifiedName().toString(); - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/apidesign/html/boot/impl/JsAgent.java --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsAgent.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.instrument.IllegalClassFormatException; -import java.lang.instrument.Instrumentation; -import java.security.ProtectionDomain; - -/** - * - * @author Jaroslav Tulach - */ -public final class JsAgent implements ClassFileTransformer { - public static void agentmain(String args, Instrumentation instr) { - instr.addTransformer(new JsAgent()); - } - - @Override - public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { - try { - return FnUtils.transform(loader, classfileBuffer); - } catch (Exception ex) { - return classfileBuffer; - } - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/apidesign/html/boot/impl/JsCallback.java --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsCallback.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - - -/** - * - * @author Jaroslav Tulach - */ -abstract class JsCallback { - final String parse(String body) { - StringBuilder sb = new StringBuilder(); - int pos = 0; - for (;;) { - int next = body.indexOf(".@", pos); - if (next == -1) { - sb.append(body.substring(pos)); - body = sb.toString(); - break; - } - int ident = next; - while (ident > 0) { - if (!Character.isJavaIdentifierPart(body.charAt(--ident))) { - ident++; - break; - } - } - String refId = body.substring(ident, next); - - sb.append(body.substring(pos, ident)); - - int sigBeg = body.indexOf('(', next); - int sigEnd = body.indexOf(')', sigBeg); - int colon4 = body.indexOf("::", next); - if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) { - throw new IllegalStateException( - "Wrong format of instance callback. " - + "Should be: 'inst.@pkg.Class::method(Ljava/lang/Object;)(param)':\n" - + body - ); - } - String fqn = body.substring(next + 2, colon4); - String method = body.substring(colon4 + 2, sigBeg); - String params = body.substring(sigBeg, sigEnd + 1); - - int paramBeg = body.indexOf('(', sigEnd + 1); - if (paramBeg == -1) { - throw new IllegalStateException( - "Wrong format of instance callback. " - + "Should be: 'inst.@pkg.Class::method(Ljava/lang/Object;)(param)':\n" - + body - ); - } - - sb.append(callMethod(refId, fqn, method, params)); - if (body.charAt(paramBeg + 1) != (')')) { - sb.append(","); - } - pos = paramBeg + 1; - } - pos = 0; - sb = null; - for (;;) { - int next = body.indexOf("@", pos); - if (next == -1) { - if (sb == null) { - return body; - } - sb.append(body.substring(pos)); - return sb.toString(); - } - if (sb == null) { - sb = new StringBuilder(); - } - - sb.append(body.substring(pos, next)); - - int sigBeg = body.indexOf('(', next); - int sigEnd = body.indexOf(')', sigBeg); - int colon4 = body.indexOf("::", next); - if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) { - throw new IllegalStateException( - "Wrong format of static callback. " - + "Should be: '@pkg.Class::staticMethod(Ljava/lang/Object;)(param)':\n" - + body - ); - } - String fqn = body.substring(next + 1, colon4); - String method = body.substring(colon4 + 2, sigBeg); - String params = body.substring(sigBeg, sigEnd + 1); - - int paramBeg = body.indexOf('(', sigEnd + 1); - - sb.append(callMethod(null, fqn, method, params)); - pos = paramBeg + 1; - } - } - - protected abstract CharSequence callMethod( - String ident, String fqn, String method, String params - ); - - static String mangle(String fqn, String method, String params) { - if (params.startsWith("(")) { - params = params.substring(1); - } - if (params.endsWith(")")) { - params = params.substring(0, params.length() - 1); - } - return - replace(fqn) + "$" + replace(method) + "$" + replace(params); - } - - private static String replace(String orig) { - return orig.replace("_", "_1"). - replace(";", "_2"). - replace("[", "_3"). - replace('.', '_').replace('/', '_'); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -import org.apidesign.html.boot.spi.Fn; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.net.URL; -import java.util.Enumeration; - -/** - * - * @author Jaroslav Tulach - */ -abstract class JsClassLoader extends ClassLoader { - JsClassLoader(ClassLoader parent) { - super(parent); - setDefaultAssertionStatus(JsClassLoader.class.desiredAssertionStatus()); - } - - @Override - protected abstract URL findResource(String name); - - @Override - protected abstract Enumeration findResources(String name); - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - if (name.startsWith("javafx")) { - return Class.forName(name); - } - if (name.startsWith("netscape")) { - return Class.forName(name); - } - if (name.startsWith("com.sun")) { - return Class.forName(name); - } - if (name.equals(JsClassLoader.class.getName())) { - return JsClassLoader.class; - } - if (name.equals(Fn.class.getName())) { - return Fn.class; - } - if (name.equals(Fn.Presenter.class.getName())) { - return Fn.Presenter.class; - } - if (name.equals(FnUtils.class.getName())) { - return FnUtils.class; - } - if ( - name.equals("org.apidesign.html.boot.spi.Fn") || - name.equals("org.apidesign.html.boot.impl.FnUtils") || - name.equals("org.apidesign.html.boot.impl.FnContext") - ) { - return Class.forName(name); - } - URL u = findResource(name.replace('.', '/') + ".class"); - if (u != null) { - InputStream is = null; - try { - is = u.openStream(); - byte[] arr = new byte[is.available()]; - int len = 0; - while (len < arr.length) { - int read = is.read(arr, len, arr.length - len); - if (read == -1) { - throw new IOException("Can't read " + u); - } - len += read; - } - is.close(); - is = null; - arr = FnUtils.transform(JsClassLoader.this, arr); - if (arr != null) { - return defineClass(name, arr, 0, arr.length); - } - } catch (IOException ex) { - throw new ClassNotFoundException("Can't load " + name, ex); - } finally { - try { - if (is != null) is.close(); - } catch (IOException ex) { - throw new ClassNotFoundException(null, ex); - } - } - } - return super.findClass(name); - } - - protected abstract Fn defineFn(String code, String... names); - protected abstract void loadScript(Reader code) throws Exception; -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/apidesign/html/boot/impl/Test.java --- a/boot/src/main/java/org/apidesign/html/boot/impl/Test.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -import java.util.concurrent.Callable; -import net.java.html.js.JavaScriptBody; - -/** - * - * @author Jaroslav Tulach - */ -public final class Test implements Callable { - @Override @JavaScriptBody(args = {}, body = "return true;") - public Boolean call() { - return false; - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/apidesign/html/boot/spi/Fn.java --- a/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java Mon Dec 16 15:48:09 2013 +0100 +++ b/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java Mon Dec 16 16:59:43 2013 +0100 @@ -51,9 +51,8 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.WeakHashMap; import net.java.html.js.JavaScriptBody; -import org.apidesign.html.boot.impl.FnContext; +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...)}. diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/netbeans/html/boot/impl/FindResources.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/FindResources.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,56 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.net.URL; +import java.util.Collection; + +/** + * + * @author Jaroslav Tulach + */ +public interface FindResources { + + public void findResources(String path, Collection results, boolean oneIsEnough); + +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,98 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.util.logging.Logger; +import org.apidesign.html.boot.spi.Fn; + +/** + * + * @author Jaroslav Tulach + */ +public final class FnContext implements Closeable { + private static final Logger LOG = Logger.getLogger(FnContext.class.getName()); + + private Object prev; + private FnContext(Fn.Presenter p) { + this.prev = p; + } + + @Override + public void close() throws IOException { + if (prev != this) { + currentPresenter((Fn.Presenter)prev); + prev = this; + } + } +/* + @Override + protected void finalize() throws Throwable { + if (prev != null) { + LOG.warning("Unclosed context!"); + } + } +*/ + public static Closeable activate(Fn.Presenter newP) { + return new FnContext(currentPresenter(newP)); + } + + + private static final ThreadLocal CURRENT = new ThreadLocal(); + + public static Fn.Presenter currentPresenter(Fn.Presenter p) { + Fn.Presenter prev = CURRENT.get(); + CURRENT.set(p); + return prev; + } + + public static Fn.Presenter currentPresenter() { + Fn.Presenter p = CURRENT.get(); + if (p == null) { + throw new IllegalStateException("No current WebView context around!"); + } + return p; + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,597 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.Callable; +import org.apidesign.html.boot.spi.Fn; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.signature.SignatureReader; +import org.objectweb.asm.signature.SignatureVisitor; +import org.objectweb.asm.signature.SignatureWriter; + +/** + * + * @author Jaroslav Tulach + */ +public final class FnUtils implements Fn.Presenter { + + private FnUtils() { + } + + public static boolean isJavaScriptCapable(ClassLoader l) { + if (l instanceof JsClassLoader) { + return true; + } + Class clazz; + try (Closeable c = Fn.activate(new FnUtils())) { + clazz = Class.forName(Test.class.getName(), true, l); + final Object is = ((Callable)clazz.newInstance()).call(); + return Boolean.TRUE.equals(is); + } catch (Exception ex) { + return false; + } + } + + public static boolean isValid(Fn fn) { + return fn != null && fn.isValid(); + } + + public static ClassLoader newLoader(final FindResources f, final Fn.Presenter d, ClassLoader parent) { + return new JsClassLoader(parent) { + @Override + protected URL findResource(String name) { + List l = res(name, true); + return l.isEmpty() ? null : l.get(0); + } + + @Override + protected Enumeration findResources(String name) { + return Collections.enumeration(res(name, false)); + } + + private List res(String name, boolean oneIsEnough) { + List l = new ArrayList(); + f.findResources(name, l, oneIsEnough); + return l; + } + + @Override + protected Fn defineFn(String code, String... names) { + return d.defineFn(code, names); + } + + @Override + protected void loadScript(Reader code) throws Exception { + d.loadScript(code); + } + }; + } + + static String callback(final String body) { + return new JsCallback() { + @Override + protected CharSequence callMethod( + String ident, String fqn, String method, String params + ) { + StringBuilder sb = new StringBuilder(); + sb.append("vm.").append(mangle(fqn, method, params)); + sb.append("("); + if (ident != null) { + sb.append(ident); + } + return sb; + } + + }.parse(body); + } + + static void loadScript(ClassLoader jcl, String resource) { + final InputStream script = jcl.getResourceAsStream(resource); + if (script == null) { + throw new NullPointerException("Can't find " + resource); + } + try { + Reader isr = null; + try { + isr = new InputStreamReader(script, "UTF-8"); + FnContext.currentPresenter().loadScript(isr); + } finally { + if (isr != null) { + isr.close(); + } + } + } catch (Exception ex) { + throw new IllegalStateException("Can't execute " + resource, ex); + } + } + + @Override + public Fn defineFn(String code, String... names) { + return new TrueFn(); + } + + @Override + public void displayPage(URL page, Runnable onPageLoad) { + } + + @Override + public void loadScript(Reader code) throws Exception { + } + + private static final class FindInClass extends ClassVisitor { + private String name; + private int found; + private ClassLoader loader; + private String resource; + + public FindInClass(ClassLoader l, ClassVisitor cv) { + super(Opcodes.ASM4, cv); + this.loader = l; + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + this.name = name; + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if ("Lnet/java/html/js/JavaScriptResource;".equals(desc)) { + return new LoadResource(); + } + return super.visitAnnotation(desc, visible); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + return new FindInMethod(access, name, desc, + super.visitMethod(access & (~Opcodes.ACC_NATIVE), name, desc, signature, exceptions) + ); + } + + private final class FindInMethod extends MethodVisitor { + + private final String name; + private final String desc; + private final int access; + private List args; + private String body; + private boolean bodyGenerated; + + public FindInMethod(int access, String name, String desc, MethodVisitor mv) { + super(Opcodes.ASM4, mv); + this.access = access; + this.name = name; + this.desc = desc; + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if ("Lnet/java/html/js/JavaScriptBody;".equals(desc) // NOI18N + || "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;".equals(desc) // NOI18N + ) { + found++; + return new FindInAnno(); + } + return super.visitAnnotation(desc, visible); + } + + private void generateJSBody(List args, String body) { + this.args = args; + this.body = body; + } + + @Override + public void visitCode() { + if (body == null) { + return; + } + generateBody(); + } + + private boolean generateBody() { + if (bodyGenerated) { + return false; + } + bodyGenerated = true; + + super.visitFieldInsn( + Opcodes.GETSTATIC, FindInClass.this.name, + "$$fn$$" + name + "_" + found, + "Lorg/apidesign/html/boot/spi/Fn;" + ); + super.visitInsn(Opcodes.DUP); + super.visitMethodInsn( + Opcodes.INVOKESTATIC, + "org/apidesign/html/boot/spi/Fn", "isValid", + "(Lorg/apidesign/html/boot/spi/Fn;)Z" + ); + Label ifNotNull = new Label(); + super.visitJumpInsn(Opcodes.IFNE, ifNotNull); + + // init Fn + super.visitInsn(Opcodes.POP); + super.visitLdcInsn(Type.getObjectType(FindInClass.this.name)); + super.visitLdcInsn(body); + super.visitIntInsn(Opcodes.SIPUSH, args.size()); + super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String"); + boolean needsVM = false; + for (int i = 0; i < args.size(); i++) { + assert !needsVM; + String argName = args.get(i); + needsVM = "vm".equals(argName); + super.visitInsn(Opcodes.DUP); + super.visitIntInsn(Opcodes.BIPUSH, i); + super.visitLdcInsn(argName); + super.visitInsn(Opcodes.AASTORE); + } + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "org/apidesign/html/boot/spi/Fn", "define", + "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;" + ); + if (resource != null) { + super.visitLdcInsn(Type.getObjectType(FindInClass.this.name)); + super.visitLdcInsn(resource); + super.visitMethodInsn(Opcodes.INVOKESTATIC, + "org/apidesign/html/boot/spi/Fn", "preload", + "(Lorg/apidesign/html/boot/spi/Fn;Ljava/lang/Class;Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;" + ); + } + super.visitInsn(Opcodes.DUP); + super.visitFieldInsn( + Opcodes.PUTSTATIC, FindInClass.this.name, + "$$fn$$" + name + "_" + found, + "Lorg/apidesign/html/boot/spi/Fn;" + ); + // end of Fn init + + super.visitLabel(ifNotNull); + + final int offset; + if ((access & Opcodes.ACC_STATIC) == 0) { + offset = 1; + super.visitIntInsn(Opcodes.ALOAD, 0); + } else { + offset = 0; + super.visitInsn(Opcodes.ACONST_NULL); + } + + super.visitIntInsn(Opcodes.SIPUSH, args.size()); + super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); + + class SV extends SignatureVisitor { + + private boolean nowReturn; + private Type returnType; + private int index; + private int loadIndex = offset; + + public SV() { + super(Opcodes.ASM4); + } + + @Override + public void visitBaseType(char descriptor) { + final Type t = Type.getType("" + descriptor); + if (nowReturn) { + returnType = t; + return; + } + FindInMethod.super.visitInsn(Opcodes.DUP); + FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++); + FindInMethod.super.visitVarInsn(t.getOpcode(Opcodes.ILOAD), loadIndex++); + String factory; + switch (descriptor) { + case 'I': + factory = "java/lang/Integer"; + break; + case 'J': + factory = "java/lang/Long"; + loadIndex++; + break; + case 'S': + factory = "java/lang/Short"; + break; + case 'F': + factory = "java/lang/Float"; + break; + case 'D': + factory = "java/lang/Double"; + loadIndex++; + break; + case 'Z': + factory = "java/lang/Boolean"; + break; + case 'C': + factory = "java/lang/Character"; + break; + case 'B': + factory = "java/lang/Byte"; + break; + default: + throw new IllegalStateException(t.toString()); + } + FindInMethod.super.visitMethodInsn(Opcodes.INVOKESTATIC, + factory, "valueOf", "(" + descriptor + ")L" + factory + ";" + ); + FindInMethod.super.visitInsn(Opcodes.AASTORE); + } + + @Override + public SignatureVisitor visitArrayType() { + if (nowReturn) { + throw new IllegalStateException("Not supported yet"); + } + loadObject(); + return new SignatureWriter(); + } + + @Override + public void visitClassType(String name) { + if (nowReturn) { + returnType = Type.getObjectType(name); + return; + } + loadObject(); + } + + @Override + public SignatureVisitor visitReturnType() { + nowReturn = true; + return this; + } + + private void loadObject() { + FindInMethod.super.visitInsn(Opcodes.DUP); + FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++); + FindInMethod.super.visitVarInsn(Opcodes.ALOAD, loadIndex++); + FindInMethod.super.visitInsn(Opcodes.AASTORE); + } + + } + SV sv = new SV(); + SignatureReader sr = new SignatureReader(desc); + sr.accept(sv); + + if (needsVM) { + FindInMethod.super.visitInsn(Opcodes.DUP); + FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, sv.index); + int lastSlash = FindInClass.this.name.lastIndexOf('/'); + String jsCallbacks = FindInClass.this.name.substring(0, lastSlash + 1) + "$JsCallbacks$"; + FindInMethod.super.visitFieldInsn(Opcodes.GETSTATIC, jsCallbacks, "VM", "L" + jsCallbacks + ";"); + FindInMethod.super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jsCallbacks, "current", "()L" + jsCallbacks + ";"); + FindInMethod.super.visitInsn(Opcodes.AASTORE); + } + + super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, + "org/apidesign/html/boot/spi/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;" + ); + switch (sv.returnType.getSort()) { + case Type.VOID: + super.visitInsn(Opcodes.RETURN); + break; + case Type.ARRAY: + case Type.OBJECT: + super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName()); + super.visitInsn(Opcodes.ARETURN); + break; + case Type.BOOLEAN: + super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean"); + super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, + "java/lang/Boolean", "booleanValue", "()Z" + ); + super.visitInsn(Opcodes.IRETURN); + break; + default: + super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number"); + super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, + "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor() + ); + super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN)); + } + return true; + } + + @Override + public void visitEnd() { + super.visitEnd(); + if (body != null) { + if (generateBody()) { + // native method + super.visitMaxs(1, 0); + } + FindInClass.this.visitField( + Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, + "$$fn$$" + name + "_" + found, + "Lorg/apidesign/html/boot/spi/Fn;", + null, null + ); + } + } + + private final class FindInAnno extends AnnotationVisitor { + + private List args = new ArrayList(); + private String body; + private boolean javacall = false; + + public FindInAnno() { + super(Opcodes.ASM4); + } + + @Override + public void visit(String name, Object value) { + if (name == null) { + args.add((String) value); + return; + } + if (name.equals("javacall")) { // NOI18N + javacall = (Boolean) value; + return; + } + assert name.equals("body"); + body = (String) value; + } + + @Override + public AnnotationVisitor visitArray(String name) { + return this; + } + + @Override + public void visitEnd() { + if (body != null) { + if (javacall) { + body = callback(body); + args.add("vm"); + } + generateJSBody(args, body); + } + } + } + } + + private final class LoadResource extends AnnotationVisitor { + + public LoadResource() { + super(Opcodes.ASM4); + } + + @Override + public void visit(String attrName, Object value) { + String relPath = (String) value; + if (relPath.startsWith("/")) { + resource = relPath; + } else { + int last = name.lastIndexOf('/'); + String fullPath = name.substring(0, last + 1) + relPath; + resource = fullPath; + } + } + } + } + + private static class ClassWriterEx extends ClassWriter { + + private ClassLoader loader; + + public ClassWriterEx(ClassLoader l, ClassReader classReader, int flags) { + super(classReader, flags); + this.loader = l; + } + + @Override + protected String getCommonSuperClass(final String type1, final String type2) { + Class c, d; + try { + c = Class.forName(type1.replace('/', '.'), false, loader); + d = Class.forName(type2.replace('/', '.'), false, loader); + } catch (Exception e) { + throw new RuntimeException(e.toString()); + } + if (c.isAssignableFrom(d)) { + return type1; + } + if (d.isAssignableFrom(c)) { + return type2; + } + if (c.isInterface() || d.isInterface()) { + return "java/lang/Object"; + } else { + do { + c = c.getSuperclass(); + } while (!c.isAssignableFrom(d)); + return c.getName().replace('.', '/'); + } + } + } + + static byte[] transform(ClassLoader loader, byte[] arr) { + ClassReader cr = new ClassReader(arr) { + // to allow us to compile with -profile compact1 on + // JDK8 while processing the class as JDK7, the highest + // class format asm 4.1 understands to + @Override + public short readShort(int index) { + short s = super.readShort(index); + if (index == 6 && s > Opcodes.V1_7) { + return Opcodes.V1_7; + } + return s; + } + }; + FindInClass tst = new FindInClass(loader, null); + cr.accept(tst, 0); + if (tst.found > 0) { + ClassWriter w = new ClassWriterEx(loader, cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + FindInClass fic = new FindInClass(loader, w); + cr.accept(fic, 0); + arr = w.toByteArray(); + } + return arr; + } + + private static final class TrueFn extends Fn { + @Override + public Object invoke(Object thiz, Object... args) throws Exception { + return Boolean.TRUE; + } + } // end of TrueFn +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,369 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.io.Writer; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Completion; +import javax.annotation.processing.Completions; +import javax.annotation.processing.Messager; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic; +import javax.tools.FileObject; +import javax.tools.StandardLocation; +import net.java.html.js.JavaScriptBody; +import net.java.html.js.JavaScriptResource; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service = Processor.class) +public final class JavaScriptProcesor extends AbstractProcessor { + private final Map> javacalls = + new HashMap>(); + + @Override + public Set getSupportedAnnotationTypes() { + Set set = new HashSet(); + set.add(JavaScriptBody.class.getName()); + set.add(JavaScriptResource.class.getName()); + return set; + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + final Messager msg = processingEnv.getMessager(); + for (Element e : roundEnv.getElementsAnnotatedWith(JavaScriptBody.class)) { + if (e.getKind() != ElementKind.METHOD && e.getKind() != ElementKind.CONSTRUCTOR) { + continue; + } + ExecutableElement ee = (ExecutableElement)e; + List params = ee.getParameters(); + + JavaScriptBody jsb = e.getAnnotation(JavaScriptBody.class); + if (jsb == null) { + continue; + } + String[] arr = jsb.args(); + if (params.size() != arr.length) { + msg.printMessage(Diagnostic.Kind.ERROR, "Number of args arguments does not match real arguments!", e); + } + if (!jsb.javacall() && jsb.body().contains(".@")) { + msg.printMessage(Diagnostic.Kind.WARNING, "Usage of .@ usually requires javacall=true", e); + } + if (jsb.javacall()) { + JsCallback verify = new VerifyCallback(e); + try { + verify.parse(jsb.body()); + } catch (IllegalStateException ex) { + msg.printMessage(Diagnostic.Kind.ERROR, ex.getLocalizedMessage(), e); + } + } + } + for (Element e : roundEnv.getElementsAnnotatedWith(JavaScriptResource.class)) { + JavaScriptResource r = e.getAnnotation(JavaScriptResource.class); + if (r == null) { + continue; + } + final String res; + if (r.value().startsWith("/")) { + res = r.value(); + } else { + res = findPkg(e).replace('.', '/') + "/" + r.value(); + } + + try { + FileObject os = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", res); + os.openInputStream().close(); + } catch (IOException ex1) { + try { + FileObject os2 = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", res); + os2.openInputStream().close(); + } catch (IOException ex2) { + msg.printMessage(Diagnostic.Kind.ERROR, "Cannot find " + res + " in " + res + " package", e); + } + } + } + + if (roundEnv.processingOver()) { + generateCallbackClass(javacalls); + javacalls.clear(); + } + return true; + } + + @Override + public Iterable getCompletions(Element e, + AnnotationMirror annotation, ExecutableElement member, String userText + ) { + StringBuilder sb = new StringBuilder(); + if (e.getKind() == ElementKind.METHOD && member.getSimpleName().contentEquals("args")) { + ExecutableElement ee = (ExecutableElement) e; + String sep = ""; + sb.append("{ "); + for (VariableElement ve : ee.getParameters()) { + sb.append(sep).append('"').append(ve.getSimpleName()) + .append('"'); + sep = ", "; + } + sb.append(" }"); + return Collections.nCopies(1, Completions.of(sb.toString())); + } + return null; + } + + private class VerifyCallback extends JsCallback { + private final Element e; + public VerifyCallback(Element e) { + this.e = e; + } + + @Override + protected CharSequence callMethod(String ident, String fqn, String method, String params) { + final TypeElement type = processingEnv.getElementUtils().getTypeElement(fqn); + if (type == null) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, + "Callback to non-existing class " + fqn, e + ); + return ""; + } + ExecutableElement found = null; + StringBuilder foundParams = new StringBuilder(); + for (Element m : type.getEnclosedElements()) { + if (m.getKind() != ElementKind.METHOD) { + continue; + } + if (m.getSimpleName().contentEquals(method)) { + String paramTypes = findParamTypes((ExecutableElement)m); + if (paramTypes.equals(params)) { + found = (ExecutableElement) m; + break; + } + foundParams.append(paramTypes).append("\n"); + } + } + if (found == null) { + if (foundParams.length() == 0) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, + "Callback to class " + fqn + " with unknown method " + method, e + ); + } else { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, + "Callback to " + fqn + "." + method + " with wrong parameters: " + + params + ". Only known parameters are " + foundParams, e + ); + } + } else { + Map mangledOnes = javacalls.get(findPkg(e)); + if (mangledOnes == null) { + mangledOnes = new TreeMap(); + javacalls.put(findPkg(e), mangledOnes); + } + String mangled = JsCallback.mangle(fqn, method, findParamTypes(found)); + mangledOnes.put(mangled, found); + } + return ""; + } + + private String findParamTypes(ExecutableElement method) { + ExecutableType t = (ExecutableType) method.asType(); + StringBuilder sb = new StringBuilder(); + sb.append('('); + for (TypeMirror tm : t.getParameterTypes()) { + if (tm.getKind().isPrimitive()) { + switch (tm.getKind()) { + case INT: sb.append('I'); break; + case BOOLEAN: sb.append('Z'); break; + case BYTE: sb.append('B'); break; + case CHAR: sb.append('C'); break; + case SHORT: sb.append('S'); break; + case DOUBLE: sb.append('D'); break; + case FLOAT: sb.append('F'); break; + case LONG: sb.append('J'); break; + default: + throw new IllegalStateException("Uknown " + tm.getKind()); + } + } else { + while (tm.getKind() == TypeKind.ARRAY) { + sb.append('['); + tm = ((ArrayType)tm).getComponentType(); + } + sb.append('L'); + sb.append(tm.toString().replace('.', '/')); + sb.append(';'); + } + } + sb.append(')'); + return sb.toString(); + } + } + + private void generateCallbackClass(Map> process) { + for (Map.Entry> pkgEn : process.entrySet()) { + String pkgName = pkgEn.getKey(); + Map map = pkgEn.getValue(); + StringBuilder source = new StringBuilder(); + source.append("package ").append(pkgName).append(";\n"); + source.append("public final class $JsCallbacks$ {\n"); + source.append(" static final $JsCallbacks$ VM = new $JsCallbacks$(null);\n"); + source.append(" private final org.apidesign.html.boot.spi.Fn.Presenter p;\n"); + source.append(" private $JsCallbacks$ last;\n"); + source.append(" private $JsCallbacks$(org.apidesign.html.boot.spi.Fn.Presenter p) {\n"); + source.append(" this.p = p;\n"); + source.append(" }\n"); + source.append(" final $JsCallbacks$ current() {\n"); + source.append(" org.apidesign.html.boot.spi.Fn.Presenter now = org.apidesign.html.boot.spi.Fn.activePresenter();\n"); + source.append(" if (now == p) return this;\n"); + source.append(" if (last != null && now == last.p) return last;\n"); + source.append(" return last = new $JsCallbacks$(now);\n"); + source.append(" }\n"); + for (Map.Entry entry : map.entrySet()) { + final String mangled = entry.getKey(); + final ExecutableElement m = entry.getValue(); + final boolean isStatic = m.getModifiers().contains(Modifier.STATIC); + + source.append("\n public java.lang.Object ") + .append(mangled) + .append("("); + + String sep = ""; + if (!isStatic) { + source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName()); + source.append(" self"); + sep = ", "; + } + + int cnt = 0; + for (VariableElement ve : m.getParameters()) { + source.append(sep); + source.append(ve.asType()); + source.append(" arg").append(++cnt); + sep = ", "; + } + source.append(") throws Throwable {\n"); + if (processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_7) >= 0) { + source.append(" try (java.io.Closeable a = org.apidesign.html.boot.spi.Fn.activate(p)) { \n"); + } else { + source.append(" java.io.Closeable a = org.apidesign.html.boot.spi.Fn.activate(p); try {\n"); + } + source.append(" "); + if (m.getReturnType().getKind() != TypeKind.VOID) { + source.append("return "); + } + if (isStatic) { + source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName()); + source.append('.'); + } else { + source.append("self."); + } + source.append(m.getSimpleName()); + source.append("("); + cnt = 0; + sep = ""; + for (VariableElement ve : m.getParameters()) { + source.append(sep); + source.append("arg").append(++cnt); + sep = ", "; + } + source.append(");\n"); + if (m.getReturnType().getKind() == TypeKind.VOID) { + source.append(" return null;\n"); + } + if (processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_7) >= 0) { + source.append(" }\n"); + } else { + + source.append(" } finally {\n"); + source.append(" a.close();\n"); + source.append(" }\n"); + } + source.append(" }\n"); + } + source.append("}\n"); + final String srcName = pkgName + ".$JsCallbacks$"; + try { + Writer w = processingEnv.getFiler().createSourceFile(srcName, + map.values().toArray(new Element[map.size()]) + ).openWriter(); + w.write(source.toString()); + w.close(); + } catch (IOException ex) { + processingEnv.getMessager().printMessage( + Diagnostic.Kind.ERROR, "Can't write " + srcName + ": " + ex.getMessage() + ); + } + } + } + + private static String findPkg(Element e) { + while (e.getKind() != ElementKind.PACKAGE) { + e = e.getEnclosingElement(); + } + return ((PackageElement)e).getQualifiedName().toString(); + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/netbeans/html/boot/impl/JsAgent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsAgent.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,67 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; + +/** + * + * @author Jaroslav Tulach + */ +public final class JsAgent implements ClassFileTransformer { + public static void agentmain(String args, Instrumentation instr) { + instr.addTransformer(new JsAgent()); + } + + @Override + public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + try { + return FnUtils.transform(loader, classfileBuffer); + } catch (Exception ex) { + return classfileBuffer; + } + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/netbeans/html/boot/impl/JsCallback.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsCallback.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,160 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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 + */ +abstract class JsCallback { + final String parse(String body) { + StringBuilder sb = new StringBuilder(); + int pos = 0; + for (;;) { + int next = body.indexOf(".@", pos); + if (next == -1) { + sb.append(body.substring(pos)); + body = sb.toString(); + break; + } + int ident = next; + while (ident > 0) { + if (!Character.isJavaIdentifierPart(body.charAt(--ident))) { + ident++; + break; + } + } + String refId = body.substring(ident, next); + + sb.append(body.substring(pos, ident)); + + int sigBeg = body.indexOf('(', next); + int sigEnd = body.indexOf(')', sigBeg); + int colon4 = body.indexOf("::", next); + if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) { + throw new IllegalStateException( + "Wrong format of instance callback. " + + "Should be: 'inst.@pkg.Class::method(Ljava/lang/Object;)(param)':\n" + + body + ); + } + String fqn = body.substring(next + 2, colon4); + String method = body.substring(colon4 + 2, sigBeg); + String params = body.substring(sigBeg, sigEnd + 1); + + int paramBeg = body.indexOf('(', sigEnd + 1); + if (paramBeg == -1) { + throw new IllegalStateException( + "Wrong format of instance callback. " + + "Should be: 'inst.@pkg.Class::method(Ljava/lang/Object;)(param)':\n" + + body + ); + } + + sb.append(callMethod(refId, fqn, method, params)); + if (body.charAt(paramBeg + 1) != (')')) { + sb.append(","); + } + pos = paramBeg + 1; + } + pos = 0; + sb = null; + for (;;) { + int next = body.indexOf("@", pos); + if (next == -1) { + if (sb == null) { + return body; + } + sb.append(body.substring(pos)); + return sb.toString(); + } + if (sb == null) { + sb = new StringBuilder(); + } + + sb.append(body.substring(pos, next)); + + int sigBeg = body.indexOf('(', next); + int sigEnd = body.indexOf(')', sigBeg); + int colon4 = body.indexOf("::", next); + if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) { + throw new IllegalStateException( + "Wrong format of static callback. " + + "Should be: '@pkg.Class::staticMethod(Ljava/lang/Object;)(param)':\n" + + body + ); + } + String fqn = body.substring(next + 1, colon4); + String method = body.substring(colon4 + 2, sigBeg); + String params = body.substring(sigBeg, sigEnd + 1); + + int paramBeg = body.indexOf('(', sigEnd + 1); + + sb.append(callMethod(null, fqn, method, params)); + pos = paramBeg + 1; + } + } + + protected abstract CharSequence callMethod( + String ident, String fqn, String method, String params + ); + + static String mangle(String fqn, String method, String params) { + if (params.startsWith("(")) { + params = params.substring(1); + } + if (params.endsWith(")")) { + params = params.substring(0, params.length() - 1); + } + return + replace(fqn) + "$" + replace(method) + "$" + replace(params); + } + + private static String replace(String orig) { + return orig.replace("_", "_1"). + replace(";", "_2"). + replace("[", "_3"). + replace('.', '_').replace('/', '_'); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/netbeans/html/boot/impl/JsClassLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsClassLoader.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,133 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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 org.apidesign.html.boot.spi.Fn; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.net.URL; +import java.util.Enumeration; + +/** + * + * @author Jaroslav Tulach + */ +abstract class JsClassLoader extends ClassLoader { + JsClassLoader(ClassLoader parent) { + super(parent); + setDefaultAssertionStatus(JsClassLoader.class.desiredAssertionStatus()); + } + + @Override + protected abstract URL findResource(String name); + + @Override + protected abstract Enumeration findResources(String name); + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.startsWith("javafx")) { + return Class.forName(name); + } + if (name.startsWith("netscape")) { + return Class.forName(name); + } + if (name.startsWith("com.sun")) { + return Class.forName(name); + } + if (name.equals(JsClassLoader.class.getName())) { + return JsClassLoader.class; + } + if (name.equals(Fn.class.getName())) { + return Fn.class; + } + if (name.equals(Fn.Presenter.class.getName())) { + return Fn.Presenter.class; + } + if (name.equals(FnUtils.class.getName())) { + return FnUtils.class; + } + if ( + name.equals("org.apidesign.html.boot.spi.Fn") || + name.equals("org.netbeans.html.boot.impl.FnUtils") || + name.equals("org.netbeans.html.boot.impl.FnContext") + ) { + return Class.forName(name); + } + URL u = findResource(name.replace('.', '/') + ".class"); + if (u != null) { + InputStream is = null; + try { + is = u.openStream(); + byte[] arr = new byte[is.available()]; + int len = 0; + while (len < arr.length) { + int read = is.read(arr, len, arr.length - len); + if (read == -1) { + throw new IOException("Can't read " + u); + } + len += read; + } + is.close(); + is = null; + arr = FnUtils.transform(JsClassLoader.this, arr); + if (arr != null) { + return defineClass(name, arr, 0, arr.length); + } + } catch (IOException ex) { + throw new ClassNotFoundException("Can't load " + name, ex); + } finally { + try { + if (is != null) is.close(); + } catch (IOException ex) { + throw new ClassNotFoundException(null, ex); + } + } + } + return super.findClass(name); + } + + protected abstract Fn defineFn(String code, String... names); + protected abstract void loadScript(Reader code) throws Exception; +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/main/java/org/netbeans/html/boot/impl/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/Test.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,57 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.util.concurrent.Callable; +import net.java.html.js.JavaScriptBody; + +/** + * + * @author Jaroslav Tulach + */ +public final class Test implements Callable { + @Override @JavaScriptBody(args = {}, body = "return true;") + public Boolean call() { + return false; + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/apidesign/html/boot/impl/Arithm.java --- a/boot/src/test/java/org/apidesign/html/boot/impl/Arithm.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -/** - * - * @author Jaroslav Tulach - */ -public class Arithm { - public int sumTwo(int a, int b) { - return a + b; - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/apidesign/html/boot/impl/Compile.java --- a/boot/src/test/java/org/apidesign/html/boot/impl/Compile.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,291 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.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 { - private final List> errors = - new ArrayList>(); - private final Map 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> getErrors() { - List> err; - err = new ArrayList>(); - for (Diagnostic diagnostic : errors) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - err.add(diagnostic); - } - } - return err; - } - - private Map compile(final String html, final String code) throws IOException { - StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null); - - final Map class2BAOS; - class2BAOS = new HashMap(); - - 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(sjfm) { - @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; - } - } - - 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 result = new HashMap(); - - for (Map.Entry e : class2BAOS.entrySet()) { - result.put(e.getKey(), e.getValue().toByteArray()); - } - - return result; - } - - - @Override - public void report(Diagnostic 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 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()); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/apidesign/html/boot/impl/FnTest.java --- a/boot/src/test/java/org/apidesign/html/boot/impl/FnTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.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.Collection; -import java.util.List; -import javax.script.Invocable; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; -import org.apidesign.html.boot.spi.Fn; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; - -/** - * - * @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 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 Object val = eng.eval(sb.toString()); - return new Fn(this) { - @Override - public Object invoke(Object thiz, Object... args) throws Exception { - List all = new ArrayList(args.length + 1); - all.add(thiz == null ? val : thiz); - all.addAll(Arrays.asList(args)); - Invocable inv = (Invocable)eng; - try { - 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(); - } - - @BeforeMethod public void initPresenter() { - FnContext.currentPresenter(presenter); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/apidesign/html/boot/impl/JavaScriptProcesorTest.java --- a/boot/src/test/java/org/apidesign/html/boot/impl/JavaScriptProcesorTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -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" - + " \"r.@java.lang.Runable::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" - + " \"r.@java.lang.Runnable::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" - + " \"r.@java.lang.Runnable::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" - + " \"r.@java.lang.Object::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 generatesCallbacksThatReturnObject() throws Exception { - Class callbacksForTestPkg = Class.forName("org.apidesign.html.boot.impl.$JsCallbacks$"); - Method m = callbacksForTestPkg.getDeclaredMethod("java_lang_Runnable$run$", Runnable.class); - assertEquals(m.getReturnType(), Object.class, "All methods always return object"); - } - - @Test public void hasInstanceField() throws Exception { - Class callbacksForTestPkg = Class.forName("org.apidesign.html.boot.impl.$JsCallbacks$"); - Field f = callbacksForTestPkg.getDeclaredField("VM"); - f.setAccessible(true); - assertTrue(callbacksForTestPkg.isInstance(f.get(null)), "Singleton field VM"); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderBase.java --- a/boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderBase.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -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 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); - 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 { - Object th = methodClass.newInstance(); - Method st = methodClass.getMethod("getThis"); - try { - assertEquals(st.invoke(th), th); - } catch (InvocationTargetException ex) { - throw ex.getTargetException(); - } - } - - @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 { - 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 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", Object.class); - assertEquals(st.invoke(methodClass.newInstance(), "Hello"), "Hello", "The same parameter returned"); - } -} \ No newline at end of file diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderTest.java --- a/boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -import java.io.Closeable; -import java.io.Reader; -import org.apidesign.html.boot.spi.Fn; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Arrays; -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.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 JsClassLoader implements Fn.Presenter { - - public MyCL(ClassLoader parent) { - super(parent); - } - - @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 Object val = eng.eval(sb.toString()); - return new Fn(this) { - @Override - public Object invoke(Object thiz, Object... args) throws Exception { - List all = new ArrayList(args.length + 1); - all.add(thiz == null ? val : thiz); - all.addAll(Arrays.asList(args)); - Invocable inv = (Invocable)eng; - try { - 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 findResources(String name) { - throw new UnsupportedOperationException(); - } - - @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 diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/apidesign/html/boot/impl/JsMethods.java --- a/boot/src/test/java/org/apidesign/html/boot/impl/JsMethods.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.boot.impl; - -import net.java.html.js.JavaScriptBody; -import net.java.html.js.JavaScriptResource; - - -/** - * - * @author Jaroslav Tulach - */ -@JavaScriptResource("jsmethods.js") -public class JsMethods { - private Object value; - - @JavaScriptBody(args = {}, body = "return 42;") - public static Object fortyTwo() { - return -42; - } - - @JavaScriptBody(args = {"x", "y" }, body = "return x + y;") - public static native int plus(int x, int y); - - @JavaScriptBody(args = {"x"}, body = "return x;") - public static native int plus(int x); - - @JavaScriptBody(args = {}, body = "return this;") - public static native Object staticThis(); - - @JavaScriptBody(args = {}, body = "return this;") - public native Object getThis(); - @JavaScriptBody(args = {"x"}, body = "return x;") - public native int plusInst(int x); - - @JavaScriptBody(args = {}, body = "return true;") - public static boolean truth() { - return false; - } - - @JavaScriptBody(args = { "r" }, javacall=true, body = "r.@java.lang.Runnable::run()();") - public static native void callback(Runnable r); - - @JavaScriptBody(args = { "at", "arr" }, javacall = true, body = - "var a = 0;\n" - + "for (var i = 0; i < arr.length; i++) {\n" - + " a = at.@org.apidesign.html.boot.impl.Arithm::sumTwo(II)(a, arr[i]);\n" - + "}\n" - + "return a;" - ) - private static native int sumArr(Arithm at, int... arr); - - public static int sumArr(int... arr) { - return sumArr(new Arithm(), arr); - } - - @JavaScriptBody(args = { "x", "y" }, body = "return mul(x, y);") - public static native int useExternalMul(int x, int y); - - @JavaScriptBody(args = { "m" }, javacall = true, body = "return m.@org.apidesign.html.boot.impl.JsMethods::getThis()();") - public static native JsMethods returnYourSelf(JsMethods m); - - @JavaScriptBody(args = { "x", "y" }, javacall = true, body = "return @org.apidesign.html.boot.impl.JsMethods::useExternalMul(II)(x, y);") - public static native int staticCallback(int x, int y); - - @JavaScriptBody(args = { "v" }, javacall = true, body = "return @java.lang.Integer::parseInt(Ljava/lang/String;)(v);") - public static native int parseInt(String v); - - @JavaScriptBody(args = { "useA", "useB", "a", "b" }, body = "var l = 0;" - + "if (useA) l += a;\n" - + "if (useB) l += b;\n" - + "return l;\n" - ) - public static native long chooseLong(boolean useA, boolean useB, long a, long b); - - protected void onError(Object o) throws Exception { - value = o; - } - - Object getError() { - return value; - } - - @JavaScriptBody(args = { "err" }, javacall = true, body = - "this.@org.apidesign.html.boot.impl.JsMethods::onError(Ljava/lang/Object;)(err);" - + "return this.@org.apidesign.html.boot.impl.JsMethods::getError()();" - ) - public native Object recordError(Object err); -} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,53 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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; + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/netbeans/html/boot/impl/Compile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,291 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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 { + private final List> errors = + new ArrayList>(); + private final Map 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> getErrors() { + List> err; + err = new ArrayList>(); + for (Diagnostic diagnostic : errors) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + err.add(diagnostic); + } + } + return err; + } + + private Map compile(final String html, final String code) throws IOException { + StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null); + + final Map class2BAOS; + class2BAOS = new HashMap(); + + 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(sjfm) { + @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; + } + } + + 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 result = new HashMap(); + + for (Map.Entry e : class2BAOS.entrySet()) { + result.put(e.getKey(), e.getValue().toByteArray()); + } + + return result; + } + + + @Override + public void report(Diagnostic 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 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()); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,148 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.Collection; +import java.util.List; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import org.apidesign.html.boot.spi.Fn; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; + +/** + * + * @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 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 Object val = eng.eval(sb.toString()); + return new Fn(this) { + @Override + public Object invoke(Object thiz, Object... args) throws Exception { + List all = new ArrayList(args.length + 1); + all.add(thiz == null ? val : thiz); + all.addAll(Arrays.asList(args)); + Invocable inv = (Invocable)eng; + try { + 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(); + } + + @BeforeMethod public void initPresenter() { + FnContext.currentPresenter(presenter); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,129 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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 static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +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" + + " \"r.@java.lang.Runable::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" + + " \"r.@java.lang.Runnable::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" + + " \"r.@java.lang.Runnable::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" + + " \"r.@java.lang.Object::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 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(), 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"); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,201 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +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 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); + 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 { + Object th = methodClass.newInstance(); + Method st = methodClass.getMethod("getThis"); + try { + assertEquals(st.invoke(th), th); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + @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 { + 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 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", Object.class); + assertEquals(st.invoke(methodClass.newInstance(), "Hello"), "Hello", "The same parameter returned"); + } +} \ No newline at end of file diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,155 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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 org.apidesign.html.boot.spi.Fn; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +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.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 JsClassLoader implements Fn.Presenter { + + public MyCL(ClassLoader parent) { + super(parent); + } + + @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 Object val = eng.eval(sb.toString()); + return new Fn(this) { + @Override + public Object invoke(Object thiz, Object... args) throws Exception { + List all = new ArrayList(args.length + 1); + all.add(thiz == null ? val : thiz); + all.addAll(Arrays.asList(args)); + Invocable inv = (Invocable)eng; + try { + 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 findResources(String name) { + throw new UnsupportedOperationException(); + } + + @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 diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/java/org/netbeans/html/boot/impl/JsMethods.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsMethods.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,129 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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 net.java.html.js.JavaScriptBody; +import net.java.html.js.JavaScriptResource; + + +/** + * + * @author Jaroslav Tulach + */ +@JavaScriptResource("jsmethods.js") +public class JsMethods { + private Object value; + + @JavaScriptBody(args = {}, body = "return 42;") + public static Object fortyTwo() { + return -42; + } + + @JavaScriptBody(args = {"x", "y" }, body = "return x + y;") + public static native int plus(int x, int y); + + @JavaScriptBody(args = {"x"}, body = "return x;") + public static native int plus(int x); + + @JavaScriptBody(args = {}, body = "return this;") + public static native Object staticThis(); + + @JavaScriptBody(args = {}, body = "return this;") + public native Object getThis(); + @JavaScriptBody(args = {"x"}, body = "return x;") + public native int plusInst(int x); + + @JavaScriptBody(args = {}, body = "return true;") + public static boolean truth() { + return false; + } + + @JavaScriptBody(args = { "r" }, javacall=true, body = "r.@java.lang.Runnable::run()();") + public static native void callback(Runnable r); + + @JavaScriptBody(args = { "at", "arr" }, javacall = true, body = + "var a = 0;\n" + + "for (var i = 0; i < arr.length; i++) {\n" + + " a = at.@org.netbeans.html.boot.impl.Arithm::sumTwo(II)(a, arr[i]);\n" + + "}\n" + + "return a;" + ) + private static native int sumArr(Arithm at, int... arr); + + public static int sumArr(int... arr) { + return sumArr(new Arithm(), arr); + } + + @JavaScriptBody(args = { "x", "y" }, body = "return mul(x, y);") + public static native int useExternalMul(int x, int y); + + @JavaScriptBody(args = { "m" }, javacall = true, body = "return m.@org.netbeans.html.boot.impl.JsMethods::getThis()();") + public static native JsMethods returnYourSelf(JsMethods m); + + @JavaScriptBody(args = { "x", "y" }, javacall = true, body = "return @org.netbeans.html.boot.impl.JsMethods::useExternalMul(II)(x, y);") + public static native int staticCallback(int x, int y); + + @JavaScriptBody(args = { "v" }, javacall = true, body = "return @java.lang.Integer::parseInt(Ljava/lang/String;)(v);") + public static native int parseInt(String v); + + @JavaScriptBody(args = { "useA", "useB", "a", "b" }, body = "var l = 0;" + + "if (useA) l += a;\n" + + "if (useB) l += b;\n" + + "return l;\n" + ) + public static native long chooseLong(boolean useA, boolean useB, long a, long b); + + protected void onError(Object o) throws Exception { + value = o; + } + + Object getError() { + return value; + } + + @JavaScriptBody(args = { "err" }, javacall = true, body = + "this.@org.netbeans.html.boot.impl.JsMethods::onError(Ljava/lang/Object;)(err);" + + "return this.@org.netbeans.html.boot.impl.JsMethods::getError()();" + ) + public native Object recordError(Object err); +} diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/resources/org/apidesign/html/boot/impl/jsmethods.js --- a/boot/src/test/resources/org/apidesign/html/boot/impl/jsmethods.js Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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. - */ -function mul(x, y) { return x * y; } diff -r 700087d2a5d3 -r 92fb71afdc0e boot/src/test/resources/org/netbeans/html/boot/impl/jsmethods.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boot/src/test/resources/org/netbeans/html/boot/impl/jsmethods.js Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,43 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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. + */ +function mul(x, y) { return x * y; } diff -r 700087d2a5d3 -r 92fb71afdc0e context/src/main/java/net/java/html/BrwsrCtx.java --- a/context/src/main/java/net/java/html/BrwsrCtx.java Mon Dec 16 15:48:09 2013 +0100 +++ b/context/src/main/java/net/java/html/BrwsrCtx.java Mon Dec 16 16:59:43 2013 +0100 @@ -44,8 +44,8 @@ import java.util.ServiceLoader; import java.util.logging.Logger; -import org.apidesign.html.context.impl.CtxAccssr; -import org.apidesign.html.context.impl.CtxImpl; +import org.netbeans.html.context.impl.CtxAccssr; +import org.netbeans.html.context.impl.CtxImpl; import org.apidesign.html.context.spi.Contexts; /** Represents context where the net.java.html.json.Model diff -r 700087d2a5d3 -r 92fb71afdc0e context/src/main/java/org/apidesign/html/context/impl/CtxAccssr.java --- a/context/src/main/java/org/apidesign/html/context/impl/CtxAccssr.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.context.impl; - -import net.java.html.BrwsrCtx; - -/** Internal communication between API (e.g. {@link BrwsrCtx}), SPI - * (e.g. {@link ContextBuilder}) and the implementation package. - * - * @author Jaroslav Tulach - */ -public abstract class CtxAccssr { - private static CtxAccssr DEFAULT; - static { - // run initializers - try { - BrwsrCtx.EMPTY.getClass(); - } catch (NullPointerException ex) { - // ignore - } - } - - protected CtxAccssr() { - if (DEFAULT != null) throw new IllegalStateException(); - DEFAULT = this; - } - - protected abstract BrwsrCtx newContext(CtxImpl impl); - protected abstract CtxImpl find(BrwsrCtx context); - - static CtxAccssr getDefault() { - return DEFAULT; - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e context/src/main/java/org/apidesign/html/context/impl/CtxImpl.java --- a/context/src/main/java/org/apidesign/html/context/impl/CtxImpl.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.context.impl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import net.java.html.BrwsrCtx; - -/** Implementation detail. Holds list of technologies for particular - * {@link BrwsrCtx}. - * - * @author Jaroslav Tulach - */ -public final class CtxImpl { - private final List> techs; - - public CtxImpl() { - techs = new ArrayList>(); - } - - private CtxImpl(List> techs) { - this.techs = techs; - } - - public static Tech find(BrwsrCtx context, Class technology) { - CtxImpl impl = CtxAccssr.getDefault().find(context); - for (Bind bind : impl.techs) { - if (technology == bind.clazz) { - return technology.cast(bind.impl); - } - } - return null; - } - - public BrwsrCtx build() { - Collections.sort(techs); - CtxImpl impl = new CtxImpl(Collections.unmodifiableList(techs)); - return CtxAccssr.getDefault().newContext(impl); - } - - public void register(Class type, Tech impl, int priority) { - techs.add(new Bind(type, impl, priority)); - } - - private static final class Bind implements Comparable> { - private final Class clazz; - private final Tech impl; - private final int priority; - - public Bind(Class clazz, Tech impl, int priority) { - this.clazz = clazz; - this.impl = impl; - this.priority = priority; - } - - @Override - public int compareTo(Bind o) { - if (priority != o.priority) { - return priority - o.priority; - } - return clazz.getName().compareTo(o.clazz.getName()); - } - - @Override - public String toString() { - return "Bind{" + "clazz=" + clazz + "@" + clazz.getClassLoader() + ", impl=" + impl + ", priority=" + priority + '}'; - } - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e context/src/main/java/org/apidesign/html/context/spi/Contexts.java --- a/context/src/main/java/org/apidesign/html/context/spi/Contexts.java Mon Dec 16 15:48:09 2013 +0100 +++ b/context/src/main/java/org/apidesign/html/context/spi/Contexts.java Mon Dec 16 16:59:43 2013 +0100 @@ -43,7 +43,7 @@ package org.apidesign.html.context.spi; import net.java.html.BrwsrCtx; -import org.apidesign.html.context.impl.CtxImpl; +import org.netbeans.html.context.impl.CtxImpl; /** * diff -r 700087d2a5d3 -r 92fb71afdc0e context/src/main/java/org/netbeans/html/context/impl/CtxAccssr.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/context/src/main/java/org/netbeans/html/context/impl/CtxAccssr.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,74 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.context.impl; + +import net.java.html.BrwsrCtx; + +/** Internal communication between API (e.g. {@link BrwsrCtx}), SPI + * (e.g. {@link ContextBuilder}) and the implementation package. + * + * @author Jaroslav Tulach + */ +public abstract class CtxAccssr { + private static CtxAccssr DEFAULT; + static { + // run initializers + try { + BrwsrCtx.EMPTY.getClass(); + } catch (NullPointerException ex) { + // ignore + } + } + + protected CtxAccssr() { + if (DEFAULT != null) throw new IllegalStateException(); + DEFAULT = this; + } + + protected abstract BrwsrCtx newContext(CtxImpl impl); + protected abstract CtxImpl find(BrwsrCtx context); + + static CtxAccssr getDefault() { + return DEFAULT; + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,110 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.context.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import net.java.html.BrwsrCtx; + +/** Implementation detail. Holds list of technologies for particular + * {@link BrwsrCtx}. + * + * @author Jaroslav Tulach + */ +public final class CtxImpl { + private final List> techs; + + public CtxImpl() { + techs = new ArrayList>(); + } + + private CtxImpl(List> techs) { + this.techs = techs; + } + + public static Tech find(BrwsrCtx context, Class technology) { + CtxImpl impl = CtxAccssr.getDefault().find(context); + for (Bind bind : impl.techs) { + if (technology == bind.clazz) { + return technology.cast(bind.impl); + } + } + return null; + } + + public BrwsrCtx build() { + Collections.sort(techs); + CtxImpl impl = new CtxImpl(Collections.unmodifiableList(techs)); + return CtxAccssr.getDefault().newContext(impl); + } + + public void register(Class type, Tech impl, int priority) { + techs.add(new Bind(type, impl, priority)); + } + + private static final class Bind implements Comparable> { + private final Class clazz; + private final Tech impl; + private final int priority; + + public Bind(Class clazz, Tech impl, int priority) { + this.clazz = clazz; + this.impl = impl; + this.priority = priority; + } + + @Override + public int compareTo(Bind o) { + if (priority != o.priority) { + return priority - o.priority; + } + return clazz.getName().compareTo(o.clazz.getName()); + } + + @Override + public String toString() { + return "Bind{" + "clazz=" + clazz + "@" + clazz.getClassLoader() + ", impl=" + impl + ", priority=" + priority + '}'; + } + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e geo/src/main/java/net/java/html/geo/Position.java --- a/geo/src/main/java/net/java/html/geo/Position.java Mon Dec 16 15:48:09 2013 +0100 +++ b/geo/src/main/java/net/java/html/geo/Position.java Mon Dec 16 16:59:43 2013 +0100 @@ -44,7 +44,7 @@ import java.util.logging.Level; import java.util.logging.Logger; -import org.apidesign.html.geo.impl.JsG; +import org.netbeans.html.geo.impl.JsG; /** Class that represents a geolocation position provided as a callback * to {@link Handle#onLocation(net.java.html.geo.Position)} method. The diff -r 700087d2a5d3 -r 92fb71afdc0e geo/src/main/java/org/apidesign/html/geo/impl/GeoProcessor.java --- a/geo/src/main/java/org/apidesign/html/geo/impl/GeoProcessor.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,289 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.geo.impl; - -import java.io.IOException; -import java.io.Writer; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.Processor; -import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.annotation.processing.SupportedSourceVersion; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeMirror; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; -import net.java.html.geo.OnLocation; -import net.java.html.geo.Position; -import org.openide.util.lookup.ServiceProvider; - -/** Annotation processor to generate callbacks from {@link GeoHandle} class. - * - * @author Jaroslav Tulach - */ -@ServiceProvider(service=Processor.class) -@SupportedSourceVersion(SourceVersion.RELEASE_6) -@SupportedAnnotationTypes({ - "net.java.html.geo.OnLocation" -}) -public final class GeoProcessor extends AbstractProcessor { - private static final Logger LOG = Logger.getLogger(GeoProcessor.class.getName()); - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - boolean ok = true; - for (Element e : roundEnv.getElementsAnnotatedWith(OnLocation.class)) { - if (!processLocation(e)) { - ok = false; - } - } - return ok; - } - - private void error(String msg, Element e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e); - } - - private boolean processLocation(Element e) { - if (e.getKind() != ElementKind.METHOD) { - return false; - } - ExecutableElement me = (ExecutableElement) e; - OnLocation ol = e.getAnnotation(OnLocation.class); - if (ol == null) { - return true; - } - if (me.getModifiers().contains(Modifier.PRIVATE)) { - error("Method annotated by @OnLocation cannot be private", e); - return false; - } - TypeMirror positionClass = processingEnv.getElementUtils().getTypeElement(Position.class.getName()).asType(); - final List params = me.getParameters(); - if (params.size() < 1 || !params.get(0).asType().equals(positionClass)) { - error("Method annotated by @OnLocation first argument must be net.java.html.geo.Position!", e); - return false; - } - String className = ol.className(); - if (className.isEmpty()) { - String n = e.getSimpleName().toString(); - if (n.isEmpty()) { - error("Empty method name", e); - return false; - } - final String firstLetter = n.substring(0, 1).toUpperCase(Locale.ENGLISH); - className = firstLetter + n.substring(1) + "Handle"; - } - TypeElement te = (TypeElement)e.getEnclosingElement(); - PackageElement pe = (PackageElement) te.getEnclosingElement(); - final String pkg = pe.getQualifiedName().toString(); - final String fqn = pkg + "." + className; - final boolean isStatic = me.getModifiers().contains(Modifier.STATIC); - String sep; - try { - JavaFileObject fo = processingEnv.getFiler().createSourceFile(fqn, e); - Writer w = fo.openWriter(); - w.append("package ").append(pkg).append(";\n"); - w.append("class ").append(className).append(" extends net.java.html.geo.Position.Handle {\n"); - if (!isStatic) { - w.append(" private final ").append(te.getSimpleName()).append(" $i;\n"); - } - for (int i = 1; i < params.size(); i++) { - final VariableElement p = params.get(i); - w.append(" private final ").append(p.asType().toString()).append(" ").append(p.getSimpleName()).append(";\n"); - } - w.append(" private ").append(className).append("(boolean oneTime"); - w.append(", ").append(te.getSimpleName()).append(" i"); - for (int i = 1; i < params.size(); i++) { - final VariableElement p = params.get(i); - w.append(", ").append(p.asType().toString()).append(" ").append(p.getSimpleName()); - } - w.append(") {\n super(oneTime);\n"); - if (!isStatic) { - w.append(" this.$i = i;\n"); - } - for (int i = 1; i < params.size(); i++) { - final VariableElement p = params.get(i); - w.append(" this.").append(p.getSimpleName()).append(" = ").append(p.getSimpleName()).append(";\n"); - } - w.append("}\n"); - w.append(" static net.java.html.geo.Position.Handle createQuery("); - String inst; - if (!isStatic) { - w.append(te.getSimpleName()).append(" instance"); - inst = "instance"; - sep = ", "; - } else { - inst = "null"; - sep = ""; - } - for (int i = 1; i < params.size(); i++) { - final VariableElement p = params.get(i); - w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName()); - sep = ", "; - } - w.append(") { return new ").append(className).append("(true, ").append(inst); - for (int i = 1; i < params.size(); i++) { - final VariableElement p = params.get(i); - w.append(", ").append(p.getSimpleName()); - } - w.append("); }\n"); - w.append(" static net.java.html.geo.Position.Handle createWatch("); - if (!isStatic) { - w.append(te.getSimpleName()).append(" instance"); - sep = ", "; - } else { - sep = ""; - } - for (int i = 1; i < params.size(); i++) { - final VariableElement p = params.get(i); - w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName()); - } - w.append(") { return new ").append(className).append("(false, ").append(inst); - for (int i = 1; i < params.size(); i++) { - final VariableElement p = params.get(i); - w.append(", ").append(p.getSimpleName()); - } - w.append("); }\n"); - w.append(" @Override protected void onError(Exception t) throws Throwable {\n"); - if (ol.onError().isEmpty()) { - w.append(" t.printStackTrace();"); - } else { - if (!findOnError(me, te, ol.onError(), isStatic)) { - return false; - } - if (isStatic) { - w.append(" ").append(te.getSimpleName()).append("."); - } else { - w.append(" $i."); - } - w.append(ol.onError()).append("(t"); - for (int i = 1; i < params.size(); i++) { - final VariableElement p = params.get(i); - w.append(", ").append(p.getSimpleName()); - } - w.append(");\n"); - } - w.append(" }\n"); - w.append(" @Override protected void onLocation(net.java.html.geo.Position p) throws Throwable {\n"); - if (isStatic) { - w.append(" ").append(te.getSimpleName()).append("."); - } else { - w.append(" $i."); - } - w.append(me.getSimpleName()).append("(p"); - for (int i = 1; i < params.size(); i++) { - final VariableElement p = params.get(i); - w.append(", ").append(p.getSimpleName()); - } - w.append(");\n"); - w.append(" }\n"); - w.append("}\n"); - w.close(); - } catch (IOException ex) { - Logger.getLogger(GeoProcessor.class.getName()).log(Level.SEVERE, null, ex); - error("Can't write handler class: " + ex.getMessage(), e); - return false; - } - - return true; - } - - private boolean findOnError(ExecutableElement errElem, TypeElement te, String name, boolean onlyStatic) { - String err = null; - METHODS: for (Element e : te.getEnclosedElements()) { - if (e.getKind() != ElementKind.METHOD) { - continue; - } - if (!e.getSimpleName().contentEquals(name)) { - continue; - } - if (onlyStatic && !e.getModifiers().contains(Modifier.STATIC)) { - errElem = (ExecutableElement) e; - err = "Would have to be static"; - continue; - } - ExecutableElement ee = (ExecutableElement) e; - TypeMirror excType = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType(); - final List params = ee.getParameters(); - if (params.size() < 1 || - !processingEnv.getTypeUtils().isAssignable(excType, ee.getParameters().get(0).asType()) - ) { - errElem = (ExecutableElement) e; - err = "Error method first argument needs to be Exception"; - continue; - } - final List origParams = errElem.getParameters(); - if (params.size() != origParams.size()) { - errElem = (ExecutableElement) e; - err = "Error method must have the same parameters as @OnLocation one"; - continue; - } - for (int i = 1; i < origParams.size(); i++) { - final TypeMirror t1 = params.get(i).asType(); - final TypeMirror t2 = origParams.get(i).asType(); - if (!processingEnv.getTypeUtils().isSameType(t1, t2)) { - errElem = (ExecutableElement) e; - err = "Error method must have the same parameters as @OnLocation one"; - continue METHODS; - } - } - return true; - } - if (err == null) { - err = "Cannot find " + name + "(Exception) method in this class"; - } - error(err, errElem); - return false; - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e geo/src/main/java/org/apidesign/html/geo/impl/JsG.java --- a/geo/src/main/java/org/apidesign/html/geo/impl/JsG.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.geo.impl; - -import net.java.html.js.JavaScriptBody; - -/** Implementation class to deal with browser's navigator.geolocation - * object. - * - * @author Jaroslav Tulach - */ -public abstract class JsG { - protected JsG() { - if (!getClass().getName().equals("net.java.html.geo.Position$Handle$JsH")) { - throw new IllegalStateException(); - } - } - - public abstract void onLocation(Object position); - public abstract void onError(Object error); - - @JavaScriptBody(args = {}, body = "return !!navigator.geolocation;") - public static boolean hasGeolocation() { - return false; - } - - @JavaScriptBody( - args = { "onlyOnce", "enableHighAccuracy", "timeout", "maximumAge" }, - javacall = true, - body = - "var self = this;\n" + - "var ok = function (position) {\n" + - " self.@org.apidesign.html.geo.impl.JsG::onLocation(Ljava/lang/Object;)(position);\n" + - "};\n" + - "var fail = function (error) {\n" + - " self.@org.apidesign.html.geo.impl.JsG::onError(Ljava/lang/Object;)(error);\n" + - "};\n" + - "var options = {};\n" + - "options.enableHighAccuracy = enableHighAccuracy;\n" + - "if (timeout >= 0) options.timeout = timeout;\n" + - "if (maximumAge >= 0) options.maximumAge = maximumAge;\n" + - "if (onlyOnce) {\n" + - " navigator.geolocation.getCurrentPosition(ok, fail);\n" + - " return 0;\n" + - "} else {\n" + - " return navigator.geolocation.watchPosition(ok, fail);\n" + - "}\n" - ) - protected long start( - boolean onlyOnce, - boolean enableHighAccuracy, - long timeout, - long maximumAge - ) { - return -1; - } - - @JavaScriptBody(args = { "watch" }, body = "navigator.geolocation.clearWatch(watch);") - protected void stop(long watch) { - } - - @JavaScriptBody(args = { "self", "property" }, body = "return self[property];") - public static Object get(Object self, String property) { - return null; - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,289 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.geo.impl; + +import java.io.IOException; +import java.io.Writer; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; +import net.java.html.geo.OnLocation; +import net.java.html.geo.Position; +import org.openide.util.lookup.ServiceProvider; + +/** Annotation processor to generate callbacks from {@link GeoHandle} class. + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service=Processor.class) +@SupportedSourceVersion(SourceVersion.RELEASE_6) +@SupportedAnnotationTypes({ + "net.java.html.geo.OnLocation" +}) +public final class GeoProcessor extends AbstractProcessor { + private static final Logger LOG = Logger.getLogger(GeoProcessor.class.getName()); + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + boolean ok = true; + for (Element e : roundEnv.getElementsAnnotatedWith(OnLocation.class)) { + if (!processLocation(e)) { + ok = false; + } + } + return ok; + } + + private void error(String msg, Element e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e); + } + + private boolean processLocation(Element e) { + if (e.getKind() != ElementKind.METHOD) { + return false; + } + ExecutableElement me = (ExecutableElement) e; + OnLocation ol = e.getAnnotation(OnLocation.class); + if (ol == null) { + return true; + } + if (me.getModifiers().contains(Modifier.PRIVATE)) { + error("Method annotated by @OnLocation cannot be private", e); + return false; + } + TypeMirror positionClass = processingEnv.getElementUtils().getTypeElement(Position.class.getName()).asType(); + final List params = me.getParameters(); + if (params.size() < 1 || !params.get(0).asType().equals(positionClass)) { + error("Method annotated by @OnLocation first argument must be net.java.html.geo.Position!", e); + return false; + } + String className = ol.className(); + if (className.isEmpty()) { + String n = e.getSimpleName().toString(); + if (n.isEmpty()) { + error("Empty method name", e); + return false; + } + final String firstLetter = n.substring(0, 1).toUpperCase(Locale.ENGLISH); + className = firstLetter + n.substring(1) + "Handle"; + } + TypeElement te = (TypeElement)e.getEnclosingElement(); + PackageElement pe = (PackageElement) te.getEnclosingElement(); + final String pkg = pe.getQualifiedName().toString(); + final String fqn = pkg + "." + className; + final boolean isStatic = me.getModifiers().contains(Modifier.STATIC); + String sep; + try { + JavaFileObject fo = processingEnv.getFiler().createSourceFile(fqn, e); + Writer w = fo.openWriter(); + w.append("package ").append(pkg).append(";\n"); + w.append("class ").append(className).append(" extends net.java.html.geo.Position.Handle {\n"); + if (!isStatic) { + w.append(" private final ").append(te.getSimpleName()).append(" $i;\n"); + } + for (int i = 1; i < params.size(); i++) { + final VariableElement p = params.get(i); + w.append(" private final ").append(p.asType().toString()).append(" ").append(p.getSimpleName()).append(";\n"); + } + w.append(" private ").append(className).append("(boolean oneTime"); + w.append(", ").append(te.getSimpleName()).append(" i"); + for (int i = 1; i < params.size(); i++) { + final VariableElement p = params.get(i); + w.append(", ").append(p.asType().toString()).append(" ").append(p.getSimpleName()); + } + w.append(") {\n super(oneTime);\n"); + if (!isStatic) { + w.append(" this.$i = i;\n"); + } + for (int i = 1; i < params.size(); i++) { + final VariableElement p = params.get(i); + w.append(" this.").append(p.getSimpleName()).append(" = ").append(p.getSimpleName()).append(";\n"); + } + w.append("}\n"); + w.append(" static net.java.html.geo.Position.Handle createQuery("); + String inst; + if (!isStatic) { + w.append(te.getSimpleName()).append(" instance"); + inst = "instance"; + sep = ", "; + } else { + inst = "null"; + sep = ""; + } + for (int i = 1; i < params.size(); i++) { + final VariableElement p = params.get(i); + w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName()); + sep = ", "; + } + w.append(") { return new ").append(className).append("(true, ").append(inst); + for (int i = 1; i < params.size(); i++) { + final VariableElement p = params.get(i); + w.append(", ").append(p.getSimpleName()); + } + w.append("); }\n"); + w.append(" static net.java.html.geo.Position.Handle createWatch("); + if (!isStatic) { + w.append(te.getSimpleName()).append(" instance"); + sep = ", "; + } else { + sep = ""; + } + for (int i = 1; i < params.size(); i++) { + final VariableElement p = params.get(i); + w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName()); + } + w.append(") { return new ").append(className).append("(false, ").append(inst); + for (int i = 1; i < params.size(); i++) { + final VariableElement p = params.get(i); + w.append(", ").append(p.getSimpleName()); + } + w.append("); }\n"); + w.append(" @Override protected void onError(Exception t) throws Throwable {\n"); + if (ol.onError().isEmpty()) { + w.append(" t.printStackTrace();"); + } else { + if (!findOnError(me, te, ol.onError(), isStatic)) { + return false; + } + if (isStatic) { + w.append(" ").append(te.getSimpleName()).append("."); + } else { + w.append(" $i."); + } + w.append(ol.onError()).append("(t"); + for (int i = 1; i < params.size(); i++) { + final VariableElement p = params.get(i); + w.append(", ").append(p.getSimpleName()); + } + w.append(");\n"); + } + w.append(" }\n"); + w.append(" @Override protected void onLocation(net.java.html.geo.Position p) throws Throwable {\n"); + if (isStatic) { + w.append(" ").append(te.getSimpleName()).append("."); + } else { + w.append(" $i."); + } + w.append(me.getSimpleName()).append("(p"); + for (int i = 1; i < params.size(); i++) { + final VariableElement p = params.get(i); + w.append(", ").append(p.getSimpleName()); + } + w.append(");\n"); + w.append(" }\n"); + w.append("}\n"); + w.close(); + } catch (IOException ex) { + Logger.getLogger(GeoProcessor.class.getName()).log(Level.SEVERE, null, ex); + error("Can't write handler class: " + ex.getMessage(), e); + return false; + } + + return true; + } + + private boolean findOnError(ExecutableElement errElem, TypeElement te, String name, boolean onlyStatic) { + String err = null; + METHODS: for (Element e : te.getEnclosedElements()) { + if (e.getKind() != ElementKind.METHOD) { + continue; + } + if (!e.getSimpleName().contentEquals(name)) { + continue; + } + if (onlyStatic && !e.getModifiers().contains(Modifier.STATIC)) { + errElem = (ExecutableElement) e; + err = "Would have to be static"; + continue; + } + ExecutableElement ee = (ExecutableElement) e; + TypeMirror excType = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType(); + final List params = ee.getParameters(); + if (params.size() < 1 || + !processingEnv.getTypeUtils().isAssignable(excType, ee.getParameters().get(0).asType()) + ) { + errElem = (ExecutableElement) e; + err = "Error method first argument needs to be Exception"; + continue; + } + final List origParams = errElem.getParameters(); + if (params.size() != origParams.size()) { + errElem = (ExecutableElement) e; + err = "Error method must have the same parameters as @OnLocation one"; + continue; + } + for (int i = 1; i < origParams.size(); i++) { + final TypeMirror t1 = params.get(i).asType(); + final TypeMirror t2 = origParams.get(i).asType(); + if (!processingEnv.getTypeUtils().isSameType(t1, t2)) { + errElem = (ExecutableElement) e; + err = "Error method must have the same parameters as @OnLocation one"; + continue METHODS; + } + } + return true; + } + if (err == null) { + err = "Cannot find " + name + "(Exception) method in this class"; + } + error(err, errElem); + return false; + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e geo/src/main/java/org/netbeans/html/geo/impl/JsG.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/geo/src/main/java/org/netbeans/html/geo/impl/JsG.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,107 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.geo.impl; + +import net.java.html.js.JavaScriptBody; + +/** Implementation class to deal with browser's navigator.geolocation + * object. + * + * @author Jaroslav Tulach + */ +public abstract class JsG { + protected JsG() { + if (!getClass().getName().equals("net.java.html.geo.Position$Handle$JsH")) { + throw new IllegalStateException(); + } + } + + public abstract void onLocation(Object position); + public abstract void onError(Object error); + + @JavaScriptBody(args = {}, body = "return !!navigator.geolocation;") + public static boolean hasGeolocation() { + return false; + } + + @JavaScriptBody( + args = { "onlyOnce", "enableHighAccuracy", "timeout", "maximumAge" }, + javacall = true, + body = + "var self = this;\n" + + "var ok = function (position) {\n" + + " self.@org.netbeans.html.geo.impl.JsG::onLocation(Ljava/lang/Object;)(position);\n" + + "};\n" + + "var fail = function (error) {\n" + + " self.@org.netbeans.html.geo.impl.JsG::onError(Ljava/lang/Object;)(error);\n" + + "};\n" + + "var options = {};\n" + + "options.enableHighAccuracy = enableHighAccuracy;\n" + + "if (timeout >= 0) options.timeout = timeout;\n" + + "if (maximumAge >= 0) options.maximumAge = maximumAge;\n" + + "if (onlyOnce) {\n" + + " navigator.geolocation.getCurrentPosition(ok, fail);\n" + + " return 0;\n" + + "} else {\n" + + " return navigator.geolocation.watchPosition(ok, fail);\n" + + "}\n" + ) + protected long start( + boolean onlyOnce, + boolean enableHighAccuracy, + long timeout, + long maximumAge + ) { + return -1; + } + + @JavaScriptBody(args = { "watch" }, body = "navigator.geolocation.clearWatch(watch);") + protected void stop(long watch) { + } + + @JavaScriptBody(args = { "self", "property" }, body = "return self[property];") + public static Object get(Object self, String property) { + return null; + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e geo/src/test/java/org/apidesign/html/geo/impl/Compile.java --- a/geo/src/test/java/org/apidesign/html/geo/impl/Compile.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,286 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.geo.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.*; - -/** - * - * @author Jaroslav Tulach - */ -final class Compile implements DiagnosticListener { - private final List> errors = - new ArrayList>(); - private final Map 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> getErrors() { - List> err; - err = new ArrayList>(); - for (Diagnostic diagnostic : errors) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - err.add(diagnostic); - } - } - return err; - } - - private Map compile(final String html, final String code) throws IOException { - StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null); - - final Map class2BAOS; - class2BAOS = new HashMap(); - - 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(sjfm) { - @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; - } - } - - 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 result = new HashMap(); - - for (Map.Entry e : class2BAOS.entrySet()) { - result.put(e.getKey(), e.getValue().toByteArray()); - } - - return result; - } - - - @Override - public void report(Diagnostic 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 e : errors) { - String msg = e.getMessage(Locale.US); - if (msg.contains(expMsg)) { - return; - } - sb.append("\n"); - sb.append(msg); - } - fail(sb.toString()); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e geo/src/test/java/org/apidesign/html/geo/impl/GeoProcessorTest.java --- a/geo/src/test/java/org/apidesign/html/geo/impl/GeoProcessorTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.geo.impl; - -import java.io.IOException; -import org.testng.annotations.Test; - -/** Test whether the annotation processor detects errors correctly. - * - * @author Jaroslav Tulach - */ -public class GeoProcessorTest { - - public GeoProcessorTest() { - } - - @Test public void onLocationMethodHasToTakePositionParameter() throws IOException { - Compile res = Compile.create("", "package x;\n" - + "class UseOnLocation {\n" - + " @net.java.html.geo.OnLocation\n" - + " public static void cantCallMe() {}\n" - + "}\n" - ); - res.assertErrors(); - res.assertError("first argument must be net.java.html.geo.Position"); - } - - @Test public void onLocationMethodCannotBePrivate() throws IOException { - Compile res = Compile.create("", "package x;\n" - + "class UseOnLocation {\n" - + " @net.java.html.geo.OnLocation\n" - + " private static void cantCallMe(net.java.html.geo.Position p) {}\n" - + "}\n" - ); - res.assertErrors(); - res.assertError("cannot be private"); - } - - @Test public void onErrorHasToExist() throws IOException { - Compile res = Compile.create("", "package x;\n" - + "class UseOnLocation {\n" - + " @net.java.html.geo.OnLocation(onError=\"doesNotExist\")\n" - + " static void cantCallMe(net.java.html.geo.Position p) {}\n" - + "}\n" - ); - res.assertErrors(); - res.assertError("not find doesNotExist"); - } - - @Test public void onErrorWouldHaveToBeStatic() throws IOException { - Compile res = Compile.create("", "package x;\n" - + "class UseOnLocation {\n" - + " @net.java.html.geo.OnLocation(onError=\"notStatic\")\n" - + " static void cantCallMe(net.java.html.geo.Position p) {}\n" - + " void notStatic(Exception e) {}\n" - + "}\n" - ); - res.assertErrors(); - res.assertError("have to be static"); - } - - @Test public void onErrorMustAcceptExceptionArgument() throws IOException { - Compile res = Compile.create("", "package x;\n" - + "class UseOnLocation {\n" - + " @net.java.html.geo.OnLocation(onError=\"notStatic\")\n" - + " static void cantCallMe(net.java.html.geo.Position p) {}\n" - + " static void notStatic(java.io.IOException e) {}\n" - + "}\n" - ); - res.assertErrors(); - res.assertError("Error method first argument needs to be Exception"); - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e geo/src/test/java/org/netbeans/html/geo/impl/Compile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/geo/src/test/java/org/netbeans/html/geo/impl/Compile.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,286 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.geo.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.*; + +/** + * + * @author Jaroslav Tulach + */ +final class Compile implements DiagnosticListener { + private final List> errors = + new ArrayList>(); + private final Map 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> getErrors() { + List> err; + err = new ArrayList>(); + for (Diagnostic diagnostic : errors) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + err.add(diagnostic); + } + } + return err; + } + + private Map compile(final String html, final String code) throws IOException { + StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null); + + final Map class2BAOS; + class2BAOS = new HashMap(); + + 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(sjfm) { + @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; + } + } + + 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 result = new HashMap(); + + for (Map.Entry e : class2BAOS.entrySet()) { + result.put(e.getKey(), e.getValue().toByteArray()); + } + + return result; + } + + + @Override + public void report(Diagnostic 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 e : errors) { + String msg = e.getMessage(Locale.US); + if (msg.contains(expMsg)) { + return; + } + sb.append("\n"); + sb.append(msg); + } + fail(sb.toString()); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e geo/src/test/java/org/netbeans/html/geo/impl/GeoProcessorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/geo/src/test/java/org/netbeans/html/geo/impl/GeoProcessorTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,114 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.geo.impl; + +import java.io.IOException; +import org.testng.annotations.Test; + +/** Test whether the annotation processor detects errors correctly. + * + * @author Jaroslav Tulach + */ +public class GeoProcessorTest { + + public GeoProcessorTest() { + } + + @Test public void onLocationMethodHasToTakePositionParameter() throws IOException { + Compile res = Compile.create("", "package x;\n" + + "class UseOnLocation {\n" + + " @net.java.html.geo.OnLocation\n" + + " public static void cantCallMe() {}\n" + + "}\n" + ); + res.assertErrors(); + res.assertError("first argument must be net.java.html.geo.Position"); + } + + @Test public void onLocationMethodCannotBePrivate() throws IOException { + Compile res = Compile.create("", "package x;\n" + + "class UseOnLocation {\n" + + " @net.java.html.geo.OnLocation\n" + + " private static void cantCallMe(net.java.html.geo.Position p) {}\n" + + "}\n" + ); + res.assertErrors(); + res.assertError("cannot be private"); + } + + @Test public void onErrorHasToExist() throws IOException { + Compile res = Compile.create("", "package x;\n" + + "class UseOnLocation {\n" + + " @net.java.html.geo.OnLocation(onError=\"doesNotExist\")\n" + + " static void cantCallMe(net.java.html.geo.Position p) {}\n" + + "}\n" + ); + res.assertErrors(); + res.assertError("not find doesNotExist"); + } + + @Test public void onErrorWouldHaveToBeStatic() throws IOException { + Compile res = Compile.create("", "package x;\n" + + "class UseOnLocation {\n" + + " @net.java.html.geo.OnLocation(onError=\"notStatic\")\n" + + " static void cantCallMe(net.java.html.geo.Position p) {}\n" + + " void notStatic(Exception e) {}\n" + + "}\n" + ); + res.assertErrors(); + res.assertError("have to be static"); + } + + @Test public void onErrorMustAcceptExceptionArgument() throws IOException { + Compile res = Compile.create("", "package x;\n" + + "class UseOnLocation {\n" + + " @net.java.html.geo.OnLocation(onError=\"notStatic\")\n" + + " static void cantCallMe(net.java.html.geo.Position p) {}\n" + + " static void notStatic(java.io.IOException e) {}\n" + + "}\n" + ); + res.assertErrors(); + res.assertError("Error method first argument needs to be Exception"); + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java --- a/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java Mon Dec 16 15:48:09 2013 +0100 +++ b/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -49,7 +49,7 @@ import java.util.Map; import net.java.html.BrwsrCtx; import net.java.html.json.Models; -import org.apidesign.html.json.impl.JSON; +import org.netbeans.html.json.impl.JSON; import org.apidesign.html.json.tck.KOTest; /** diff -r 700087d2a5d3 -r 92fb71afdc0e json-tck/src/main/java/net/java/html/json/tests/JSONTest.java --- a/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java Mon Dec 16 15:48:09 2013 +0100 +++ b/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -49,7 +49,7 @@ import net.java.html.json.Models; import net.java.html.json.OnReceive; import net.java.html.json.Property; -import org.apidesign.html.json.impl.JSON; +import org.netbeans.html.json.impl.JSON; import org.apidesign.html.json.tck.KOTest; /** Need to verify that models produce reasonable JSON objects. diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/net/java/html/json/Models.java --- a/json/src/main/java/net/java/html/json/Models.java Mon Dec 16 15:48:09 2013 +0100 +++ b/json/src/main/java/net/java/html/json/Models.java Mon Dec 16 16:59:43 2013 +0100 @@ -45,7 +45,7 @@ import net.java.html.BrwsrCtx; import java.io.IOException; import java.io.InputStream; -import org.apidesign.html.json.impl.JSON; +import org.netbeans.html.json.impl.JSON; /** Information about and * operations for classes generated by the {@link Model @Model} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/impl/Bindings.java --- a/json/src/main/java/org/apidesign/html/json/impl/Bindings.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import org.apidesign.html.json.spi.PropertyBinding; -import net.java.html.BrwsrCtx; -import org.apidesign.html.json.impl.PropertyBindingAccessor.FBData; -import org.apidesign.html.json.impl.PropertyBindingAccessor.PBData; -import org.apidesign.html.json.spi.FunctionBinding; -import org.apidesign.html.json.spi.Technology; - -/** - * - * @author Jaroslav Tulach - */ -public final class Bindings { - private Data data; - private final Technology bp; - - private Bindings(Technology bp) { - this.bp = bp; - } - - public PropertyBinding registerProperty(String propName, M model, SetAndGet access, boolean readOnly) { - return PropertyBindingAccessor.create(new PBData(this, propName, model, access, readOnly)); - } - - public FunctionBinding registerFunction(String name, M model, Callback access) { - return PropertyBindingAccessor.createFunction(new FBData(name, model, access)); - } - - public static Bindings apply(BrwsrCtx c, Object model) { - Technology bp = JSON.findTechnology(c); - return apply(bp); - } - - private static Bindings apply(Technology bp) { - return new Bindings(bp); - } - - public final void finish(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) { - assert data == null; - if (bp instanceof Technology.BatchInit) { - Technology.BatchInit bi = (Technology.BatchInit)bp; - data = bi.wrapModel(model, propArr, funcArr); - } else { - data = bp.wrapModel(model); - for (PropertyBinding b : propArr) { - bp.bind(b, model, data); - } - for (FunctionBinding b : funcArr) { - bp.expose(b, model, data); - } - } - } - - - public Data koData() { - return data; - } - - public void valueHasMutated(String firstName) { - bp.valueHasMutated(data, firstName); - } - - public void applyBindings() { - bp.applyBindings(data); - } - - Object wrapArray(Object[] arr) { - return bp.wrapArray(arr); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/impl/Callback.java --- a/json/src/main/java/org/apidesign/html/json/impl/Callback.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -/** - * - * @author Jaroslav Tulach - */ -public interface Callback { - public void call(Data model, Object data, Object ev); -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/impl/FromJSON.java --- a/json/src/main/java/org/apidesign/html/json/impl/FromJSON.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import net.java.html.BrwsrCtx; - -/** - * - * @author Jaroslav Tulach - */ -public interface FromJSON { - public Class factoryFor(); - public Data read(BrwsrCtx c, Object d); - public Data cloneTo(Object d, BrwsrCtx c); -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/impl/JSON.java --- a/json/src/main/java/org/apidesign/html/json/impl/JSON.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,474 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import net.java.html.BrwsrCtx; -import org.apidesign.html.context.spi.Contexts; -import org.apidesign.html.json.spi.FunctionBinding; -import org.apidesign.html.json.spi.JSONCall; -import org.apidesign.html.json.spi.PropertyBinding; -import org.apidesign.html.json.spi.Technology; -import org.apidesign.html.json.spi.Transfer; -import org.apidesign.html.json.spi.WSTransfer; - -/** - * - * @author Jaroslav Tulach - */ -public final class JSON { - private JSON() { - } - - static Technology findTechnology(BrwsrCtx c) { - Technology t = Contexts.find(c, Technology.class); - return t == null ? EmptyTech.EMPTY : t; - } - - static Transfer findTransfer(BrwsrCtx c) { - Transfer t = Contexts.find(c, Transfer.class); - return t == null ? EmptyTech.EMPTY : t; - } - - static WSTransfer findWSTransfer(BrwsrCtx c) { - WSTransfer t = Contexts.find(c, WSTransfer.class); - return t == null ? EmptyTech.EMPTY : t; - } - - public static void runInBrowser(BrwsrCtx c, Runnable runnable) { - findTechnology(c).runSafe(runnable); - } - - public static void extract(BrwsrCtx c, Object value, String[] props, Object[] values) { - Transfer t = findTransfer(c); - t.extract(value, props, values); - } - - private static Object getProperty(BrwsrCtx c, Object obj, String prop) { - if (prop == null) return obj; - - String[] arr = { prop }; - Object[] val = { null }; - extract(c, obj, arr, val); - return val[0]; - } - - public static Object toJSON(Object value) { - if (value == null) { - return "null"; - } - if (value instanceof Enum) { - value = value.toString(); - } - if (value instanceof String) { - String s = (String)value; - int len = s.length(); - StringBuilder sb = new StringBuilder(len + 10); - sb.append('"'); - for (int i = 0; i < len; i++) { - char ch = s.charAt(i); - switch (ch) { - case '\"': sb.append("\\\""); break; - case '\n': sb.append("\\n"); break; - case '\r': sb.append("\\r"); break; - case '\t': sb.append("\\t"); break; - case '\\': sb.append("\\\\"); break; - default: sb.append(ch); - } - } - sb.append('"'); - return sb.toString(); - } - return value.toString(); - } - - public static String toString(BrwsrCtx c, Object obj, String prop) { - obj = getProperty(c, obj, prop); - return obj instanceof String ? (String)obj : null; - } - public static Number toNumber(BrwsrCtx c, Object obj, String prop) { - obj = getProperty(c, obj, prop); - if (!(obj instanceof Number)) { - obj = Double.NaN; - } - return (Number)obj; - } - public static M toModel(BrwsrCtx c, Class aClass, Object data, Object object) { - Technology t = findTechnology(c); - Object o = t.toModel(aClass, data); - return aClass.cast(o); - } - - public static boolean isSame(int a, int b) { - return a == b; - } - - public static boolean isSame(double a, double b) { - return a == b; - } - - public static boolean isSame(Object a, Object b) { - if (a == b) { - return true; - } - if (a == null || b == null) { - return false; - } - return a.equals(b); - } - - public static int hashPlus(Object o, int h) { - return o == null ? h : h ^ o.hashCode(); - } - - public static T extractValue(Class type, Object val) { - if (Number.class.isAssignableFrom(type)) { - val = numberValue(val); - } - if (Boolean.class == type) { - val = boolValue(val); - } - if (String.class == type) { - val = stringValue(val); - } - if (Character.class == type) { - val = charValue(val); - } - if (Integer.class == type) { - val = val instanceof Number ? ((Number)val).intValue() : 0; - } - if (Long.class == type) { - val = val instanceof Number ? ((Number)val).longValue() : 0; - } - if (Short.class == type) { - val = val instanceof Number ? ((Number)val).shortValue() : 0; - } - if (Byte.class == type) { - val = val instanceof Number ? ((Number)val).byteValue() : 0; - } - if (Double.class == type) { - val = val instanceof Number ? ((Number)val).doubleValue() : Double.NaN; - } - if (Float.class == type) { - val = val instanceof Number ? ((Number)val).floatValue() : Float.NaN; - } - return type.cast(val); - } - - protected static boolean isNumeric(Object val) { - return ((val instanceof Integer) || (val instanceof Long) || (val instanceof Short) || (val instanceof Byte)); - } - - public static String stringValue(Object val) { - if (val instanceof Boolean) { - return ((Boolean)val ? "true" : "false"); - } - if (isNumeric(val)) { - return Long.toString(((Number)val).longValue()); - } - if (val instanceof Float) { - return Float.toString((Float)val); - } - if (val instanceof Double) { - return Double.toString((Double)val); - } - return (String)val; - } - - public static Number numberValue(Object val) { - if (val instanceof String) { - try { - return Double.valueOf((String)val); - } catch (NumberFormatException ex) { - return Double.NaN; - } - } - if (val instanceof Boolean) { - return (Boolean)val ? 1 : 0; - } - return (Number)val; - } - - public static Character charValue(Object val) { - if (val instanceof Number) { - return Character.toChars(numberValue(val).intValue())[0]; - } - if (val instanceof Boolean) { - return (Boolean)val ? (char)1 : (char)0; - } - if (val instanceof String) { - String s = (String)val; - return s.isEmpty() ? (char)0 : s.charAt(0); - } - return (Character)val; - } - - public static Boolean boolValue(Object val) { - if (val instanceof String) { - return Boolean.parseBoolean((String)val); - } - if (val instanceof Number) { - return numberValue(val).doubleValue() != 0.0; - } - - return Boolean.TRUE.equals(val); - } - - public static void loadJSON( - BrwsrCtx c, RcvrJSON callback, - String urlBefore, String urlAfter, String method, - Object data - ) { - JSONCall call = PropertyBindingAccessor.createCall(c, callback, urlBefore, urlAfter, method, data); - Transfer t = findTransfer(c); - t.loadJSON(call); - } - public static WS openWS( - BrwsrCtx c, RcvrJSON r, String url, Object data - ) { - WS ws = WSImpl.create(findWSTransfer(c), r); - ws.send(c, url, data); - return ws; - } - - public static abstract class WS { - private WS() { - } - - public abstract void send(BrwsrCtx ctx, String url, Object model); - } - - private static final class WSImpl extends WS { - - private final WSTransfer trans; - private final RcvrJSON rcvr; - private Socket socket; - private String prevURL; - - private WSImpl(WSTransfer trans, RcvrJSON rcvr) { - this.trans = trans; - this.rcvr = rcvr; - } - - static WS create(WSTransfer t, RcvrJSON r) { - return new WSImpl(t, r); - } - - @Override - public void send(BrwsrCtx ctx, String url, Object data) { - Socket s = socket; - if (s == null) { - if (data != null) { - throw new IllegalStateException("WebSocket is not opened yet. Call with null data, was: " + data); - } - JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, url, null, "WebSocket", null); - socket = trans.open(url, call); - prevURL = url; - return; - } - if (data == null) { - trans.close(s); - socket = null; - return; - } - if (!prevURL.equals(url)) { - throw new IllegalStateException( - "Can't call to different URL " + url + " was: " + prevURL + "!" - + " Close the socket by calling it will null data first!" - ); - } - JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, prevURL, null, "WebSocket", data); - trans.send(s, call); - } - - } - - private static final Map> froms; - static { - Map> m = new HashMap>(); - froms = m; - } - public static void register(FromJSON from) { - froms.put(from.factoryFor(), from); - } - - public static boolean isModel(Class clazz) { - return findFrom(clazz) != null; - } - - private static FromJSON findFrom(Class clazz) { - for (int i = 0; i < 2; i++) { - FromJSON from = froms.get(clazz); - if (from == null) { - initClass(clazz); - } else { - return from; - } - } - return null; - } - - public static Model bindTo(Model model, BrwsrCtx c) { - FromJSON from = findFrom(model.getClass()); - if (from == null) { - throw new IllegalArgumentException(); - } - return (Model) from.cloneTo(model, c); - } - - public static T readStream(BrwsrCtx c, Class modelClazz, InputStream data) - throws IOException { - Transfer tr = findTransfer(c); - return read(c, modelClazz, tr.toJSON((InputStream)data)); - } - public static T read(BrwsrCtx c, Class modelClazz, Object data) { - if (data == null) { - return null; - } - if (modelClazz == String.class) { - return modelClazz.cast(data.toString()); - } - for (int i = 0; i < 2; i++) { - FromJSON from = froms.get(modelClazz); - if (from == null) { - initClass(modelClazz); - } else { - return modelClazz.cast(from.read(c, data)); - } - } - throw new NullPointerException(); - } - static void initClass(Class modelClazz) { - try { - // try to resolve the class - ClassLoader l; - try { - l = modelClazz.getClassLoader(); - } catch (SecurityException ex) { - l = null; - } - if (l != null) { - Class.forName(modelClazz.getName(), true, l); - } - modelClazz.newInstance(); - } catch (Exception ex) { - // ignore and try again - } - } - - private static final class EmptyTech - implements Technology, Transfer, WSTransfer { - private static final EmptyTech EMPTY = new EmptyTech(); - - @Override - public Object wrapModel(Object model) { - return model; - } - - @Override - public void valueHasMutated(Object data, String propertyName) { - } - - @Override - public void bind(PropertyBinding b, Object model, Object data) { - } - - @Override - public void expose(FunctionBinding fb, Object model, Object d) { - } - - @Override - public void applyBindings(Object data) { - } - - @Override - public Object wrapArray(Object[] arr) { - return arr; - } - - @Override - public void extract(Object obj, String[] props, Object[] values) { - for (int i = 0; i < values.length; i++) { - values[i] = null; - } - } - - @Override - public void loadJSON(JSONCall call) { - call.notifyError(new UnsupportedOperationException()); - } - - @Override - public M toModel(Class modelClass, Object data) { - return modelClass.cast(data); - } - - @Override - public Object toJSON(InputStream is) throws IOException { - throw new IOException("Not supported"); - } - - @Override - public synchronized void runSafe(Runnable r) { - r.run(); - } - - @Override - public Void open(String url, JSONCall onReply) { - onReply.notifyError(new UnsupportedOperationException("WebSockets not supported!")); - return null; - } - - @Override - public void send(Void socket, JSONCall data) { - } - - @Override - public void close(Void socket) { - } - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/impl/JSONList.java --- a/json/src/main/java/org/apidesign/html/json/impl/JSONList.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,236 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import net.java.html.BrwsrCtx; - -/** - * - * @author Jaroslav Tulach - */ -public final class JSONList extends ArrayList { - private final String name; - private final String[] deps; - private Bindings[] model; - private Runnable onchange; - - public JSONList(Bindings[] model, String name, String... deps) { - assert model.length == 1; - this.model = model; - this.name = name; - this.deps = deps; - } - - public void init(T... values) { - if (values == null || values.length == 0) { - return; - } - if (this.model[0] != null || !isEmpty()) { - throw new IllegalStateException(); - } - super.addAll(Arrays.asList(values)); - } - - public void init(Object values) { - int len; - if (values == null || (len = Array.getLength(values)) == 0) { - return; - } - if (this.model[0] != null || !isEmpty()) { - throw new IllegalStateException(); - } - for (int i = 0; i < len; i++) { - Object data = Array.get(values, i); - super.add((T)data); - } - } - - public JSONList onChange(Runnable r) { - if (this.onchange != null) { - throw new IllegalStateException(); - } - this.onchange = r; - return this; - } - - @Override - public boolean add(T e) { - boolean ret = super.add(e); - notifyChange(); - return ret; - } - - @Override - public boolean addAll(Collection c) { - boolean ret = super.addAll(c); - notifyChange(); - return ret; - } - - @Override - public boolean addAll(int index, Collection c) { - boolean ret = super.addAll(index, c); - notifyChange(); - return ret; - } - - @Override - public boolean remove(Object o) { - boolean ret = super.remove(o); - notifyChange(); - return ret; - } - - @Override - public void clear() { - super.clear(); - notifyChange(); - } - - @Override - public boolean removeAll(Collection c) { - boolean ret = super.removeAll(c); - notifyChange(); - return ret; - } - - @Override - public boolean retainAll(Collection c) { - boolean ret = super.retainAll(c); - notifyChange(); - return ret; - } - - @Override - public T set(int index, T element) { - T ret = super.set(index, element); - notifyChange(); - return ret; - } - - @Override - public void add(int index, T element) { - super.add(index, element); - notifyChange(); - } - - @Override - public T remove(int index) { - T ret = super.remove(index); - notifyChange(); - return ret; - } - - @Override - public String toString() { - Iterator it = iterator(); - if (!it.hasNext()) { - return "[]"; - } - String sep = ""; - StringBuilder sb = new StringBuilder(); - sb.append('['); - while (it.hasNext()) { - T t = it.next(); - sb.append(sep); - sb.append(JSON.toJSON(t)); - sep = ","; - } - sb.append(']'); - return sb.toString(); - } - - private void notifyChange() { - Bindings m = model[0]; - if (m != null) { - m.valueHasMutated(name); - for (String dependant : deps) { - m.valueHasMutated(dependant); - } - Runnable r = onchange; - if (r != null) { - r.run(); - } - } - } - - public void cloneAll(BrwsrCtx c, Collection other) { - Boolean isModel = null; - for (T t : other) { - if (isModel == null) { - isModel = JSON.isModel(t.getClass()); - } - if (isModel) { - add(JSON.bindTo(t, c)); - } else { - add(t); - } - } - } - - @Override - public JSONList clone() { - throw new UnsupportedOperationException(); - } - - static final Object koData(Collection c, Bindings m) { - Object[] arr = c.toArray(new Object[c.size()]); - for (int i = 0; i < arr.length; i++) { - Object r = WrapperObject.find(arr[i], m); - if (r != null) { - arr[i] = r; - } - } - return m.wrapArray(arr); - } - - final Object koData() { - return koData(this, model[0]); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java --- a/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1767 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.StringWriter; -import java.io.Writer; -import java.lang.annotation.AnnotationTypeMismatchException; -import java.lang.annotation.IncompleteAnnotationException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.ResourceBundle; -import java.util.Set; -import java.util.WeakHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.Completion; -import javax.annotation.processing.Completions; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.Processor; -import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.annotation.processing.SupportedSourceVersion; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.MirroredTypeException; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; -import javax.tools.Diagnostic; -import javax.tools.FileObject; -import net.java.html.json.ComputedProperty; -import net.java.html.json.Model; -import net.java.html.json.Function; -import net.java.html.json.ModelOperation; -import net.java.html.json.OnPropertyChange; -import net.java.html.json.OnReceive; -import net.java.html.json.Property; -import org.openide.util.lookup.ServiceProvider; - -/** Annotation processor to process {@link Model @Model} annotations and - * generate appropriate model classes. - * - * @author Jaroslav Tulach - */ -@ServiceProvider(service=Processor.class) -@SupportedSourceVersion(SourceVersion.RELEASE_6) -@SupportedAnnotationTypes({ - "net.java.html.json.Model", - "net.java.html.json.ModelOperation", - "net.java.html.json.Function", - "net.java.html.json.OnReceive", - "net.java.html.json.OnPropertyChange", - "net.java.html.json.ComputedProperty", - "net.java.html.json.Property" -}) -public final class ModelProcessor extends AbstractProcessor { - private static final Logger LOG = Logger.getLogger(ModelProcessor.class.getName()); - private final Map models = new WeakHashMap(); - private final Map verify = new WeakHashMap(); - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - boolean ok = true; - for (Element e : roundEnv.getElementsAnnotatedWith(Model.class)) { - if (!processModel(e)) { - ok = false; - } - } - if (roundEnv.processingOver()) { - models.clear(); - for (Map.Entry entry : verify.entrySet()) { - TypeElement te = (TypeElement)entry.getKey(); - String fqn = processingEnv.getElementUtils().getBinaryName(te).toString(); - Element finalElem = processingEnv.getElementUtils().getTypeElement(fqn); - if (finalElem == null) { - continue; - } - Prprt[] props; - Model m = finalElem.getAnnotation(Model.class); - if (m == null) { - continue; - } - props = Prprt.wrap(processingEnv, finalElem, m.properties()); - for (Prprt p : props) { - boolean[] isModel = { false }; - boolean[] isEnum = { false }; - boolean[] isPrimitive = { false }; - String t = checkType(p, isModel, isEnum, isPrimitive); - if (isEnum[0]) { - continue; - } - if (isPrimitive[0]) { - continue; - } - if (isModel[0]) { - continue; - } - if ("java.lang.String".equals(t)) { - continue; - } - error("The type " + t + " should be defined by @Model annotation", entry.getKey()); - } - } - verify.clear(); - } - return ok; - } - - private void error(String msg, Element e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e); - } - - private boolean processModel(Element e) { - boolean ok = true; - Model m = e.getAnnotation(Model.class); - if (m == null) { - return true; - } - String pkg = findPkgName(e); - Writer w; - String className = m.className(); - models.put(e, className); - try { - StringWriter body = new StringWriter(); - List propsGetSet = new ArrayList(); - List functions = new ArrayList(); - Map> propsDeps = new HashMap>(); - Map> functionDeps = new HashMap>(); - Prprt[] props = createProps(e, m.properties()); - - if (!generateComputedProperties(body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) { - ok = false; - } - if (!generateOnChange(e, propsDeps, props, className, functionDeps)) { - ok = false; - } - if (!generateProperties(e, body, props, propsGetSet, propsDeps, functionDeps)) { - ok = false; - } - if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) { - ok = false; - } - if (!generateReceive(e, body, className, e.getEnclosedElements(), functions)) { - ok = false; - } - if (!generateOperation(e, body, className, e.getEnclosedElements())) { - ok = false; - } - FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e); - w = new OutputStreamWriter(java.openOutputStream()); - try { - w.append("package " + pkg + ";\n"); - w.append("import net.java.html.json.*;\n"); - w.append("public final class ").append(className).append(" implements Cloneable {\n"); - w.append(" private boolean locked;\n"); - w.append(" private net.java.html.BrwsrCtx context;\n"); - w.append(" private org.apidesign.html.json.impl.Bindings[] ko = { null };\n"); - w.append(body.toString()); - w.append(" private static Class<" + inPckName(e) + "> modelFor() { return null; }\n"); - w.append(" private ").append(className).append("(net.java.html.BrwsrCtx context) {\n"); - w.append(" this.context = context;\n"); - w.append(" };\n"); - w.append(" public ").append(className).append("() {\n"); - w.append(" this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n"); - for (Prprt p : props) { - if (p.array()) { - continue; - } - boolean[] isModel = {false}; - boolean[] isEnum = {false}; - boolean isPrimitive[] = {false}; - String tn = checkType(p, isModel, isEnum, isPrimitive); - if (isModel[0]) { - w.write(" prop_" + p.name() + " = new " + tn + "();\n"); - } - } - w.append(" };\n"); - if (props.length > 0) { - w.append(" public ").append(className).append("("); - Prprt firstArray = null; - String sep = ""; - for (Prprt p : props) { - if (p.array()) { - if (firstArray == null) { - firstArray = p; - } - continue; - } - String tn = typeName(e, p); - w.write(sep); - w.write(tn); - w.write(" " + p.name()); - sep = ", "; - } - if (firstArray != null) { - String tn; - boolean[] isModel = {false}; - boolean[] isEnum = {false}; - boolean isPrimitive[] = {false}; - tn = checkType(firstArray, isModel, isEnum, isPrimitive); - w.write(sep); - w.write(tn); - w.write("... " + firstArray.name()); - } - w.append(") {\n"); - w.append(" this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n"); - for (Prprt p : props) { - if (p.array()) { - continue; - } - w.write(" this.prop_" + p.name() + " = " + p.name() + ";\n"); - } - if (firstArray != null) { - w.write(" this.prop_" + firstArray.name() + ".init(" + firstArray.name() + ");\n"); - } - w.append(" };\n"); - } - w.append(" private org.apidesign.html.json.impl.Bindings intKnckt() {\n"); - w.append(" if (ko[0] != null) return ko[0];\n"); - w.append(" ko[0] = org.apidesign.html.json.impl.Bindings.apply(context, this);\n"); - { - w.append(" org.apidesign.html.json.spi.PropertyBinding[] propArr = {\n"); - for (int i = 0; i < propsGetSet.size(); i += 5) { - w.append(" ko[0].registerProperty(\"").append(propsGetSet.get(i)).append("\", this, new P("); - w.append((i / 5) + "), " + (propsGetSet.get(i + 2) == null) + "),\n"); - } - w.append(" };\n"); - } - { - w.append(" org.apidesign.html.json.spi.FunctionBinding[] funcArr = {\n"); - for (int i = 0; i < functions.size(); i += 2) { - w.append(" ko[0].registerFunction(\"").append(functions.get(i)).append("\", this, new P("); - w.append((i / 2) + ")),\n"); - } - w.append(" };\n"); - } - w.append(" ko[0].finish(this, propArr, funcArr);\n"); - w.append(" return ko[0];\n"); - w.append(" };\n"); - w.append(" private static final class P implements org.apidesign.html.json.impl.SetAndGet<" + className + ">,\n"); - w.append(" org.apidesign.html.json.impl.Callback<" + className + ">,\n"); - w.append(" org.apidesign.html.json.impl.FromJSON<" + className + "> {\n"); - w.append(" private final int type;\n"); - w.append(" P(int t) { type = t; };\n"); - w.append(" public void setValue(" + className + " data, Object value) {\n"); - w.append(" switch (type) {\n"); - for (int i = 0; i < propsGetSet.size(); i += 5) { - final String set = propsGetSet.get(i + 2); - String tn = propsGetSet.get(i + 4); - String btn = findBoxedType(tn); - if (btn != null) { - tn = btn; - } - if (set != null) { - w.append(" case " + (i / 5) + ": data." + strip(set) + "(org.apidesign.html.json.impl.JSON.extractValue(" + tn + ".class, value)); return;\n"); - } - } - w.append(" }\n"); - w.append(" }\n"); - w.append(" public Object getValue(" + className + " data) {\n"); - w.append(" switch (type) {\n"); - for (int i = 0; i < propsGetSet.size(); i += 5) { - final String get = propsGetSet.get(i + 1); - if (get != null) { - w.append(" case " + (i / 5) + ": return data." + strip(get) + "();\n"); - } - } - w.append(" }\n"); - w.append(" throw new UnsupportedOperationException();\n"); - w.append(" }\n"); - w.append(" public void call(" + className + " model, Object data, Object ev) {\n"); - w.append(" switch (type) {\n"); - for (int i = 0; i < functions.size(); i += 2) { - final String name = functions.get(i); - w.append(" case " + (i / 2) + ": model." + name + "(data, ev); return;\n"); - } - w.append(" }\n"); - w.append(" throw new UnsupportedOperationException();\n"); - w.append(" }\n"); - w.append(" public Class<" + className + "> factoryFor() { return " + className + ".class; }\n"); - w.append(" public " + className + " read(net.java.html.BrwsrCtx c, Object json) { return new " + className + "(c, json); }\n"); - w.append(" public " + className + " cloneTo(Object o, net.java.html.BrwsrCtx c) { return ((" + className + ")o).clone(c); }\n"); - w.append(" }\n"); - w.append(" static { org.apidesign.html.json.impl.JSON.register(new P(0)); }\n"); - w.append(" private ").append(className).append("(net.java.html.BrwsrCtx c, Object json) {\n"); - w.append(" this.context = c;\n"); - int values = 0; - for (int i = 0; i < propsGetSet.size(); i += 5) { - Prprt p = findPrprt(props, propsGetSet.get(i)); - if (p == null) { - continue; - } - values++; - } - w.append(" Object[] ret = new Object[" + values + "];\n"); - w.append(" org.apidesign.html.json.impl.JSON.extract(context, json, new String[] {\n"); - for (int i = 0; i < propsGetSet.size(); i += 5) { - Prprt p = findPrprt(props, propsGetSet.get(i)); - if (p == null) { - continue; - } - w.append(" \"").append(propsGetSet.get(i)).append("\",\n"); - } - w.append(" }, ret);\n"); - for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i += 5) { - final String pn = propsGetSet.get(i); - Prprt p = findPrprt(props, pn); - if (p == null) { - continue; - } - boolean[] isModel = { false }; - boolean[] isEnum = { false }; - boolean isPrimitive[] = { false }; - String type = checkType(props[prop++], isModel, isEnum, isPrimitive); - if (p.array()) { - w.append(" if (ret[" + cnt + "] instanceof Object[]) {\n"); - w.append(" for (Object e : ((Object[])ret[" + cnt + "])) {\n"); - if (isModel[0]) { - w.append(" this.prop_").append(pn).append(".add(org.apidesign.html.json.impl.JSON.read"); - w.append("(c, " + type + ".class, e));\n"); - } else if (isEnum[0]) { - w.append(" this.prop_").append(pn); - w.append(".add(e == null ? null : "); - w.append(type).append(".valueOf(org.apidesign.html.json.impl.JSON.stringValue(e)));\n"); - } else { - if (isPrimitive(type)) { - w.append(" this.prop_").append(pn).append(".add(org.apidesign.html.json.impl.JSON.numberValue(e)."); - w.append(type).append("Value());\n"); - } else { - w.append(" this.prop_").append(pn).append(".add(("); - w.append(type).append(")e);\n"); - } - } - w.append(" }\n"); - w.append(" }\n"); - } else { - if (isEnum[0]) { - w.append(" try {\n"); - w.append(" this.prop_").append(pn); - w.append(" = ret[" + cnt + "] == null ? null : "); - w.append(type).append(".valueOf(org.apidesign.html.json.impl.JSON.stringValue(ret[" + cnt + "]));\n"); - w.append(" } catch (IllegalArgumentException ex) {\n"); - w.append(" ex.printStackTrace();\n"); - w.append(" }\n"); - } else if (isPrimitive(type)) { - w.append(" this.prop_").append(pn); - w.append(" = ret[" + cnt + "] == null ? "); - if ("char".equals(type)) { - w.append("0 : (org.apidesign.html.json.impl.JSON.charValue("); - } else if ("boolean".equals(type)) { - w.append("false : (org.apidesign.html.json.impl.JSON.boolValue("); - } else { - w.append("0 : (org.apidesign.html.json.impl.JSON.numberValue("); - } - w.append("ret[" + cnt + "]))."); - w.append(type).append("Value();\n"); - } else if (isModel[0]) { - w.append(" this.prop_").append(pn).append(" = org.apidesign.html.json.impl.JSON.read"); - w.append("(c, " + type + ".class, "); - w.append("ret[" + cnt + "]);\n"); - }else { - w.append(" this.prop_").append(pn); - w.append(" = (").append(type).append(')'); - w.append("ret[" + cnt + "];\n"); - } - } - cnt++; - } - w.append(" };\n"); - writeToString(props, w); - writeClone(className, props, w); - w.write(" /** Activates this model instance in the current {@link \n" - + "net.java.html.json.Models#bind(java.lang.Object, net.java.html.BrwsrCtx) browser context}. \n" - + "In case of using Knockout technology, this means to \n" - + "bind JSON like data in this model instance with Knockout tags in \n" - + "the surrounding HTML page.\n" - + "*/\n" - ); - w.write(" public " + className + " applyBindings() {\n"); - w.write(" intKnckt().applyBindings();\n"); - w.write(" return this;\n"); - w.write(" }\n"); - w.write(" public boolean equals(Object o) {\n"); - w.write(" if (o == this) return true;\n"); - w.write(" if (o instanceof org.apidesign.html.json.impl.WrapperObject) {\n"); - w.write(" ((org.apidesign.html.json.impl.WrapperObject)o).setRealObject(intKnckt().koData());\n"); - w.write(" return false;\n"); - w.write(" }\n"); - w.write(" if (!(o instanceof " + className + ")) return false;\n"); - w.write(" " + className + " p = (" + className + ")o;\n"); - for (Prprt p : props) { - w.write(" if (!org.apidesign.html.json.impl.JSON.isSame(prop_" + p.name() + ", p.prop_" + p.name() + ")) return false;\n"); - } - w.write(" return true;\n"); - w.write(" }\n"); - w.write(" public int hashCode() {\n"); - w.write(" int h = " + className + ".class.getName().hashCode();\n"); - for (Prprt p : props) { - w.write(" h = org.apidesign.html.json.impl.JSON.hashPlus(prop_" + p.name() + ", h);\n"); - } - w.write(" return h;\n"); - w.write(" }\n"); - w.write("}\n"); - } finally { - w.close(); - } - } catch (IOException ex) { - error("Can't create " + className + ".java", e); - return false; - } - return ok; - } - - private boolean generateProperties( - Element where, - Writer w, Prprt[] properties, - Collection props, - Map> deps, - Map> functionDeps - ) throws IOException { - boolean ok = true; - for (Prprt p : properties) { - final String tn; - tn = typeName(where, p); - String[] gs = toGetSet(p.name(), tn, p.array()); - String castTo; - - if (p.array()) { - w.write(" private org.apidesign.html.json.impl.JSONList<" + tn + "> prop_" + p.name() + " = new org.apidesign.html.json.impl.JSONList<" + tn + ">(ko, \"" - + p.name() + "\""); - Collection dependants = deps.get(p.name()); - if (dependants != null) { - for (String depProp : dependants) { - w.write(", "); - w.write('\"'); - w.write(depProp); - w.write('\"'); - } - } - w.write(")"); - - dependants = functionDeps.get(p.name()); - if (dependants != null) { - w.write(".onChange(new Runnable() { public void run() {\n"); - for (String call : dependants) { - w.append(" ").append(call); - } - w.write(" }})"); - } - w.write(";\n"); - - castTo = "java.util.List"; - w.write(" public java.util.List<" + tn + "> " + gs[0] + "() {\n"); - w.write(" if (locked) throw new IllegalStateException();\n"); - w.write(" return prop_" + p.name() + ";\n"); - w.write(" }\n"); - } else { - castTo = tn; - w.write(" private " + tn + " prop_" + p.name() + ";\n"); - w.write(" public " + tn + " " + gs[0] + "() {\n"); - w.write(" if (locked) throw new IllegalStateException();\n"); - w.write(" return prop_" + p.name() + ";\n"); - w.write(" }\n"); - w.write(" public void " + gs[1] + "(" + tn + " v) {\n"); - w.write(" if (locked) throw new IllegalStateException();\n"); - w.write(" if (org.apidesign.html.json.impl.JSON.isSame(prop_" + p.name() + ", v)) return;\n"); - w.write(" prop_" + p.name() + " = v;\n"); - w.write(" org.apidesign.html.json.impl.Bindings b = ko[0];\n"); - w.write(" if (b != null) {\n"); - w.write(" b.valueHasMutated(\"" + p.name() + "\");\n"); - Collection dependants = deps.get(p.name()); - if (dependants != null) { - for (String depProp : dependants) { - w.write(" b.valueHasMutated(\"" + depProp + "\");\n"); - } - } - w.write(" }\n"); - dependants = functionDeps.get(p.name()); - if (dependants != null) { - for (String call : dependants) { - w.append(" ").append(call); - } - } - w.write(" }\n"); - } - - props.add(p.name()); - props.add(gs[2]); - props.add(gs[3]); - props.add(gs[0]); - props.add(castTo); - } - return ok; - } - - private boolean generateComputedProperties( - Writer w, Prprt[] fixedProps, - Collection arr, Collection props, - Map> deps - ) throws IOException { - boolean ok = true; - for (Element e : arr) { - if (e.getKind() != ElementKind.METHOD) { - continue; - } - if (e.getAnnotation(ComputedProperty.class) == null) { - continue; - } - if (!e.getModifiers().contains(Modifier.STATIC)) { - error("Method " + e.getSimpleName() + " has to be static when annotated by @ComputedProperty", e); - ok = false; - continue; - } - ExecutableElement ee = (ExecutableElement)e; - final TypeMirror rt = ee.getReturnType(); - final Types tu = processingEnv.getTypeUtils(); - TypeMirror ert = tu.erasure(rt); - String tn = fqn(ert, ee); - boolean array = false; - final TypeMirror toCheck; - if (tn.equals("java.util.List")) { - array = true; - toCheck = ((DeclaredType)rt).getTypeArguments().get(0); - } else { - toCheck = rt; - } - - final String sn = ee.getSimpleName().toString(); - - if (toCheck.getKind().isPrimitive()) { - // OK - } else { - TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType(); - TypeMirror enumType = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType(); - - if (tu.isSubtype(toCheck, stringType)) { - // OK - } else if (tu.isSubtype(tu.erasure(toCheck), tu.erasure(enumType))) { - // OK - } else if (isModel(toCheck)) { - // OK - } else { - ok = false; - error(sn + " cannot return " + toCheck, e); - } - } - - String[] gs = toGetSet(sn, tn, array); - - w.write(" public " + tn + " " + gs[0] + "() {\n"); - w.write(" if (locked) throw new IllegalStateException();\n"); - int arg = 0; - for (VariableElement pe : ee.getParameters()) { - final String dn = pe.getSimpleName().toString(); - - if (!verifyPropName(pe, dn, fixedProps)) { - ok = false; - } - - final String dt = fqn(pe.asType(), ee); - String[] call = toGetSet(dn, dt, false); - w.write(" " + dt + " arg" + (++arg) + " = "); - w.write(call[0] + "();\n"); - - Collection depends = deps.get(dn); - if (depends == null) { - depends = new LinkedHashSet(); - deps.put(dn, depends); - } - depends.add(sn); - } - w.write(" try {\n"); - w.write(" locked = true;\n"); - w.write(" return " + fqn(ee.getEnclosingElement().asType(), ee) + '.' + e.getSimpleName() + "("); - String sep = ""; - for (int i = 1; i <= arg; i++) { - w.write(sep); - w.write("arg" + i); - sep = ", "; - } - w.write(");\n"); - w.write(" } finally {\n"); - w.write(" locked = false;\n"); - w.write(" }\n"); - w.write(" }\n"); - - props.add(e.getSimpleName().toString()); - props.add(gs[2]); - props.add(null); - props.add(gs[0]); - props.add(tn); - } - - return ok; - } - - private static String[] toGetSet(String name, String type, boolean array) { - String n = Character.toUpperCase(name.charAt(0)) + name.substring(1); - String bck2brwsrType = "L" + type.replace('.', '_') + "_2"; - if ("int".equals(type)) { - bck2brwsrType = "I"; - } - if ("double".equals(type)) { - bck2brwsrType = "D"; - } - String pref = "get"; - if ("boolean".equals(type)) { - pref = "is"; - bck2brwsrType = "Z"; - } - final String nu = n.replace('.', '_'); - if (array) { - return new String[] { - "get" + n, - null, - "get" + nu + "__Ljava_util_List_2", - null - }; - } - return new String[]{ - pref + n, - "set" + n, - pref + nu + "__" + bck2brwsrType, - "set" + nu + "__V" + bck2brwsrType - }; - } - - private String typeName(Element where, Prprt p) { - String ret; - boolean[] isModel = { false }; - boolean[] isEnum = { false }; - boolean isPrimitive[] = { false }; - ret = checkType(p, isModel, isEnum, isPrimitive); - if (p.array()) { - String bt = findBoxedType(ret); - if (bt != null) { - return bt; - } - } - return ret; - } - - private static String findBoxedType(String ret) { - if (ret.equals("boolean")) { - return Boolean.class.getName(); - } - if (ret.equals("byte")) { - return Byte.class.getName(); - } - if (ret.equals("short")) { - return Short.class.getName(); - } - if (ret.equals("char")) { - return Character.class.getName(); - } - if (ret.equals("int")) { - return Integer.class.getName(); - } - if (ret.equals("long")) { - return Long.class.getName(); - } - if (ret.equals("float")) { - return Float.class.getName(); - } - if (ret.equals("double")) { - return Double.class.getName(); - } - return null; - } - - private boolean verifyPropName(Element e, String propName, Prprt[] existingProps) { - StringBuilder sb = new StringBuilder(); - String sep = ""; - for (Prprt Prprt : existingProps) { - if (Prprt.name().equals(propName)) { - return true; - } - sb.append(sep); - sb.append('"'); - sb.append(Prprt.name()); - sb.append('"'); - sep = ", "; - } - error( - propName + " is not one of known properties: " + sb - , e - ); - return false; - } - - private static String findPkgName(Element e) { - for (;;) { - if (e.getKind() == ElementKind.PACKAGE) { - return ((PackageElement)e).getQualifiedName().toString(); - } - e = e.getEnclosingElement(); - } - } - - private boolean generateFunctions( - Element clazz, StringWriter body, String className, - List enclosedElements, List functions - ) { - for (Element m : enclosedElements) { - if (m.getKind() != ElementKind.METHOD) { - continue; - } - ExecutableElement e = (ExecutableElement)m; - Function onF = e.getAnnotation(Function.class); - if (onF == null) { - continue; - } - if (!e.getModifiers().contains(Modifier.STATIC)) { - error("@OnFunction method needs to be static", e); - return false; - } - if (e.getModifiers().contains(Modifier.PRIVATE)) { - error("@OnFunction method cannot be private", e); - return false; - } - if (e.getReturnType().getKind() != TypeKind.VOID) { - error("@OnFunction method should return void", e); - return false; - } - String n = e.getSimpleName().toString(); - body.append(" private void ").append(n).append("(Object data, Object ev) {\n"); - body.append(" ").append(((TypeElement)clazz).getQualifiedName()).append(".").append(n).append("("); - body.append(wrapParams(e, null, className, "ev", "data")); - body.append(");\n"); - body.append(" }\n"); - - functions.add(n); - functions.add(n + "__VLjava_lang_Object_2Ljava_lang_Object_2"); - } - return true; - } - - private boolean generateOnChange(Element clazz, Map> propDeps, - Prprt[] properties, String className, - Map> functionDeps - ) { - for (Element m : clazz.getEnclosedElements()) { - if (m.getKind() != ElementKind.METHOD) { - continue; - } - ExecutableElement e = (ExecutableElement) m; - OnPropertyChange onPC = e.getAnnotation(OnPropertyChange.class); - if (onPC == null) { - continue; - } - for (String pn : onPC.value()) { - if (findPrprt(properties, pn) == null && findDerivedFrom(propDeps, pn).isEmpty()) { - error("No Prprt named '" + pn + "' in the model", clazz); - return false; - } - } - if (!e.getModifiers().contains(Modifier.STATIC)) { - error("@OnPrprtChange method needs to be static", e); - return false; - } - if (e.getModifiers().contains(Modifier.PRIVATE)) { - error("@OnPrprtChange method cannot be private", e); - return false; - } - if (e.getReturnType().getKind() != TypeKind.VOID) { - error("@OnPrprtChange method should return void", e); - return false; - } - String n = e.getSimpleName().toString(); - - - for (String pn : onPC.value()) { - StringBuilder call = new StringBuilder(); - call.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("("); - call.append(wrapPropName(e, className, "name", pn)); - call.append(");\n"); - - Collection change = functionDeps.get(pn); - if (change == null) { - change = new ArrayList(); - functionDeps.put(pn, change); - } - change.add(call.toString()); - for (String dpn : findDerivedFrom(propDeps, pn)) { - change = functionDeps.get(dpn); - if (change == null) { - change = new ArrayList(); - functionDeps.put(dpn, change); - } - change.add(call.toString()); - } - } - } - return true; - } - - private boolean generateOperation(Element clazz, - StringWriter body, String className, - List enclosedElements - ) { - for (Element m : enclosedElements) { - if (m.getKind() != ElementKind.METHOD) { - continue; - } - ExecutableElement e = (ExecutableElement)m; - ModelOperation mO = e.getAnnotation(ModelOperation.class); - if (mO == null) { - continue; - } - if (!e.getModifiers().contains(Modifier.STATIC)) { - error("@ModelOperation method needs to be static", e); - return false; - } - if (e.getModifiers().contains(Modifier.PRIVATE)) { - error("@ModelOperation method cannot be private", e); - return false; - } - if (e.getReturnType().getKind() != TypeKind.VOID) { - error("@ModelOperation method should return void", e); - return false; - } - List args = new ArrayList(); - { - body.append(" public void ").append(m.getSimpleName()).append("("); - String sep = ""; - boolean checkFirst = true; - for (VariableElement ve : e.getParameters()) { - final TypeMirror type = ve.asType(); - CharSequence simpleName; - if (type.getKind() == TypeKind.DECLARED) { - simpleName = ((DeclaredType)type).asElement().getSimpleName(); - } else { - simpleName = type.toString(); - } - if (simpleName.toString().equals(className)) { - checkFirst = false; - } else { - if (checkFirst) { - error("First parameter of @ModelOperation method must be " + className, m); - return false; - } - args.add(ve.getSimpleName().toString()); - body.append(sep).append("final "); - body.append(ve.asType().toString()).append(" "); - body.append(ve.toString()); - sep = ", "; - } - } - body.append(") {\n"); - body.append(" org.apidesign.html.json.impl.JSON.runInBrowser(this.context, new Runnable() { public void run() {\n"); - body.append(" ").append(clazz.getSimpleName()).append(".").append(m.getSimpleName()).append("("); - body.append(className).append(".this"); - for (String s : args) { - body.append(", ").append(s); - } - body.append(");\n"); - body.append(" }});\n"); - body.append(" }\n"); - } - - } - return true; - } - - - private boolean generateReceive( - Element clazz, StringWriter body, String className, - List enclosedElements, List functions - ) { - for (Element m : enclosedElements) { - if (m.getKind() != ElementKind.METHOD) { - continue; - } - ExecutableElement e = (ExecutableElement)m; - OnReceive onR = e.getAnnotation(OnReceive.class); - if (onR == null) { - continue; - } - if (!e.getModifiers().contains(Modifier.STATIC)) { - error("@OnReceive method needs to be static", e); - return false; - } - if (e.getModifiers().contains(Modifier.PRIVATE)) { - error("@OnReceive method cannot be private", e); - return false; - } - if (e.getReturnType().getKind() != TypeKind.VOID) { - error("@OnReceive method should return void", e); - return false; - } - if (!onR.jsonp().isEmpty() && !"GET".equals(onR.method())) { - error("JSONP works only with GET transport method", e); - } - String dataMirror = findDataSpecified(e, onR); - if ("PUT".equals(onR.method()) && dataMirror == null) { - error("PUT method needs to specify a data() class", e); - return false; - } - if ("POST".equals(onR.method()) && dataMirror == null) { - error("POST method needs to specify a data() class", e); - return false; - } - String modelClass = null; - boolean expectsList = false; - List args = new ArrayList(); - { - for (VariableElement ve : e.getParameters()) { - TypeMirror modelType = null; - final TypeMirror type = ve.asType(); - CharSequence simpleName; - if (type.getKind() == TypeKind.DECLARED) { - simpleName = ((DeclaredType)type).asElement().getSimpleName(); - } else { - simpleName = type.toString(); - } - if (simpleName.toString().equals(className)) { - args.add(className + ".this"); - } else if (isModel(ve.asType())) { - modelType = ve.asType(); - } else if (ve.asType().getKind() == TypeKind.ARRAY) { - modelType = ((ArrayType)ve.asType()).getComponentType(); - expectsList = true; - } else if (ve.asType().toString().equals("java.lang.String")) { - modelType = ve.asType(); - } - if (modelType != null) { - if (modelClass != null) { - error("There can be only one model class among arguments", e); - } else { - modelClass = modelType.toString(); - if (expectsList) { - args.add("arr"); - } else { - args.add("arr[0]"); - } - } - } - } - } - if (modelClass == null) { - error("The method needs to have one @Model class as parameter", e); - } - String n = e.getSimpleName().toString(); - if ("WebSocket".equals(onR.method())) { - body.append(" /** Performs WebSocket communication. Call with null data parameter\n"); - body.append(" * to open the connection (even if not required). Call with non-null data to\n"); - body.append(" * send messages to server. Call again with null data to close the socket.\n"); - body.append(" */\n"); - } - body.append(" public void ").append(n).append("("); - StringBuilder urlBefore = new StringBuilder(); - StringBuilder urlAfter = new StringBuilder(); - String jsonpVarName = null; - { - String sep = ""; - boolean skipJSONP = onR.jsonp().isEmpty(); - for (String p : findParamNames(e, onR.url(), onR.jsonp(), urlBefore, urlAfter)) { - if (!skipJSONP && p.equals(onR.jsonp())) { - skipJSONP = true; - jsonpVarName = p; - continue; - } - body.append(sep); - body.append("String ").append(p); - sep = ", "; - } - if (!skipJSONP) { - error( - "Name of jsonp attribute ('" + onR.jsonp() + - "') is not used in url attribute '" + onR.url() + "'", e - ); - } - if (dataMirror != null) { - body.append(sep).append(dataMirror.toString()).append(" data"); - } - } - body.append(") {\n"); - boolean webSocket = onR.method().equals("WebSocket"); - if (webSocket) { - if (generateWSReceiveBody(body, onR, e, clazz, className, expectsList, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) { - return false; - } - body.append(" }\n"); - body.append(" private org.apidesign.html.json.impl.JSON.WS ws_" + e.getSimpleName() + ";\n"); - } else { - if (generateJSONReceiveBody(body, onR, e, clazz, className, expectsList, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) { - return false; - } - body.append(" }\n"); - } - } - return true; - } - - private boolean generateJSONReceiveBody(StringWriter body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) { - body.append( - " class ProcessResult extends org.apidesign.html.json.impl.RcvrJSON {\n" + - " @Override\n" + - " public void onError(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" + - " Exception value = ev.getException();\n" - ); - if (onR.onError().isEmpty()) { - body.append( - " value.printStackTrace();\n" - ); - } else { - if (!findOnError(e, ((TypeElement)clazz), onR.onError(), className)) { - return true; - } - body.append(" ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("("); - body.append(className).append(".this, value);\n"); - } - body.append( - " }\n" + - " @Override\n" + - " public void onMessage(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" - ); - if (expectsList) { - body.append( - " " + modelClass + "[] arr = new " + modelClass + "[ev.dataSize()];\n" - ); - } else { - body.append( - " " + modelClass + "[] arr = { null };\n" - ); - } - body.append( - " ev.dataRead(context, " + modelClass + ".class, arr);\n" - ); - { - body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("("); - String sep = ""; - for (String arg : args) { - body.append(sep); - body.append(arg); - sep = ", "; - } - body.append(");\n"); - } - body.append( - " }\n" + - " }\n" - ); - body.append(" ProcessResult pr = new ProcessResult();\n"); - body.append(" org.apidesign.html.json.impl.JSON.loadJSON(context, pr,\n "); - body.append(urlBefore).append(", "); - if (jsonpVarName != null) { - body.append(urlAfter); - } else { - body.append("null"); - } - if (!"GET".equals(onR.method()) || dataMirror != null) { - body.append(", \"").append(onR.method()).append('"'); - if (dataMirror != null) { - body.append(", data"); - } else { - body.append(", null"); - } - } else { - body.append(", null, null"); - } - body.append(");\n"); - return false; - } - - private boolean generateWSReceiveBody(StringWriter body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) { - body.append( - " class ProcessResult extends org.apidesign.html.json.impl.RcvrJSON {\n" + - " @Override\n" + - " public void onOpen(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" - ); - body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("("); - { - String sep = ""; - for (String arg : args) { - body.append(sep); - if (arg.startsWith("arr")) { - body.append("null"); - } else { - body.append(arg); - } - sep = ", "; - } - } - body.append(");\n"); - body.append( - " }\n" + - " @Override\n" + - " public void onError(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" + - " Exception value = ev.getException();\n" - ); - if (onR.onError().isEmpty()) { - body.append( - " value.printStackTrace();\n" - ); - } else { - if (!findOnError(e, ((TypeElement)clazz), onR.onError(), className)) { - return true; - } - body.append(" ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("("); - body.append(className).append(".this, value);\n"); - } - body.append( - " }\n" + - " @Override\n" + - " public void onMessage(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" - ); - if (expectsList) { - body.append( - " " + modelClass + "[] arr = new " + modelClass + "[ev.dataSize()];\n" - ); - } else { - body.append( - " " + modelClass + "[] arr = { null };\n" - ); - } - body.append( - " ev.dataRead(context, " + modelClass + ".class, arr);\n" - ); - { - body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("("); - String sep = ""; - for (String arg : args) { - body.append(sep); - body.append(arg); - sep = ", "; - } - body.append(");\n"); - } - body.append( - " }\n" - ); - if (!onR.onError().isEmpty()) { - body.append( - " @Override\n" - + " public void onClose(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" - ); - body.append(" ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("("); - body.append(className).append(".this, null);\n"); - body.append( - " }\n" - ); - } - body.append(" }\n"); - body.append(" if (this.ws_").append(e.getSimpleName()).append(" == null) {\n"); - body.append(" ProcessResult pr = new ProcessResult();\n"); - body.append(" this.ws_").append(e.getSimpleName()); - body.append("= org.apidesign.html.json.impl.JSON.openWS(context, pr,\n "); - body.append(urlBefore).append(", data);\n"); - body.append(" } else {\n"); - body.append(" this.ws_").append(e.getSimpleName()).append(".send(context, ").append(urlBefore).append(", data);\n"); - body.append(" }\n"); - return false; - } - - private CharSequence wrapParams( - ExecutableElement ee, String id, String className, String evName, String dataName - ) { - TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType(); - StringBuilder params = new StringBuilder(); - boolean first = true; - for (VariableElement ve : ee.getParameters()) { - if (!first) { - params.append(", "); - } - first = false; - String toCall = null; - String toFinish = null; - if (ve.asType() == stringType) { - if (ve.getSimpleName().contentEquals("id")) { - params.append('"').append(id).append('"'); - continue; - } - toCall = "org.apidesign.html.json.impl.JSON.toString(context, "; - } - if (ve.asType().getKind() == TypeKind.DOUBLE) { - toCall = "org.apidesign.html.json.impl.JSON.toNumber(context, "; - toFinish = ".doubleValue()"; - } - if (ve.asType().getKind() == TypeKind.INT) { - toCall = "org.apidesign.html.json.impl.JSON.toNumber(context, "; - toFinish = ".intValue()"; - } - if (dataName != null && ve.getSimpleName().contentEquals(dataName) && isModel(ve.asType())) { - toCall = "org.apidesign.html.json.impl.JSON.toModel(context, " + ve.asType() + ".class, "; - } - - if (toCall != null) { - params.append(toCall); - if (dataName != null && ve.getSimpleName().contentEquals(dataName)) { - params.append(dataName); - params.append(", null"); - } else { - if (evName == null) { - final StringBuilder sb = new StringBuilder(); - sb.append("Unexpected string parameter name."); - if (dataName != null) { - sb.append(" Try \"").append(dataName).append("\""); - } - error(sb.toString(), ee); - } - params.append(evName); - params.append(", \""); - params.append(ve.getSimpleName().toString()); - params.append("\""); - } - params.append(")"); - if (toFinish != null) { - params.append(toFinish); - } - continue; - } - String rn = fqn(ve.asType(), ee); - int last = rn.lastIndexOf('.'); - if (last >= 0) { - rn = rn.substring(last + 1); - } - if (rn.equals(className)) { - params.append(className).append(".this"); - continue; - } - error( - "The annotated method can only accept " + className + " argument or argument named 'data'", - ee - ); - } - return params; - } - - - private CharSequence wrapPropName( - ExecutableElement ee, String className, String propName, String propValue - ) { - TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType(); - StringBuilder params = new StringBuilder(); - boolean first = true; - for (VariableElement ve : ee.getParameters()) { - if (!first) { - params.append(", "); - } - first = false; - if (ve.asType() == stringType) { - if (propName != null && ve.getSimpleName().contentEquals(propName)) { - params.append('"').append(propValue).append('"'); - } else { - error("Unexpected string parameter name. Try \"" + propName + "\".", ee); - } - continue; - } - String rn = fqn(ve.asType(), ee); - int last = rn.lastIndexOf('.'); - if (last >= 0) { - rn = rn.substring(last + 1); - } - if (rn.equals(className)) { - params.append(className).append(".this"); - continue; - } - error( - "@OnPrprtChange method can only accept String or " + className + " arguments", - ee); - } - return params; - } - - private boolean isModel(TypeMirror tm) { - if (tm.getKind() == TypeKind.ERROR) { - return true; - } - final Element e = processingEnv.getTypeUtils().asElement(tm); - if (e == null) { - return false; - } - for (Element ch : e.getEnclosedElements()) { - if (ch.getKind() == ElementKind.METHOD) { - ExecutableElement ee = (ExecutableElement)ch; - if (ee.getParameters().isEmpty() && ee.getSimpleName().contentEquals("modelFor")) { - return true; - } - } - } - return models.values().contains(e.getSimpleName().toString()); - } - - private void writeToString(Prprt[] props, Writer w) throws IOException { - w.write(" public String toString() {\n"); - w.write(" StringBuilder sb = new StringBuilder();\n"); - w.write(" sb.append('{');\n"); - String sep = ""; - for (Prprt p : props) { - w.write(sep); - w.append(" sb.append('\"').append(\"" + p.name() + "\")"); - w.append(".append('\"').append(\":\");\n"); - w.append(" sb.append(org.apidesign.html.json.impl.JSON.toJSON(prop_"); - w.append(p.name()).append("));\n"); - sep = " sb.append(',');\n"; - } - w.write(" sb.append('}');\n"); - w.write(" return sb.toString();\n"); - w.write(" }\n"); - } - private void writeClone(String className, Prprt[] props, Writer w) throws IOException { - w.write(" public " + className + " clone() {\n"); - w.write(" return clone(context);\n"); - w.write(" }\n"); - w.write(" private " + className + " clone(net.java.html.BrwsrCtx ctx) {\n"); - w.write(" " + className + " ret = new " + className + "(ctx);\n"); - for (Prprt p : props) { - if (!p.array()) { - boolean isModel[] = { false }; - boolean isEnum[] = { false }; - boolean isPrimitive[] = { false }; - checkType(p, isModel, isEnum, isPrimitive); - if (!isModel[0]) { - w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + ";\n"); - continue; - } - w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + " == null ? null : prop_" + p.name() + ".clone();\n"); - } else { - w.write(" ret.prop_" + p.name() + ".cloneAll(ctx, prop_" + p.name() + ");\n"); - } - } - - w.write(" return ret;\n"); - w.write(" }\n"); - } - - private String inPckName(Element e) { - StringBuilder sb = new StringBuilder(); - while (e.getKind() != ElementKind.PACKAGE) { - if (sb.length() == 0) { - sb.append(e.getSimpleName()); - } else { - sb.insert(0, '.'); - sb.insert(0, e.getSimpleName()); - } - e = e.getEnclosingElement(); - } - return sb.toString(); - } - - private String fqn(TypeMirror pt, Element relative) { - if (pt.getKind() == TypeKind.ERROR) { - final Elements eu = processingEnv.getElementUtils(); - PackageElement pckg = eu.getPackageOf(relative); - return pckg.getQualifiedName() + "." + pt.toString(); - } - return pt.toString(); - } - - private String checkType(Prprt p, boolean[] isModel, boolean[] isEnum, boolean[] isPrimitive) { - TypeMirror tm; - try { - String ret = p.typeName(processingEnv); - TypeElement e = processingEnv.getElementUtils().getTypeElement(ret); - if (e == null) { - isModel[0] = true; - isEnum[0] = false; - isPrimitive[0] = false; - return ret; - } - tm = e.asType(); - } catch (MirroredTypeException ex) { - tm = ex.getTypeMirror(); - } - tm = processingEnv.getTypeUtils().erasure(tm); - if (isPrimitive[0] = tm.getKind().isPrimitive()) { - isEnum[0] = false; - isModel[0] = false; - return tm.toString(); - } - final Element e = processingEnv.getTypeUtils().asElement(tm); - if (e.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) { - isModel[0] = true; - isEnum[0] = false; - return e.getSimpleName().toString(); - } - - final Model m = e == null ? null : e.getAnnotation(Model.class); - String ret; - if (m != null) { - ret = findPkgName(e) + '.' + m.className(); - isModel[0] = true; - models.put(e, m.className()); - } else if (findModelForMthd(e)) { - ret = ((TypeElement)e).getQualifiedName().toString(); - isModel[0] = true; - } else { - ret = tm.toString(); - } - TypeMirror enm = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType(); - enm = processingEnv.getTypeUtils().erasure(enm); - isEnum[0] = processingEnv.getTypeUtils().isSubtype(tm, enm); - return ret; - } - - private static boolean findModelForMthd(Element clazz) { - if (clazz == null) { - return false; - } - for (Element e : clazz.getEnclosedElements()) { - if (e.getKind() == ElementKind.METHOD) { - ExecutableElement ee = (ExecutableElement)e; - if ( - ee.getSimpleName().contentEquals("modelFor") && - ee.getParameters().isEmpty() - ) { - return true; - } - } - } - return false; - } - - private Iterable findParamNames( - Element e, String url, String jsonParam, StringBuilder... both - ) { - List params = new ArrayList(); - int wasJSON = 0; - - for (int pos = 0; ;) { - int next = url.indexOf('{', pos); - if (next == -1) { - both[wasJSON].append('"') - .append(url.substring(pos)) - .append('"'); - return params; - } - int close = url.indexOf('}', next); - if (close == -1) { - error("Unbalanced '{' and '}' in " + url, e); - return params; - } - final String paramName = url.substring(next + 1, close); - params.add(paramName); - if (paramName.equals(jsonParam) && !jsonParam.isEmpty()) { - both[wasJSON].append('"') - .append(url.substring(pos, next)) - .append('"'); - wasJSON = 1; - } else { - both[wasJSON].append('"') - .append(url.substring(pos, next)) - .append("\" + ").append(paramName).append(" + "); - } - pos = close + 1; - } - } - - private static Prprt findPrprt(Prprt[] properties, String propName) { - for (Prprt p : properties) { - if (propName.equals(p.name())) { - return p; - } - } - return null; - } - - private boolean isPrimitive(String type) { - return - "int".equals(type) || - "double".equals(type) || - "long".equals(type) || - "short".equals(type) || - "byte".equals(type) || - "char".equals(type) || - "boolean".equals(type) || - "float".equals(type); - } - - private static Collection findDerivedFrom(Map> propsDeps, String derivedProp) { - Set names = new HashSet(); - for (Map.Entry> e : propsDeps.entrySet()) { - if (e.getValue().contains(derivedProp)) { - names.add(e.getKey()); - } - } - return names; - } - - private Prprt[] createProps(Element e, Property[] arr) { - Prprt[] ret = Prprt.wrap(processingEnv, e, arr); - Prprt[] prev = verify.put(e, ret); - if (prev != null) { - error("Two sets of properties for ", e); - } - return ret; - } - - private static String strip(String s) { - int indx = s.indexOf("__"); - if (indx >= 0) { - return s.substring(0, indx); - } else { - return s; - } - } - - private String findDataSpecified(ExecutableElement e, OnReceive onR) { - try { - return onR.data().getName(); - } catch (MirroredTypeException ex) { - final TypeMirror tm = ex.getTypeMirror(); - String name; - final Element te = processingEnv.getTypeUtils().asElement(tm); - if (te.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) { - name = te.getSimpleName().toString(); - } else { - name = tm.toString(); - } - return "java.lang.Object".equals(name) ? null : name; - } catch (Exception ex) { - // fallback - } - - AnnotationMirror found = null; - for (AnnotationMirror am : e.getAnnotationMirrors()) { - if (am.getAnnotationType().toString().equals(OnReceive.class.getName())) { - found = am; - } - } - if (found == null) { - return null; - } - - for (Map.Entry entry : found.getElementValues().entrySet()) { - ExecutableElement ee = entry.getKey(); - AnnotationValue av = entry.getValue(); - if (ee.getSimpleName().contentEquals("data")) { - List values = getAnnoValues(processingEnv, e, found); - for (Object v : values) { - String sv = v.toString(); - if (sv.startsWith("data = ") && sv.endsWith(".class")) { - return sv.substring(7, sv.length() - 6); - } - } - return "error"; - } - } - return null; - } - - static List getAnnoValues(ProcessingEnvironment pe, Element e, AnnotationMirror am) { - try { - Class trees = Class.forName("com.sun.tools.javac.api.JavacTrees"); - Method m = trees.getMethod("instance", ProcessingEnvironment.class); - Object instance = m.invoke(null, pe); - m = instance.getClass().getMethod("getPath", Element.class, AnnotationMirror.class); - Object path = m.invoke(instance, e, am); - m = path.getClass().getMethod("getLeaf"); - Object leaf = m.invoke(path); - m = leaf.getClass().getMethod("getArguments"); - return (List) m.invoke(leaf); - } catch (Exception ex) { - return Collections.emptyList(); - } - } - - private static class Prprt { - private final Element e; - private final AnnotationMirror tm; - private final Property p; - - public Prprt(Element e, AnnotationMirror tm, Property p) { - this.e = e; - this.tm = tm; - this.p = p; - } - - String name() { - return p.name(); - } - - boolean array() { - return p.array(); - } - - String typeName(ProcessingEnvironment env) { - RuntimeException ex; - try { - return p.type().getName(); - } catch (IncompleteAnnotationException e) { - ex = e; - } catch (AnnotationTypeMismatchException e) { - ex = e; - } - for (Object v : getAnnoValues(env, e, tm)) { - String s = v.toString().replace(" ", ""); - if (s.startsWith("type=") && s.endsWith(".class")) { - return s.substring(5, s.length() - 6); - } - } - throw ex; - } - - - static Prprt[] wrap(ProcessingEnvironment pe, Element e, Property[] arr) { - if (arr.length == 0) { - return new Prprt[0]; - } - - if (e.getKind() != ElementKind.CLASS) { - throw new IllegalStateException("" + e.getKind()); - } - TypeElement te = (TypeElement)e; - List val = null; - for (AnnotationMirror an : te.getAnnotationMirrors()) { - for (Map.Entry entry : an.getElementValues().entrySet()) { - if (entry.getKey().getSimpleName().contentEquals("properties")) { - val = (List)entry.getValue().getValue(); - break; - } - } - } - if (val == null || val.size() != arr.length) { - pe.getMessager().printMessage(Diagnostic.Kind.ERROR, "" + val, e); - return new Prprt[0]; - } - Prprt[] ret = new Prprt[arr.length]; - BIG: for (int i = 0; i < ret.length; i++) { - AnnotationMirror am = (AnnotationMirror)val.get(i).getValue(); - ret[i] = new Prprt(e, am, arr[i]); - - } - return ret; - } - } - - @Override - public Iterable getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) { - final Level l = Level.FINE; - LOG.log(l, " element: {0}", element); - LOG.log(l, " annotation: {0}", annotation); - LOG.log(l, " member: {0}", member); - LOG.log(l, " userText: {0}", userText); - LOG.log(l, "str: {0}", annotation.getAnnotationType().toString()); - if (annotation.getAnnotationType().toString().equals(OnReceive.class.getName())) { - if (member.getSimpleName().contentEquals("method")) { - return Arrays.asList( - methodOf("GET"), - methodOf("POST"), - methodOf("PUT"), - methodOf("DELETE"), - methodOf("HEAD"), - methodOf("WebSocket") - ); - } - } - - return super.getCompletions(element, annotation, member, userText); - } - - private static final Completion methodOf(String method) { - ResourceBundle rb = ResourceBundle.getBundle("org.apidesign.html.json.impl.Bundle"); - return Completions.of('"' + method + '"', rb.getString("MSG_Completion_" + method)); - } - - private boolean findOnError(ExecutableElement errElem, TypeElement te, String name, String className) { - String err = null; - METHODS: - for (Element e : te.getEnclosedElements()) { - if (e.getKind() != ElementKind.METHOD) { - continue; - } - if (!e.getSimpleName().contentEquals(name)) { - continue; - } - if (!e.getModifiers().contains(Modifier.STATIC)) { - errElem = (ExecutableElement) e; - err = "Would have to be static"; - continue; - } - ExecutableElement ee = (ExecutableElement) e; - TypeMirror excType = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType(); - final List params = ee.getParameters(); - boolean error = false; - if (params.size() != 2) { - error = true; - } else { - String firstType = params.get(0).asType().toString(); - int lastDot = firstType.lastIndexOf('.'); - if (lastDot != -1) { - firstType = firstType.substring(lastDot + 1); - } - if (!firstType.equals(className)) { - error = true; - } - if (!processingEnv.getTypeUtils().isAssignable(excType, params.get(1).asType())) { - error = true; - } - } - if (error) { - errElem = (ExecutableElement) e; - err = "Error method first argument needs to be " + className + " and second Exception"; - continue; - } - return true; - } - if (err == null) { - err = "Cannot find " + name + "(" + className + ", Exception) method in this class"; - } - error(err, errElem); - return false; - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java --- a/json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import net.java.html.BrwsrCtx; -import org.apidesign.html.json.spi.FunctionBinding; -import org.apidesign.html.json.spi.JSONCall; -import org.apidesign.html.json.spi.PropertyBinding; - -/** - * - * @author Jaroslav Tulach - */ -public abstract class PropertyBindingAccessor { - private static PropertyBindingAccessor DEFAULT; - - protected PropertyBindingAccessor() { - if (DEFAULT != null) throw new IllegalStateException(); - DEFAULT = this; - } - - static { - JSON.initClass(PropertyBinding.class); - } - - protected abstract PropertyBinding newBinding(PBData d); - protected abstract FunctionBinding newFunction(FBData d); - protected abstract JSONCall newCall( - BrwsrCtx ctx, RcvrJSON callback, String urlBefore, String urlAfter, - String method, Object data - ); - - - static PropertyBinding create(PBData d) { - return DEFAULT.newBinding(d); - } - static FunctionBinding createFunction(FBData d) { - return DEFAULT.newFunction(d); - } - static JSONCall createCall( - BrwsrCtx ctx, RcvrJSON callback, String urlBefore, String urlAfter, - String method, Object data - ) { - return DEFAULT.newCall(ctx, callback, urlBefore, urlAfter, method, data); - } - - public static final class PBData { - public final String name; - public final boolean readOnly; - private final M model; - private final SetAndGet access; - private final Bindings bindings; - - public PBData(Bindings bindings, String name, M model, SetAndGet access, boolean readOnly) { - this.bindings = bindings; - this.name = name; - this.model = model; - this.access = access; - this.readOnly = readOnly; - } - - public void setValue(Object v) { - access.setValue(model, v); - } - - public Object getValue() { - return access.getValue(model); - } - - public boolean isReadOnly() { - return readOnly; - } - - public Bindings getBindings() { - return bindings; - } - } // end of PBData - - public static final class FBData { - public final String name; - private final M model; - private final Callback access; - - public FBData(String name, M model, Callback access) { - this.name = name; - this.model = model; - this.access = access; - } - - - public void call(Object data, Object ev) { - access.call(model, data, ev); - } - } // end of FBData -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/impl/RcvrJSON.java --- a/json/src/main/java/org/apidesign/html/json/impl/RcvrJSON.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import net.java.html.BrwsrCtx; - -/** Super type for those who wish to receive JSON messages. - * - * @author Jaroslav Tulach - */ -public abstract class RcvrJSON { - protected void onOpen(MsgEvnt msg) {} - protected abstract void onMessage(MsgEvnt msg); - protected void onClose(MsgEvnt msg) {} - protected abstract void onError(MsgEvnt msg); - - public abstract static class MsgEvnt { - MsgEvnt() { - } - - public Throwable getError() { - return null; - } - - public final Exception getException() { - Throwable t = getError(); - if (t instanceof Exception) { - return (Exception)t; - } - if (t == null) { - return null; - } - return new Exception(t); - } - - public int dataSize() { - return -1; - } - - public void dataRead(BrwsrCtx ctx, Class type, Data[] fillTheArray) { - } - - public abstract void dispatch(RcvrJSON r); - - public static MsgEvnt createError(final Throwable t) { - return new MsgEvnt() { - @Override - public Throwable getError() { - return t; - } - - @Override - public void dispatch(RcvrJSON r) { - r.onError(this); - } - }; - } - - public static MsgEvnt createMessage(final Object value) { - return new MsgEvnt() { - @Override - public int dataSize() { - if (value instanceof Object[]) { - return ((Object[])value).length; - } else { - return 1; - } - } - - @Override - public void dataRead(BrwsrCtx context, Class type, Data[] arr) { - if (value instanceof Object[]) { - Object[] data = ((Object[]) value); - for (int i = 0; i < data.length && i < arr.length; i++) { - arr[i] = org.apidesign.html.json.impl.JSON.read(context, type, data[i]); - } - } else { - if (arr.length > 0) { - arr[0] = org.apidesign.html.json.impl.JSON.read(context, type, value); - } - } - } - - @Override - public void dispatch(RcvrJSON r) { - r.onMessage(this); - } - }; - } - - public static MsgEvnt createOpen() { - return new MsgEvnt() { - @Override - public void dispatch(RcvrJSON r) { - r.onOpen(this); - } - }; - } - - public static MsgEvnt createClose() { - return new MsgEvnt() { - @Override - public void dispatch(RcvrJSON r) { - r.onClose(this); - } - }; - } - } // end MsgEvnt -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/impl/SetAndGet.java --- a/json/src/main/java/org/apidesign/html/json/impl/SetAndGet.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import org.apidesign.html.json.spi.PropertyBinding; - -/** A way to implement a {@link PropertyBinding}. - * - * @author Jaroslav Tulach - */ -public interface SetAndGet { - public void setValue(Data data, Object value); - public Object getValue(Data data); -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/impl/WrapperObject.java --- a/json/src/main/java/org/apidesign/html/json/impl/WrapperObject.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import java.util.Collection; -import org.apidesign.html.json.impl.PropertyBindingAccessor.PBData; - -/** A way to extract real object from a model classes. - * - * @author Jaroslav Tulach - */ -public final class WrapperObject { - private Object ko; - - private WrapperObject() { - } - - public void setRealObject(Object ko) { - this.ko = ko; - } - - public static Object find(Object object) { - return find(object, null); - } - - public static Object find(Object object, Bindings model) { - if (object == null) { - return null; - } - - if (object instanceof JSONList) { - return ((JSONList)object).koData(); - } - if (object instanceof Collection) { - return JSONList.koData((Collection)object, model); - } - - WrapperObject ro = new WrapperObject(); - object.equals(ro); - return ro.ko; - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/spi/FunctionBinding.java --- a/json/src/main/java/org/apidesign/html/json/spi/FunctionBinding.java Mon Dec 16 15:48:09 2013 +0100 +++ b/json/src/main/java/org/apidesign/html/json/spi/FunctionBinding.java Mon Dec 16 16:59:43 2013 +0100 @@ -44,7 +44,7 @@ import net.java.html.json.Function; import net.java.html.json.Model; -import org.apidesign.html.json.impl.PropertyBindingAccessor.FBData; +import org.netbeans.html.json.impl.PropertyBindingAccessor.FBData; /** Describes a function provided by the {@link Model} and * annotated by {@link Function} annotation. diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/spi/JSONCall.java --- a/json/src/main/java/org/apidesign/html/json/spi/JSONCall.java Mon Dec 16 15:48:09 2013 +0100 +++ b/json/src/main/java/org/apidesign/html/json/spi/JSONCall.java Mon Dec 16 16:59:43 2013 +0100 @@ -45,8 +45,8 @@ import java.io.IOException; import java.io.OutputStream; import net.java.html.BrwsrCtx; -import org.apidesign.html.json.impl.JSON; -import org.apidesign.html.json.impl.RcvrJSON; +import org.netbeans.html.json.impl.JSON; +import org.netbeans.html.json.impl.RcvrJSON; /** Description of a JSON call request that is supposed to be processed * by {@link Transfer#loadJSON(org.apidesign.html.json.spi.JSONCall)} implementors. diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java --- a/json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java Mon Dec 16 15:48:09 2013 +0100 +++ b/json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java Mon Dec 16 16:59:43 2013 +0100 @@ -43,10 +43,10 @@ package org.apidesign.html.json.spi; import net.java.html.BrwsrCtx; -import org.apidesign.html.json.impl.PropertyBindingAccessor; -import org.apidesign.html.json.impl.PropertyBindingAccessor.PBData; -import org.apidesign.html.json.impl.RcvrJSON; -import org.apidesign.html.json.impl.WrapperObject; +import org.netbeans.html.json.impl.PropertyBindingAccessor; +import org.netbeans.html.json.impl.PropertyBindingAccessor.PBData; +import org.netbeans.html.json.impl.RcvrJSON; +import org.netbeans.html.json.impl.WrapperObject; /** Describes a property when one is asked to * bind it diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/netbeans/html/json/impl/Bindings.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/java/org/netbeans/html/json/impl/Bindings.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,113 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import org.apidesign.html.json.spi.PropertyBinding; +import net.java.html.BrwsrCtx; +import org.netbeans.html.json.impl.PropertyBindingAccessor.FBData; +import org.netbeans.html.json.impl.PropertyBindingAccessor.PBData; +import org.apidesign.html.json.spi.FunctionBinding; +import org.apidesign.html.json.spi.Technology; + +/** + * + * @author Jaroslav Tulach + */ +public final class Bindings { + private Data data; + private final Technology bp; + + private Bindings(Technology bp) { + this.bp = bp; + } + + public PropertyBinding registerProperty(String propName, M model, SetAndGet access, boolean readOnly) { + return PropertyBindingAccessor.create(new PBData(this, propName, model, access, readOnly)); + } + + public FunctionBinding registerFunction(String name, M model, Callback access) { + return PropertyBindingAccessor.createFunction(new FBData(name, model, access)); + } + + public static Bindings apply(BrwsrCtx c, Object model) { + Technology bp = JSON.findTechnology(c); + return apply(bp); + } + + private static Bindings apply(Technology bp) { + return new Bindings(bp); + } + + public final void finish(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) { + assert data == null; + if (bp instanceof Technology.BatchInit) { + Technology.BatchInit bi = (Technology.BatchInit)bp; + data = bi.wrapModel(model, propArr, funcArr); + } else { + data = bp.wrapModel(model); + for (PropertyBinding b : propArr) { + bp.bind(b, model, data); + } + for (FunctionBinding b : funcArr) { + bp.expose(b, model, data); + } + } + } + + + public Data koData() { + return data; + } + + public void valueHasMutated(String firstName) { + bp.valueHasMutated(data, firstName); + } + + public void applyBindings() { + bp.applyBindings(data); + } + + Object wrapArray(Object[] arr) { + return bp.wrapArray(arr); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/netbeans/html/json/impl/Callback.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/java/org/netbeans/html/json/impl/Callback.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,51 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +/** + * + * @author Jaroslav Tulach + */ +public interface Callback { + public void call(Data model, Object data, Object ev); +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/netbeans/html/json/impl/FromJSON.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/java/org/netbeans/html/json/impl/FromJSON.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,55 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import net.java.html.BrwsrCtx; + +/** + * + * @author Jaroslav Tulach + */ +public interface FromJSON { + public Class factoryFor(); + public Data read(BrwsrCtx c, Object d); + public Data cloneTo(Object d, BrwsrCtx c); +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/netbeans/html/json/impl/JSON.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/java/org/netbeans/html/json/impl/JSON.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,474 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import net.java.html.BrwsrCtx; +import org.apidesign.html.context.spi.Contexts; +import org.apidesign.html.json.spi.FunctionBinding; +import org.apidesign.html.json.spi.JSONCall; +import org.apidesign.html.json.spi.PropertyBinding; +import org.apidesign.html.json.spi.Technology; +import org.apidesign.html.json.spi.Transfer; +import org.apidesign.html.json.spi.WSTransfer; + +/** + * + * @author Jaroslav Tulach + */ +public final class JSON { + private JSON() { + } + + static Technology findTechnology(BrwsrCtx c) { + Technology t = Contexts.find(c, Technology.class); + return t == null ? EmptyTech.EMPTY : t; + } + + static Transfer findTransfer(BrwsrCtx c) { + Transfer t = Contexts.find(c, Transfer.class); + return t == null ? EmptyTech.EMPTY : t; + } + + static WSTransfer findWSTransfer(BrwsrCtx c) { + WSTransfer t = Contexts.find(c, WSTransfer.class); + return t == null ? EmptyTech.EMPTY : t; + } + + public static void runInBrowser(BrwsrCtx c, Runnable runnable) { + findTechnology(c).runSafe(runnable); + } + + public static void extract(BrwsrCtx c, Object value, String[] props, Object[] values) { + Transfer t = findTransfer(c); + t.extract(value, props, values); + } + + private static Object getProperty(BrwsrCtx c, Object obj, String prop) { + if (prop == null) return obj; + + String[] arr = { prop }; + Object[] val = { null }; + extract(c, obj, arr, val); + return val[0]; + } + + public static Object toJSON(Object value) { + if (value == null) { + return "null"; + } + if (value instanceof Enum) { + value = value.toString(); + } + if (value instanceof String) { + String s = (String)value; + int len = s.length(); + StringBuilder sb = new StringBuilder(len + 10); + sb.append('"'); + for (int i = 0; i < len; i++) { + char ch = s.charAt(i); + switch (ch) { + case '\"': sb.append("\\\""); break; + case '\n': sb.append("\\n"); break; + case '\r': sb.append("\\r"); break; + case '\t': sb.append("\\t"); break; + case '\\': sb.append("\\\\"); break; + default: sb.append(ch); + } + } + sb.append('"'); + return sb.toString(); + } + return value.toString(); + } + + public static String toString(BrwsrCtx c, Object obj, String prop) { + obj = getProperty(c, obj, prop); + return obj instanceof String ? (String)obj : null; + } + public static Number toNumber(BrwsrCtx c, Object obj, String prop) { + obj = getProperty(c, obj, prop); + if (!(obj instanceof Number)) { + obj = Double.NaN; + } + return (Number)obj; + } + public static M toModel(BrwsrCtx c, Class aClass, Object data, Object object) { + Technology t = findTechnology(c); + Object o = t.toModel(aClass, data); + return aClass.cast(o); + } + + public static boolean isSame(int a, int b) { + return a == b; + } + + public static boolean isSame(double a, double b) { + return a == b; + } + + public static boolean isSame(Object a, Object b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + return a.equals(b); + } + + public static int hashPlus(Object o, int h) { + return o == null ? h : h ^ o.hashCode(); + } + + public static T extractValue(Class type, Object val) { + if (Number.class.isAssignableFrom(type)) { + val = numberValue(val); + } + if (Boolean.class == type) { + val = boolValue(val); + } + if (String.class == type) { + val = stringValue(val); + } + if (Character.class == type) { + val = charValue(val); + } + if (Integer.class == type) { + val = val instanceof Number ? ((Number)val).intValue() : 0; + } + if (Long.class == type) { + val = val instanceof Number ? ((Number)val).longValue() : 0; + } + if (Short.class == type) { + val = val instanceof Number ? ((Number)val).shortValue() : 0; + } + if (Byte.class == type) { + val = val instanceof Number ? ((Number)val).byteValue() : 0; + } + if (Double.class == type) { + val = val instanceof Number ? ((Number)val).doubleValue() : Double.NaN; + } + if (Float.class == type) { + val = val instanceof Number ? ((Number)val).floatValue() : Float.NaN; + } + return type.cast(val); + } + + protected static boolean isNumeric(Object val) { + return ((val instanceof Integer) || (val instanceof Long) || (val instanceof Short) || (val instanceof Byte)); + } + + public static String stringValue(Object val) { + if (val instanceof Boolean) { + return ((Boolean)val ? "true" : "false"); + } + if (isNumeric(val)) { + return Long.toString(((Number)val).longValue()); + } + if (val instanceof Float) { + return Float.toString((Float)val); + } + if (val instanceof Double) { + return Double.toString((Double)val); + } + return (String)val; + } + + public static Number numberValue(Object val) { + if (val instanceof String) { + try { + return Double.valueOf((String)val); + } catch (NumberFormatException ex) { + return Double.NaN; + } + } + if (val instanceof Boolean) { + return (Boolean)val ? 1 : 0; + } + return (Number)val; + } + + public static Character charValue(Object val) { + if (val instanceof Number) { + return Character.toChars(numberValue(val).intValue())[0]; + } + if (val instanceof Boolean) { + return (Boolean)val ? (char)1 : (char)0; + } + if (val instanceof String) { + String s = (String)val; + return s.isEmpty() ? (char)0 : s.charAt(0); + } + return (Character)val; + } + + public static Boolean boolValue(Object val) { + if (val instanceof String) { + return Boolean.parseBoolean((String)val); + } + if (val instanceof Number) { + return numberValue(val).doubleValue() != 0.0; + } + + return Boolean.TRUE.equals(val); + } + + public static void loadJSON( + BrwsrCtx c, RcvrJSON callback, + String urlBefore, String urlAfter, String method, + Object data + ) { + JSONCall call = PropertyBindingAccessor.createCall(c, callback, urlBefore, urlAfter, method, data); + Transfer t = findTransfer(c); + t.loadJSON(call); + } + public static WS openWS( + BrwsrCtx c, RcvrJSON r, String url, Object data + ) { + WS ws = WSImpl.create(findWSTransfer(c), r); + ws.send(c, url, data); + return ws; + } + + public static abstract class WS { + private WS() { + } + + public abstract void send(BrwsrCtx ctx, String url, Object model); + } + + private static final class WSImpl extends WS { + + private final WSTransfer trans; + private final RcvrJSON rcvr; + private Socket socket; + private String prevURL; + + private WSImpl(WSTransfer trans, RcvrJSON rcvr) { + this.trans = trans; + this.rcvr = rcvr; + } + + static WS create(WSTransfer t, RcvrJSON r) { + return new WSImpl(t, r); + } + + @Override + public void send(BrwsrCtx ctx, String url, Object data) { + Socket s = socket; + if (s == null) { + if (data != null) { + throw new IllegalStateException("WebSocket is not opened yet. Call with null data, was: " + data); + } + JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, url, null, "WebSocket", null); + socket = trans.open(url, call); + prevURL = url; + return; + } + if (data == null) { + trans.close(s); + socket = null; + return; + } + if (!prevURL.equals(url)) { + throw new IllegalStateException( + "Can't call to different URL " + url + " was: " + prevURL + "!" + + " Close the socket by calling it will null data first!" + ); + } + JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, prevURL, null, "WebSocket", data); + trans.send(s, call); + } + + } + + private static final Map> froms; + static { + Map> m = new HashMap>(); + froms = m; + } + public static void register(FromJSON from) { + froms.put(from.factoryFor(), from); + } + + public static boolean isModel(Class clazz) { + return findFrom(clazz) != null; + } + + private static FromJSON findFrom(Class clazz) { + for (int i = 0; i < 2; i++) { + FromJSON from = froms.get(clazz); + if (from == null) { + initClass(clazz); + } else { + return from; + } + } + return null; + } + + public static Model bindTo(Model model, BrwsrCtx c) { + FromJSON from = findFrom(model.getClass()); + if (from == null) { + throw new IllegalArgumentException(); + } + return (Model) from.cloneTo(model, c); + } + + public static T readStream(BrwsrCtx c, Class modelClazz, InputStream data) + throws IOException { + Transfer tr = findTransfer(c); + return read(c, modelClazz, tr.toJSON((InputStream)data)); + } + public static T read(BrwsrCtx c, Class modelClazz, Object data) { + if (data == null) { + return null; + } + if (modelClazz == String.class) { + return modelClazz.cast(data.toString()); + } + for (int i = 0; i < 2; i++) { + FromJSON from = froms.get(modelClazz); + if (from == null) { + initClass(modelClazz); + } else { + return modelClazz.cast(from.read(c, data)); + } + } + throw new NullPointerException(); + } + static void initClass(Class modelClazz) { + try { + // try to resolve the class + ClassLoader l; + try { + l = modelClazz.getClassLoader(); + } catch (SecurityException ex) { + l = null; + } + if (l != null) { + Class.forName(modelClazz.getName(), true, l); + } + modelClazz.newInstance(); + } catch (Exception ex) { + // ignore and try again + } + } + + private static final class EmptyTech + implements Technology, Transfer, WSTransfer { + private static final EmptyTech EMPTY = new EmptyTech(); + + @Override + public Object wrapModel(Object model) { + return model; + } + + @Override + public void valueHasMutated(Object data, String propertyName) { + } + + @Override + public void bind(PropertyBinding b, Object model, Object data) { + } + + @Override + public void expose(FunctionBinding fb, Object model, Object d) { + } + + @Override + public void applyBindings(Object data) { + } + + @Override + public Object wrapArray(Object[] arr) { + return arr; + } + + @Override + public void extract(Object obj, String[] props, Object[] values) { + for (int i = 0; i < values.length; i++) { + values[i] = null; + } + } + + @Override + public void loadJSON(JSONCall call) { + call.notifyError(new UnsupportedOperationException()); + } + + @Override + public M toModel(Class modelClass, Object data) { + return modelClass.cast(data); + } + + @Override + public Object toJSON(InputStream is) throws IOException { + throw new IOException("Not supported"); + } + + @Override + public synchronized void runSafe(Runnable r) { + r.run(); + } + + @Override + public Void open(String url, JSONCall onReply) { + onReply.notifyError(new UnsupportedOperationException("WebSockets not supported!")); + return null; + } + + @Override + public void send(Void socket, JSONCall data) { + } + + @Override + public void close(Void socket) { + } + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/netbeans/html/json/impl/JSONList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/java/org/netbeans/html/json/impl/JSONList.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,236 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import net.java.html.BrwsrCtx; + +/** + * + * @author Jaroslav Tulach + */ +public final class JSONList extends ArrayList { + private final String name; + private final String[] deps; + private Bindings[] model; + private Runnable onchange; + + public JSONList(Bindings[] model, String name, String... deps) { + assert model.length == 1; + this.model = model; + this.name = name; + this.deps = deps; + } + + public void init(T... values) { + if (values == null || values.length == 0) { + return; + } + if (this.model[0] != null || !isEmpty()) { + throw new IllegalStateException(); + } + super.addAll(Arrays.asList(values)); + } + + public void init(Object values) { + int len; + if (values == null || (len = Array.getLength(values)) == 0) { + return; + } + if (this.model[0] != null || !isEmpty()) { + throw new IllegalStateException(); + } + for (int i = 0; i < len; i++) { + Object data = Array.get(values, i); + super.add((T)data); + } + } + + public JSONList onChange(Runnable r) { + if (this.onchange != null) { + throw new IllegalStateException(); + } + this.onchange = r; + return this; + } + + @Override + public boolean add(T e) { + boolean ret = super.add(e); + notifyChange(); + return ret; + } + + @Override + public boolean addAll(Collection c) { + boolean ret = super.addAll(c); + notifyChange(); + return ret; + } + + @Override + public boolean addAll(int index, Collection c) { + boolean ret = super.addAll(index, c); + notifyChange(); + return ret; + } + + @Override + public boolean remove(Object o) { + boolean ret = super.remove(o); + notifyChange(); + return ret; + } + + @Override + public void clear() { + super.clear(); + notifyChange(); + } + + @Override + public boolean removeAll(Collection c) { + boolean ret = super.removeAll(c); + notifyChange(); + return ret; + } + + @Override + public boolean retainAll(Collection c) { + boolean ret = super.retainAll(c); + notifyChange(); + return ret; + } + + @Override + public T set(int index, T element) { + T ret = super.set(index, element); + notifyChange(); + return ret; + } + + @Override + public void add(int index, T element) { + super.add(index, element); + notifyChange(); + } + + @Override + public T remove(int index) { + T ret = super.remove(index); + notifyChange(); + return ret; + } + + @Override + public String toString() { + Iterator it = iterator(); + if (!it.hasNext()) { + return "[]"; + } + String sep = ""; + StringBuilder sb = new StringBuilder(); + sb.append('['); + while (it.hasNext()) { + T t = it.next(); + sb.append(sep); + sb.append(JSON.toJSON(t)); + sep = ","; + } + sb.append(']'); + return sb.toString(); + } + + private void notifyChange() { + Bindings m = model[0]; + if (m != null) { + m.valueHasMutated(name); + for (String dependant : deps) { + m.valueHasMutated(dependant); + } + Runnable r = onchange; + if (r != null) { + r.run(); + } + } + } + + public void cloneAll(BrwsrCtx c, Collection other) { + Boolean isModel = null; + for (T t : other) { + if (isModel == null) { + isModel = JSON.isModel(t.getClass()); + } + if (isModel) { + add(JSON.bindTo(t, c)); + } else { + add(t); + } + } + } + + @Override + public JSONList clone() { + throw new UnsupportedOperationException(); + } + + static final Object koData(Collection c, Bindings m) { + Object[] arr = c.toArray(new Object[c.size()]); + for (int i = 0; i < arr.length; i++) { + Object r = WrapperObject.find(arr[i], m); + if (r != null) { + arr[i] = r; + } + } + return m.wrapArray(arr); + } + + final Object koData() { + return koData(this, model[0]); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,1767 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.annotation.AnnotationTypeMismatchException; +import java.lang.annotation.IncompleteAnnotationException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Completion; +import javax.annotation.processing.Completions; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.MirroredTypeException; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import javax.tools.Diagnostic; +import javax.tools.FileObject; +import net.java.html.json.ComputedProperty; +import net.java.html.json.Model; +import net.java.html.json.Function; +import net.java.html.json.ModelOperation; +import net.java.html.json.OnPropertyChange; +import net.java.html.json.OnReceive; +import net.java.html.json.Property; +import org.openide.util.lookup.ServiceProvider; + +/** Annotation processor to process {@link Model @Model} annotations and + * generate appropriate model classes. + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service=Processor.class) +@SupportedSourceVersion(SourceVersion.RELEASE_6) +@SupportedAnnotationTypes({ + "net.java.html.json.Model", + "net.java.html.json.ModelOperation", + "net.java.html.json.Function", + "net.java.html.json.OnReceive", + "net.java.html.json.OnPropertyChange", + "net.java.html.json.ComputedProperty", + "net.java.html.json.Property" +}) +public final class ModelProcessor extends AbstractProcessor { + private static final Logger LOG = Logger.getLogger(ModelProcessor.class.getName()); + private final Map models = new WeakHashMap(); + private final Map verify = new WeakHashMap(); + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + boolean ok = true; + for (Element e : roundEnv.getElementsAnnotatedWith(Model.class)) { + if (!processModel(e)) { + ok = false; + } + } + if (roundEnv.processingOver()) { + models.clear(); + for (Map.Entry entry : verify.entrySet()) { + TypeElement te = (TypeElement)entry.getKey(); + String fqn = processingEnv.getElementUtils().getBinaryName(te).toString(); + Element finalElem = processingEnv.getElementUtils().getTypeElement(fqn); + if (finalElem == null) { + continue; + } + Prprt[] props; + Model m = finalElem.getAnnotation(Model.class); + if (m == null) { + continue; + } + props = Prprt.wrap(processingEnv, finalElem, m.properties()); + for (Prprt p : props) { + boolean[] isModel = { false }; + boolean[] isEnum = { false }; + boolean[] isPrimitive = { false }; + String t = checkType(p, isModel, isEnum, isPrimitive); + if (isEnum[0]) { + continue; + } + if (isPrimitive[0]) { + continue; + } + if (isModel[0]) { + continue; + } + if ("java.lang.String".equals(t)) { + continue; + } + error("The type " + t + " should be defined by @Model annotation", entry.getKey()); + } + } + verify.clear(); + } + return ok; + } + + private void error(String msg, Element e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e); + } + + private boolean processModel(Element e) { + boolean ok = true; + Model m = e.getAnnotation(Model.class); + if (m == null) { + return true; + } + String pkg = findPkgName(e); + Writer w; + String className = m.className(); + models.put(e, className); + try { + StringWriter body = new StringWriter(); + List propsGetSet = new ArrayList(); + List functions = new ArrayList(); + Map> propsDeps = new HashMap>(); + Map> functionDeps = new HashMap>(); + Prprt[] props = createProps(e, m.properties()); + + if (!generateComputedProperties(body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) { + ok = false; + } + if (!generateOnChange(e, propsDeps, props, className, functionDeps)) { + ok = false; + } + if (!generateProperties(e, body, props, propsGetSet, propsDeps, functionDeps)) { + ok = false; + } + if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) { + ok = false; + } + if (!generateReceive(e, body, className, e.getEnclosedElements(), functions)) { + ok = false; + } + if (!generateOperation(e, body, className, e.getEnclosedElements())) { + ok = false; + } + FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e); + w = new OutputStreamWriter(java.openOutputStream()); + try { + w.append("package " + pkg + ";\n"); + w.append("import net.java.html.json.*;\n"); + w.append("public final class ").append(className).append(" implements Cloneable {\n"); + w.append(" private boolean locked;\n"); + w.append(" private net.java.html.BrwsrCtx context;\n"); + w.append(" private org.netbeans.html.json.impl.Bindings[] ko = { null };\n"); + w.append(body.toString()); + w.append(" private static Class<" + inPckName(e) + "> modelFor() { return null; }\n"); + w.append(" private ").append(className).append("(net.java.html.BrwsrCtx context) {\n"); + w.append(" this.context = context;\n"); + w.append(" };\n"); + w.append(" public ").append(className).append("() {\n"); + w.append(" this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n"); + for (Prprt p : props) { + if (p.array()) { + continue; + } + boolean[] isModel = {false}; + boolean[] isEnum = {false}; + boolean isPrimitive[] = {false}; + String tn = checkType(p, isModel, isEnum, isPrimitive); + if (isModel[0]) { + w.write(" prop_" + p.name() + " = new " + tn + "();\n"); + } + } + w.append(" };\n"); + if (props.length > 0) { + w.append(" public ").append(className).append("("); + Prprt firstArray = null; + String sep = ""; + for (Prprt p : props) { + if (p.array()) { + if (firstArray == null) { + firstArray = p; + } + continue; + } + String tn = typeName(e, p); + w.write(sep); + w.write(tn); + w.write(" " + p.name()); + sep = ", "; + } + if (firstArray != null) { + String tn; + boolean[] isModel = {false}; + boolean[] isEnum = {false}; + boolean isPrimitive[] = {false}; + tn = checkType(firstArray, isModel, isEnum, isPrimitive); + w.write(sep); + w.write(tn); + w.write("... " + firstArray.name()); + } + w.append(") {\n"); + w.append(" this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n"); + for (Prprt p : props) { + if (p.array()) { + continue; + } + w.write(" this.prop_" + p.name() + " = " + p.name() + ";\n"); + } + if (firstArray != null) { + w.write(" this.prop_" + firstArray.name() + ".init(" + firstArray.name() + ");\n"); + } + w.append(" };\n"); + } + w.append(" private org.netbeans.html.json.impl.Bindings intKnckt() {\n"); + w.append(" if (ko[0] != null) return ko[0];\n"); + w.append(" ko[0] = org.netbeans.html.json.impl.Bindings.apply(context, this);\n"); + { + w.append(" org.apidesign.html.json.spi.PropertyBinding[] propArr = {\n"); + for (int i = 0; i < propsGetSet.size(); i += 5) { + w.append(" ko[0].registerProperty(\"").append(propsGetSet.get(i)).append("\", this, new P("); + w.append((i / 5) + "), " + (propsGetSet.get(i + 2) == null) + "),\n"); + } + w.append(" };\n"); + } + { + w.append(" org.apidesign.html.json.spi.FunctionBinding[] funcArr = {\n"); + for (int i = 0; i < functions.size(); i += 2) { + w.append(" ko[0].registerFunction(\"").append(functions.get(i)).append("\", this, new P("); + w.append((i / 2) + ")),\n"); + } + w.append(" };\n"); + } + w.append(" ko[0].finish(this, propArr, funcArr);\n"); + w.append(" return ko[0];\n"); + w.append(" };\n"); + w.append(" private static final class P implements org.netbeans.html.json.impl.SetAndGet<" + className + ">,\n"); + w.append(" org.netbeans.html.json.impl.Callback<" + className + ">,\n"); + w.append(" org.netbeans.html.json.impl.FromJSON<" + className + "> {\n"); + w.append(" private final int type;\n"); + w.append(" P(int t) { type = t; };\n"); + w.append(" public void setValue(" + className + " data, Object value) {\n"); + w.append(" switch (type) {\n"); + for (int i = 0; i < propsGetSet.size(); i += 5) { + final String set = propsGetSet.get(i + 2); + String tn = propsGetSet.get(i + 4); + String btn = findBoxedType(tn); + if (btn != null) { + tn = btn; + } + if (set != null) { + w.append(" case " + (i / 5) + ": data." + strip(set) + "(org.netbeans.html.json.impl.JSON.extractValue(" + tn + ".class, value)); return;\n"); + } + } + w.append(" }\n"); + w.append(" }\n"); + w.append(" public Object getValue(" + className + " data) {\n"); + w.append(" switch (type) {\n"); + for (int i = 0; i < propsGetSet.size(); i += 5) { + final String get = propsGetSet.get(i + 1); + if (get != null) { + w.append(" case " + (i / 5) + ": return data." + strip(get) + "();\n"); + } + } + w.append(" }\n"); + w.append(" throw new UnsupportedOperationException();\n"); + w.append(" }\n"); + w.append(" public void call(" + className + " model, Object data, Object ev) {\n"); + w.append(" switch (type) {\n"); + for (int i = 0; i < functions.size(); i += 2) { + final String name = functions.get(i); + w.append(" case " + (i / 2) + ": model." + name + "(data, ev); return;\n"); + } + w.append(" }\n"); + w.append(" throw new UnsupportedOperationException();\n"); + w.append(" }\n"); + w.append(" public Class<" + className + "> factoryFor() { return " + className + ".class; }\n"); + w.append(" public " + className + " read(net.java.html.BrwsrCtx c, Object json) { return new " + className + "(c, json); }\n"); + w.append(" public " + className + " cloneTo(Object o, net.java.html.BrwsrCtx c) { return ((" + className + ")o).clone(c); }\n"); + w.append(" }\n"); + w.append(" static { org.netbeans.html.json.impl.JSON.register(new P(0)); }\n"); + w.append(" private ").append(className).append("(net.java.html.BrwsrCtx c, Object json) {\n"); + w.append(" this.context = c;\n"); + int values = 0; + for (int i = 0; i < propsGetSet.size(); i += 5) { + Prprt p = findPrprt(props, propsGetSet.get(i)); + if (p == null) { + continue; + } + values++; + } + w.append(" Object[] ret = new Object[" + values + "];\n"); + w.append(" org.netbeans.html.json.impl.JSON.extract(context, json, new String[] {\n"); + for (int i = 0; i < propsGetSet.size(); i += 5) { + Prprt p = findPrprt(props, propsGetSet.get(i)); + if (p == null) { + continue; + } + w.append(" \"").append(propsGetSet.get(i)).append("\",\n"); + } + w.append(" }, ret);\n"); + for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i += 5) { + final String pn = propsGetSet.get(i); + Prprt p = findPrprt(props, pn); + if (p == null) { + continue; + } + boolean[] isModel = { false }; + boolean[] isEnum = { false }; + boolean isPrimitive[] = { false }; + String type = checkType(props[prop++], isModel, isEnum, isPrimitive); + if (p.array()) { + w.append(" if (ret[" + cnt + "] instanceof Object[]) {\n"); + w.append(" for (Object e : ((Object[])ret[" + cnt + "])) {\n"); + if (isModel[0]) { + w.append(" this.prop_").append(pn).append(".add(org.netbeans.html.json.impl.JSON.read"); + w.append("(c, " + type + ".class, e));\n"); + } else if (isEnum[0]) { + w.append(" this.prop_").append(pn); + w.append(".add(e == null ? null : "); + w.append(type).append(".valueOf(org.netbeans.html.json.impl.JSON.stringValue(e)));\n"); + } else { + if (isPrimitive(type)) { + w.append(" this.prop_").append(pn).append(".add(org.netbeans.html.json.impl.JSON.numberValue(e)."); + w.append(type).append("Value());\n"); + } else { + w.append(" this.prop_").append(pn).append(".add(("); + w.append(type).append(")e);\n"); + } + } + w.append(" }\n"); + w.append(" }\n"); + } else { + if (isEnum[0]) { + w.append(" try {\n"); + w.append(" this.prop_").append(pn); + w.append(" = ret[" + cnt + "] == null ? null : "); + w.append(type).append(".valueOf(org.netbeans.html.json.impl.JSON.stringValue(ret[" + cnt + "]));\n"); + w.append(" } catch (IllegalArgumentException ex) {\n"); + w.append(" ex.printStackTrace();\n"); + w.append(" }\n"); + } else if (isPrimitive(type)) { + w.append(" this.prop_").append(pn); + w.append(" = ret[" + cnt + "] == null ? "); + if ("char".equals(type)) { + w.append("0 : (org.netbeans.html.json.impl.JSON.charValue("); + } else if ("boolean".equals(type)) { + w.append("false : (org.netbeans.html.json.impl.JSON.boolValue("); + } else { + w.append("0 : (org.netbeans.html.json.impl.JSON.numberValue("); + } + w.append("ret[" + cnt + "]))."); + w.append(type).append("Value();\n"); + } else if (isModel[0]) { + w.append(" this.prop_").append(pn).append(" = org.netbeans.html.json.impl.JSON.read"); + w.append("(c, " + type + ".class, "); + w.append("ret[" + cnt + "]);\n"); + }else { + w.append(" this.prop_").append(pn); + w.append(" = (").append(type).append(')'); + w.append("ret[" + cnt + "];\n"); + } + } + cnt++; + } + w.append(" };\n"); + writeToString(props, w); + writeClone(className, props, w); + w.write(" /** Activates this model instance in the current {@link \n" + + "net.java.html.json.Models#bind(java.lang.Object, net.java.html.BrwsrCtx) browser context}. \n" + + "In case of using Knockout technology, this means to \n" + + "bind JSON like data in this model instance with Knockout tags in \n" + + "the surrounding HTML page.\n" + + "*/\n" + ); + w.write(" public " + className + " applyBindings() {\n"); + w.write(" intKnckt().applyBindings();\n"); + w.write(" return this;\n"); + w.write(" }\n"); + w.write(" public boolean equals(Object o) {\n"); + w.write(" if (o == this) return true;\n"); + w.write(" if (o instanceof org.netbeans.html.json.impl.WrapperObject) {\n"); + w.write(" ((org.netbeans.html.json.impl.WrapperObject)o).setRealObject(intKnckt().koData());\n"); + w.write(" return false;\n"); + w.write(" }\n"); + w.write(" if (!(o instanceof " + className + ")) return false;\n"); + w.write(" " + className + " p = (" + className + ")o;\n"); + for (Prprt p : props) { + w.write(" if (!org.netbeans.html.json.impl.JSON.isSame(prop_" + p.name() + ", p.prop_" + p.name() + ")) return false;\n"); + } + w.write(" return true;\n"); + w.write(" }\n"); + w.write(" public int hashCode() {\n"); + w.write(" int h = " + className + ".class.getName().hashCode();\n"); + for (Prprt p : props) { + w.write(" h = org.netbeans.html.json.impl.JSON.hashPlus(prop_" + p.name() + ", h);\n"); + } + w.write(" return h;\n"); + w.write(" }\n"); + w.write("}\n"); + } finally { + w.close(); + } + } catch (IOException ex) { + error("Can't create " + className + ".java", e); + return false; + } + return ok; + } + + private boolean generateProperties( + Element where, + Writer w, Prprt[] properties, + Collection props, + Map> deps, + Map> functionDeps + ) throws IOException { + boolean ok = true; + for (Prprt p : properties) { + final String tn; + tn = typeName(where, p); + String[] gs = toGetSet(p.name(), tn, p.array()); + String castTo; + + if (p.array()) { + w.write(" private org.netbeans.html.json.impl.JSONList<" + tn + "> prop_" + p.name() + " = new org.netbeans.html.json.impl.JSONList<" + tn + ">(ko, \"" + + p.name() + "\""); + Collection dependants = deps.get(p.name()); + if (dependants != null) { + for (String depProp : dependants) { + w.write(", "); + w.write('\"'); + w.write(depProp); + w.write('\"'); + } + } + w.write(")"); + + dependants = functionDeps.get(p.name()); + if (dependants != null) { + w.write(".onChange(new Runnable() { public void run() {\n"); + for (String call : dependants) { + w.append(" ").append(call); + } + w.write(" }})"); + } + w.write(";\n"); + + castTo = "java.util.List"; + w.write(" public java.util.List<" + tn + "> " + gs[0] + "() {\n"); + w.write(" if (locked) throw new IllegalStateException();\n"); + w.write(" return prop_" + p.name() + ";\n"); + w.write(" }\n"); + } else { + castTo = tn; + w.write(" private " + tn + " prop_" + p.name() + ";\n"); + w.write(" public " + tn + " " + gs[0] + "() {\n"); + w.write(" if (locked) throw new IllegalStateException();\n"); + w.write(" return prop_" + p.name() + ";\n"); + w.write(" }\n"); + w.write(" public void " + gs[1] + "(" + tn + " v) {\n"); + w.write(" if (locked) throw new IllegalStateException();\n"); + w.write(" if (org.netbeans.html.json.impl.JSON.isSame(prop_" + p.name() + ", v)) return;\n"); + w.write(" prop_" + p.name() + " = v;\n"); + w.write(" org.netbeans.html.json.impl.Bindings b = ko[0];\n"); + w.write(" if (b != null) {\n"); + w.write(" b.valueHasMutated(\"" + p.name() + "\");\n"); + Collection dependants = deps.get(p.name()); + if (dependants != null) { + for (String depProp : dependants) { + w.write(" b.valueHasMutated(\"" + depProp + "\");\n"); + } + } + w.write(" }\n"); + dependants = functionDeps.get(p.name()); + if (dependants != null) { + for (String call : dependants) { + w.append(" ").append(call); + } + } + w.write(" }\n"); + } + + props.add(p.name()); + props.add(gs[2]); + props.add(gs[3]); + props.add(gs[0]); + props.add(castTo); + } + return ok; + } + + private boolean generateComputedProperties( + Writer w, Prprt[] fixedProps, + Collection arr, Collection props, + Map> deps + ) throws IOException { + boolean ok = true; + for (Element e : arr) { + if (e.getKind() != ElementKind.METHOD) { + continue; + } + if (e.getAnnotation(ComputedProperty.class) == null) { + continue; + } + if (!e.getModifiers().contains(Modifier.STATIC)) { + error("Method " + e.getSimpleName() + " has to be static when annotated by @ComputedProperty", e); + ok = false; + continue; + } + ExecutableElement ee = (ExecutableElement)e; + final TypeMirror rt = ee.getReturnType(); + final Types tu = processingEnv.getTypeUtils(); + TypeMirror ert = tu.erasure(rt); + String tn = fqn(ert, ee); + boolean array = false; + final TypeMirror toCheck; + if (tn.equals("java.util.List")) { + array = true; + toCheck = ((DeclaredType)rt).getTypeArguments().get(0); + } else { + toCheck = rt; + } + + final String sn = ee.getSimpleName().toString(); + + if (toCheck.getKind().isPrimitive()) { + // OK + } else { + TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType(); + TypeMirror enumType = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType(); + + if (tu.isSubtype(toCheck, stringType)) { + // OK + } else if (tu.isSubtype(tu.erasure(toCheck), tu.erasure(enumType))) { + // OK + } else if (isModel(toCheck)) { + // OK + } else { + ok = false; + error(sn + " cannot return " + toCheck, e); + } + } + + String[] gs = toGetSet(sn, tn, array); + + w.write(" public " + tn + " " + gs[0] + "() {\n"); + w.write(" if (locked) throw new IllegalStateException();\n"); + int arg = 0; + for (VariableElement pe : ee.getParameters()) { + final String dn = pe.getSimpleName().toString(); + + if (!verifyPropName(pe, dn, fixedProps)) { + ok = false; + } + + final String dt = fqn(pe.asType(), ee); + String[] call = toGetSet(dn, dt, false); + w.write(" " + dt + " arg" + (++arg) + " = "); + w.write(call[0] + "();\n"); + + Collection depends = deps.get(dn); + if (depends == null) { + depends = new LinkedHashSet(); + deps.put(dn, depends); + } + depends.add(sn); + } + w.write(" try {\n"); + w.write(" locked = true;\n"); + w.write(" return " + fqn(ee.getEnclosingElement().asType(), ee) + '.' + e.getSimpleName() + "("); + String sep = ""; + for (int i = 1; i <= arg; i++) { + w.write(sep); + w.write("arg" + i); + sep = ", "; + } + w.write(");\n"); + w.write(" } finally {\n"); + w.write(" locked = false;\n"); + w.write(" }\n"); + w.write(" }\n"); + + props.add(e.getSimpleName().toString()); + props.add(gs[2]); + props.add(null); + props.add(gs[0]); + props.add(tn); + } + + return ok; + } + + private static String[] toGetSet(String name, String type, boolean array) { + String n = Character.toUpperCase(name.charAt(0)) + name.substring(1); + String bck2brwsrType = "L" + type.replace('.', '_') + "_2"; + if ("int".equals(type)) { + bck2brwsrType = "I"; + } + if ("double".equals(type)) { + bck2brwsrType = "D"; + } + String pref = "get"; + if ("boolean".equals(type)) { + pref = "is"; + bck2brwsrType = "Z"; + } + final String nu = n.replace('.', '_'); + if (array) { + return new String[] { + "get" + n, + null, + "get" + nu + "__Ljava_util_List_2", + null + }; + } + return new String[]{ + pref + n, + "set" + n, + pref + nu + "__" + bck2brwsrType, + "set" + nu + "__V" + bck2brwsrType + }; + } + + private String typeName(Element where, Prprt p) { + String ret; + boolean[] isModel = { false }; + boolean[] isEnum = { false }; + boolean isPrimitive[] = { false }; + ret = checkType(p, isModel, isEnum, isPrimitive); + if (p.array()) { + String bt = findBoxedType(ret); + if (bt != null) { + return bt; + } + } + return ret; + } + + private static String findBoxedType(String ret) { + if (ret.equals("boolean")) { + return Boolean.class.getName(); + } + if (ret.equals("byte")) { + return Byte.class.getName(); + } + if (ret.equals("short")) { + return Short.class.getName(); + } + if (ret.equals("char")) { + return Character.class.getName(); + } + if (ret.equals("int")) { + return Integer.class.getName(); + } + if (ret.equals("long")) { + return Long.class.getName(); + } + if (ret.equals("float")) { + return Float.class.getName(); + } + if (ret.equals("double")) { + return Double.class.getName(); + } + return null; + } + + private boolean verifyPropName(Element e, String propName, Prprt[] existingProps) { + StringBuilder sb = new StringBuilder(); + String sep = ""; + for (Prprt Prprt : existingProps) { + if (Prprt.name().equals(propName)) { + return true; + } + sb.append(sep); + sb.append('"'); + sb.append(Prprt.name()); + sb.append('"'); + sep = ", "; + } + error( + propName + " is not one of known properties: " + sb + , e + ); + return false; + } + + private static String findPkgName(Element e) { + for (;;) { + if (e.getKind() == ElementKind.PACKAGE) { + return ((PackageElement)e).getQualifiedName().toString(); + } + e = e.getEnclosingElement(); + } + } + + private boolean generateFunctions( + Element clazz, StringWriter body, String className, + List enclosedElements, List functions + ) { + for (Element m : enclosedElements) { + if (m.getKind() != ElementKind.METHOD) { + continue; + } + ExecutableElement e = (ExecutableElement)m; + Function onF = e.getAnnotation(Function.class); + if (onF == null) { + continue; + } + if (!e.getModifiers().contains(Modifier.STATIC)) { + error("@OnFunction method needs to be static", e); + return false; + } + if (e.getModifiers().contains(Modifier.PRIVATE)) { + error("@OnFunction method cannot be private", e); + return false; + } + if (e.getReturnType().getKind() != TypeKind.VOID) { + error("@OnFunction method should return void", e); + return false; + } + String n = e.getSimpleName().toString(); + body.append(" private void ").append(n).append("(Object data, Object ev) {\n"); + body.append(" ").append(((TypeElement)clazz).getQualifiedName()).append(".").append(n).append("("); + body.append(wrapParams(e, null, className, "ev", "data")); + body.append(");\n"); + body.append(" }\n"); + + functions.add(n); + functions.add(n + "__VLjava_lang_Object_2Ljava_lang_Object_2"); + } + return true; + } + + private boolean generateOnChange(Element clazz, Map> propDeps, + Prprt[] properties, String className, + Map> functionDeps + ) { + for (Element m : clazz.getEnclosedElements()) { + if (m.getKind() != ElementKind.METHOD) { + continue; + } + ExecutableElement e = (ExecutableElement) m; + OnPropertyChange onPC = e.getAnnotation(OnPropertyChange.class); + if (onPC == null) { + continue; + } + for (String pn : onPC.value()) { + if (findPrprt(properties, pn) == null && findDerivedFrom(propDeps, pn).isEmpty()) { + error("No Prprt named '" + pn + "' in the model", clazz); + return false; + } + } + if (!e.getModifiers().contains(Modifier.STATIC)) { + error("@OnPrprtChange method needs to be static", e); + return false; + } + if (e.getModifiers().contains(Modifier.PRIVATE)) { + error("@OnPrprtChange method cannot be private", e); + return false; + } + if (e.getReturnType().getKind() != TypeKind.VOID) { + error("@OnPrprtChange method should return void", e); + return false; + } + String n = e.getSimpleName().toString(); + + + for (String pn : onPC.value()) { + StringBuilder call = new StringBuilder(); + call.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("("); + call.append(wrapPropName(e, className, "name", pn)); + call.append(");\n"); + + Collection change = functionDeps.get(pn); + if (change == null) { + change = new ArrayList(); + functionDeps.put(pn, change); + } + change.add(call.toString()); + for (String dpn : findDerivedFrom(propDeps, pn)) { + change = functionDeps.get(dpn); + if (change == null) { + change = new ArrayList(); + functionDeps.put(dpn, change); + } + change.add(call.toString()); + } + } + } + return true; + } + + private boolean generateOperation(Element clazz, + StringWriter body, String className, + List enclosedElements + ) { + for (Element m : enclosedElements) { + if (m.getKind() != ElementKind.METHOD) { + continue; + } + ExecutableElement e = (ExecutableElement)m; + ModelOperation mO = e.getAnnotation(ModelOperation.class); + if (mO == null) { + continue; + } + if (!e.getModifiers().contains(Modifier.STATIC)) { + error("@ModelOperation method needs to be static", e); + return false; + } + if (e.getModifiers().contains(Modifier.PRIVATE)) { + error("@ModelOperation method cannot be private", e); + return false; + } + if (e.getReturnType().getKind() != TypeKind.VOID) { + error("@ModelOperation method should return void", e); + return false; + } + List args = new ArrayList(); + { + body.append(" public void ").append(m.getSimpleName()).append("("); + String sep = ""; + boolean checkFirst = true; + for (VariableElement ve : e.getParameters()) { + final TypeMirror type = ve.asType(); + CharSequence simpleName; + if (type.getKind() == TypeKind.DECLARED) { + simpleName = ((DeclaredType)type).asElement().getSimpleName(); + } else { + simpleName = type.toString(); + } + if (simpleName.toString().equals(className)) { + checkFirst = false; + } else { + if (checkFirst) { + error("First parameter of @ModelOperation method must be " + className, m); + return false; + } + args.add(ve.getSimpleName().toString()); + body.append(sep).append("final "); + body.append(ve.asType().toString()).append(" "); + body.append(ve.toString()); + sep = ", "; + } + } + body.append(") {\n"); + body.append(" org.netbeans.html.json.impl.JSON.runInBrowser(this.context, new Runnable() { public void run() {\n"); + body.append(" ").append(clazz.getSimpleName()).append(".").append(m.getSimpleName()).append("("); + body.append(className).append(".this"); + for (String s : args) { + body.append(", ").append(s); + } + body.append(");\n"); + body.append(" }});\n"); + body.append(" }\n"); + } + + } + return true; + } + + + private boolean generateReceive( + Element clazz, StringWriter body, String className, + List enclosedElements, List functions + ) { + for (Element m : enclosedElements) { + if (m.getKind() != ElementKind.METHOD) { + continue; + } + ExecutableElement e = (ExecutableElement)m; + OnReceive onR = e.getAnnotation(OnReceive.class); + if (onR == null) { + continue; + } + if (!e.getModifiers().contains(Modifier.STATIC)) { + error("@OnReceive method needs to be static", e); + return false; + } + if (e.getModifiers().contains(Modifier.PRIVATE)) { + error("@OnReceive method cannot be private", e); + return false; + } + if (e.getReturnType().getKind() != TypeKind.VOID) { + error("@OnReceive method should return void", e); + return false; + } + if (!onR.jsonp().isEmpty() && !"GET".equals(onR.method())) { + error("JSONP works only with GET transport method", e); + } + String dataMirror = findDataSpecified(e, onR); + if ("PUT".equals(onR.method()) && dataMirror == null) { + error("PUT method needs to specify a data() class", e); + return false; + } + if ("POST".equals(onR.method()) && dataMirror == null) { + error("POST method needs to specify a data() class", e); + return false; + } + String modelClass = null; + boolean expectsList = false; + List args = new ArrayList(); + { + for (VariableElement ve : e.getParameters()) { + TypeMirror modelType = null; + final TypeMirror type = ve.asType(); + CharSequence simpleName; + if (type.getKind() == TypeKind.DECLARED) { + simpleName = ((DeclaredType)type).asElement().getSimpleName(); + } else { + simpleName = type.toString(); + } + if (simpleName.toString().equals(className)) { + args.add(className + ".this"); + } else if (isModel(ve.asType())) { + modelType = ve.asType(); + } else if (ve.asType().getKind() == TypeKind.ARRAY) { + modelType = ((ArrayType)ve.asType()).getComponentType(); + expectsList = true; + } else if (ve.asType().toString().equals("java.lang.String")) { + modelType = ve.asType(); + } + if (modelType != null) { + if (modelClass != null) { + error("There can be only one model class among arguments", e); + } else { + modelClass = modelType.toString(); + if (expectsList) { + args.add("arr"); + } else { + args.add("arr[0]"); + } + } + } + } + } + if (modelClass == null) { + error("The method needs to have one @Model class as parameter", e); + } + String n = e.getSimpleName().toString(); + if ("WebSocket".equals(onR.method())) { + body.append(" /** Performs WebSocket communication. Call with null data parameter\n"); + body.append(" * to open the connection (even if not required). Call with non-null data to\n"); + body.append(" * send messages to server. Call again with null data to close the socket.\n"); + body.append(" */\n"); + } + body.append(" public void ").append(n).append("("); + StringBuilder urlBefore = new StringBuilder(); + StringBuilder urlAfter = new StringBuilder(); + String jsonpVarName = null; + { + String sep = ""; + boolean skipJSONP = onR.jsonp().isEmpty(); + for (String p : findParamNames(e, onR.url(), onR.jsonp(), urlBefore, urlAfter)) { + if (!skipJSONP && p.equals(onR.jsonp())) { + skipJSONP = true; + jsonpVarName = p; + continue; + } + body.append(sep); + body.append("String ").append(p); + sep = ", "; + } + if (!skipJSONP) { + error( + "Name of jsonp attribute ('" + onR.jsonp() + + "') is not used in url attribute '" + onR.url() + "'", e + ); + } + if (dataMirror != null) { + body.append(sep).append(dataMirror.toString()).append(" data"); + } + } + body.append(") {\n"); + boolean webSocket = onR.method().equals("WebSocket"); + if (webSocket) { + if (generateWSReceiveBody(body, onR, e, clazz, className, expectsList, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) { + return false; + } + body.append(" }\n"); + body.append(" private org.netbeans.html.json.impl.JSON.WS ws_" + e.getSimpleName() + ";\n"); + } else { + if (generateJSONReceiveBody(body, onR, e, clazz, className, expectsList, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) { + return false; + } + body.append(" }\n"); + } + } + return true; + } + + private boolean generateJSONReceiveBody(StringWriter body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) { + body.append( + " class ProcessResult extends org.netbeans.html.json.impl.RcvrJSON {\n" + + " @Override\n" + + " public void onError(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" + + " Exception value = ev.getException();\n" + ); + if (onR.onError().isEmpty()) { + body.append( + " value.printStackTrace();\n" + ); + } else { + if (!findOnError(e, ((TypeElement)clazz), onR.onError(), className)) { + return true; + } + body.append(" ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("("); + body.append(className).append(".this, value);\n"); + } + body.append( + " }\n" + + " @Override\n" + + " public void onMessage(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" + ); + if (expectsList) { + body.append( + " " + modelClass + "[] arr = new " + modelClass + "[ev.dataSize()];\n" + ); + } else { + body.append( + " " + modelClass + "[] arr = { null };\n" + ); + } + body.append( + " ev.dataRead(context, " + modelClass + ".class, arr);\n" + ); + { + body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("("); + String sep = ""; + for (String arg : args) { + body.append(sep); + body.append(arg); + sep = ", "; + } + body.append(");\n"); + } + body.append( + " }\n" + + " }\n" + ); + body.append(" ProcessResult pr = new ProcessResult();\n"); + body.append(" org.netbeans.html.json.impl.JSON.loadJSON(context, pr,\n "); + body.append(urlBefore).append(", "); + if (jsonpVarName != null) { + body.append(urlAfter); + } else { + body.append("null"); + } + if (!"GET".equals(onR.method()) || dataMirror != null) { + body.append(", \"").append(onR.method()).append('"'); + if (dataMirror != null) { + body.append(", data"); + } else { + body.append(", null"); + } + } else { + body.append(", null, null"); + } + body.append(");\n"); + return false; + } + + private boolean generateWSReceiveBody(StringWriter body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) { + body.append( + " class ProcessResult extends org.netbeans.html.json.impl.RcvrJSON {\n" + + " @Override\n" + + " public void onOpen(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" + ); + body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("("); + { + String sep = ""; + for (String arg : args) { + body.append(sep); + if (arg.startsWith("arr")) { + body.append("null"); + } else { + body.append(arg); + } + sep = ", "; + } + } + body.append(");\n"); + body.append( + " }\n" + + " @Override\n" + + " public void onError(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" + + " Exception value = ev.getException();\n" + ); + if (onR.onError().isEmpty()) { + body.append( + " value.printStackTrace();\n" + ); + } else { + if (!findOnError(e, ((TypeElement)clazz), onR.onError(), className)) { + return true; + } + body.append(" ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("("); + body.append(className).append(".this, value);\n"); + } + body.append( + " }\n" + + " @Override\n" + + " public void onMessage(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" + ); + if (expectsList) { + body.append( + " " + modelClass + "[] arr = new " + modelClass + "[ev.dataSize()];\n" + ); + } else { + body.append( + " " + modelClass + "[] arr = { null };\n" + ); + } + body.append( + " ev.dataRead(context, " + modelClass + ".class, arr);\n" + ); + { + body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("("); + String sep = ""; + for (String arg : args) { + body.append(sep); + body.append(arg); + sep = ", "; + } + body.append(");\n"); + } + body.append( + " }\n" + ); + if (!onR.onError().isEmpty()) { + body.append( + " @Override\n" + + " public void onClose(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" + ); + body.append(" ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("("); + body.append(className).append(".this, null);\n"); + body.append( + " }\n" + ); + } + body.append(" }\n"); + body.append(" if (this.ws_").append(e.getSimpleName()).append(" == null) {\n"); + body.append(" ProcessResult pr = new ProcessResult();\n"); + body.append(" this.ws_").append(e.getSimpleName()); + body.append("= org.netbeans.html.json.impl.JSON.openWS(context, pr,\n "); + body.append(urlBefore).append(", data);\n"); + body.append(" } else {\n"); + body.append(" this.ws_").append(e.getSimpleName()).append(".send(context, ").append(urlBefore).append(", data);\n"); + body.append(" }\n"); + return false; + } + + private CharSequence wrapParams( + ExecutableElement ee, String id, String className, String evName, String dataName + ) { + TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType(); + StringBuilder params = new StringBuilder(); + boolean first = true; + for (VariableElement ve : ee.getParameters()) { + if (!first) { + params.append(", "); + } + first = false; + String toCall = null; + String toFinish = null; + if (ve.asType() == stringType) { + if (ve.getSimpleName().contentEquals("id")) { + params.append('"').append(id).append('"'); + continue; + } + toCall = "org.netbeans.html.json.impl.JSON.toString(context, "; + } + if (ve.asType().getKind() == TypeKind.DOUBLE) { + toCall = "org.netbeans.html.json.impl.JSON.toNumber(context, "; + toFinish = ".doubleValue()"; + } + if (ve.asType().getKind() == TypeKind.INT) { + toCall = "org.netbeans.html.json.impl.JSON.toNumber(context, "; + toFinish = ".intValue()"; + } + if (dataName != null && ve.getSimpleName().contentEquals(dataName) && isModel(ve.asType())) { + toCall = "org.netbeans.html.json.impl.JSON.toModel(context, " + ve.asType() + ".class, "; + } + + if (toCall != null) { + params.append(toCall); + if (dataName != null && ve.getSimpleName().contentEquals(dataName)) { + params.append(dataName); + params.append(", null"); + } else { + if (evName == null) { + final StringBuilder sb = new StringBuilder(); + sb.append("Unexpected string parameter name."); + if (dataName != null) { + sb.append(" Try \"").append(dataName).append("\""); + } + error(sb.toString(), ee); + } + params.append(evName); + params.append(", \""); + params.append(ve.getSimpleName().toString()); + params.append("\""); + } + params.append(")"); + if (toFinish != null) { + params.append(toFinish); + } + continue; + } + String rn = fqn(ve.asType(), ee); + int last = rn.lastIndexOf('.'); + if (last >= 0) { + rn = rn.substring(last + 1); + } + if (rn.equals(className)) { + params.append(className).append(".this"); + continue; + } + error( + "The annotated method can only accept " + className + " argument or argument named 'data'", + ee + ); + } + return params; + } + + + private CharSequence wrapPropName( + ExecutableElement ee, String className, String propName, String propValue + ) { + TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType(); + StringBuilder params = new StringBuilder(); + boolean first = true; + for (VariableElement ve : ee.getParameters()) { + if (!first) { + params.append(", "); + } + first = false; + if (ve.asType() == stringType) { + if (propName != null && ve.getSimpleName().contentEquals(propName)) { + params.append('"').append(propValue).append('"'); + } else { + error("Unexpected string parameter name. Try \"" + propName + "\".", ee); + } + continue; + } + String rn = fqn(ve.asType(), ee); + int last = rn.lastIndexOf('.'); + if (last >= 0) { + rn = rn.substring(last + 1); + } + if (rn.equals(className)) { + params.append(className).append(".this"); + continue; + } + error( + "@OnPrprtChange method can only accept String or " + className + " arguments", + ee); + } + return params; + } + + private boolean isModel(TypeMirror tm) { + if (tm.getKind() == TypeKind.ERROR) { + return true; + } + final Element e = processingEnv.getTypeUtils().asElement(tm); + if (e == null) { + return false; + } + for (Element ch : e.getEnclosedElements()) { + if (ch.getKind() == ElementKind.METHOD) { + ExecutableElement ee = (ExecutableElement)ch; + if (ee.getParameters().isEmpty() && ee.getSimpleName().contentEquals("modelFor")) { + return true; + } + } + } + return models.values().contains(e.getSimpleName().toString()); + } + + private void writeToString(Prprt[] props, Writer w) throws IOException { + w.write(" public String toString() {\n"); + w.write(" StringBuilder sb = new StringBuilder();\n"); + w.write(" sb.append('{');\n"); + String sep = ""; + for (Prprt p : props) { + w.write(sep); + w.append(" sb.append('\"').append(\"" + p.name() + "\")"); + w.append(".append('\"').append(\":\");\n"); + w.append(" sb.append(org.netbeans.html.json.impl.JSON.toJSON(prop_"); + w.append(p.name()).append("));\n"); + sep = " sb.append(',');\n"; + } + w.write(" sb.append('}');\n"); + w.write(" return sb.toString();\n"); + w.write(" }\n"); + } + private void writeClone(String className, Prprt[] props, Writer w) throws IOException { + w.write(" public " + className + " clone() {\n"); + w.write(" return clone(context);\n"); + w.write(" }\n"); + w.write(" private " + className + " clone(net.java.html.BrwsrCtx ctx) {\n"); + w.write(" " + className + " ret = new " + className + "(ctx);\n"); + for (Prprt p : props) { + if (!p.array()) { + boolean isModel[] = { false }; + boolean isEnum[] = { false }; + boolean isPrimitive[] = { false }; + checkType(p, isModel, isEnum, isPrimitive); + if (!isModel[0]) { + w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + ";\n"); + continue; + } + w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + " == null ? null : prop_" + p.name() + ".clone();\n"); + } else { + w.write(" ret.prop_" + p.name() + ".cloneAll(ctx, prop_" + p.name() + ");\n"); + } + } + + w.write(" return ret;\n"); + w.write(" }\n"); + } + + private String inPckName(Element e) { + StringBuilder sb = new StringBuilder(); + while (e.getKind() != ElementKind.PACKAGE) { + if (sb.length() == 0) { + sb.append(e.getSimpleName()); + } else { + sb.insert(0, '.'); + sb.insert(0, e.getSimpleName()); + } + e = e.getEnclosingElement(); + } + return sb.toString(); + } + + private String fqn(TypeMirror pt, Element relative) { + if (pt.getKind() == TypeKind.ERROR) { + final Elements eu = processingEnv.getElementUtils(); + PackageElement pckg = eu.getPackageOf(relative); + return pckg.getQualifiedName() + "." + pt.toString(); + } + return pt.toString(); + } + + private String checkType(Prprt p, boolean[] isModel, boolean[] isEnum, boolean[] isPrimitive) { + TypeMirror tm; + try { + String ret = p.typeName(processingEnv); + TypeElement e = processingEnv.getElementUtils().getTypeElement(ret); + if (e == null) { + isModel[0] = true; + isEnum[0] = false; + isPrimitive[0] = false; + return ret; + } + tm = e.asType(); + } catch (MirroredTypeException ex) { + tm = ex.getTypeMirror(); + } + tm = processingEnv.getTypeUtils().erasure(tm); + if (isPrimitive[0] = tm.getKind().isPrimitive()) { + isEnum[0] = false; + isModel[0] = false; + return tm.toString(); + } + final Element e = processingEnv.getTypeUtils().asElement(tm); + if (e.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) { + isModel[0] = true; + isEnum[0] = false; + return e.getSimpleName().toString(); + } + + final Model m = e == null ? null : e.getAnnotation(Model.class); + String ret; + if (m != null) { + ret = findPkgName(e) + '.' + m.className(); + isModel[0] = true; + models.put(e, m.className()); + } else if (findModelForMthd(e)) { + ret = ((TypeElement)e).getQualifiedName().toString(); + isModel[0] = true; + } else { + ret = tm.toString(); + } + TypeMirror enm = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType(); + enm = processingEnv.getTypeUtils().erasure(enm); + isEnum[0] = processingEnv.getTypeUtils().isSubtype(tm, enm); + return ret; + } + + private static boolean findModelForMthd(Element clazz) { + if (clazz == null) { + return false; + } + for (Element e : clazz.getEnclosedElements()) { + if (e.getKind() == ElementKind.METHOD) { + ExecutableElement ee = (ExecutableElement)e; + if ( + ee.getSimpleName().contentEquals("modelFor") && + ee.getParameters().isEmpty() + ) { + return true; + } + } + } + return false; + } + + private Iterable findParamNames( + Element e, String url, String jsonParam, StringBuilder... both + ) { + List params = new ArrayList(); + int wasJSON = 0; + + for (int pos = 0; ;) { + int next = url.indexOf('{', pos); + if (next == -1) { + both[wasJSON].append('"') + .append(url.substring(pos)) + .append('"'); + return params; + } + int close = url.indexOf('}', next); + if (close == -1) { + error("Unbalanced '{' and '}' in " + url, e); + return params; + } + final String paramName = url.substring(next + 1, close); + params.add(paramName); + if (paramName.equals(jsonParam) && !jsonParam.isEmpty()) { + both[wasJSON].append('"') + .append(url.substring(pos, next)) + .append('"'); + wasJSON = 1; + } else { + both[wasJSON].append('"') + .append(url.substring(pos, next)) + .append("\" + ").append(paramName).append(" + "); + } + pos = close + 1; + } + } + + private static Prprt findPrprt(Prprt[] properties, String propName) { + for (Prprt p : properties) { + if (propName.equals(p.name())) { + return p; + } + } + return null; + } + + private boolean isPrimitive(String type) { + return + "int".equals(type) || + "double".equals(type) || + "long".equals(type) || + "short".equals(type) || + "byte".equals(type) || + "char".equals(type) || + "boolean".equals(type) || + "float".equals(type); + } + + private static Collection findDerivedFrom(Map> propsDeps, String derivedProp) { + Set names = new HashSet(); + for (Map.Entry> e : propsDeps.entrySet()) { + if (e.getValue().contains(derivedProp)) { + names.add(e.getKey()); + } + } + return names; + } + + private Prprt[] createProps(Element e, Property[] arr) { + Prprt[] ret = Prprt.wrap(processingEnv, e, arr); + Prprt[] prev = verify.put(e, ret); + if (prev != null) { + error("Two sets of properties for ", e); + } + return ret; + } + + private static String strip(String s) { + int indx = s.indexOf("__"); + if (indx >= 0) { + return s.substring(0, indx); + } else { + return s; + } + } + + private String findDataSpecified(ExecutableElement e, OnReceive onR) { + try { + return onR.data().getName(); + } catch (MirroredTypeException ex) { + final TypeMirror tm = ex.getTypeMirror(); + String name; + final Element te = processingEnv.getTypeUtils().asElement(tm); + if (te.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) { + name = te.getSimpleName().toString(); + } else { + name = tm.toString(); + } + return "java.lang.Object".equals(name) ? null : name; + } catch (Exception ex) { + // fallback + } + + AnnotationMirror found = null; + for (AnnotationMirror am : e.getAnnotationMirrors()) { + if (am.getAnnotationType().toString().equals(OnReceive.class.getName())) { + found = am; + } + } + if (found == null) { + return null; + } + + for (Map.Entry entry : found.getElementValues().entrySet()) { + ExecutableElement ee = entry.getKey(); + AnnotationValue av = entry.getValue(); + if (ee.getSimpleName().contentEquals("data")) { + List values = getAnnoValues(processingEnv, e, found); + for (Object v : values) { + String sv = v.toString(); + if (sv.startsWith("data = ") && sv.endsWith(".class")) { + return sv.substring(7, sv.length() - 6); + } + } + return "error"; + } + } + return null; + } + + static List getAnnoValues(ProcessingEnvironment pe, Element e, AnnotationMirror am) { + try { + Class trees = Class.forName("com.sun.tools.javac.api.JavacTrees"); + Method m = trees.getMethod("instance", ProcessingEnvironment.class); + Object instance = m.invoke(null, pe); + m = instance.getClass().getMethod("getPath", Element.class, AnnotationMirror.class); + Object path = m.invoke(instance, e, am); + m = path.getClass().getMethod("getLeaf"); + Object leaf = m.invoke(path); + m = leaf.getClass().getMethod("getArguments"); + return (List) m.invoke(leaf); + } catch (Exception ex) { + return Collections.emptyList(); + } + } + + private static class Prprt { + private final Element e; + private final AnnotationMirror tm; + private final Property p; + + public Prprt(Element e, AnnotationMirror tm, Property p) { + this.e = e; + this.tm = tm; + this.p = p; + } + + String name() { + return p.name(); + } + + boolean array() { + return p.array(); + } + + String typeName(ProcessingEnvironment env) { + RuntimeException ex; + try { + return p.type().getName(); + } catch (IncompleteAnnotationException e) { + ex = e; + } catch (AnnotationTypeMismatchException e) { + ex = e; + } + for (Object v : getAnnoValues(env, e, tm)) { + String s = v.toString().replace(" ", ""); + if (s.startsWith("type=") && s.endsWith(".class")) { + return s.substring(5, s.length() - 6); + } + } + throw ex; + } + + + static Prprt[] wrap(ProcessingEnvironment pe, Element e, Property[] arr) { + if (arr.length == 0) { + return new Prprt[0]; + } + + if (e.getKind() != ElementKind.CLASS) { + throw new IllegalStateException("" + e.getKind()); + } + TypeElement te = (TypeElement)e; + List val = null; + for (AnnotationMirror an : te.getAnnotationMirrors()) { + for (Map.Entry entry : an.getElementValues().entrySet()) { + if (entry.getKey().getSimpleName().contentEquals("properties")) { + val = (List)entry.getValue().getValue(); + break; + } + } + } + if (val == null || val.size() != arr.length) { + pe.getMessager().printMessage(Diagnostic.Kind.ERROR, "" + val, e); + return new Prprt[0]; + } + Prprt[] ret = new Prprt[arr.length]; + BIG: for (int i = 0; i < ret.length; i++) { + AnnotationMirror am = (AnnotationMirror)val.get(i).getValue(); + ret[i] = new Prprt(e, am, arr[i]); + + } + return ret; + } + } + + @Override + public Iterable getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) { + final Level l = Level.FINE; + LOG.log(l, " element: {0}", element); + LOG.log(l, " annotation: {0}", annotation); + LOG.log(l, " member: {0}", member); + LOG.log(l, " userText: {0}", userText); + LOG.log(l, "str: {0}", annotation.getAnnotationType().toString()); + if (annotation.getAnnotationType().toString().equals(OnReceive.class.getName())) { + if (member.getSimpleName().contentEquals("method")) { + return Arrays.asList( + methodOf("GET"), + methodOf("POST"), + methodOf("PUT"), + methodOf("DELETE"), + methodOf("HEAD"), + methodOf("WebSocket") + ); + } + } + + return super.getCompletions(element, annotation, member, userText); + } + + private static final Completion methodOf(String method) { + ResourceBundle rb = ResourceBundle.getBundle("org.netbeans.html.json.impl.Bundle"); + return Completions.of('"' + method + '"', rb.getString("MSG_Completion_" + method)); + } + + private boolean findOnError(ExecutableElement errElem, TypeElement te, String name, String className) { + String err = null; + METHODS: + for (Element e : te.getEnclosedElements()) { + if (e.getKind() != ElementKind.METHOD) { + continue; + } + if (!e.getSimpleName().contentEquals(name)) { + continue; + } + if (!e.getModifiers().contains(Modifier.STATIC)) { + errElem = (ExecutableElement) e; + err = "Would have to be static"; + continue; + } + ExecutableElement ee = (ExecutableElement) e; + TypeMirror excType = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType(); + final List params = ee.getParameters(); + boolean error = false; + if (params.size() != 2) { + error = true; + } else { + String firstType = params.get(0).asType().toString(); + int lastDot = firstType.lastIndexOf('.'); + if (lastDot != -1) { + firstType = firstType.substring(lastDot + 1); + } + if (!firstType.equals(className)) { + error = true; + } + if (!processingEnv.getTypeUtils().isAssignable(excType, params.get(1).asType())) { + error = true; + } + } + if (error) { + errElem = (ExecutableElement) e; + err = "Error method first argument needs to be " + className + " and second Exception"; + continue; + } + return true; + } + if (err == null) { + err = "Cannot find " + name + "(" + className + ", Exception) method in this class"; + } + error(err, errElem); + return false; + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/netbeans/html/json/impl/PropertyBindingAccessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/java/org/netbeans/html/json/impl/PropertyBindingAccessor.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,135 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import net.java.html.BrwsrCtx; +import org.apidesign.html.json.spi.FunctionBinding; +import org.apidesign.html.json.spi.JSONCall; +import org.apidesign.html.json.spi.PropertyBinding; + +/** + * + * @author Jaroslav Tulach + */ +public abstract class PropertyBindingAccessor { + private static PropertyBindingAccessor DEFAULT; + + protected PropertyBindingAccessor() { + if (DEFAULT != null) throw new IllegalStateException(); + DEFAULT = this; + } + + static { + JSON.initClass(PropertyBinding.class); + } + + protected abstract PropertyBinding newBinding(PBData d); + protected abstract FunctionBinding newFunction(FBData d); + protected abstract JSONCall newCall( + BrwsrCtx ctx, RcvrJSON callback, String urlBefore, String urlAfter, + String method, Object data + ); + + + static PropertyBinding create(PBData d) { + return DEFAULT.newBinding(d); + } + static FunctionBinding createFunction(FBData d) { + return DEFAULT.newFunction(d); + } + static JSONCall createCall( + BrwsrCtx ctx, RcvrJSON callback, String urlBefore, String urlAfter, + String method, Object data + ) { + return DEFAULT.newCall(ctx, callback, urlBefore, urlAfter, method, data); + } + + public static final class PBData { + public final String name; + public final boolean readOnly; + private final M model; + private final SetAndGet access; + private final Bindings bindings; + + public PBData(Bindings bindings, String name, M model, SetAndGet access, boolean readOnly) { + this.bindings = bindings; + this.name = name; + this.model = model; + this.access = access; + this.readOnly = readOnly; + } + + public void setValue(Object v) { + access.setValue(model, v); + } + + public Object getValue() { + return access.getValue(model); + } + + public boolean isReadOnly() { + return readOnly; + } + + public Bindings getBindings() { + return bindings; + } + } // end of PBData + + public static final class FBData { + public final String name; + private final M model; + private final Callback access; + + public FBData(String name, M model, Callback access) { + this.name = name; + this.model = model; + this.access = access; + } + + + public void call(Object data, Object ev) { + access.call(model, data, ev); + } + } // end of FBData +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/netbeans/html/json/impl/RcvrJSON.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/java/org/netbeans/html/json/impl/RcvrJSON.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,149 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import net.java.html.BrwsrCtx; + +/** Super type for those who wish to receive JSON messages. + * + * @author Jaroslav Tulach + */ +public abstract class RcvrJSON { + protected void onOpen(MsgEvnt msg) {} + protected abstract void onMessage(MsgEvnt msg); + protected void onClose(MsgEvnt msg) {} + protected abstract void onError(MsgEvnt msg); + + public abstract static class MsgEvnt { + MsgEvnt() { + } + + public Throwable getError() { + return null; + } + + public final Exception getException() { + Throwable t = getError(); + if (t instanceof Exception) { + return (Exception)t; + } + if (t == null) { + return null; + } + return new Exception(t); + } + + public int dataSize() { + return -1; + } + + public void dataRead(BrwsrCtx ctx, Class type, Data[] fillTheArray) { + } + + public abstract void dispatch(RcvrJSON r); + + public static MsgEvnt createError(final Throwable t) { + return new MsgEvnt() { + @Override + public Throwable getError() { + return t; + } + + @Override + public void dispatch(RcvrJSON r) { + r.onError(this); + } + }; + } + + public static MsgEvnt createMessage(final Object value) { + return new MsgEvnt() { + @Override + public int dataSize() { + if (value instanceof Object[]) { + return ((Object[])value).length; + } else { + return 1; + } + } + + @Override + public void dataRead(BrwsrCtx context, Class type, Data[] arr) { + if (value instanceof Object[]) { + Object[] data = ((Object[]) value); + for (int i = 0; i < data.length && i < arr.length; i++) { + arr[i] = org.netbeans.html.json.impl.JSON.read(context, type, data[i]); + } + } else { + if (arr.length > 0) { + arr[0] = org.netbeans.html.json.impl.JSON.read(context, type, value); + } + } + } + + @Override + public void dispatch(RcvrJSON r) { + r.onMessage(this); + } + }; + } + + public static MsgEvnt createOpen() { + return new MsgEvnt() { + @Override + public void dispatch(RcvrJSON r) { + r.onOpen(this); + } + }; + } + + public static MsgEvnt createClose() { + return new MsgEvnt() { + @Override + public void dispatch(RcvrJSON r) { + r.onClose(this); + } + }; + } + } // end MsgEvnt +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/netbeans/html/json/impl/SetAndGet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/java/org/netbeans/html/json/impl/SetAndGet.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,54 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import org.apidesign.html.json.spi.PropertyBinding; + +/** A way to implement a {@link PropertyBinding}. + * + * @author Jaroslav Tulach + */ +public interface SetAndGet { + public void setValue(Data data, Object value); + public Object getValue(Data data); +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/java/org/netbeans/html/json/impl/WrapperObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/java/org/netbeans/html/json/impl/WrapperObject.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,82 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import java.util.Collection; +import org.netbeans.html.json.impl.PropertyBindingAccessor.PBData; + +/** A way to extract real object from a model classes. + * + * @author Jaroslav Tulach + */ +public final class WrapperObject { + private Object ko; + + private WrapperObject() { + } + + public void setRealObject(Object ko) { + this.ko = ko; + } + + public static Object find(Object object) { + return find(object, null); + } + + public static Object find(Object object, Bindings model) { + if (object == null) { + return null; + } + + if (object instanceof JSONList) { + return ((JSONList)object).koData(); + } + if (object instanceof Collection) { + return JSONList.koData((Collection)object, model); + } + + WrapperObject ro = new WrapperObject(); + object.equals(ro); + return ro.ko; + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/resources/org/apidesign/html/json/impl/Bundle.properties --- a/json/src/main/resources/org/apidesign/html/json/impl/Bundle.properties Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -# -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. -# -# Copyright 1997-2010 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-2013 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. -# - -MSG_Completion_GET=The GET method means retrieve whatever information \ - (in the form of an entity) is identified by the Request-URI. \ - If the Request-URI refers to a data-producing process, \ - it is the produced data which shall be returned as the entity in \ - the response and not the source text of the process, \ - unless that text happens to be the output of the process. - -MSG_Completion_HEAD=The HEAD method is identical to GET except that the server \ - MUST NOT return a message-body in the response. The metainformation \ - contained in the HTTP headers in response to a HEAD request SHOULD be \ - identical to the information sent in response to a GET request. \ - This method can be used for obtaining metainformation about the entity implied \ - by the request without transferring the entity-body itself. \ - This method is often used for testing hypertext links for validity, \ - accessibility, and recent modification. - -MSG_Completion_POST=The POST method is used to request that the origin server \ - accept the entity enclosed in the request as a new subordinate of the resource \ - identified by the Request-URI in the Request-Line. POST is designed to allow \ - a uniform method to cover annotation of existing resources,\ - posting a message to a bulletin board, newsgroup, mailing list, or similar \ - group of articles, providing a block of data, such as the result of submitting a \ - form, to a data-handling process or extending a database through an append operation. \ - The actual function performed by the POST method is determined by the server \ - and is usually dependent on the Request-URI. The posted entity is subordinate \ - to that URI in the same way that a file is subordinate to a directory containing it, \ - a news article is subordinate to a newsgroup to which it is posted, \ - or a record is subordinate to a database. - -MSG_Completion_PUT=The PUT method requests that the enclosed entity be stored \ - under the supplied Request-URI. If the Request-URI refers to an already \ - existing resource, the enclosed entity SHOULD be considered as a modified \ - version of the one residing on the origin server. If the Request-URI does \ - not point to an existing resource, and that URI is capable of being defined \ - as a new resource by the requesting user agent, the origin server can \ - create the resource with that URI. If a new resource is created, the origin \ - server MUST inform the user agent via the 201 (Created) response. \ - If an existing resource is modified, either the 200 (OK) or 204 (No Content) \ - response codes SHOULD be sent to indicate successful completion of the request. \ - If the resource could not be created or modified with the Request-URI, an \ - appropriate error response SHOULD be given that reflects the nature of the problem. \ - The recipient of the entity MUST NOT ignore any Content-* (e.g. Content-Range) \ - headers that it does not understand or implement and MUST return \ - a 501 (Not Implemented) response in such cases. - -MSG_Completion_DELETE=The DELETE method requests that the origin server delete \ - the resource identified by the Request-URI. This method MAY be overridden \ - by human intervention (or other means) on the origin server. The client \ - cannot be guaranteed that the operation has been carried out, even if \ - the status code returned from the origin server indicates that the action \ - has been completed successfully. However, the server SHOULD NOT indicate \ - success unless, at the time the response is given, it intends to delete \ - the resource or move it to an inaccessible location. - diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/resources/org/apidesign/html/json/spi/package.html --- a/json/src/main/resources/org/apidesign/html/json/spi/package.html Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ - - - - - - - - -
Implement - Technology and - Transfer and use - ContextBuilder to create an instance - of Context representing your technology. -
- - diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/resources/org/netbeans/html/json/impl/Bundle.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/resources/org/netbeans/html/json/impl/Bundle.properties Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,97 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 1997-2010 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-2013 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. +# + +MSG_Completion_GET=The GET method means retrieve whatever information \ + (in the form of an entity) is identified by the Request-URI. \ + If the Request-URI refers to a data-producing process, \ + it is the produced data which shall be returned as the entity in \ + the response and not the source text of the process, \ + unless that text happens to be the output of the process. + +MSG_Completion_HEAD=The HEAD method is identical to GET except that the server \ + MUST NOT return a message-body in the response. The metainformation \ + contained in the HTTP headers in response to a HEAD request SHOULD be \ + identical to the information sent in response to a GET request. \ + This method can be used for obtaining metainformation about the entity implied \ + by the request without transferring the entity-body itself. \ + This method is often used for testing hypertext links for validity, \ + accessibility, and recent modification. + +MSG_Completion_POST=The POST method is used to request that the origin server \ + accept the entity enclosed in the request as a new subordinate of the resource \ + identified by the Request-URI in the Request-Line. POST is designed to allow \ + a uniform method to cover annotation of existing resources,\ + posting a message to a bulletin board, newsgroup, mailing list, or similar \ + group of articles, providing a block of data, such as the result of submitting a \ + form, to a data-handling process or extending a database through an append operation. \ + The actual function performed by the POST method is determined by the server \ + and is usually dependent on the Request-URI. The posted entity is subordinate \ + to that URI in the same way that a file is subordinate to a directory containing it, \ + a news article is subordinate to a newsgroup to which it is posted, \ + or a record is subordinate to a database. + +MSG_Completion_PUT=The PUT method requests that the enclosed entity be stored \ + under the supplied Request-URI. If the Request-URI refers to an already \ + existing resource, the enclosed entity SHOULD be considered as a modified \ + version of the one residing on the origin server. If the Request-URI does \ + not point to an existing resource, and that URI is capable of being defined \ + as a new resource by the requesting user agent, the origin server can \ + create the resource with that URI. If a new resource is created, the origin \ + server MUST inform the user agent via the 201 (Created) response. \ + If an existing resource is modified, either the 200 (OK) or 204 (No Content) \ + response codes SHOULD be sent to indicate successful completion of the request. \ + If the resource could not be created or modified with the Request-URI, an \ + appropriate error response SHOULD be given that reflects the nature of the problem. \ + The recipient of the entity MUST NOT ignore any Content-* (e.g. Content-Range) \ + headers that it does not understand or implement and MUST return \ + a 501 (Not Implemented) response in such cases. + +MSG_Completion_DELETE=The DELETE method requests that the origin server delete \ + the resource identified by the Request-URI. This method MAY be overridden \ + by human intervention (or other means) on the origin server. The client \ + cannot be guaranteed that the operation has been carried out, even if \ + the status code returned from the origin server indicates that the action \ + has been completed successfully. However, the server SHOULD NOT indicate \ + success unless, at the time the response is given, it intends to delete \ + the resource or move it to an inaccessible location. + diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/main/resources/org/netbeans/html/json/spi/package.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/main/resources/org/netbeans/html/json/spi/package.html Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,59 @@ + + + + + + + + +
Implement + Technology and + Transfer and use + ContextBuilder to create an instance + of Context representing your technology. +
+ + diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/net/java/html/json/MapModelTest.java --- a/json/src/test/java/net/java/html/json/MapModelTest.java Mon Dec 16 15:48:09 2013 +0100 +++ b/json/src/test/java/net/java/html/json/MapModelTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -49,7 +49,7 @@ import java.util.HashMap; import java.util.Map; import org.apidesign.html.context.spi.Contexts; -import org.apidesign.html.json.impl.WrapperObject; +import org.netbeans.html.json.impl.WrapperObject; import org.apidesign.html.json.spi.FunctionBinding; import org.apidesign.html.json.spi.JSONCall; import org.apidesign.html.json.spi.PropertyBinding; diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/net/java/html/json/TypesTest.java --- a/json/src/test/java/net/java/html/json/TypesTest.java Mon Dec 16 15:48:09 2013 +0100 +++ b/json/src/test/java/net/java/html/json/TypesTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -46,7 +46,7 @@ import java.util.Map; import net.java.html.json.MapModelTest.One; import org.apidesign.html.context.spi.Contexts; -import org.apidesign.html.json.impl.WrapperObject; +import org.netbeans.html.json.impl.WrapperObject; import org.apidesign.html.json.spi.Technology; import org.apidesign.html.json.spi.Transfer; import org.testng.annotations.BeforeMethod; diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/apidesign/html/json/impl/ConstructorTest.java --- a/json/src/test/java/org/apidesign/html/json/impl/ConstructorTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import net.java.html.json.Model; -import net.java.html.json.Property; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.Test; - -/** - * - * @author Jaroslav Tulach - */ -@Model(className="Man", properties={ - @Property(name = "name", type = String.class), - @Property(name = "other", type = Address.class, array = true), - @Property(name = "primary", type = Address.class), - @Property(name = "childrenNames", type = String.class, array = true) -}) -public class ConstructorTest { - @Model(className = "Address", properties = { - @Property(name = "place", type = String.class) - }) - static final class AddressModel { - } - - @Test public void initializedByDefault() { - Man m = new Man(); - assertNotNull(m.getPrimary(), "Single subobjects are initialized"); - } - - @Test public void hasRichConstructor() { - Man m = new Man("Jarda", new Address("home"), new Address("work"), new Address("hotel")); - assertEquals(m.getName(), "Jarda"); - assertNotNull(m.getPrimary(), "Primary address specified"); - assertNotNull(m.getPrimary().getPlace(), "home"); - assertEquals(m.getOther().size(), 2, "Two other addresses"); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/apidesign/html/json/impl/EmployeeImpl.java --- a/json/src/test/java/org/apidesign/html/json/impl/EmployeeImpl.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import net.java.html.json.Model; -import net.java.html.json.OnReceive; -import net.java.html.json.Person; -import net.java.html.json.Property; - -/** - * - * @author Jaroslav Tulach - */ -@Model(className = "Employee", properties = { - @Property(name = "person", type = Person.class), - @Property(name = "employer", type = Employer.class) -}) -public class EmployeeImpl { - @OnReceive(url = "some/url") - static void changePersonality(Employee e, Person p) { - e.setPerson(p); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/apidesign/html/json/impl/EmployerTest.java --- a/json/src/test/java/org/apidesign/html/json/impl/EmployerTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import net.java.html.BrwsrCtx; -import net.java.html.json.Model; -import net.java.html.json.Models; -import net.java.html.json.Property; -import org.testng.Assert; -import org.testng.annotations.Test; - -/** - * - * @author Jaroslav Tulach - */ -@Model(className = "Employer", properties = { - @Property(name = "name", type = String.class) -}) -public class EmployerTest { - @Test public void preLoadsTheClass() { - Employer em = Models.fromRaw(BrwsrCtx.EMPTY, Employer.class, this); - Assert.assertNotNull(em, "Class loaded"); - em.applyBindings(); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/apidesign/html/json/impl/JSONListTest.java --- a/json/src/test/java/org/apidesign/html/json/impl/JSONListTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import java.util.HashMap; -import java.util.Map; -import net.java.html.BrwsrCtx; -import net.java.html.json.Models; -import net.java.html.json.People; -import net.java.html.json.Person; -import net.java.html.json.Sex; -import org.apidesign.html.context.spi.Contexts; -import org.apidesign.html.json.spi.FunctionBinding; -import org.apidesign.html.json.spi.PropertyBinding; -import org.apidesign.html.json.spi.Technology; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * - * @author Jaroslav Tulach - */ -public class JSONListTest implements Technology { - private boolean replaceArray; - private final Map bindings = new HashMap(); - - public JSONListTest() { - } - - @BeforeMethod public void clear() { - replaceArray = false; - } - - @Test public void testConvertorOnAnObject() { - BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build(); - - Person p = Models.bind(new Person(), c); - p.setFirstName("1"); - p.setLastName("2"); - p.setSex(Sex.MALE); - - Object real = WrapperObject.find(p); - assertEquals(this, real, "I am the right model"); - } - - @Test public void testConvertorOnAnArray() { - BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build(); - - Person p = Models.bind(new Person(), c); - p.setFirstName("1"); - p.setLastName("2"); - p.setSex(Sex.MALE); - - People people = Models.bind(new People(p), c).applyBindings(); - assertEquals(people.getInfo().toString(), "[{\"firstName\":\"1\",\"lastName\":\"2\",\"sex\":\"MALE\"}]", "Converted to real JSON"); - - PropertyBinding pb = bindings.get("info"); - assertNotNull(pb, "Binding for info found"); - - Object real = pb.getValue(); - assertTrue(real instanceof Object[], "It is an array: " + real); - Object[] arr = (Object[])real; - assertEquals(arr.length, 1, "Size is one"); - assertEquals(this, arr[0], "I am the right model"); - } - - @Test public void testNicknames() { - BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build(); - - People people = Models.bind(new People(), c).applyBindings(); - people.getNicknames().add("One"); - people.getNicknames().add("Two"); - - PropertyBinding pb = bindings.get("nicknames"); - assertNotNull(pb, "Binding for info found"); - - Object real = pb.getValue(); - assertTrue(real instanceof Object[], "It is an array: " + real); - Object[] arr = (Object[])real; - assertEquals(arr.length, 2, "Length two"); - assertEquals(arr[0], "One", "Text should be in the model"); - assertEquals(arr[1], "Two", "2nd text in the model"); - } - - @Test public void testConvertorOnAnArrayWithWrapper() { - this.replaceArray = true; - BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build(); - - Person p = Models.bind(new Person(), c); - p.setFirstName("1"); - p.setLastName("2"); - p.setSex(Sex.MALE); - - People people = Models.bind(new People(), c).applyBindings(); - people.getInfo().add(p); - - Object real = WrapperObject.find(people.getInfo()); - assertEquals(real, this, "I am the model of the array"); - } - - @Test public void bindingsOnArray() { - this.replaceArray = true; - BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build(); - - People p = Models.bind(new People(), c).applyBindings(); - p.getAge().add(30); - - PropertyBinding pb = bindings.get("age"); - assertNotNull(pb, "There is a binding for age list"); - - assertEquals(pb.getValue(), this, "I am the model of the array"); - } - - @Override - public Object wrapModel(Object model) { - return this; - } - - @Override - public void bind(PropertyBinding b, Object model, Object data) { - bindings.put(b.getPropertyName(), b); - } - - @Override - public void valueHasMutated(Object data, String propertyName) { - } - - @Override - public void expose(FunctionBinding fb, Object model, Object d) { - } - - @Override - public void applyBindings(Object data) { - } - - @Override - public Object wrapArray(Object[] arr) { - return replaceArray ? this : arr; - } - - @Override - public M toModel(Class modelClass, Object data) { - return modelClass.cast(data); - } - - @Override - public void runSafe(Runnable r) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/apidesign/html/json/impl/JSONTest.java --- a/json/src/test/java/org/apidesign/html/json/impl/JSONTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import static org.testng.Assert.*; -import org.testng.annotations.Test; - -/** - * - * @author Jaroslav Tulach - */ -public class JSONTest { - - public JSONTest() { - } - - @Test public void longToStringValue() { - assertEquals(JSON.stringValue(Long.valueOf(1)), "1"); - } - - @Test public void booleanIsSortOfNumber() { - assertEquals(JSON.numberValue(Boolean.TRUE), Integer.valueOf(1)); - assertEquals(JSON.numberValue(Boolean.FALSE), Integer.valueOf(0)); - } - - @Test public void numberToChar() { - assertEquals(JSON.charValue(65), Character.valueOf('A')); - } - @Test public void booleanToChar() { - assertEquals(JSON.charValue(false), Character.valueOf((char)0)); - assertEquals(JSON.charValue(true), Character.valueOf((char)1)); - } - @Test public void stringToChar() { - assertEquals(JSON.charValue("Ahoj"), Character.valueOf('A')); - } - @Test public void stringToBoolean() { - assertEquals(JSON.boolValue("false"), Boolean.FALSE); - assertEquals(JSON.boolValue("True"), Boolean.TRUE); - } - @Test public void numberToBoolean() { - assertEquals(JSON.boolValue(0), Boolean.FALSE); - assertEquals(JSON.boolValue(1), Boolean.TRUE); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/apidesign/html/json/impl/NoPropertiesTest.java --- a/json/src/test/java/org/apidesign/html/json/impl/NoPropertiesTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.json.impl; - -import net.java.html.json.Model; - -/** Originally could not compile. - * - * @author Jaroslav Tulach - */ -@Model(className="NoProperties", properties = { -}) -public class NoPropertiesTest { - -} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/netbeans/html/json/impl/ConstructorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/test/java/org/netbeans/html/json/impl/ConstructorTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,80 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import net.java.html.json.Model; +import net.java.html.json.Property; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertEquals; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +@Model(className="Man", properties={ + @Property(name = "name", type = String.class), + @Property(name = "other", type = Address.class, array = true), + @Property(name = "primary", type = Address.class), + @Property(name = "childrenNames", type = String.class, array = true) +}) +public class ConstructorTest { + @Model(className = "Address", properties = { + @Property(name = "place", type = String.class) + }) + static final class AddressModel { + } + + @Test public void initializedByDefault() { + Man m = new Man(); + assertNotNull(m.getPrimary(), "Single subobjects are initialized"); + } + + @Test public void hasRichConstructor() { + Man m = new Man("Jarda", new Address("home"), new Address("work"), new Address("hotel")); + assertEquals(m.getName(), "Jarda"); + assertNotNull(m.getPrimary(), "Primary address specified"); + assertNotNull(m.getPrimary().getPlace(), "home"); + assertEquals(m.getOther().size(), 2, "Two other addresses"); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/netbeans/html/json/impl/EmployeeImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/test/java/org/netbeans/html/json/impl/EmployeeImpl.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,63 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import net.java.html.json.Model; +import net.java.html.json.OnReceive; +import net.java.html.json.Person; +import net.java.html.json.Property; + +/** + * + * @author Jaroslav Tulach + */ +@Model(className = "Employee", properties = { + @Property(name = "person", type = Person.class), + @Property(name = "employer", type = Employer.class) +}) +public class EmployeeImpl { + @OnReceive(url = "some/url") + static void changePersonality(Employee e, Person p) { + e.setPerson(p); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/netbeans/html/json/impl/EmployerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/test/java/org/netbeans/html/json/impl/EmployerTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,65 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import net.java.html.BrwsrCtx; +import net.java.html.json.Model; +import net.java.html.json.Models; +import net.java.html.json.Property; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +@Model(className = "Employer", properties = { + @Property(name = "name", type = String.class) +}) +public class EmployerTest { + @Test public void preLoadsTheClass() { + Employer em = Models.fromRaw(BrwsrCtx.EMPTY, Employer.class, this); + Assert.assertNotNull(em, "Class loaded"); + em.applyBindings(); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/netbeans/html/json/impl/JSONListTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/test/java/org/netbeans/html/json/impl/JSONListTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,192 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import java.util.HashMap; +import java.util.Map; +import net.java.html.BrwsrCtx; +import net.java.html.json.Models; +import net.java.html.json.People; +import net.java.html.json.Person; +import net.java.html.json.Sex; +import org.apidesign.html.context.spi.Contexts; +import org.apidesign.html.json.spi.FunctionBinding; +import org.apidesign.html.json.spi.PropertyBinding; +import org.apidesign.html.json.spi.Technology; +import static org.testng.Assert.*; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class JSONListTest implements Technology { + private boolean replaceArray; + private final Map bindings = new HashMap(); + + public JSONListTest() { + } + + @BeforeMethod public void clear() { + replaceArray = false; + } + + @Test public void testConvertorOnAnObject() { + BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build(); + + Person p = Models.bind(new Person(), c); + p.setFirstName("1"); + p.setLastName("2"); + p.setSex(Sex.MALE); + + Object real = WrapperObject.find(p); + assertEquals(this, real, "I am the right model"); + } + + @Test public void testConvertorOnAnArray() { + BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build(); + + Person p = Models.bind(new Person(), c); + p.setFirstName("1"); + p.setLastName("2"); + p.setSex(Sex.MALE); + + People people = Models.bind(new People(p), c).applyBindings(); + assertEquals(people.getInfo().toString(), "[{\"firstName\":\"1\",\"lastName\":\"2\",\"sex\":\"MALE\"}]", "Converted to real JSON"); + + PropertyBinding pb = bindings.get("info"); + assertNotNull(pb, "Binding for info found"); + + Object real = pb.getValue(); + assertTrue(real instanceof Object[], "It is an array: " + real); + Object[] arr = (Object[])real; + assertEquals(arr.length, 1, "Size is one"); + assertEquals(this, arr[0], "I am the right model"); + } + + @Test public void testNicknames() { + BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build(); + + People people = Models.bind(new People(), c).applyBindings(); + people.getNicknames().add("One"); + people.getNicknames().add("Two"); + + PropertyBinding pb = bindings.get("nicknames"); + assertNotNull(pb, "Binding for info found"); + + Object real = pb.getValue(); + assertTrue(real instanceof Object[], "It is an array: " + real); + Object[] arr = (Object[])real; + assertEquals(arr.length, 2, "Length two"); + assertEquals(arr[0], "One", "Text should be in the model"); + assertEquals(arr[1], "Two", "2nd text in the model"); + } + + @Test public void testConvertorOnAnArrayWithWrapper() { + this.replaceArray = true; + BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build(); + + Person p = Models.bind(new Person(), c); + p.setFirstName("1"); + p.setLastName("2"); + p.setSex(Sex.MALE); + + People people = Models.bind(new People(), c).applyBindings(); + people.getInfo().add(p); + + Object real = WrapperObject.find(people.getInfo()); + assertEquals(real, this, "I am the model of the array"); + } + + @Test public void bindingsOnArray() { + this.replaceArray = true; + BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build(); + + People p = Models.bind(new People(), c).applyBindings(); + p.getAge().add(30); + + PropertyBinding pb = bindings.get("age"); + assertNotNull(pb, "There is a binding for age list"); + + assertEquals(pb.getValue(), this, "I am the model of the array"); + } + + @Override + public Object wrapModel(Object model) { + return this; + } + + @Override + public void bind(PropertyBinding b, Object model, Object data) { + bindings.put(b.getPropertyName(), b); + } + + @Override + public void valueHasMutated(Object data, String propertyName) { + } + + @Override + public void expose(FunctionBinding fb, Object model, Object d) { + } + + @Override + public void applyBindings(Object data) { + } + + @Override + public Object wrapArray(Object[] arr) { + return replaceArray ? this : arr; + } + + @Override + public M toModel(Class modelClass, Object data) { + return modelClass.cast(data); + } + + @Override + public void runSafe(Runnable r) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/netbeans/html/json/impl/JSONTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/test/java/org/netbeans/html/json/impl/JSONTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,85 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import org.netbeans.html.json.impl.JSON; +import static org.testng.Assert.*; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class JSONTest { + + public JSONTest() { + } + + @Test public void longToStringValue() { + assertEquals(JSON.stringValue(Long.valueOf(1)), "1"); + } + + @Test public void booleanIsSortOfNumber() { + assertEquals(JSON.numberValue(Boolean.TRUE), Integer.valueOf(1)); + assertEquals(JSON.numberValue(Boolean.FALSE), Integer.valueOf(0)); + } + + @Test public void numberToChar() { + assertEquals(JSON.charValue(65), Character.valueOf('A')); + } + @Test public void booleanToChar() { + assertEquals(JSON.charValue(false), Character.valueOf((char)0)); + assertEquals(JSON.charValue(true), Character.valueOf((char)1)); + } + @Test public void stringToChar() { + assertEquals(JSON.charValue("Ahoj"), Character.valueOf('A')); + } + @Test public void stringToBoolean() { + assertEquals(JSON.boolValue("false"), Boolean.FALSE); + assertEquals(JSON.boolValue("True"), Boolean.TRUE); + } + @Test public void numberToBoolean() { + assertEquals(JSON.boolValue(0), Boolean.FALSE); + assertEquals(JSON.boolValue(1), Boolean.TRUE); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e json/src/test/java/org/netbeans/html/json/impl/NoPropertiesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/src/test/java/org/netbeans/html/json/impl/NoPropertiesTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,55 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.json.impl; + +import net.java.html.json.Model; + +/** Originally could not compile. + * + * @author Jaroslav Tulach + */ +@Model(className="NoProperties", properties = { +}) +public class NoPropertiesTest { + +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-archetype-test/src/test/java/org/apidesign/html/archetype/test/ArchetypeVersionTest.java --- a/ko-archetype-test/src/test/java/org/apidesign/html/archetype/test/ArchetypeVersionTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.archetype.test; - -import java.io.IOException; -import java.net.URL; -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; -import javax.xml.xpath.XPathFactoryConfigurationException; -import org.testng.annotations.Test; -import static org.testng.Assert.*; -import org.testng.annotations.BeforeClass; -import org.w3c.dom.Document; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -/** - * - * @author Jaroslav Tulach - */ -public class ArchetypeVersionTest { - private String version; - - public ArchetypeVersionTest() { - } - - @BeforeClass public void readCurrentVersion() throws Exception { - version = findCurrentVersion(); - assertFalse(version.isEmpty(), "There should be some version string"); - } - - - @Test public void testComparePomDepsVersions() throws Exception { - final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); - URL r = l.getResource("archetype-resources/pom.xml"); - assertNotNull(r, "Archetype pom found"); - - final XPathFactory fact = XPathFactory.newInstance(); - XPathExpression xp2 = fact.newXPath().compile( - "//properties/net.java.html.version/text()" - ); - - Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream()); - String arch = (String) xp2.evaluate(dom, XPathConstants.STRING); - - assertEquals(arch, version, "net.java.html.json dependency needs to be on latest version"); - } - - @Test public void testNbActions() throws Exception { - final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); - URL r = l.getResource("archetype-resources/nbactions.xml"); - assertNotNull(r, "Archetype nb file found"); - - final XPathFactory fact = XPathFactory.newInstance(); - XPathExpression xp2 = fact.newXPath().compile( - "//goal/text()" - ); - - Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream()); - NodeList goals = (NodeList) xp2.evaluate(dom, XPathConstants.NODESET); - - for (int i = 0; i < goals.getLength(); i++) { - String s = goals.item(i).getTextContent(); - if (s.contains("apidesign")) { - assertFalse(s.matches(".*apidesign.*[0-9].*"), "No numbers: " + s); - } - } - } - - static String findCurrentVersion() throws XPathExpressionException, IOException, ParserConfigurationException, SAXException, XPathFactoryConfigurationException { - final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); - URL u = l.getResource("META-INF/maven/org.netbeans.html/knockout4j-archetype/pom.xml"); - assertNotNull(u, "Own pom found: " + System.getProperty("java.class.path")); - - final XPathFactory fact = XPathFactory.newInstance(); - fact.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - - XPathExpression xp = fact.newXPath().compile("project/version/text()"); - - Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(u.openStream()); - return xp.evaluate(dom); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-archetype-test/src/test/java/org/apidesign/html/archetype/test/VerifyArchetypeTest.java --- a/ko-archetype-test/src/test/java/org/apidesign/html/archetype/test/VerifyArchetypeTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.archetype.test; - -import java.io.File; -import java.util.Properties; -import org.apache.maven.it.Verifier; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/** - * - * @author Jaroslav Tulach - */ -public class VerifyArchetypeTest { - @Test public void projectCompiles() throws Exception { - final File dir = new File("target/tests/fxcompile/").getAbsoluteFile(); - generateFromArchetype(dir); - - File created = new File(dir, "o-a-test"); - assertTrue(created.isDirectory(), "Project created"); - assertTrue(new File(created, "pom.xml").isFile(), "Pom file is in there"); - - Verifier v = new Verifier(created.getAbsolutePath()); - v.executeGoal("verify"); - - v.verifyErrorFreeLog(); - - for (String l : v.loadFile(v.getBasedir(), v.getLogFileName(), false)) { - if (l.contains("j2js")) { - fail("No pre-compilaton:\n" + l); - } - } - - v.verifyTextInLog("fxcompile/o-a-test/target/o-a-test-1.0-SNAPSHOT-html.java.net.zip"); - } - - private Verifier generateFromArchetype(final File dir, String... params) throws Exception { - Verifier v = new Verifier(dir.getAbsolutePath()); - v.setAutoclean(false); - v.setLogFileName("generate.log"); - v.deleteDirectory(""); - dir.mkdirs(); - Properties sysProp = v.getSystemProperties(); - sysProp.put("groupId", "org.apidesign.test"); - sysProp.put("artifactId", "o-a-test"); - sysProp.put("package", "org.apidesign.test.oat"); - sysProp.put("archetypeGroupId", "org.apidesign.html"); - sysProp.put("archetypeArtifactId", "knockout4j-archetype"); - sysProp.put("archetypeVersion", ArchetypeVersionTest.findCurrentVersion()); - - for (String p : params) { - v.addCliOption(p); - } - v.executeGoal("archetype:generate"); - v.verifyErrorFreeLog(); - return v; - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-archetype-test/src/test/java/org/netbeans/html/archetype/test/ArchetypeVersionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-archetype-test/src/test/java/org/netbeans/html/archetype/test/ArchetypeVersionTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,128 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.archetype.test; + +import java.io.IOException; +import java.net.URL; +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import javax.xml.xpath.XPathFactoryConfigurationException; +import org.testng.annotations.Test; +import static org.testng.Assert.*; +import org.testng.annotations.BeforeClass; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +/** + * + * @author Jaroslav Tulach + */ +public class ArchetypeVersionTest { + private String version; + + public ArchetypeVersionTest() { + } + + @BeforeClass public void readCurrentVersion() throws Exception { + version = findCurrentVersion(); + assertFalse(version.isEmpty(), "There should be some version string"); + } + + + @Test public void testComparePomDepsVersions() throws Exception { + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); + URL r = l.getResource("archetype-resources/pom.xml"); + assertNotNull(r, "Archetype pom found"); + + final XPathFactory fact = XPathFactory.newInstance(); + XPathExpression xp2 = fact.newXPath().compile( + "//properties/net.java.html.version/text()" + ); + + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream()); + String arch = (String) xp2.evaluate(dom, XPathConstants.STRING); + + assertEquals(arch, version, "net.java.html.json dependency needs to be on latest version"); + } + + @Test public void testNbActions() throws Exception { + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); + URL r = l.getResource("archetype-resources/nbactions.xml"); + assertNotNull(r, "Archetype nb file found"); + + final XPathFactory fact = XPathFactory.newInstance(); + XPathExpression xp2 = fact.newXPath().compile( + "//goal/text()" + ); + + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream()); + NodeList goals = (NodeList) xp2.evaluate(dom, XPathConstants.NODESET); + + for (int i = 0; i < goals.getLength(); i++) { + String s = goals.item(i).getTextContent(); + if (s.contains("apidesign")) { + assertFalse(s.matches(".*apidesign.*[0-9].*"), "No numbers: " + s); + } + } + } + + static String findCurrentVersion() throws XPathExpressionException, IOException, ParserConfigurationException, SAXException, XPathFactoryConfigurationException { + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader(); + URL u = l.getResource("META-INF/maven/org.netbeans.html/knockout4j-archetype/pom.xml"); + assertNotNull(u, "Own pom found: " + System.getProperty("java.class.path")); + + final XPathFactory fact = XPathFactory.newInstance(); + fact.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + + XPathExpression xp = fact.newXPath().compile("project/version/text()"); + + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(u.openStream()); + return xp.evaluate(dom); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-archetype-test/src/test/java/org/netbeans/html/archetype/test/VerifyArchetypeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-archetype-test/src/test/java/org/netbeans/html/archetype/test/VerifyArchetypeTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,99 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.archetype.test; + +import java.io.File; +import java.util.Properties; +import org.apache.maven.it.Verifier; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * + * @author Jaroslav Tulach + */ +public class VerifyArchetypeTest { + @Test public void projectCompiles() throws Exception { + final File dir = new File("target/tests/fxcompile/").getAbsoluteFile(); + generateFromArchetype(dir); + + File created = new File(dir, "o-a-test"); + assertTrue(created.isDirectory(), "Project created"); + assertTrue(new File(created, "pom.xml").isFile(), "Pom file is in there"); + + Verifier v = new Verifier(created.getAbsolutePath()); + v.executeGoal("verify"); + + v.verifyErrorFreeLog(); + + for (String l : v.loadFile(v.getBasedir(), v.getLogFileName(), false)) { + if (l.contains("j2js")) { + fail("No pre-compilaton:\n" + l); + } + } + + v.verifyTextInLog("fxcompile/o-a-test/target/o-a-test-1.0-SNAPSHOT-html.java.net.zip"); + } + + private Verifier generateFromArchetype(final File dir, String... params) throws Exception { + Verifier v = new Verifier(dir.getAbsolutePath()); + v.setAutoclean(false); + v.setLogFileName("generate.log"); + v.deleteDirectory(""); + dir.mkdirs(); + Properties sysProp = v.getSystemProperties(); + sysProp.put("groupId", "org.apidesign.test"); + sysProp.put("artifactId", "o-a-test"); + sysProp.put("package", "org.apidesign.test.oat"); + sysProp.put("archetypeGroupId", "org.apidesign.html"); + sysProp.put("archetypeArtifactId", "knockout4j-archetype"); + sysProp.put("archetypeVersion", ArchetypeVersionTest.findCurrentVersion()); + + for (String p : params) { + v.addCliOption(p); + } + v.executeGoal("archetype:generate"); + v.verifyErrorFreeLog(); + return v; + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-archetype/src/main/java/org/apidesign/html/archetype/package-info.java --- a/ko-archetype/src/main/java/org/apidesign/html/archetype/package-info.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.archetype; diff -r 700087d2a5d3 -r 92fb71afdc0e ko-archetype/src/main/java/org/netbeans/html/archetype/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-archetype/src/main/java/org/netbeans/html/archetype/package-info.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,43 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.archetype; diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/java/org/apidesign/html/kofx/Console.java --- a/ko-fx/src/main/java/org/apidesign/html/kofx/Console.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.kofx; - -import java.util.logging.Level; -import java.util.logging.Logger; -import net.java.html.js.JavaScriptBody; - -/** This is an implementation package - just - * include its JAR on classpath and use official {@link Context} API - * to access the functionality. - *

- * Redirects JavaScript's messages to Java's {@link Logger}. - * - * @author Jaroslav Tulach - */ -final class Console { - private static final Logger LOG = Logger.getLogger(Console.class.getName()); - - private Console() { - } - - static void register() { - registerImpl("log", Level.INFO); - registerImpl("info", Level.INFO); - registerImpl("warn", Level.WARNING); - registerImpl("error", Level.SEVERE); - } - - @JavaScriptBody(args = { "attr", "l" }, - javacall = true, body = - " window.console[attr] = function(m) {\n" - + " @org.apidesign.html.kofx.Console::log(Ljava/util/logging/Level;Ljava/lang/String;)(l, m);\n" - + " };\n" - ) - private static native void registerImpl(String attr, Level l); - - static void log(Level l, String msg) { - LOG.log(l, msg); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/java/org/apidesign/html/kofx/FXContext.java --- a/ko-fx/src/main/java/org/apidesign/html/kofx/FXContext.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.kofx; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.util.ServiceLoader; -import java.util.logging.Logger; -import javafx.application.Platform; -import net.java.html.js.JavaScriptBody; -import netscape.javascript.JSObject; -import org.apidesign.html.boot.spi.Fn; -import org.apidesign.html.context.spi.Contexts; -import org.apidesign.html.json.spi.FunctionBinding; -import org.apidesign.html.json.spi.JSONCall; -import org.apidesign.html.json.spi.PropertyBinding; -import org.apidesign.html.json.spi.Technology; -import org.apidesign.html.json.spi.Transfer; -import org.apidesign.html.json.spi.WSTransfer; -import org.openide.util.lookup.ServiceProvider; - -/** This is an implementation package - just - * include its JAR on classpath and use official {@link Context} API - * to access the functionality. - *

- * Registers {@link ContextProvider}, so {@link ServiceLoader} can find it. - * - * @author Jaroslav Tulach - */ -public final class FXContext -implements Technology.BatchInit, Transfer, WSTransfer { - static final Logger LOG = Logger.getLogger(FXContext.class.getName()); - private static Boolean javaScriptEnabled; - private final Fn.Presenter browserContext; - - public FXContext(Fn.Presenter browserContext) { - this.browserContext = browserContext; - } - - @JavaScriptBody(args = {}, body = "return true;") - private static boolean isJavaScriptEnabledJs() { - return false; - } - - static boolean isJavaScriptEnabled() { - if (javaScriptEnabled != null) { - return javaScriptEnabled; - } - return javaScriptEnabled = isJavaScriptEnabledJs(); - } - - final boolean areWebSocketsSupported() { - return LoadWS.isSupported(); - } - - - @Override - public JSObject wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) { - String[] propNames = new String[propArr.length]; - boolean[] propReadOnly = new boolean[propArr.length]; - Object[] propValues = new Object[propArr.length]; - for (int i = 0; i < propNames.length; i++) { - propNames[i] = propArr[i].getPropertyName(); - propReadOnly[i] = propArr[i].isReadOnly(); - propValues[i] = propArr[i].getValue(); - } - String[] funcNames = new String[funcArr.length]; - for (int i = 0; i < funcNames.length; i++) { - funcNames[i] = funcArr[i].getFunctionName(); - } - - return Knockout.wrapModel(model, - propNames, propReadOnly, Knockout.toArray(propValues), propArr, - funcNames, funcArr - ); - } - - @Override - public JSObject wrapModel(Object model) { - throw new UnsupportedOperationException(); - } - - @Override - public void bind(PropertyBinding b, Object model, JSObject data) { - throw new UnsupportedOperationException(); - } - - @Override - public void valueHasMutated(JSObject data, String propertyName) { - Knockout.valueHasMutated(data, propertyName); - } - - @Override - public void expose(FunctionBinding fb, Object model, JSObject d) { - throw new UnsupportedOperationException(); - } - - @Override - public void applyBindings(JSObject data) { - Knockout.applyBindings(data); - } - - @Override - public Object wrapArray(Object[] arr) { - return Knockout.toArray(arr); - } - - @Override - public void extract(Object obj, String[] props, Object[] values) { - LoadJSON.extractJSON(obj, props, values); - } - - @Override - public void loadJSON(final JSONCall call) { - LoadJSON.loadJSON(call); - } - - @Override - public M toModel(Class modelClass, Object data) { - if (data instanceof JSObject) { - data = ((JSObject)data).getMember("ko-fx.model"); // NOI18N - } - return modelClass.cast(data); - } - - @Override - public Object toJSON(InputStream is) throws IOException { - return LoadJSON.parse(is); - } - - @Override - public void runSafe(final Runnable r) { - class Wrap implements Runnable { - @Override public void run() { - try (Closeable c = Fn.activate(browserContext)) { - r.run(); - } catch (IOException ex) { - // cannot be thrown - } - } - } - Wrap w = new Wrap(); - - if (Platform.isFxApplicationThread()) { - w.run(); - } else { - Platform.runLater(w); - } - } - - @Override - public LoadWS open(String url, JSONCall onReply) { - return new LoadWS(onReply, url); - } - - @Override - public void send(LoadWS socket, JSONCall data) { - socket.send(data); - } - - @Override - public void close(LoadWS socket) { - socket.close(); - } - - @ServiceProvider(service = Contexts.Provider.class) - public static final class Prvdr implements Contexts.Provider { - @Override - public void fillContext(Contexts.Builder context, Class requestor) { - if (isJavaScriptEnabled()) { - FXContext c = new FXContext(Fn.activePresenter()); - - context.register(Technology.class, c, 100); - context.register(Transfer.class, c, 100); - if (c.areWebSocketsSupported()) { - context.register(WSTransfer.class, c, 100); - } - } - } - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/java/org/apidesign/html/kofx/Knockout.java --- a/ko-fx/src/main/java/org/apidesign/html/kofx/Knockout.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.kofx; - -import net.java.html.js.JavaScriptBody; -import net.java.html.js.JavaScriptResource; -import net.java.html.json.Model; -import netscape.javascript.JSObject; -import org.apidesign.html.json.spi.FunctionBinding; -import org.apidesign.html.json.spi.PropertyBinding; - -/** This is an implementation package - just - * include its JAR on classpath and use official {@link Context} API - * to access the functionality. - *

- * Provides binding between {@link Model models} and knockout.js running - * inside a JavaFX WebView. - * - * @author Jaroslav Tulach - */ -@JavaScriptResource("knockout-2.2.1.js") -final class Knockout { - static final JSObject KObject; - static { - Console.register(); - KObject = (JSObject) kObj(); - } - - static Object toArray(Object[] arr) { - return KObject.call("array", arr); - } - - @JavaScriptBody(args = { "model", "prop" }, body = - "if (model) {\n" - + " var koProp = model[prop];\n" - + " if (koProp && koProp['valueHasMutated']) {\n" - + " koProp['valueHasMutated']();\n" - + " }\n" - + "}\n" - ) - public native static void valueHasMutated(JSObject model, String prop); - - @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);") - native static void applyBindings(Object bindings); - - @JavaScriptBody(args = {}, body = - " var k = {};" - + " k.array= function() {" - + " return Array.prototype.slice.call(arguments);" - + " };" - + " return k;" - ) - private static native Object kObj(); - - - @JavaScriptBody( - javacall = true, - args = {"model", "propNames", "propReadOnly", "propValues", "propArr", "funcNames", "funcArr"}, - body - = "var ret = {};\n" - + "ret['ko-fx.model'] = model;\n" - + "function koComputed(name, readOnly, value, prop) {\n" - + " function realGetter() {\n" - + " try {" - + " var v = prop.@org.apidesign.html.json.spi.PropertyBinding::getValue()();" - + " return v;" - + " } catch (e) {" - + " alert(\"Cannot call getValue on \" + model + \" prop: \" + name + \" error: \" + e);" - + " }" - + " }\n" - + " var activeGetter = function() { return value; };\n" - + " var bnd = {" - + " read: function() {" - + " var r = activeGetter();" - + " activeGetter = realGetter;" - + " return r;" - + " }," - + " owner: ret\n" - + " };\n" - + " if (!readOnly) {\n" - + " bnd.write = function(val) {\n" - + " prop.@org.apidesign.html.json.spi.PropertyBinding::setValue(Ljava/lang/Object;)(val);\n" - + " };" - + " };" - + " ret[name] = ko.computed(bnd);" - + "}\n" - + "for (var i = 0; i < propNames.length; i++) {\n" - + " koComputed(propNames[i], propReadOnly[i], propValues[i], propArr[i]);\n" - + "}\n" - + "function koExpose(name, func) {\n" - + " ret[name] = function(data, ev) {\n" - + " func.@org.apidesign.html.json.spi.FunctionBinding::call(Ljava/lang/Object;Ljava/lang/Object;)(data, ev);\n" - + " };\n" - + "}\n" - + "for (var i = 0; i < funcNames.length; i++) {\n" - + " koExpose(funcNames[i], funcArr[i]);\n" - + "}\n" - + "return ret;\n" - ) - static native JSObject wrapModel( - Object model, - String[] propNames, boolean[] propReadOnly, Object propValues, PropertyBinding[] propArr, - String[] funcNames, FunctionBinding[] funcArr - ); -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/java/org/apidesign/html/kofx/LoadJSON.java --- a/ko-fx/src/main/java/org/apidesign/html/kofx/LoadJSON.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.kofx; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PushbackInputStream; -import java.io.Reader; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.util.Iterator; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.logging.Level; -import java.util.logging.Logger; -import javafx.application.Platform; -import net.java.html.js.JavaScriptBody; -import netscape.javascript.JSObject; -import org.apidesign.html.json.spi.JSONCall; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONTokener; - -/** This is an implementation package - just - * include its JAR on classpath and use official {@link Context} API - * to access the functionality. - * - * @author Jaroslav Tulach - */ -final class LoadJSON implements Runnable { - private static final Logger LOG = FXContext.LOG; - private static final Executor REQ = Executors.newCachedThreadPool(new ThreadFactory() { - @Override - public Thread newThread(Runnable runnable) { - Thread thread = Executors.defaultThreadFactory().newThread(runnable); - thread.setDaemon(true); - return thread; - } - }); - - private final JSONCall call; - private final URL base; - private Throwable error; - private Object json; - - - private LoadJSON(JSONCall call) { - this.call = call; - URL b; - try { - b = new URL(findBaseURL()); - } catch (MalformedURLException ex) { - LOG.log(Level.SEVERE, "Can't find base url for " + call.composeURL("dummy"), ex); - b = null; - } - this.base = b; - } - - public static void loadJSON(JSONCall call) { - assert !"WebSocket".equals(call.getMethod()); - REQ.execute(new LoadJSON((call))); - } - - @Override - public void run() { - if (Platform.isFxApplicationThread()) { - if (error != null) { - call.notifyError(error); - } else { - call.notifySuccess(json); - } - return; - } - final String url; - if (call.isJSONP()) { - url = call.composeURL("dummy"); - } else { - url = call.composeURL(null); - } - try { - final URL u = new URL(base, url.replace(" ", "%20")); - URLConnection conn = u.openConnection(); - if (conn instanceof HttpURLConnection) { - HttpURLConnection huc = (HttpURLConnection) conn; - if (call.getMethod() != null) { - huc.setRequestMethod(call.getMethod()); - } - if (call.isDoOutput()) { - huc.setDoOutput(true); - final OutputStream os = huc.getOutputStream(); - call.writeData(os); - os.flush(); - } - } - final PushbackInputStream is = new PushbackInputStream( - conn.getInputStream(), 1 - ); - boolean array = false; - boolean string = false; - if (call.isJSONP()) { - for (;;) { - int ch = is.read(); - if (ch == -1) { - break; - } - if (ch == '[') { - is.unread(ch); - array = true; - break; - } - if (ch == '{') { - is.unread(ch); - break; - } - } - } else { - int ch = is.read(); - if (ch == -1) { - string = true; - } else { - array = ch == '['; - is.unread(ch); - if (!array && ch != '{') { - string = true; - } - } - } - try { - if (string) { - throw new JSONException(""); - } - Reader r = new InputStreamReader(is, "UTF-8"); - - JSONTokener tok = new JSONTokener(r); - Object obj; - obj = array ? new JSONArray(tok) : new JSONObject(tok); - json = convertToArray(obj); - } catch (JSONException ex) { - Reader r = new InputStreamReader(is, "UTF-8"); - StringBuilder sb = new StringBuilder(); - for (;;) { - int ch = r.read(); - if (ch == -1) { - break; - } - sb.append((char)ch); - } - json = sb.toString(); - } - } catch (IOException ex) { - error = ex; - } finally { - Platform.runLater(this); - } - } - - static Object convertToArray(Object o) throws JSONException { - if (o instanceof JSONArray) { - JSONArray ja = (JSONArray)o; - Object[] arr = new Object[ja.length()]; - for (int i = 0; i < arr.length; i++) { - arr[i] = convertToArray(ja.get(i)); - } - return arr; - } else if (o instanceof JSONObject) { - JSONObject obj = (JSONObject)o; - Iterator it = obj.keys(); - while (it.hasNext()) { - String key = (String)it.next(); - obj.put(key, convertToArray(obj.get(key))); - } - return obj; - } else { - return o; - } - } - - public static void extractJSON(Object jsonObject, String[] props, Object[] values) { - if (jsonObject instanceof JSONObject) { - JSONObject obj = (JSONObject)jsonObject; - for (int i = 0; i < props.length; i++) { - try { - values[i] = obj.has(props[i]) ? obj.get(props[i]) : null; - } catch (JSONException ex) { - LoadJSON.LOG.log(Level.SEVERE, "Can't read " + props[i] + " from " + jsonObject, ex); - } - } - } - if (jsonObject instanceof JSObject) { - JSObject obj = (JSObject)jsonObject; - for (int i = 0; i < props.length; i++) { - Object val = obj.getMember(props[i]); - values[i] = isDefined(val) ? val : null; - } - } - } - - public static Object parse(InputStream is) throws IOException { - try { - InputStreamReader r = new InputStreamReader(is, "UTF-8"); - JSONTokener t = new JSONTokener(r); - return new JSONObject(t); - } catch (JSONException ex) { - throw new IOException(ex); - } - } - - @JavaScriptBody(args = { }, body = - "var h;" - + "if (!!window && !!window.location && !!window.location.href)\n" - + " h = window.location.href;\n" - + "else " - + " h = null;" - + "return h;\n" - ) - private static native String findBaseURL(); - - private static boolean isDefined(Object val) { - return !"undefined".equals(val); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/java/org/apidesign/html/kofx/LoadWS.java --- a/ko-fx/src/main/java/org/apidesign/html/kofx/LoadWS.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.kofx; - -import net.java.html.js.JavaScriptBody; -import org.apidesign.html.json.spi.JSONCall; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONTokener; - -/** Communication with WebSockets for WebView 1.8. - * - * @author Jaroslav Tulach - */ -final class LoadWS { - private static final boolean SUPPORTED = isWebSocket(); - private final Object ws; - private final JSONCall call; - - LoadWS(JSONCall first, String url) { - call = first; - ws = initWebSocket(this, url); - if (ws == null) { - first.notifyError(new IllegalArgumentException("Wrong URL: " + url)); - } - } - - static boolean isSupported() { - return SUPPORTED; - } - - void send(JSONCall call) { - push(call); - } - - private synchronized void push(JSONCall call) { - send(ws, call.getMessage()); - } - - void onOpen(Object ev) { - if (!call.isDoOutput()) { - call.notifySuccess(null); - } - } - - void onMessage(Object ev, String data) { - Object json; - try { - data = data.trim(); - - JSONTokener tok = new JSONTokener(data); - Object obj; - obj = data.startsWith("[") ? new JSONArray(tok) : new JSONObject(tok); - json = LoadJSON.convertToArray(obj); - } catch (JSONException ex) { - json = data; - } - call.notifySuccess(json); - } - - void onError(Object ev) { - call.notifyError(new Exception(ev.toString())); - } - - void onClose(boolean wasClean, int code, String reason) { - call.notifyError(null); - } - - @JavaScriptBody(args = {}, body = "if (window.WebSocket) return true; else return false;") - private static boolean isWebSocket() { - return false; - } - - @JavaScriptBody(args = { "back", "url" }, javacall = true, body = "" - + "if (window.WebSocket) {" - + " try {" - + " var ws = new window.WebSocket(url);" - + " ws.onopen = function(ev) { back.@org.apidesign.html.kofx.LoadWS::onOpen(Ljava/lang/Object;)(ev); };" - + " ws.onmessage = function(ev) { back.@org.apidesign.html.kofx.LoadWS::onMessage(Ljava/lang/Object;Ljava/lang/String;)(ev, ev.data); };" - + " ws.onerror = function(ev) { back.@org.apidesign.html.kofx.LoadWS::onError(Ljava/lang/Object;)(ev); };" - + " ws.onclose = function(ev) { back.@org.apidesign.html.kofx.LoadWS::onClose(ZILjava/lang/String;)(ev.wasClean, ev.code, ev.reason); };" - + " return ws;" - + " } catch (ex) {" - + " return null;" - + " }" - + "} else {" - + " return null;" - + "}" - ) - private static Object initWebSocket(Object back, String url) { - return null; - } - - - @JavaScriptBody(args = { "ws", "msg" }, body = "" - + "ws.send(msg);" - ) - private void send(Object ws, String msg) { - } - - @JavaScriptBody(args = { "ws" }, body = "ws.close();") - private static void close(Object ws) { - } - - void close() { - close(ws); - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/java/org/netbeans/html/kofx/Console.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-fx/src/main/java/org/netbeans/html/kofx/Console.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,81 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.kofx; + +import java.util.logging.Level; +import java.util.logging.Logger; +import net.java.html.js.JavaScriptBody; + +/** This is an implementation package - just + * include its JAR on classpath and use official {@link Context} API + * to access the functionality. + *

+ * Redirects JavaScript's messages to Java's {@link Logger}. + * + * @author Jaroslav Tulach + */ +final class Console { + private static final Logger LOG = Logger.getLogger(Console.class.getName()); + + private Console() { + } + + static void register() { + registerImpl("log", Level.INFO); + registerImpl("info", Level.INFO); + registerImpl("warn", Level.WARNING); + registerImpl("error", Level.SEVERE); + } + + @JavaScriptBody(args = { "attr", "l" }, + javacall = true, body = + " window.console[attr] = function(m) {\n" + + " @org.netbeans.html.kofx.Console::log(Ljava/util/logging/Level;Ljava/lang/String;)(l, m);\n" + + " };\n" + ) + private static native void registerImpl(String attr, Level l); + + static void log(Level l, String msg) { + LOG.log(l, msg); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/java/org/netbeans/html/kofx/FXContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-fx/src/main/java/org/netbeans/html/kofx/FXContext.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,222 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.kofx; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.util.ServiceLoader; +import java.util.logging.Logger; +import javafx.application.Platform; +import net.java.html.js.JavaScriptBody; +import netscape.javascript.JSObject; +import org.apidesign.html.boot.spi.Fn; +import org.apidesign.html.context.spi.Contexts; +import org.apidesign.html.json.spi.FunctionBinding; +import org.apidesign.html.json.spi.JSONCall; +import org.apidesign.html.json.spi.PropertyBinding; +import org.apidesign.html.json.spi.Technology; +import org.apidesign.html.json.spi.Transfer; +import org.apidesign.html.json.spi.WSTransfer; +import org.openide.util.lookup.ServiceProvider; + +/** This is an implementation package - just + * include its JAR on classpath and use official {@link Context} API + * to access the functionality. + *

+ * Registers {@link ContextProvider}, so {@link ServiceLoader} can find it. + * + * @author Jaroslav Tulach + */ +public final class FXContext +implements Technology.BatchInit, Transfer, WSTransfer { + static final Logger LOG = Logger.getLogger(FXContext.class.getName()); + private static Boolean javaScriptEnabled; + private final Fn.Presenter browserContext; + + public FXContext(Fn.Presenter browserContext) { + this.browserContext = browserContext; + } + + @JavaScriptBody(args = {}, body = "return true;") + private static boolean isJavaScriptEnabledJs() { + return false; + } + + static boolean isJavaScriptEnabled() { + if (javaScriptEnabled != null) { + return javaScriptEnabled; + } + return javaScriptEnabled = isJavaScriptEnabledJs(); + } + + final boolean areWebSocketsSupported() { + return LoadWS.isSupported(); + } + + + @Override + public JSObject wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) { + String[] propNames = new String[propArr.length]; + boolean[] propReadOnly = new boolean[propArr.length]; + Object[] propValues = new Object[propArr.length]; + for (int i = 0; i < propNames.length; i++) { + propNames[i] = propArr[i].getPropertyName(); + propReadOnly[i] = propArr[i].isReadOnly(); + propValues[i] = propArr[i].getValue(); + } + String[] funcNames = new String[funcArr.length]; + for (int i = 0; i < funcNames.length; i++) { + funcNames[i] = funcArr[i].getFunctionName(); + } + + return Knockout.wrapModel(model, + propNames, propReadOnly, Knockout.toArray(propValues), propArr, + funcNames, funcArr + ); + } + + @Override + public JSObject wrapModel(Object model) { + throw new UnsupportedOperationException(); + } + + @Override + public void bind(PropertyBinding b, Object model, JSObject data) { + throw new UnsupportedOperationException(); + } + + @Override + public void valueHasMutated(JSObject data, String propertyName) { + Knockout.valueHasMutated(data, propertyName); + } + + @Override + public void expose(FunctionBinding fb, Object model, JSObject d) { + throw new UnsupportedOperationException(); + } + + @Override + public void applyBindings(JSObject data) { + Knockout.applyBindings(data); + } + + @Override + public Object wrapArray(Object[] arr) { + return Knockout.toArray(arr); + } + + @Override + public void extract(Object obj, String[] props, Object[] values) { + LoadJSON.extractJSON(obj, props, values); + } + + @Override + public void loadJSON(final JSONCall call) { + LoadJSON.loadJSON(call); + } + + @Override + public M toModel(Class modelClass, Object data) { + if (data instanceof JSObject) { + data = ((JSObject)data).getMember("ko-fx.model"); // NOI18N + } + return modelClass.cast(data); + } + + @Override + public Object toJSON(InputStream is) throws IOException { + return LoadJSON.parse(is); + } + + @Override + public void runSafe(final Runnable r) { + class Wrap implements Runnable { + @Override public void run() { + try (Closeable c = Fn.activate(browserContext)) { + r.run(); + } catch (IOException ex) { + // cannot be thrown + } + } + } + Wrap w = new Wrap(); + + if (Platform.isFxApplicationThread()) { + w.run(); + } else { + Platform.runLater(w); + } + } + + @Override + public LoadWS open(String url, JSONCall onReply) { + return new LoadWS(onReply, url); + } + + @Override + public void send(LoadWS socket, JSONCall data) { + socket.send(data); + } + + @Override + public void close(LoadWS socket) { + socket.close(); + } + + @ServiceProvider(service = Contexts.Provider.class) + public static final class Prvdr implements Contexts.Provider { + @Override + public void fillContext(Contexts.Builder context, Class requestor) { + if (isJavaScriptEnabled()) { + FXContext c = new FXContext(Fn.activePresenter()); + + context.register(Technology.class, c, 100); + context.register(Transfer.class, c, 100); + if (c.areWebSocketsSupported()) { + context.register(WSTransfer.class, c, 100); + } + } + } + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/java/org/netbeans/html/kofx/Knockout.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-fx/src/main/java/org/netbeans/html/kofx/Knockout.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,145 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.kofx; + +import net.java.html.js.JavaScriptBody; +import net.java.html.js.JavaScriptResource; +import net.java.html.json.Model; +import netscape.javascript.JSObject; +import org.apidesign.html.json.spi.FunctionBinding; +import org.apidesign.html.json.spi.PropertyBinding; + +/** This is an implementation package - just + * include its JAR on classpath and use official {@link Context} API + * to access the functionality. + *

+ * Provides binding between {@link Model models} and knockout.js running + * inside a JavaFX WebView. + * + * @author Jaroslav Tulach + */ +@JavaScriptResource("knockout-2.2.1.js") +final class Knockout { + static final JSObject KObject; + static { + Console.register(); + KObject = (JSObject) kObj(); + } + + static Object toArray(Object[] arr) { + return KObject.call("array", arr); + } + + @JavaScriptBody(args = { "model", "prop" }, body = + "if (model) {\n" + + " var koProp = model[prop];\n" + + " if (koProp && koProp['valueHasMutated']) {\n" + + " koProp['valueHasMutated']();\n" + + " }\n" + + "}\n" + ) + public native static void valueHasMutated(JSObject model, String prop); + + @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);") + native static void applyBindings(Object bindings); + + @JavaScriptBody(args = {}, body = + " var k = {};" + + " k.array= function() {" + + " return Array.prototype.slice.call(arguments);" + + " };" + + " return k;" + ) + private static native Object kObj(); + + + @JavaScriptBody( + javacall = true, + args = {"model", "propNames", "propReadOnly", "propValues", "propArr", "funcNames", "funcArr"}, + body + = "var ret = {};\n" + + "ret['ko-fx.model'] = model;\n" + + "function koComputed(name, readOnly, value, prop) {\n" + + " function realGetter() {\n" + + " try {" + + " var v = prop.@org.apidesign.html.json.spi.PropertyBinding::getValue()();" + + " return v;" + + " } catch (e) {" + + " alert(\"Cannot call getValue on \" + model + \" prop: \" + name + \" error: \" + e);" + + " }" + + " }\n" + + " var activeGetter = function() { return value; };\n" + + " var bnd = {" + + " read: function() {" + + " var r = activeGetter();" + + " activeGetter = realGetter;" + + " return r;" + + " }," + + " owner: ret\n" + + " };\n" + + " if (!readOnly) {\n" + + " bnd.write = function(val) {\n" + + " prop.@org.apidesign.html.json.spi.PropertyBinding::setValue(Ljava/lang/Object;)(val);\n" + + " };" + + " };" + + " ret[name] = ko.computed(bnd);" + + "}\n" + + "for (var i = 0; i < propNames.length; i++) {\n" + + " koComputed(propNames[i], propReadOnly[i], propValues[i], propArr[i]);\n" + + "}\n" + + "function koExpose(name, func) {\n" + + " ret[name] = function(data, ev) {\n" + + " func.@org.apidesign.html.json.spi.FunctionBinding::call(Ljava/lang/Object;Ljava/lang/Object;)(data, ev);\n" + + " };\n" + + "}\n" + + "for (var i = 0; i < funcNames.length; i++) {\n" + + " koExpose(funcNames[i], funcArr[i]);\n" + + "}\n" + + "return ret;\n" + ) + static native JSObject wrapModel( + Object model, + String[] propNames, boolean[] propReadOnly, Object propValues, PropertyBinding[] propArr, + String[] funcNames, FunctionBinding[] funcArr + ); +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/java/org/netbeans/html/kofx/LoadJSON.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-fx/src/main/java/org/netbeans/html/kofx/LoadJSON.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,267 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.kofx; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PushbackInputStream; +import java.io.Reader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Iterator; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.logging.Level; +import java.util.logging.Logger; +import javafx.application.Platform; +import net.java.html.js.JavaScriptBody; +import netscape.javascript.JSObject; +import org.apidesign.html.json.spi.JSONCall; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; + +/** This is an implementation package - just + * include its JAR on classpath and use official {@link Context} API + * to access the functionality. + * + * @author Jaroslav Tulach + */ +final class LoadJSON implements Runnable { + private static final Logger LOG = FXContext.LOG; + private static final Executor REQ = Executors.newCachedThreadPool(new ThreadFactory() { + @Override + public Thread newThread(Runnable runnable) { + Thread thread = Executors.defaultThreadFactory().newThread(runnable); + thread.setDaemon(true); + return thread; + } + }); + + private final JSONCall call; + private final URL base; + private Throwable error; + private Object json; + + + private LoadJSON(JSONCall call) { + this.call = call; + URL b; + try { + b = new URL(findBaseURL()); + } catch (MalformedURLException ex) { + LOG.log(Level.SEVERE, "Can't find base url for " + call.composeURL("dummy"), ex); + b = null; + } + this.base = b; + } + + public static void loadJSON(JSONCall call) { + assert !"WebSocket".equals(call.getMethod()); + REQ.execute(new LoadJSON((call))); + } + + @Override + public void run() { + if (Platform.isFxApplicationThread()) { + if (error != null) { + call.notifyError(error); + } else { + call.notifySuccess(json); + } + return; + } + final String url; + if (call.isJSONP()) { + url = call.composeURL("dummy"); + } else { + url = call.composeURL(null); + } + try { + final URL u = new URL(base, url.replace(" ", "%20")); + URLConnection conn = u.openConnection(); + if (conn instanceof HttpURLConnection) { + HttpURLConnection huc = (HttpURLConnection) conn; + if (call.getMethod() != null) { + huc.setRequestMethod(call.getMethod()); + } + if (call.isDoOutput()) { + huc.setDoOutput(true); + final OutputStream os = huc.getOutputStream(); + call.writeData(os); + os.flush(); + } + } + final PushbackInputStream is = new PushbackInputStream( + conn.getInputStream(), 1 + ); + boolean array = false; + boolean string = false; + if (call.isJSONP()) { + for (;;) { + int ch = is.read(); + if (ch == -1) { + break; + } + if (ch == '[') { + is.unread(ch); + array = true; + break; + } + if (ch == '{') { + is.unread(ch); + break; + } + } + } else { + int ch = is.read(); + if (ch == -1) { + string = true; + } else { + array = ch == '['; + is.unread(ch); + if (!array && ch != '{') { + string = true; + } + } + } + try { + if (string) { + throw new JSONException(""); + } + Reader r = new InputStreamReader(is, "UTF-8"); + + JSONTokener tok = new JSONTokener(r); + Object obj; + obj = array ? new JSONArray(tok) : new JSONObject(tok); + json = convertToArray(obj); + } catch (JSONException ex) { + Reader r = new InputStreamReader(is, "UTF-8"); + StringBuilder sb = new StringBuilder(); + for (;;) { + int ch = r.read(); + if (ch == -1) { + break; + } + sb.append((char)ch); + } + json = sb.toString(); + } + } catch (IOException ex) { + error = ex; + } finally { + Platform.runLater(this); + } + } + + static Object convertToArray(Object o) throws JSONException { + if (o instanceof JSONArray) { + JSONArray ja = (JSONArray)o; + Object[] arr = new Object[ja.length()]; + for (int i = 0; i < arr.length; i++) { + arr[i] = convertToArray(ja.get(i)); + } + return arr; + } else if (o instanceof JSONObject) { + JSONObject obj = (JSONObject)o; + Iterator it = obj.keys(); + while (it.hasNext()) { + String key = (String)it.next(); + obj.put(key, convertToArray(obj.get(key))); + } + return obj; + } else { + return o; + } + } + + public static void extractJSON(Object jsonObject, String[] props, Object[] values) { + if (jsonObject instanceof JSONObject) { + JSONObject obj = (JSONObject)jsonObject; + for (int i = 0; i < props.length; i++) { + try { + values[i] = obj.has(props[i]) ? obj.get(props[i]) : null; + } catch (JSONException ex) { + LoadJSON.LOG.log(Level.SEVERE, "Can't read " + props[i] + " from " + jsonObject, ex); + } + } + } + if (jsonObject instanceof JSObject) { + JSObject obj = (JSObject)jsonObject; + for (int i = 0; i < props.length; i++) { + Object val = obj.getMember(props[i]); + values[i] = isDefined(val) ? val : null; + } + } + } + + public static Object parse(InputStream is) throws IOException { + try { + InputStreamReader r = new InputStreamReader(is, "UTF-8"); + JSONTokener t = new JSONTokener(r); + return new JSONObject(t); + } catch (JSONException ex) { + throw new IOException(ex); + } + } + + @JavaScriptBody(args = { }, body = + "var h;" + + "if (!!window && !!window.location && !!window.location.href)\n" + + " h = window.location.href;\n" + + "else " + + " h = null;" + + "return h;\n" + ) + private static native String findBaseURL(); + + private static boolean isDefined(Object val) { + return !"undefined".equals(val); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/java/org/netbeans/html/kofx/LoadWS.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-fx/src/main/java/org/netbeans/html/kofx/LoadWS.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,149 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.kofx; + +import net.java.html.js.JavaScriptBody; +import org.apidesign.html.json.spi.JSONCall; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; + +/** Communication with WebSockets for WebView 1.8. + * + * @author Jaroslav Tulach + */ +final class LoadWS { + private static final boolean SUPPORTED = isWebSocket(); + private final Object ws; + private final JSONCall call; + + LoadWS(JSONCall first, String url) { + call = first; + ws = initWebSocket(this, url); + if (ws == null) { + first.notifyError(new IllegalArgumentException("Wrong URL: " + url)); + } + } + + static boolean isSupported() { + return SUPPORTED; + } + + void send(JSONCall call) { + push(call); + } + + private synchronized void push(JSONCall call) { + send(ws, call.getMessage()); + } + + void onOpen(Object ev) { + if (!call.isDoOutput()) { + call.notifySuccess(null); + } + } + + void onMessage(Object ev, String data) { + Object json; + try { + data = data.trim(); + + JSONTokener tok = new JSONTokener(data); + Object obj; + obj = data.startsWith("[") ? new JSONArray(tok) : new JSONObject(tok); + json = LoadJSON.convertToArray(obj); + } catch (JSONException ex) { + json = data; + } + call.notifySuccess(json); + } + + void onError(Object ev) { + call.notifyError(new Exception(ev.toString())); + } + + void onClose(boolean wasClean, int code, String reason) { + call.notifyError(null); + } + + @JavaScriptBody(args = {}, body = "if (window.WebSocket) return true; else return false;") + private static boolean isWebSocket() { + return false; + } + + @JavaScriptBody(args = { "back", "url" }, javacall = true, body = "" + + "if (window.WebSocket) {" + + " try {" + + " var ws = new window.WebSocket(url);" + + " ws.onopen = function(ev) { back.@org.netbeans.html.kofx.LoadWS::onOpen(Ljava/lang/Object;)(ev); };" + + " ws.onmessage = function(ev) { back.@org.netbeans.html.kofx.LoadWS::onMessage(Ljava/lang/Object;Ljava/lang/String;)(ev, ev.data); };" + + " ws.onerror = function(ev) { back.@org.netbeans.html.kofx.LoadWS::onError(Ljava/lang/Object;)(ev); };" + + " ws.onclose = function(ev) { back.@org.netbeans.html.kofx.LoadWS::onClose(ZILjava/lang/String;)(ev.wasClean, ev.code, ev.reason); };" + + " return ws;" + + " } catch (ex) {" + + " return null;" + + " }" + + "} else {" + + " return null;" + + "}" + ) + private static Object initWebSocket(Object back, String url) { + return null; + } + + + @JavaScriptBody(args = { "ws", "msg" }, body = "" + + "ws.send(msg);" + ) + private void send(Object ws, String msg) { + } + + @JavaScriptBody(args = { "ws" }, body = "ws.close();") + private static void close(Object ws) { + } + + void close() { + close(ws); + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/resources/org/apidesign/html/kofx/knockout-2.2.1.js --- a/ko-fx/src/main/resources/org/apidesign/html/kofx/knockout-2.2.1.js Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3594 +0,0 @@ -// Knockout JavaScript library v2.2.1 -// (c) Steven Sanderson - http://knockoutjs.com/ -// License: MIT (http://www.opensource.org/licenses/mit-license.php) - -(function(){ -var DEBUG=true; -(function(window,document,navigator,jQuery,undefined){ -!function(factory) { - // Support three module loading scenarios - if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { - // [1] CommonJS/Node.js - var target = module['exports'] || exports; // module.exports is for Node.js - factory(target); - } else if (typeof define === 'function' && define['amd']) { - // [2] AMD anonymous module - define(['exports'], factory); - } else { - // [3] No module loader (plain "); - }; - - if (jQueryTmplVersion > 0) { - jQuery['tmpl']['tag']['ko_code'] = { - open: "__.push($1 || '');" - }; - jQuery['tmpl']['tag']['ko_with'] = { - open: "with($1) {", - close: "} " - }; - } - }; - - ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine(); - - // Use this one by default *only if jquery.tmpl is referenced* - var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine(); - if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0) - ko.setTemplateEngine(jqueryTmplTemplateEngineInstance); - - ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine); -})(); -}); -})(window,document,navigator,window["jQuery"]); -})(); \ No newline at end of file diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/main/resources/org/netbeans/html/kofx/knockout-2.2.1.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-fx/src/main/resources/org/netbeans/html/kofx/knockout-2.2.1.js Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,3594 @@ +// Knockout JavaScript library v2.2.1 +// (c) Steven Sanderson - http://knockoutjs.com/ +// License: MIT (http://www.opensource.org/licenses/mit-license.php) + +(function(){ +var DEBUG=true; +(function(window,document,navigator,jQuery,undefined){ +!function(factory) { + // Support three module loading scenarios + if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { + // [1] CommonJS/Node.js + var target = module['exports'] || exports; // module.exports is for Node.js + factory(target); + } else if (typeof define === 'function' && define['amd']) { + // [2] AMD anonymous module + define(['exports'], factory); + } else { + // [3] No module loader (plain "); + }; + + if (jQueryTmplVersion > 0) { + jQuery['tmpl']['tag']['ko_code'] = { + open: "__.push($1 || '');" + }; + jQuery['tmpl']['tag']['ko_with'] = { + open: "with($1) {", + close: "} " + }; + } + }; + + ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine(); + + // Use this one by default *only if jquery.tmpl is referenced* + var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine(); + if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0) + ko.setTemplateEngine(jqueryTmplTemplateEngineInstance); + + ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine); +})(); +}); +})(window,document,navigator,window["jQuery"]); +})(); \ No newline at end of file diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/test/java/org/apidesign/html/kofx/DynamicHTTP.java --- a/ko-fx/src/test/java/org/apidesign/html/kofx/DynamicHTTP.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,259 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.kofx; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.glassfish.grizzly.PortRange; -import org.glassfish.grizzly.http.server.HttpHandler; -import org.glassfish.grizzly.http.server.HttpServer; -import org.glassfish.grizzly.http.server.NetworkListener; -import org.glassfish.grizzly.http.server.Request; -import org.glassfish.grizzly.http.server.Response; -import org.glassfish.grizzly.http.server.ServerConfiguration; -import org.glassfish.grizzly.websockets.WebSocket; -import org.glassfish.grizzly.websockets.WebSocketAddOn; -import org.glassfish.grizzly.websockets.WebSocketApplication; -import org.glassfish.grizzly.websockets.WebSocketEngine; - -/** - * - * @author Jaroslav Tulach - */ -final class DynamicHTTP extends HttpHandler { - private static final Logger LOG = Logger.getLogger(DynamicHTTP.class.getName()); - private static int resourcesCount; - private static List resources; - private static ServerConfiguration conf; - private static HttpServer server; - - private DynamicHTTP() { - } - - static URI initServer() throws Exception { - server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535)); - final WebSocketAddOn addon = new WebSocketAddOn(); - for (NetworkListener listener : server.getListeners()) { - listener.registerAddOn(addon); - } - resources = new ArrayList(); - - conf = server.getServerConfiguration(); - final DynamicHTTP dh = new DynamicHTTP(); - - conf.addHttpHandler(dh, "/"); - - server.start(); - - return pageURL("http", server, "/test.html"); - } - - @Override - public void service(Request request, Response response) throws Exception { - if ("/test.html".equals(request.getRequestURI())) { - response.setContentType("text/html"); - final InputStream is = DynamicHTTP.class.getResourceAsStream("test.html"); - copyStream(is, response.getOutputStream(), null); - return; - } - if ("/dynamic".equals(request.getRequestURI())) { - String mimeType = request.getParameter("mimeType"); - List params = new ArrayList(); - boolean webSocket = false; - for (int i = 0;; i++) { - String p = request.getParameter("param" + i); - if (p == null) { - break; - } - if ("protocol:ws".equals(p)) { - webSocket = true; - continue; - } - params.add(p); - } - final String cnt = request.getParameter("content"); - String mangle = cnt.replace("%20", " ").replace("%0A", "\n"); - ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8")); - URI url; - final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()])); - if (webSocket) { - url = registerWebSocket(res); - } else { - url = registerResource(res); - } - response.getWriter().write(url.toString()); - response.getWriter().write("\n"); - return; - } - - for (Resource r : resources) { - if (r.httpPath.equals(request.getRequestURI())) { - response.setContentType(r.httpType); - r.httpContent.reset(); - String[] params = null; - if (r.parameters.length != 0) { - params = new String[r.parameters.length]; - for (int i = 0; i < r.parameters.length; i++) { - params[i] = request.getParameter(r.parameters[i]); - if (params[i] == null) { - if ("http.method".equals(r.parameters[i])) { - params[i] = request.getMethod().toString(); - } else if ("http.requestBody".equals(r.parameters[i])) { - Reader rdr = request.getReader(); - StringBuilder sb = new StringBuilder(); - for (;;) { - int ch = rdr.read(); - if (ch == -1) { - break; - } - sb.append((char) ch); - } - params[i] = sb.toString(); - } - } - if (params[i] == null) { - params[i] = "null"; - } - } - } - - copyStream(r.httpContent, response.getOutputStream(), null, params); - } - } - } - - private URI registerWebSocket(Resource r) { - WebSocketEngine.getEngine().register("", r.httpPath, new WS(r)); - return pageURL("ws", server, r.httpPath); - } - - private URI registerResource(Resource r) { - if (!resources.contains(r)) { - resources.add(r); - conf.addHttpHandler(this, r.httpPath); - } - return pageURL("http", server, r.httpPath); - } - - private static URI pageURL(String proto, HttpServer server, final String page) { - NetworkListener listener = server.getListeners().iterator().next(); - int port = listener.getPort(); - try { - return new URI(proto + "://localhost:" + port + page); - } catch (URISyntaxException ex) { - throw new IllegalStateException(ex); - } - } - - static final class Resource { - - final InputStream httpContent; - final String httpType; - final String httpPath; - final String[] parameters; - - Resource(InputStream httpContent, String httpType, String httpPath, - String[] parameters) { - httpContent.mark(Integer.MAX_VALUE); - this.httpContent = httpContent; - this.httpType = httpType; - this.httpPath = httpPath; - this.parameters = parameters; - } - } - - static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException { - for (;;) { - int ch = is.read(); - if (ch == -1) { - break; - } - if (ch == '$' && params.length > 0) { - int cnt = is.read() - '0'; - if (baseURL != null && cnt == 'U' - '0') { - os.write(baseURL.getBytes("UTF-8")); - } else { - if (cnt >= 0 && cnt < params.length) { - os.write(params[cnt].getBytes("UTF-8")); - } else { - os.write('$'); - os.write(cnt + '0'); - } - } - } else { - os.write(ch); - } - } - } - - private static class WS extends WebSocketApplication { - private final Resource r; - - private WS(Resource r) { - this.r = r; - } - - @Override - public void onMessage(WebSocket socket, String text) { - try { - r.httpContent.reset(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - copyStream(r.httpContent, out, null, text); - String s = new String(out.toByteArray(), "UTF-8"); - socket.send(s); - } catch (IOException ex) { - LOG.log(Level.WARNING, "Error processing message " + text, ex); - } - } - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/test/java/org/apidesign/html/kofx/KOFx.java --- a/ko-fx/src/test/java/org/apidesign/html/kofx/KOFx.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.kofx; - -import java.io.Closeable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import javafx.application.Platform; -import org.apidesign.html.boot.spi.Fn; -import org.testng.ITest; -import org.testng.annotations.Test; - -/** - * - * @author Jaroslav Tulach - */ -public final class KOFx implements ITest, Runnable { - private final Fn.Presenter p; - private final Method m; - private Object result; - private Object inst; - private int count; - - KOFx(Fn.Presenter p, Method m) { - this.p = p; - this.m = m; - } - - @Override - public String getTestName() { - return m.getName(); - } - - @Test - public synchronized void executeTest() throws Exception { - if (result == null) { - Platform.runLater(this); - wait(); - } - if (result instanceof Exception) { - throw (Exception)result; - } - if (result instanceof Error) { - throw (Error)result; - } - } - - @Override - public synchronized void run() { - boolean notify = true; - try (Closeable a = Fn.activate(p)) { - if (inst == null) { - inst = m.getDeclaringClass().newInstance(); - } - result = m.invoke(inst); - if (result == null) { - result = this; - } - } catch (InvocationTargetException ex) { - Throwable r = ex.getTargetException(); - if (r instanceof InterruptedException) { - if (count++ < 10000) { - notify = false; - Platform.runLater(this); - return; - } - } - result = r; - } catch (Exception ex) { - result = ex; - } finally { - if (notify) { - notifyAll(); - } - } - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/test/java/org/apidesign/html/kofx/KnockoutFXTest.java --- a/ko-fx/src/test/java/org/apidesign/html/kofx/KnockoutFXTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,229 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.kofx; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; -import net.java.html.BrwsrCtx; -import net.java.html.boot.BrowserBuilder; -import net.java.html.js.JavaScriptBody; -import org.apidesign.html.boot.impl.FnContext; -import org.apidesign.html.boot.spi.Fn; -import org.apidesign.html.context.spi.Contexts; -import org.apidesign.html.json.spi.Technology; -import org.apidesign.html.json.spi.Transfer; -import org.apidesign.html.json.spi.WSTransfer; -import org.apidesign.html.json.tck.KOTest; -import org.apidesign.html.json.tck.KnockoutTCK; -import org.json.JSONException; -import org.json.JSONObject; -import org.openide.util.lookup.ServiceProvider; -import org.testng.annotations.Factory; -import static org.testng.Assert.*; - -/** - * - * @author Jaroslav Tulach - */ -@ServiceProvider(service = KnockoutTCK.class) -public final class KnockoutFXTest extends KnockoutTCK { - private static Class browserClass; - private static Fn.Presenter browserContext; - - public KnockoutFXTest() { - } - - @Factory public static Object[] compatibilityTests() throws Exception { - Class[] arr = testClasses(); - for (int i = 0; i < arr.length; i++) { - assertEquals( - arr[i].getClassLoader(), - KnockoutFXTest.class.getClassLoader(), - "All classes loaded by the same classloader" - ); - } - - URI uri = DynamicHTTP.initServer(); - - final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(KnockoutFXTest.class). - loadPage(uri.toString()). - invoke("initialized"); - - Executors.newSingleThreadExecutor().submit(new Runnable() { - @Override - public void run() { - bb.showAndWait(); - } - }); - - ClassLoader l = getClassLoader(); - List res = new ArrayList(); - for (int i = 0; i < arr.length; i++) { - Class c = Class.forName(arr[i].getName(), true, l); - seekKOTests(c, res); - } - Class c = Class.forName(LessCallbacksCheck.class.getName(), true, l); - seekKOTests(c, res); - return res.toArray(); - } - - private static void seekKOTests(Class c, List res) throws SecurityException, ClassNotFoundException { - Class koTest = - c.getClassLoader().loadClass(KOTest.class.getName()). - asSubclass(Annotation.class); - for (Method m : c.getMethods()) { - if (m.getAnnotation(koTest) != null) { - res.add(new KOFx(browserContext, m)); - } - } - } - - static synchronized ClassLoader getClassLoader() throws InterruptedException { - while (browserClass == null) { - KnockoutFXTest.class.wait(); - } - return browserClass.getClassLoader(); - } - - public static synchronized void initialized(Class browserCls) throws Exception { - browserClass = browserCls; - browserContext = FnContext.currentPresenter(); - KnockoutFXTest.class.notifyAll(); - } - - public static void initialized() throws Exception { - Class classpathClass = ClassLoader.getSystemClassLoader().loadClass(KnockoutFXTest.class.getName()); - Method m = classpathClass.getMethod("initialized", Class.class); - m.invoke(null, KnockoutFXTest.class); - browserContext = FnContext.currentPresenter(); - } - - @Override - public BrwsrCtx createContext() { - FXContext fx = new FXContext(browserContext); - Contexts.Builder cb = Contexts.newBuilder(). - register(Technology.class, fx, 10). - register(Transfer.class, fx, 10); - if (fx.areWebSocketsSupported()) { - cb.register(WSTransfer.class, fx, 10); - } - return cb.build(); - } - - @Override - public Object createJSON(Map values) { - JSONObject json = new JSONObject(); - for (Map.Entry entry : values.entrySet()) { - try { - json.put(entry.getKey(), entry.getValue()); - } catch (JSONException ex) { - throw new IllegalStateException(ex); - } - } - return json; - } - - @Override - @JavaScriptBody(args = { "s", "args" }, body = "" - + "var f = new Function(s); " - + "return f.apply(null, args);" - ) - public native Object executeScript(String script, Object[] arguments); - - @JavaScriptBody(args = { }, body = - "var h;" - + "if (!!window && !!window.location && !!window.location.href)\n" - + " h = window.location.href;\n" - + "else " - + " h = null;" - + "return h;\n" - ) - private static native String findBaseURL(); - - @Override - public URI prepareURL(String content, String mimeType, String[] parameters) { - try { - final URL baseURL = new URL(findBaseURL()); - StringBuilder sb = new StringBuilder(); - sb.append("/dynamic?mimeType=").append(mimeType); - for (int i = 0; i < parameters.length; i++) { - sb.append("¶m" + i).append("=").append(parameters[i]); - } - String mangle = content.replace("\n", "%0a") - .replace("\"", "\\\"").replace(" ", "%20"); - sb.append("&content=").append(mangle); - - URL query = new URL(baseURL, sb.toString()); - URLConnection c = query.openConnection(); - BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); - URI connectTo = new URI(br.readLine()); - return connectTo; - } catch (IOException ex) { - throw new IllegalStateException(ex); - } catch (URISyntaxException ex) { - throw new IllegalStateException(ex); - } - } - - @Override - public boolean canFailWebSocketTest() { - try { - Class.forName("java.util.function.Function"); - return false; - } catch (ClassNotFoundException ex) { - // running on JDK7, FX WebView WebSocket impl does not work - return true; - } - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/test/java/org/apidesign/html/kofx/LessCallbacksCheck.java --- a/ko-fx/src/test/java/org/apidesign/html/kofx/LessCallbacksCheck.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.kofx; - -import java.io.PrintWriter; -import java.io.StringWriter; -import net.java.html.json.ComputedProperty; -import net.java.html.json.Model; -import net.java.html.json.Property; -import org.apidesign.html.json.tck.KOTest; - -/** - * - * @author Jaroslav Tulach - */ -@Model(className = "LessCalls", properties = { - @Property(name = "value", type = int.class) -}) -public class LessCallbacksCheck { - private static StringWriter sw; - - @ComputedProperty static int plusOne(int value) { - if (sw == null) { - sw = new StringWriter(); - } - new Exception("Who calls me?").printStackTrace( - new PrintWriter(sw) - ); - return value + 1; - } - - @KOTest public void dontCallForInitialValueBackToJavaVM() { - LessCalls m = new LessCalls(10).applyBindings(); - assert m.getPlusOne() == 11 : "Expecting 11: " + m.getPlusOne(); - - assert sw != null : "StringWriter should be initialized: " + sw; - - if (sw.toString().contains("$JsCallbacks$")) { - assert false : "Don't call for initial value via JsCallbacks:\n" + sw; - } - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/test/java/org/netbeans/html/kofx/DynamicHTTP.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-fx/src/test/java/org/netbeans/html/kofx/DynamicHTTP.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,259 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.kofx; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.glassfish.grizzly.PortRange; +import org.glassfish.grizzly.http.server.HttpHandler; +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.grizzly.http.server.NetworkListener; +import org.glassfish.grizzly.http.server.Request; +import org.glassfish.grizzly.http.server.Response; +import org.glassfish.grizzly.http.server.ServerConfiguration; +import org.glassfish.grizzly.websockets.WebSocket; +import org.glassfish.grizzly.websockets.WebSocketAddOn; +import org.glassfish.grizzly.websockets.WebSocketApplication; +import org.glassfish.grizzly.websockets.WebSocketEngine; + +/** + * + * @author Jaroslav Tulach + */ +final class DynamicHTTP extends HttpHandler { + private static final Logger LOG = Logger.getLogger(DynamicHTTP.class.getName()); + private static int resourcesCount; + private static List resources; + private static ServerConfiguration conf; + private static HttpServer server; + + private DynamicHTTP() { + } + + static URI initServer() throws Exception { + server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535)); + final WebSocketAddOn addon = new WebSocketAddOn(); + for (NetworkListener listener : server.getListeners()) { + listener.registerAddOn(addon); + } + resources = new ArrayList(); + + conf = server.getServerConfiguration(); + final DynamicHTTP dh = new DynamicHTTP(); + + conf.addHttpHandler(dh, "/"); + + server.start(); + + return pageURL("http", server, "/test.html"); + } + + @Override + public void service(Request request, Response response) throws Exception { + if ("/test.html".equals(request.getRequestURI())) { + response.setContentType("text/html"); + final InputStream is = DynamicHTTP.class.getResourceAsStream("test.html"); + copyStream(is, response.getOutputStream(), null); + return; + } + if ("/dynamic".equals(request.getRequestURI())) { + String mimeType = request.getParameter("mimeType"); + List params = new ArrayList(); + boolean webSocket = false; + for (int i = 0;; i++) { + String p = request.getParameter("param" + i); + if (p == null) { + break; + } + if ("protocol:ws".equals(p)) { + webSocket = true; + continue; + } + params.add(p); + } + final String cnt = request.getParameter("content"); + String mangle = cnt.replace("%20", " ").replace("%0A", "\n"); + ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8")); + URI url; + final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()])); + if (webSocket) { + url = registerWebSocket(res); + } else { + url = registerResource(res); + } + response.getWriter().write(url.toString()); + response.getWriter().write("\n"); + return; + } + + for (Resource r : resources) { + if (r.httpPath.equals(request.getRequestURI())) { + response.setContentType(r.httpType); + r.httpContent.reset(); + String[] params = null; + if (r.parameters.length != 0) { + params = new String[r.parameters.length]; + for (int i = 0; i < r.parameters.length; i++) { + params[i] = request.getParameter(r.parameters[i]); + if (params[i] == null) { + if ("http.method".equals(r.parameters[i])) { + params[i] = request.getMethod().toString(); + } else if ("http.requestBody".equals(r.parameters[i])) { + Reader rdr = request.getReader(); + StringBuilder sb = new StringBuilder(); + for (;;) { + int ch = rdr.read(); + if (ch == -1) { + break; + } + sb.append((char) ch); + } + params[i] = sb.toString(); + } + } + if (params[i] == null) { + params[i] = "null"; + } + } + } + + copyStream(r.httpContent, response.getOutputStream(), null, params); + } + } + } + + private URI registerWebSocket(Resource r) { + WebSocketEngine.getEngine().register("", r.httpPath, new WS(r)); + return pageURL("ws", server, r.httpPath); + } + + private URI registerResource(Resource r) { + if (!resources.contains(r)) { + resources.add(r); + conf.addHttpHandler(this, r.httpPath); + } + return pageURL("http", server, r.httpPath); + } + + private static URI pageURL(String proto, HttpServer server, final String page) { + NetworkListener listener = server.getListeners().iterator().next(); + int port = listener.getPort(); + try { + return new URI(proto + "://localhost:" + port + page); + } catch (URISyntaxException ex) { + throw new IllegalStateException(ex); + } + } + + static final class Resource { + + final InputStream httpContent; + final String httpType; + final String httpPath; + final String[] parameters; + + Resource(InputStream httpContent, String httpType, String httpPath, + String[] parameters) { + httpContent.mark(Integer.MAX_VALUE); + this.httpContent = httpContent; + this.httpType = httpType; + this.httpPath = httpPath; + this.parameters = parameters; + } + } + + static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException { + for (;;) { + int ch = is.read(); + if (ch == -1) { + break; + } + if (ch == '$' && params.length > 0) { + int cnt = is.read() - '0'; + if (baseURL != null && cnt == 'U' - '0') { + os.write(baseURL.getBytes("UTF-8")); + } else { + if (cnt >= 0 && cnt < params.length) { + os.write(params[cnt].getBytes("UTF-8")); + } else { + os.write('$'); + os.write(cnt + '0'); + } + } + } else { + os.write(ch); + } + } + } + + private static class WS extends WebSocketApplication { + private final Resource r; + + private WS(Resource r) { + this.r = r; + } + + @Override + public void onMessage(WebSocket socket, String text) { + try { + r.httpContent.reset(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + copyStream(r.httpContent, out, null, text); + String s = new String(out.toByteArray(), "UTF-8"); + socket.send(s); + } catch (IOException ex) { + LOG.log(Level.WARNING, "Error processing message " + text, ex); + } + } + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/test/java/org/netbeans/html/kofx/KOFx.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-fx/src/test/java/org/netbeans/html/kofx/KOFx.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,118 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.kofx; + +import java.io.Closeable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import javafx.application.Platform; +import org.apidesign.html.boot.spi.Fn; +import org.testng.ITest; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public final class KOFx implements ITest, Runnable { + private final Fn.Presenter p; + private final Method m; + private Object result; + private Object inst; + private int count; + + KOFx(Fn.Presenter p, Method m) { + this.p = p; + this.m = m; + } + + @Override + public String getTestName() { + return m.getName(); + } + + @Test + public synchronized void executeTest() throws Exception { + if (result == null) { + Platform.runLater(this); + wait(); + } + if (result instanceof Exception) { + throw (Exception)result; + } + if (result instanceof Error) { + throw (Error)result; + } + } + + @Override + public synchronized void run() { + boolean notify = true; + try (Closeable a = Fn.activate(p)) { + if (inst == null) { + inst = m.getDeclaringClass().newInstance(); + } + result = m.invoke(inst); + if (result == null) { + result = this; + } + } catch (InvocationTargetException ex) { + Throwable r = ex.getTargetException(); + if (r instanceof InterruptedException) { + if (count++ < 10000) { + notify = false; + Platform.runLater(this); + return; + } + } + result = r; + } catch (Exception ex) { + result = ex; + } finally { + if (notify) { + notifyAll(); + } + } + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/test/java/org/netbeans/html/kofx/KnockoutFXTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-fx/src/test/java/org/netbeans/html/kofx/KnockoutFXTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,229 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.kofx; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; +import net.java.html.BrwsrCtx; +import net.java.html.boot.BrowserBuilder; +import net.java.html.js.JavaScriptBody; +import org.netbeans.html.boot.impl.FnContext; +import org.apidesign.html.boot.spi.Fn; +import org.apidesign.html.context.spi.Contexts; +import org.apidesign.html.json.spi.Technology; +import org.apidesign.html.json.spi.Transfer; +import org.apidesign.html.json.spi.WSTransfer; +import org.apidesign.html.json.tck.KOTest; +import org.apidesign.html.json.tck.KnockoutTCK; +import org.json.JSONException; +import org.json.JSONObject; +import org.openide.util.lookup.ServiceProvider; +import org.testng.annotations.Factory; +import static org.testng.Assert.*; + +/** + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service = KnockoutTCK.class) +public final class KnockoutFXTest extends KnockoutTCK { + private static Class browserClass; + private static Fn.Presenter browserContext; + + public KnockoutFXTest() { + } + + @Factory public static Object[] compatibilityTests() throws Exception { + Class[] arr = testClasses(); + for (int i = 0; i < arr.length; i++) { + assertEquals( + arr[i].getClassLoader(), + KnockoutFXTest.class.getClassLoader(), + "All classes loaded by the same classloader" + ); + } + + URI uri = DynamicHTTP.initServer(); + + final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(KnockoutFXTest.class). + loadPage(uri.toString()). + invoke("initialized"); + + Executors.newSingleThreadExecutor().submit(new Runnable() { + @Override + public void run() { + bb.showAndWait(); + } + }); + + ClassLoader l = getClassLoader(); + List res = new ArrayList(); + for (int i = 0; i < arr.length; i++) { + Class c = Class.forName(arr[i].getName(), true, l); + seekKOTests(c, res); + } + Class c = Class.forName(LessCallbacksCheck.class.getName(), true, l); + seekKOTests(c, res); + return res.toArray(); + } + + private static void seekKOTests(Class c, List res) throws SecurityException, ClassNotFoundException { + Class koTest = + c.getClassLoader().loadClass(KOTest.class.getName()). + asSubclass(Annotation.class); + for (Method m : c.getMethods()) { + if (m.getAnnotation(koTest) != null) { + res.add(new KOFx(browserContext, m)); + } + } + } + + static synchronized ClassLoader getClassLoader() throws InterruptedException { + while (browserClass == null) { + KnockoutFXTest.class.wait(); + } + return browserClass.getClassLoader(); + } + + public static synchronized void initialized(Class browserCls) throws Exception { + browserClass = browserCls; + browserContext = FnContext.currentPresenter(); + KnockoutFXTest.class.notifyAll(); + } + + public static void initialized() throws Exception { + Class classpathClass = ClassLoader.getSystemClassLoader().loadClass(KnockoutFXTest.class.getName()); + Method m = classpathClass.getMethod("initialized", Class.class); + m.invoke(null, KnockoutFXTest.class); + browserContext = FnContext.currentPresenter(); + } + + @Override + public BrwsrCtx createContext() { + FXContext fx = new FXContext(browserContext); + Contexts.Builder cb = Contexts.newBuilder(). + register(Technology.class, fx, 10). + register(Transfer.class, fx, 10); + if (fx.areWebSocketsSupported()) { + cb.register(WSTransfer.class, fx, 10); + } + return cb.build(); + } + + @Override + public Object createJSON(Map values) { + JSONObject json = new JSONObject(); + for (Map.Entry entry : values.entrySet()) { + try { + json.put(entry.getKey(), entry.getValue()); + } catch (JSONException ex) { + throw new IllegalStateException(ex); + } + } + return json; + } + + @Override + @JavaScriptBody(args = { "s", "args" }, body = "" + + "var f = new Function(s); " + + "return f.apply(null, args);" + ) + public native Object executeScript(String script, Object[] arguments); + + @JavaScriptBody(args = { }, body = + "var h;" + + "if (!!window && !!window.location && !!window.location.href)\n" + + " h = window.location.href;\n" + + "else " + + " h = null;" + + "return h;\n" + ) + private static native String findBaseURL(); + + @Override + public URI prepareURL(String content, String mimeType, String[] parameters) { + try { + final URL baseURL = new URL(findBaseURL()); + StringBuilder sb = new StringBuilder(); + sb.append("/dynamic?mimeType=").append(mimeType); + for (int i = 0; i < parameters.length; i++) { + sb.append("¶m" + i).append("=").append(parameters[i]); + } + String mangle = content.replace("\n", "%0a") + .replace("\"", "\\\"").replace(" ", "%20"); + sb.append("&content=").append(mangle); + + URL query = new URL(baseURL, sb.toString()); + URLConnection c = query.openConnection(); + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); + URI connectTo = new URI(br.readLine()); + return connectTo; + } catch (IOException ex) { + throw new IllegalStateException(ex); + } catch (URISyntaxException ex) { + throw new IllegalStateException(ex); + } + } + + @Override + public boolean canFailWebSocketTest() { + try { + Class.forName("java.util.function.Function"); + return false; + } catch (ClassNotFoundException ex) { + // running on JDK7, FX WebView WebSocket impl does not work + return true; + } + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/test/java/org/netbeans/html/kofx/LessCallbacksCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-fx/src/test/java/org/netbeans/html/kofx/LessCallbacksCheck.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,82 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.kofx; + +import java.io.PrintWriter; +import java.io.StringWriter; +import net.java.html.json.ComputedProperty; +import net.java.html.json.Model; +import net.java.html.json.Property; +import org.apidesign.html.json.tck.KOTest; + +/** + * + * @author Jaroslav Tulach + */ +@Model(className = "LessCalls", properties = { + @Property(name = "value", type = int.class) +}) +public class LessCallbacksCheck { + private static StringWriter sw; + + @ComputedProperty static int plusOne(int value) { + if (sw == null) { + sw = new StringWriter(); + } + new Exception("Who calls me?").printStackTrace( + new PrintWriter(sw) + ); + return value + 1; + } + + @KOTest public void dontCallForInitialValueBackToJavaVM() { + LessCalls m = new LessCalls(10).applyBindings(); + assert m.getPlusOne() == 11 : "Expecting 11: " + m.getPlusOne(); + + assert sw != null : "StringWriter should be initialized: " + sw; + + if (sw.toString().contains("$JsCallbacks$")) { + assert false : "Don't call for initial value via JsCallbacks:\n" + sw; + } + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/test/resources/org/apidesign/html/kofx/test.html --- a/ko-fx/src/test/resources/org/apidesign/html/kofx/test.html Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ - - - - - Knockout.fx Execution Harness - - - - -

Knockout.fx Execution Harness

- - - diff -r 700087d2a5d3 -r 92fb71afdc0e ko-fx/src/test/resources/org/netbeans/html/kofx/test.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-fx/src/test/resources/org/netbeans/html/kofx/test.html Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,56 @@ + + + + + Knockout.fx Execution Harness + + + + +

Knockout.fx Execution Harness

+ + + diff -r 700087d2a5d3 -r 92fb71afdc0e ko-ws-tyrus/src/main/java/org/apidesign/html/wstyrus/TyrusContext.java --- a/ko-ws-tyrus/src/main/java/org/apidesign/html/wstyrus/TyrusContext.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,190 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.wstyrus; - -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Iterator; -import javax.websocket.ClientEndpoint; -import javax.websocket.ContainerProvider; -import javax.websocket.DeploymentException; -import javax.websocket.OnClose; -import javax.websocket.OnError; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.Session; -import javax.websocket.WebSocketContainer; -import net.java.html.json.OnReceive; -import org.apidesign.html.context.spi.Contexts; -import org.apidesign.html.json.spi.JSONCall; -import org.apidesign.html.json.spi.WSTransfer; -import org.apidesign.html.wstyrus.TyrusContext.Comm; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONTokener; -import org.openide.util.lookup.ServiceProvider; - -/** This is an implementation module that provides support for - * WebSocket protocol for {@link OnReceive} communication end point for - * JDK7. - *

- * Don't deal with this module directly, rather use the - * {@link OnReceive @OnReceive(url="ws://...", ...)} API to establish your - * WebSocket connection. - *

- * There is no need to include this module in your application if you are - * running on JDK8. JDK8 WebView provides its own implementation of the - * WebSocket API based on WebSocket object inside a browser. This is included - * in the org.apidesign.html:ko-fx:0.5 module. - * - * @author Jaroslav Tulach - */ -@ServiceProvider(service = Contexts.Provider.class) -public final class TyrusContext implements Contexts.Provider, WSTransfer { - @Override - public void fillContext(Contexts.Builder context, Class requestor) { - // default WebSocket transfer implementation is registered - // in ko-fx module with 100, provide this one as a fallback only - context.register(WSTransfer.class, this, 1000); - } - - @Override - public Comm open(String url, JSONCall callback) { - try { - return new Comm(new URI(url), callback); - } catch (URISyntaxException ex) { - throw new IllegalStateException(ex); - } - } - - @Override - public void send(Comm socket, JSONCall data) { - socket.session.getAsyncRemote().sendText(data.getMessage()); - } - - @Override - public void close(Comm socket) { - try { - final Session s = socket.session; - if (s != null) { - s.close(); - } - } catch (IOException ex) { - socket.callback.notifyError(ex); - } - } - - /** Implementation class in an implementation. Represents a {@link ClientEndpoint} of the - * WebSocket channel. You are unlikely to get on hold of it. - */ - @ClientEndpoint - public static final class Comm { - private final JSONCall callback; - private Session session; - - Comm(final URI url, JSONCall callback) { - this.callback = callback; - try { - final WebSocketContainer c = ContainerProvider.getWebSocketContainer(); - c.connectToServer(Comm.this, url); - } catch (DeploymentException | IOException ex) { - wasAnError(ex); - } - } - - @OnOpen - public synchronized void open(Session s) { - this.session = s; - callback.notifySuccess(null); - } - - @OnClose - public void close() { - this.session = null; - callback.notifyError(null); - } - - @OnMessage - public void message(final String orig, Session s) { - Object json; - String data = orig.trim(); - try { - JSONTokener tok = new JSONTokener(data); - Object obj = data.startsWith("[") ? new JSONArray(tok) : new JSONObject(tok); - json = convertToArray(obj); - } catch (JSONException ex) { - json = data; - } - callback.notifySuccess(json); - } - - @OnError - public void wasAnError(Throwable t) { - callback.notifyError(t); - } - - static Object convertToArray(Object o) throws JSONException { - if (o instanceof JSONArray) { - JSONArray ja = (JSONArray) o; - Object[] arr = new Object[ja.length()]; - for (int i = 0; i < arr.length; i++) { - arr[i] = convertToArray(ja.get(i)); - } - return arr; - } else if (o instanceof JSONObject) { - JSONObject obj = (JSONObject) o; - Iterator it = obj.keys(); - while (it.hasNext()) { - String key = (String) it.next(); - obj.put(key, convertToArray(obj.get(key))); - } - return obj; - } else { - return o; - } - } - - } // end of Comm -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,190 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.wstyrus; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Iterator; +import javax.websocket.ClientEndpoint; +import javax.websocket.ContainerProvider; +import javax.websocket.DeploymentException; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.WebSocketContainer; +import net.java.html.json.OnReceive; +import org.apidesign.html.context.spi.Contexts; +import org.apidesign.html.json.spi.JSONCall; +import org.apidesign.html.json.spi.WSTransfer; +import org.netbeans.html.wstyrus.TyrusContext.Comm; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.openide.util.lookup.ServiceProvider; + +/** This is an implementation module that provides support for + * WebSocket protocol for {@link OnReceive} communication end point for + * JDK7. + *

+ * Don't deal with this module directly, rather use the + * {@link OnReceive @OnReceive(url="ws://...", ...)} API to establish your + * WebSocket connection. + *

+ * There is no need to include this module in your application if you are + * running on JDK8. JDK8 WebView provides its own implementation of the + * WebSocket API based on WebSocket object inside a browser. This is included + * in the org.apidesign.html:ko-fx:0.5 module. + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service = Contexts.Provider.class) +public final class TyrusContext implements Contexts.Provider, WSTransfer { + @Override + public void fillContext(Contexts.Builder context, Class requestor) { + // default WebSocket transfer implementation is registered + // in ko-fx module with 100, provide this one as a fallback only + context.register(WSTransfer.class, this, 1000); + } + + @Override + public Comm open(String url, JSONCall callback) { + try { + return new Comm(new URI(url), callback); + } catch (URISyntaxException ex) { + throw new IllegalStateException(ex); + } + } + + @Override + public void send(Comm socket, JSONCall data) { + socket.session.getAsyncRemote().sendText(data.getMessage()); + } + + @Override + public void close(Comm socket) { + try { + final Session s = socket.session; + if (s != null) { + s.close(); + } + } catch (IOException ex) { + socket.callback.notifyError(ex); + } + } + + /** Implementation class in an implementation. Represents a {@link ClientEndpoint} of the + * WebSocket channel. You are unlikely to get on hold of it. + */ + @ClientEndpoint + public static final class Comm { + private final JSONCall callback; + private Session session; + + Comm(final URI url, JSONCall callback) { + this.callback = callback; + try { + final WebSocketContainer c = ContainerProvider.getWebSocketContainer(); + c.connectToServer(Comm.this, url); + } catch (DeploymentException | IOException ex) { + wasAnError(ex); + } + } + + @OnOpen + public synchronized void open(Session s) { + this.session = s; + callback.notifySuccess(null); + } + + @OnClose + public void close() { + this.session = null; + callback.notifyError(null); + } + + @OnMessage + public void message(final String orig, Session s) { + Object json; + String data = orig.trim(); + try { + JSONTokener tok = new JSONTokener(data); + Object obj = data.startsWith("[") ? new JSONArray(tok) : new JSONObject(tok); + json = convertToArray(obj); + } catch (JSONException ex) { + json = data; + } + callback.notifySuccess(json); + } + + @OnError + public void wasAnError(Throwable t) { + callback.notifyError(t); + } + + static Object convertToArray(Object o) throws JSONException { + if (o instanceof JSONArray) { + JSONArray ja = (JSONArray) o; + Object[] arr = new Object[ja.length()]; + for (int i = 0; i < arr.length; i++) { + arr[i] = convertToArray(ja.get(i)); + } + return arr; + } else if (o instanceof JSONObject) { + JSONObject obj = (JSONObject) o; + Iterator it = obj.keys(); + while (it.hasNext()) { + String key = (String) it.next(); + obj.put(key, convertToArray(obj.get(key))); + } + return obj; + } else { + return o; + } + } + + } // end of Comm +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusDynamicHTTP.java --- a/ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusDynamicHTTP.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,260 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.wstyrus; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.glassfish.grizzly.PortRange; -import org.glassfish.grizzly.http.server.HttpHandler; -import org.glassfish.grizzly.http.server.HttpServer; -import org.glassfish.grizzly.http.server.NetworkListener; -import org.glassfish.grizzly.http.server.Request; -import org.glassfish.grizzly.http.server.Response; -import org.glassfish.grizzly.http.server.ServerConfiguration; -import org.glassfish.grizzly.websockets.WebSocket; -import org.glassfish.grizzly.websockets.WebSocketAddOn; -import org.glassfish.grizzly.websockets.WebSocketApplication; -import org.glassfish.grizzly.websockets.WebSocketEngine; - -/** - * - * @author Jaroslav Tulach - */ -final class TyrusDynamicHTTP extends HttpHandler { - private static int resourcesCount; - private static List resources; - private static ServerConfiguration conf; - private static HttpServer server; - - private TyrusDynamicHTTP() { - } - - static URI initServer() throws Exception { - server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535)); - final WebSocketAddOn addon = new WebSocketAddOn(); - for (NetworkListener listener : server.getListeners()) { - listener.registerAddOn(addon); - } - resources = new ArrayList(); - - conf = server.getServerConfiguration(); - final TyrusDynamicHTTP dh = new TyrusDynamicHTTP(); - - conf.addHttpHandler(dh, "/"); - - server.start(); - - return pageURL("http", server, "/test.html"); - } - - @Override - public void service(Request request, Response response) throws Exception { - if ("/test.html".equals(request.getRequestURI())) { - response.setContentType("text/html"); - final InputStream is = TyrusDynamicHTTP.class.getResourceAsStream("test.html"); - copyStream(is, response.getOutputStream(), null); - return; - } - if ("/dynamic".equals(request.getRequestURI())) { - String mimeType = request.getParameter("mimeType"); - List params = new ArrayList(); - boolean webSocket = false; - for (int i = 0;; i++) { - String p = request.getParameter("param" + i); - if (p == null) { - break; - } - if ("protocol:ws".equals(p)) { - webSocket = true; - continue; - } - params.add(p); - } - final String cnt = request.getParameter("content"); - String mangle = cnt.replace("%20", " ").replace("%0A", "\n"); - ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8")); - URI url; - final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()])); - if (webSocket) { - url = registerWebSocket(res); - } else { - url = registerResource(res); - } - response.getWriter().write(url.toString()); - response.getWriter().write("\n"); - return; - } - - for (Resource r : resources) { - if (r.httpPath.equals(request.getRequestURI())) { - response.setContentType(r.httpType); - r.httpContent.reset(); - String[] params = null; - if (r.parameters.length != 0) { - params = new String[r.parameters.length]; - for (int i = 0; i < r.parameters.length; i++) { - params[i] = request.getParameter(r.parameters[i]); - if (params[i] == null) { - if ("http.method".equals(r.parameters[i])) { - params[i] = request.getMethod().toString(); - } else if ("http.requestBody".equals(r.parameters[i])) { - Reader rdr = request.getReader(); - StringBuilder sb = new StringBuilder(); - for (;;) { - int ch = rdr.read(); - if (ch == -1) { - break; - } - sb.append((char) ch); - } - params[i] = sb.toString(); - } - } - if (params[i] == null) { - params[i] = "null"; - } - } - } - - copyStream(r.httpContent, response.getOutputStream(), null, params); - } - } - } - - private URI registerWebSocket(Resource r) { - WebSocketEngine.getEngine().register("", r.httpPath, new WS(r)); - return pageURL("ws", server, r.httpPath); - } - - private URI registerResource(Resource r) { - if (!resources.contains(r)) { - resources.add(r); - conf.addHttpHandler(this, r.httpPath); - } - return pageURL("http", server, r.httpPath); - } - - private static URI pageURL(String proto, HttpServer server, final String page) { - NetworkListener listener = server.getListeners().iterator().next(); - int port = listener.getPort(); - try { - return new URI(proto + "://localhost:" + port + page); - } catch (URISyntaxException ex) { - throw new IllegalStateException(ex); - } - } - - static final class Resource { - - final InputStream httpContent; - final String httpType; - final String httpPath; - final String[] parameters; - - Resource(InputStream httpContent, String httpType, String httpPath, - String[] parameters) { - httpContent.mark(Integer.MAX_VALUE); - this.httpContent = httpContent; - this.httpType = httpType; - this.httpPath = httpPath; - this.parameters = parameters; - } - } - - static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException { - for (;;) { - int ch = is.read(); - if (ch == -1) { - break; - } - if (ch == '$' && params.length > 0) { - int cnt = is.read() - '0'; - if (baseURL != null && cnt == 'U' - '0') { - os.write(baseURL.getBytes("UTF-8")); - } else { - if (cnt >= 0 && cnt < params.length) { - os.write(params[cnt].getBytes("UTF-8")); - } else { - os.write('$'); - os.write(cnt + '0'); - } - } - } else { - os.write(ch); - } - } - } - - private static class WS extends WebSocketApplication { - private final Resource r; - - private WS(Resource r) { - this.r = r; - } - - @Override - public void onMessage(WebSocket socket, String text) { - try { - r.httpContent.reset(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - copyStream(r.httpContent, out, null, text); - String s = new String(out.toByteArray(), "UTF-8"); - socket.send(s); - } catch (IOException ex) { - LOG.log(Level.WARNING, null, ex); - } - } - private static final Logger LOG = Logger.getLogger(WS.class.getName()); - - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusFX.java --- a/ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusFX.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.wstyrus; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import javafx.application.Platform; -import org.apidesign.html.boot.impl.FnContext; -import org.apidesign.html.boot.spi.Fn; -import org.testng.ITest; -import org.testng.annotations.Test; - -/** - * - * @author Jaroslav Tulach - */ -public final class TyrusFX implements ITest, Runnable { - private final Fn.Presenter p; - private final Method m; - private Object result; - private Object inst; - private int count; - - TyrusFX(Fn.Presenter p, Method m) { - this.p = p; - this.m = m; - } - - @Override - public String getTestName() { - return m.getName(); - } - - @Test - public synchronized void executeTest() throws Exception { - if (result == null) { - Platform.runLater(this); - wait(); - } - if (result instanceof Exception) { - throw (Exception)result; - } - if (result instanceof Error) { - throw (Error)result; - } - } - - @Override - public synchronized void run() { - boolean notify = true; - try { - FnContext.currentPresenter(p); - if (inst == null) { - inst = m.getDeclaringClass().newInstance(); - } - result = m.invoke(inst); - if (result == null) { - result = this; - } - } catch (InvocationTargetException ex) { - Throwable r = ex.getTargetException(); - if (r instanceof InterruptedException) { - if (count++ < 10000) { - notify = false; - Platform.runLater(this); - return; - } - } - result = r; - } catch (Exception ex) { - result = ex; - } finally { - if (notify) { - notifyAll(); - } - FnContext.currentPresenter(null); - } - } - -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusKnockoutTest.java --- a/ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusKnockoutTest.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,213 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.wstyrus; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; -import net.java.html.BrwsrCtx; -import net.java.html.boot.BrowserBuilder; -import net.java.html.js.JavaScriptBody; -import org.apidesign.html.boot.impl.FnContext; -import org.apidesign.html.boot.impl.FnUtils; -import org.apidesign.html.boot.spi.Fn; -import org.apidesign.html.context.spi.Contexts; -import org.apidesign.html.json.spi.Technology; -import org.apidesign.html.json.spi.Transfer; -import org.apidesign.html.json.spi.WSTransfer; -import org.apidesign.html.json.tck.KOTest; -import org.apidesign.html.json.tck.KnockoutTCK; -import org.apidesign.html.kofx.FXContext; -import org.json.JSONException; -import org.json.JSONObject; -import org.openide.util.lookup.ServiceProvider; -import org.testng.annotations.Factory; -import static org.testng.Assert.*; - -/** - * - * @author Jaroslav Tulach - */ -@ServiceProvider(service = KnockoutTCK.class) -public final class TyrusKnockoutTest extends KnockoutTCK { - private static Class browserClass; - private static Fn.Presenter browserContext; - - public TyrusKnockoutTest() { - } - - @Factory public static Object[] compatibilityTests() throws Exception { - Class[] arr = testClasses(); - for (int i = 0; i < arr.length; i++) { - assertEquals( - arr[i].getClassLoader(), - TyrusKnockoutTest.class.getClassLoader(), - "All classes loaded by the same classloader" - ); - } - - URI uri = TyrusDynamicHTTP.initServer(); - - final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(TyrusKnockoutTest.class). - loadPage(uri.toString()). - invoke("initialized"); - - Executors.newSingleThreadExecutor().submit(new Runnable() { - @Override - public void run() { - bb.showAndWait(); - } - }); - - ClassLoader l = getClassLoader(); - List res = new ArrayList(); - for (int i = 0; i < arr.length; i++) { - Class c = Class.forName(arr[i].getName(), true, l); - Class koTest = - c.getClassLoader().loadClass(KOTest.class.getName()). - asSubclass(Annotation.class); - for (Method m : c.getMethods()) { - if (m.getAnnotation(koTest) != null) { - res.add(new TyrusFX(browserContext, m)); - } - } - } - return res.toArray(); - } - - static synchronized ClassLoader getClassLoader() throws InterruptedException { - while (browserClass == null) { - TyrusKnockoutTest.class.wait(); - } - return browserClass.getClassLoader(); - } - - public static synchronized void initialized(Class browserCls) throws Exception { - browserClass = browserCls; - browserContext = FnContext.currentPresenter(); - TyrusKnockoutTest.class.notifyAll(); - } - - public static void initialized() throws Exception { - Class classpathClass = ClassLoader.getSystemClassLoader().loadClass(TyrusKnockoutTest.class.getName()); - Method m = classpathClass.getMethod("initialized", Class.class); - m.invoke(null, TyrusKnockoutTest.class); - browserContext = FnContext.currentPresenter(); - } - - @Override - public BrwsrCtx createContext() { - FXContext fx = new FXContext(browserContext); - TyrusContext tc = new TyrusContext(); - Contexts.Builder cb = Contexts.newBuilder(). - register(Technology.class, fx, 10). - register(Transfer.class, fx, 10). - register(WSTransfer.class, tc, 10); - return cb.build(); - } - - @Override - public Object createJSON(Map values) { - JSONObject json = new JSONObject(); - for (Map.Entry entry : values.entrySet()) { - try { - json.put(entry.getKey(), entry.getValue()); - } catch (JSONException ex) { - throw new IllegalStateException(ex); - } - } - return json; - } - - @Override - @JavaScriptBody(args = { "s", "args" }, body = "" - + "var f = new Function(s); " - + "return f.apply(null, args);" - ) - public native Object executeScript(String script, Object[] arguments); - - @JavaScriptBody(args = { }, body = - "var h;" - + "if (!!window && !!window.location && !!window.location.href)\n" - + " h = window.location.href;\n" - + "else " - + " h = null;" - + "return h;\n" - ) - private static native String findBaseURL(); - - @Override - public URI prepareURL(String content, String mimeType, String[] parameters) { - try { - final URL baseURL = new URL(findBaseURL()); - StringBuilder sb = new StringBuilder(); - sb.append("/dynamic?mimeType=").append(mimeType); - for (int i = 0; i < parameters.length; i++) { - sb.append("¶m" + i).append("=").append(parameters[i]); - } - String mangle = content.replace("\n", "%0a") - .replace("\"", "\\\"").replace(" ", "%20"); - sb.append("&content=").append(mangle); - - URL query = new URL(baseURL, sb.toString()); - URLConnection c = query.openConnection(); - BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); - URI connectTo = new URI(br.readLine()); - return connectTo; - } catch (IOException ex) { - throw new IllegalStateException(ex); - } catch (URISyntaxException ex) { - throw new IllegalStateException(ex); - } - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusDynamicHTTP.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusDynamicHTTP.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,260 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.wstyrus; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.glassfish.grizzly.PortRange; +import org.glassfish.grizzly.http.server.HttpHandler; +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.grizzly.http.server.NetworkListener; +import org.glassfish.grizzly.http.server.Request; +import org.glassfish.grizzly.http.server.Response; +import org.glassfish.grizzly.http.server.ServerConfiguration; +import org.glassfish.grizzly.websockets.WebSocket; +import org.glassfish.grizzly.websockets.WebSocketAddOn; +import org.glassfish.grizzly.websockets.WebSocketApplication; +import org.glassfish.grizzly.websockets.WebSocketEngine; + +/** + * + * @author Jaroslav Tulach + */ +final class TyrusDynamicHTTP extends HttpHandler { + private static int resourcesCount; + private static List resources; + private static ServerConfiguration conf; + private static HttpServer server; + + private TyrusDynamicHTTP() { + } + + static URI initServer() throws Exception { + server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535)); + final WebSocketAddOn addon = new WebSocketAddOn(); + for (NetworkListener listener : server.getListeners()) { + listener.registerAddOn(addon); + } + resources = new ArrayList(); + + conf = server.getServerConfiguration(); + final TyrusDynamicHTTP dh = new TyrusDynamicHTTP(); + + conf.addHttpHandler(dh, "/"); + + server.start(); + + return pageURL("http", server, "/test.html"); + } + + @Override + public void service(Request request, Response response) throws Exception { + if ("/test.html".equals(request.getRequestURI())) { + response.setContentType("text/html"); + final InputStream is = TyrusDynamicHTTP.class.getResourceAsStream("test.html"); + copyStream(is, response.getOutputStream(), null); + return; + } + if ("/dynamic".equals(request.getRequestURI())) { + String mimeType = request.getParameter("mimeType"); + List params = new ArrayList(); + boolean webSocket = false; + for (int i = 0;; i++) { + String p = request.getParameter("param" + i); + if (p == null) { + break; + } + if ("protocol:ws".equals(p)) { + webSocket = true; + continue; + } + params.add(p); + } + final String cnt = request.getParameter("content"); + String mangle = cnt.replace("%20", " ").replace("%0A", "\n"); + ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8")); + URI url; + final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()])); + if (webSocket) { + url = registerWebSocket(res); + } else { + url = registerResource(res); + } + response.getWriter().write(url.toString()); + response.getWriter().write("\n"); + return; + } + + for (Resource r : resources) { + if (r.httpPath.equals(request.getRequestURI())) { + response.setContentType(r.httpType); + r.httpContent.reset(); + String[] params = null; + if (r.parameters.length != 0) { + params = new String[r.parameters.length]; + for (int i = 0; i < r.parameters.length; i++) { + params[i] = request.getParameter(r.parameters[i]); + if (params[i] == null) { + if ("http.method".equals(r.parameters[i])) { + params[i] = request.getMethod().toString(); + } else if ("http.requestBody".equals(r.parameters[i])) { + Reader rdr = request.getReader(); + StringBuilder sb = new StringBuilder(); + for (;;) { + int ch = rdr.read(); + if (ch == -1) { + break; + } + sb.append((char) ch); + } + params[i] = sb.toString(); + } + } + if (params[i] == null) { + params[i] = "null"; + } + } + } + + copyStream(r.httpContent, response.getOutputStream(), null, params); + } + } + } + + private URI registerWebSocket(Resource r) { + WebSocketEngine.getEngine().register("", r.httpPath, new WS(r)); + return pageURL("ws", server, r.httpPath); + } + + private URI registerResource(Resource r) { + if (!resources.contains(r)) { + resources.add(r); + conf.addHttpHandler(this, r.httpPath); + } + return pageURL("http", server, r.httpPath); + } + + private static URI pageURL(String proto, HttpServer server, final String page) { + NetworkListener listener = server.getListeners().iterator().next(); + int port = listener.getPort(); + try { + return new URI(proto + "://localhost:" + port + page); + } catch (URISyntaxException ex) { + throw new IllegalStateException(ex); + } + } + + static final class Resource { + + final InputStream httpContent; + final String httpType; + final String httpPath; + final String[] parameters; + + Resource(InputStream httpContent, String httpType, String httpPath, + String[] parameters) { + httpContent.mark(Integer.MAX_VALUE); + this.httpContent = httpContent; + this.httpType = httpType; + this.httpPath = httpPath; + this.parameters = parameters; + } + } + + static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException { + for (;;) { + int ch = is.read(); + if (ch == -1) { + break; + } + if (ch == '$' && params.length > 0) { + int cnt = is.read() - '0'; + if (baseURL != null && cnt == 'U' - '0') { + os.write(baseURL.getBytes("UTF-8")); + } else { + if (cnt >= 0 && cnt < params.length) { + os.write(params[cnt].getBytes("UTF-8")); + } else { + os.write('$'); + os.write(cnt + '0'); + } + } + } else { + os.write(ch); + } + } + } + + private static class WS extends WebSocketApplication { + private final Resource r; + + private WS(Resource r) { + this.r = r; + } + + @Override + public void onMessage(WebSocket socket, String text) { + try { + r.httpContent.reset(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + copyStream(r.httpContent, out, null, text); + String s = new String(out.toByteArray(), "UTF-8"); + socket.send(s); + } catch (IOException ex) { + LOG.log(Level.WARNING, null, ex); + } + } + private static final Logger LOG = Logger.getLogger(WS.class.getName()); + + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusFX.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusFX.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,120 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.wstyrus; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import javafx.application.Platform; +import org.netbeans.html.boot.impl.FnContext; +import org.apidesign.html.boot.spi.Fn; +import org.testng.ITest; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public final class TyrusFX implements ITest, Runnable { + private final Fn.Presenter p; + private final Method m; + private Object result; + private Object inst; + private int count; + + TyrusFX(Fn.Presenter p, Method m) { + this.p = p; + this.m = m; + } + + @Override + public String getTestName() { + return m.getName(); + } + + @Test + public synchronized void executeTest() throws Exception { + if (result == null) { + Platform.runLater(this); + wait(); + } + if (result instanceof Exception) { + throw (Exception)result; + } + if (result instanceof Error) { + throw (Error)result; + } + } + + @Override + public synchronized void run() { + boolean notify = true; + try { + FnContext.currentPresenter(p); + if (inst == null) { + inst = m.getDeclaringClass().newInstance(); + } + result = m.invoke(inst); + if (result == null) { + result = this; + } + } catch (InvocationTargetException ex) { + Throwable r = ex.getTargetException(); + if (r instanceof InterruptedException) { + if (count++ < 10000) { + notify = false; + Platform.runLater(this); + return; + } + } + result = r; + } catch (Exception ex) { + result = ex; + } finally { + if (notify) { + notifyAll(); + } + FnContext.currentPresenter(null); + } + } + +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,212 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.wstyrus; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; +import net.java.html.BrwsrCtx; +import net.java.html.boot.BrowserBuilder; +import net.java.html.js.JavaScriptBody; +import org.netbeans.html.boot.impl.FnContext; +import org.apidesign.html.boot.spi.Fn; +import org.apidesign.html.context.spi.Contexts; +import org.apidesign.html.json.spi.Technology; +import org.apidesign.html.json.spi.Transfer; +import org.apidesign.html.json.spi.WSTransfer; +import org.apidesign.html.json.tck.KOTest; +import org.apidesign.html.json.tck.KnockoutTCK; +import org.json.JSONException; +import org.json.JSONObject; +import org.netbeans.html.kofx.FXContext; +import org.openide.util.lookup.ServiceProvider; +import org.testng.annotations.Factory; +import static org.testng.Assert.*; + +/** + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service = KnockoutTCK.class) +public final class TyrusKnockoutTest extends KnockoutTCK { + private static Class browserClass; + private static Fn.Presenter browserContext; + + public TyrusKnockoutTest() { + } + + @Factory public static Object[] compatibilityTests() throws Exception { + Class[] arr = testClasses(); + for (int i = 0; i < arr.length; i++) { + assertEquals( + arr[i].getClassLoader(), + TyrusKnockoutTest.class.getClassLoader(), + "All classes loaded by the same classloader" + ); + } + + URI uri = TyrusDynamicHTTP.initServer(); + + final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(TyrusKnockoutTest.class). + loadPage(uri.toString()). + invoke("initialized"); + + Executors.newSingleThreadExecutor().submit(new Runnable() { + @Override + public void run() { + bb.showAndWait(); + } + }); + + ClassLoader l = getClassLoader(); + List res = new ArrayList(); + for (int i = 0; i < arr.length; i++) { + Class c = Class.forName(arr[i].getName(), true, l); + Class koTest = + c.getClassLoader().loadClass(KOTest.class.getName()). + asSubclass(Annotation.class); + for (Method m : c.getMethods()) { + if (m.getAnnotation(koTest) != null) { + res.add(new TyrusFX(browserContext, m)); + } + } + } + return res.toArray(); + } + + static synchronized ClassLoader getClassLoader() throws InterruptedException { + while (browserClass == null) { + TyrusKnockoutTest.class.wait(); + } + return browserClass.getClassLoader(); + } + + public static synchronized void initialized(Class browserCls) throws Exception { + browserClass = browserCls; + browserContext = FnContext.currentPresenter(); + TyrusKnockoutTest.class.notifyAll(); + } + + public static void initialized() throws Exception { + Class classpathClass = ClassLoader.getSystemClassLoader().loadClass(TyrusKnockoutTest.class.getName()); + Method m = classpathClass.getMethod("initialized", Class.class); + m.invoke(null, TyrusKnockoutTest.class); + browserContext = FnContext.currentPresenter(); + } + + @Override + public BrwsrCtx createContext() { + FXContext fx = new FXContext(browserContext); + TyrusContext tc = new TyrusContext(); + Contexts.Builder cb = Contexts.newBuilder(). + register(Technology.class, fx, 10). + register(Transfer.class, fx, 10). + register(WSTransfer.class, tc, 10); + return cb.build(); + } + + @Override + public Object createJSON(Map values) { + JSONObject json = new JSONObject(); + for (Map.Entry entry : values.entrySet()) { + try { + json.put(entry.getKey(), entry.getValue()); + } catch (JSONException ex) { + throw new IllegalStateException(ex); + } + } + return json; + } + + @Override + @JavaScriptBody(args = { "s", "args" }, body = "" + + "var f = new Function(s); " + + "return f.apply(null, args);" + ) + public native Object executeScript(String script, Object[] arguments); + + @JavaScriptBody(args = { }, body = + "var h;" + + "if (!!window && !!window.location && !!window.location.href)\n" + + " h = window.location.href;\n" + + "else " + + " h = null;" + + "return h;\n" + ) + private static native String findBaseURL(); + + @Override + public URI prepareURL(String content, String mimeType, String[] parameters) { + try { + final URL baseURL = new URL(findBaseURL()); + StringBuilder sb = new StringBuilder(); + sb.append("/dynamic?mimeType=").append(mimeType); + for (int i = 0; i < parameters.length; i++) { + sb.append("¶m" + i).append("=").append(parameters[i]); + } + String mangle = content.replace("\n", "%0a") + .replace("\"", "\\\"").replace(" ", "%20"); + sb.append("&content=").append(mangle); + + URL query = new URL(baseURL, sb.toString()); + URLConnection c = query.openConnection(); + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); + URI connectTo = new URI(br.readLine()); + return connectTo; + } catch (IOException ex) { + throw new IllegalStateException(ex); + } catch (URISyntaxException ex) { + throw new IllegalStateException(ex); + } + } +} diff -r 700087d2a5d3 -r 92fb71afdc0e ko-ws-tyrus/src/test/resources/org/apidesign/html/wstyrus/test.html --- a/ko-ws-tyrus/src/test/resources/org/apidesign/html/wstyrus/test.html Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ - - - - - Tyrus WebSockets Execution Harness - - - - -

Tyrus WebSockets Execution Harness

- - - diff -r 700087d2a5d3 -r 92fb71afdc0e ko-ws-tyrus/src/test/resources/org/netbeans/html/wstyrus/test.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko-ws-tyrus/src/test/resources/org/netbeans/html/wstyrus/test.html Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,56 @@ + + + + + Tyrus WebSockets Execution Harness + + + + +

Tyrus WebSockets Execution Harness

+ + + diff -r 700087d2a5d3 -r 92fb71afdc0e pom.xml --- a/pom.xml Mon Dec 16 15:48:09 2013 +0100 +++ b/pom.xml Mon Dec 16 16:59:43 2013 +0100 @@ -92,7 +92,7 @@ * .*/** ko-archetype/src/main/resources/** - ko-fx/src/main/resources/org/apidesign/html/kofx/knockout*.js + ko-fx/src/main/resources/org/netbeans/html/kofx/knockout*.js diff -r 700087d2a5d3 -r 92fb71afdc0e sound/src/main/java/org/apidesign/html/sound/impl/BrowserAudioEnv.java --- a/sound/src/main/java/org/apidesign/html/sound/impl/BrowserAudioEnv.java Mon Dec 16 15:48:09 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/** - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 1997-2010 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-2013 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.apidesign.html.sound.impl; - -import net.java.html.js.JavaScriptBody; -import org.apidesign.html.sound.spi.AudioEnvironment; -import org.openide.util.lookup.ServiceProvider; - -/** Registers an audio provider that delegates to HTML5 Audio tag. - * - * @author Jaroslav Tulach - */ -@ServiceProvider(service = AudioEnvironment.class, position = 100) -public final class BrowserAudioEnv implements AudioEnvironment { - @Override - @JavaScriptBody(args = { "src" }, body = "" - + "if (!Audio) return null;" - + "return new Audio(src);") - public Object create(String src) { - // null if not running in browser - return null; - } - - @Override @JavaScriptBody(args = { "a" }, body = "a.play();") - public void play(Object a) { - } - - @Override @JavaScriptBody(args = { "a" }, body = "a.pause();") - public void pause(Object a) { - } - - @Override @JavaScriptBody(args = { "a", "volume" }, body = "a.setVolume(volume);") - public void setVolume(Object a, double volume) { - } - - @Override - @JavaScriptBody(args = "a", body = "return true;") - public boolean isSupported(Object a) { - return false; - } -} diff -r 700087d2a5d3 -r 92fb71afdc0e sound/src/main/java/org/netbeans/html/sound/impl/BrowserAudioEnv.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sound/src/main/java/org/netbeans/html/sound/impl/BrowserAudioEnv.java Mon Dec 16 16:59:43 2013 +0100 @@ -0,0 +1,81 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2010 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-2013 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.sound.impl; + +import net.java.html.js.JavaScriptBody; +import org.apidesign.html.sound.spi.AudioEnvironment; +import org.openide.util.lookup.ServiceProvider; + +/** Registers an audio provider that delegates to HTML5 Audio tag. + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service = AudioEnvironment.class, position = 100) +public final class BrowserAudioEnv implements AudioEnvironment { + @Override + @JavaScriptBody(args = { "src" }, body = "" + + "if (!Audio) return null;" + + "return new Audio(src);") + public Object create(String src) { + // null if not running in browser + return null; + } + + @Override @JavaScriptBody(args = { "a" }, body = "a.play();") + public void play(Object a) { + } + + @Override @JavaScriptBody(args = { "a" }, body = "a.pause();") + public void pause(Object a) { + } + + @Override @JavaScriptBody(args = { "a", "volume" }, body = "a.setVolume(volume);") + public void setVolume(Object a, double volume) { + } + + @Override + @JavaScriptBody(args = "a", body = "return true;") + public boolean isSupported(Object a) { + return false; + } +}