You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by jt...@apache.org on 2017/10/26 08:23:32 UTC
[incubator-netbeans-html4j] 02/02: NETBEANS-99: Let @Model classes
point directly to Knockout structures and only indirectly to JavaScript
representation of ko objects. Stress test by FXGCPresenter
This is an automated email from the ASF dual-hosted git repository.
jtulach pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-netbeans-html4j.git
commit 246d0733a636def7bd4c951895e3b5d7cd73ce65
Author: Jaroslav Tulach <ja...@oracle.com>
AuthorDate: Thu Oct 26 10:24:07 2017 +0200
NETBEANS-99: Let @Model classes point directly to Knockout structures and only indirectly to JavaScript representation of ko objects. Stress test by FXGCPresenter
---
.../java/net/java/html/boot/fx/FXBrowsers.java | 71 ++---------------
.../netbeans/html/boot/fx/AbstractFXPresenter.java | 34 +++++---
.../java/org/netbeans/html/boot/fx/FXBrwsr.java | 4 +-
.../fx/{FXPresenter.java => FXGCPresenter.java} | 57 +++++++++++---
.../org/netbeans/html/boot/fx/FXPresenter.java | 6 +-
.../netbeans/html/boot/fx/InitializeWebView.java | 90 ++++++++++++++++++++++
.../java/org/netbeans/html/json/impl/Bindings.java | 6 +-
.../java/org/netbeans/html/json/impl/JSON.java | 2 +-
.../org/netbeans/html/json/spi/Technology.java | 36 +++++++--
.../netbeans/html/wstyrus/TyrusKnockoutTest.java | 10 +--
.../main/java/org/netbeans/html/ko4j/KOTech.java | 41 ++++++----
.../main/java/org/netbeans/html/ko4j/Knockout.java | 4 +
.../org/netbeans/html/ko4j/KnockoutFXTest.java | 3 +-
src/main/javadoc/overview.html | 3 +
.../org/netbeans/html/xhr4j/JsonKnockoutTest.java | 3 +-
15 files changed, 247 insertions(+), 123 deletions(-)
diff --git a/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java b/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java
index 8ceae82..4ae8909 100644
--- a/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java
+++ b/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java
@@ -18,16 +18,13 @@
*/
package net.java.html.boot.fx;
+import org.netbeans.html.boot.fx.InitializeWebView;
import java.net.URL;
import javafx.application.Platform;
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.concurrent.Worker;
import javafx.scene.web.WebView;
import net.java.html.BrwsrCtx;
import net.java.html.boot.BrowserBuilder;
import net.java.html.js.JavaScriptBody;
-import org.netbeans.html.boot.fx.AbstractFXPresenter;
import org.netbeans.html.context.spi.Contexts;
import org.netbeans.html.context.spi.Contexts.Id;
@@ -89,7 +86,7 @@ public final class FXBrowsers {
) {
Object[] context = new Object[args.length + 1];
System.arraycopy(args, 0, context, 1, args.length);
- final Load load = new Load(webView, null);
+ final InitializeWebView load = new InitializeWebView(webView, null);
context[0] = load;
BrowserBuilder.newBrowser(context).
loadPage(url.toExternalForm()).
@@ -172,7 +169,7 @@ public final class FXBrowsers {
) {
Object[] newCtx = new Object[context.length + 1];
System.arraycopy(context, 0, newCtx, 1, context.length);
- final Load load = new Load(webView, onPageLoad);
+ final InitializeWebView load = new InitializeWebView(webView, onPageLoad);
newCtx[0] = load;
BrowserBuilder.newBrowser(newCtx).
loadPage(url.toExternalForm()).
@@ -203,67 +200,9 @@ public final class FXBrowsers {
*/
public static void runInBrowser(WebView webView, Runnable code) {
Object ud = webView.getUserData();
- if (!(ud instanceof Load)) {
+ if (!(ud instanceof InitializeWebView)) {
throw new IllegalArgumentException();
}
- ((Load)ud).ctx.execute(code);
+ ((InitializeWebView)ud).runInContext(code);
}
-
- private static class Load extends AbstractFXPresenter implements Runnable {
- private final WebView webView;
- private final Runnable myLoad;
- private BrwsrCtx ctx;
-
- public Load(WebView webView, Runnable onLoad) {
- this.webView = webView;
- this.myLoad = onLoad;
- webView.setUserData(this);
- }
-
- public void run() {
- ctx = BrwsrCtx.findDefault(Load.class);
- if (myLoad != null) {
- myLoad.run();
- }
- }
-
- @Override
- protected void waitFinished() {
- // don't wait
- }
-
- @Override
- protected WebView findView(final URL resource) {
- final Worker<Void> w = webView.getEngine().getLoadWorker();
- w.stateProperty().addListener(new ChangeListener<Worker.State>() {
- private String previous;
-
- @Override
- public void changed(ObservableValue<? extends Worker.State> ov, Worker.State t, Worker.State newState) {
- if (newState.equals(Worker.State.SUCCEEDED)) {
- if (checkValid()) {
- onPageLoad();
- }
- }
- if (newState.equals(Worker.State.FAILED)) {
- checkValid();
- throw new IllegalStateException("Failed to load " + resource);
- }
- }
-
- private boolean checkValid() {
- final String crnt = webView.getEngine().getLocation();
- if (previous != null && !previous.equals(crnt)) {
- w.stateProperty().removeListener(this);
- return false;
- }
- previous = crnt;
- return true;
- }
- });
-
- return webView;
- }
- }
-
}
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java
index 08590c1..53dce08 100644
--- a/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java
@@ -22,6 +22,7 @@ import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.Reader;
+import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.net.URL;
@@ -182,9 +183,9 @@ Fn.KeepAlive, Fn.ToJavaScript, Fn.FromJavaScript, Executor, Cloneable {
waitFinished();
}
- protected abstract void waitFinished();
+ abstract void waitFinished();
- protected abstract WebView findView(final URL resource);
+ abstract WebView findView(final URL resource);
final JSObject convertArrays(Object[] arr) {
for (int i = 0; i < arr.length; i++) {
@@ -569,8 +570,9 @@ Fn.KeepAlive, Fn.ToJavaScript, Fn.FromJavaScript, Executor, Cloneable {
Object java = obj.getMember("fxBrwsrId");
if (java instanceof JSObject) {
for (;;) {
- int resultHash;
- int resultId;
+ final int resultHash;
+ final int resultId;
+ final NavigableSet<Ref> refs;
synchronized (this) {
this.hash = -1;
this.id = -1;
@@ -579,28 +581,38 @@ Fn.KeepAlive, Fn.ToJavaScript, Fn.FromJavaScript, Executor, Cloneable {
assert this.id != -1;
resultHash = this.hash;
resultId = this.id;
+ refs = values.get(resultHash);
+ if (refs == null) {
+ return null;
+ }
}
- final NavigableSet<Ref> refs = values.get(resultHash);
Iterator<Ref> it = refs.iterator();
while (it.hasNext()) {
Ref next = it.next();
- Object pojo = next.value();
- if (next.id() == resultId) {
- return pojo;
- }
- if (pojo == null) {
+ Object[] pojo = { next.value() };
+ if (pojo[0] == null) {
it.remove();
+ continue;
+ }
+ if (next.id() == resultId) {
+ return emitJavaObject(pojo, resultHash, resultId);
}
}
if (refs.isEmpty()) {
- values.remove(resultHash);
+ synchronized (this) {
+ values.remove(resultHash);
+ }
}
}
}
return obj;
}
+
}
+ Object emitJavaObject(Object[] pojo, int hash, int id) {
+ return pojo[0];
+ }
}
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java
index 5fd6039..a6f96f7 100644
--- a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java
@@ -65,7 +65,7 @@ public class FXBrwsr extends Application {
private static final CountDownLatch FINISHED = new CountDownLatch(1);
private BorderPane root;
- public static synchronized WebView findWebView(final URL url, final FXPresenter onLoad) {
+ public static synchronized WebView findWebView(final URL url, final AbstractFXPresenter onLoad) {
if (INSTANCE == null) {
final String callee = findCalleeClassName();
Executors.newFixedThreadPool(1).submit(new Runnable() {
@@ -211,7 +211,7 @@ public class FXBrwsr extends Application {
return arr;
}
- private WebView newView(final URL url, final FXPresenter onLoad) {
+ private WebView newView(final URL url, final AbstractFXPresenter onLoad) {
final WebView view = new WebView();
view.setContextMenuEnabled(false);
Stage newStage;
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXGCPresenter.java
similarity index 53%
copy from boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
copy to boot-fx/src/main/java/org/netbeans/html/boot/fx/FXGCPresenter.java
index 3be269e..330b13a 100644
--- a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXGCPresenter.java
@@ -19,22 +19,22 @@
package org.netbeans.html.boot.fx;
import java.io.File;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.logging.Level;
import javafx.scene.web.WebView;
-import net.java.html.boot.BrowserBuilder;
-import org.netbeans.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.
+/** Presenter for stress testing. It tries to force few GC cycles
+ * before returning a Java object from {@link WebView} to simulate the
+ * fact that in JDK8 newer than build 112 the Java objects exposed to
+ * {@link WebView} are held by weak references.
*
* @author Jaroslav Tulach
*/
-@ServiceProvider(service = Fn.Presenter.class)
-public final class FXPresenter extends AbstractFXPresenter {
+public final class FXGCPresenter extends AbstractFXPresenter {
static {
try {
try {
@@ -54,11 +54,48 @@ public final class FXPresenter extends AbstractFXPresenter {
}
}
- protected void waitFinished() {
+ @Override
+ void waitFinished() {
FXBrwsr.waitFinished();
}
- protected WebView findView(final URL resource) {
+ @Override
+ WebView findView(final URL resource) {
return FXBrwsr.findWebView(resource, this);
}
+
+ @Override
+ Object emitJavaObject(Object[] pojo, int hash, int id) {
+ Reference<Object> ref = new WeakReference<Object>(pojo[0]);
+ boolean nonNull = ref.get() != null;
+ assertGC(ref);
+ Object r;
+ if ((r = ref.get()) == null && nonNull) {
+ throw new NullPointerException("Value has been GCed to null for " + hash + " and " + id);
+ }
+ return r;
+ }
+
+ private static boolean isGone(Reference<?> ref) {
+ return ref.get() == null;
+ }
+
+ private static void assertGC(Reference<Object> ref) {
+ long l = System.currentTimeMillis();
+ for (int i = 0; i < 3; i++) {
+ if (isGone(ref)) {
+ return;
+ }
+
+ try {
+ System.gc();
+ System.runFinalization();
+ } catch (Error err) {
+ LOG.log(Level.INFO, "Problems during GCing attempt of " + ref.get(), err);
+ }
+ }
+ final long took = System.currentTimeMillis() - l;
+ LOG.log(Level.FINE, "Good: No GC of {1} for {0} ms.", new Object[]{took, ref.get()});
+ }
+
}
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
index 3be269e..1554113 100644
--- a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
@@ -54,11 +54,13 @@ public final class FXPresenter extends AbstractFXPresenter {
}
}
- protected void waitFinished() {
+ @Override
+ void waitFinished() {
FXBrwsr.waitFinished();
}
- protected WebView findView(final URL resource) {
+ @Override
+ WebView findView(final URL resource) {
return FXBrwsr.findWebView(resource, this);
}
}
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/InitializeWebView.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/InitializeWebView.java
new file mode 100644
index 0000000..b093565
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/InitializeWebView.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.html.boot.fx;
+
+import java.net.URL;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.concurrent.Worker;
+import javafx.scene.web.WebView;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.boot.fx.AbstractFXPresenter;
+
+public final class InitializeWebView extends AbstractFXPresenter implements Runnable {
+
+ private final WebView webView;
+ private final Runnable myLoad;
+ BrwsrCtx ctx;
+
+ public InitializeWebView(WebView webView, Runnable onLoad) {
+ this.webView = webView;
+ this.myLoad = onLoad;
+ webView.setUserData(this);
+ }
+
+ @Override
+ public void run() {
+ ctx = BrwsrCtx.findDefault(InitializeWebView.class);
+ if (myLoad != null) {
+ myLoad.run();
+ }
+ }
+
+ @Override
+ void waitFinished() {
+ // don't wait
+ }
+
+ @Override
+ WebView findView(final URL resource) {
+ final Worker<Void> w = webView.getEngine().getLoadWorker();
+ w.stateProperty().addListener(new ChangeListener<Worker.State>() {
+ private String previous;
+
+ @Override
+ public void changed(ObservableValue<? extends Worker.State> ov, Worker.State t, Worker.State newState) {
+ if (newState.equals(Worker.State.SUCCEEDED)) {
+ if (checkValid()) {
+ onPageLoad();
+ }
+ }
+ if (newState.equals(Worker.State.FAILED)) {
+ checkValid();
+ throw new IllegalStateException("Failed to load " + resource);
+ }
+ }
+
+ private boolean checkValid() {
+ final String crnt = webView.getEngine().getLocation();
+ if (previous != null && !previous.equals(crnt)) {
+ w.stateProperty().removeListener(this);
+ return false;
+ }
+ previous = crnt;
+ return true;
+ }
+ });
+ return webView;
+ }
+
+ public final void runInContext(Runnable r) {
+ ctx.execute(r);
+ }
+
+}
diff --git a/json/src/main/java/org/netbeans/html/json/impl/Bindings.java b/json/src/main/java/org/netbeans/html/json/impl/Bindings.java
index fdd1b57..3b0e062 100644
--- a/json/src/main/java/org/netbeans/html/json/impl/Bindings.java
+++ b/json/src/main/java/org/netbeans/html/json/impl/Bindings.java
@@ -69,7 +69,11 @@ public final class Bindings<Data> {
}
- public Data koData() {
+ final Object jsObj() {
+ if (bp instanceof Technology.ToJavaScript) {
+ Technology.ToJavaScript<Data> toJS = (Technology.ToJavaScript<Data>) bp;
+ return toJS.toJavaScript(data);
+ }
return data;
}
diff --git a/json/src/main/java/org/netbeans/html/json/impl/JSON.java b/json/src/main/java/org/netbeans/html/json/impl/JSON.java
index 1745c0c..09c691f 100644
--- a/json/src/main/java/org/netbeans/html/json/impl/JSON.java
+++ b/json/src/main/java/org/netbeans/html/json/impl/JSON.java
@@ -267,7 +267,7 @@ public final class JSON {
return null;
}
final Bindings b = PropertyBindingAccessor.getBindings(proto, true, null);
- return b == null ? null : b.koData();
+ return b == null ? null : b.jsObj();
}
private static Proto findProto(Object object) {
diff --git a/json/src/main/java/org/netbeans/html/json/spi/Technology.java b/json/src/main/java/org/netbeans/html/json/spi/Technology.java
index 2e0a206..b138dbe 100644
--- a/json/src/main/java/org/netbeans/html/json/spi/Technology.java
+++ b/json/src/main/java/org/netbeans/html/json/spi/Technology.java
@@ -23,16 +23,19 @@ import net.java.html.json.Model;
import net.java.html.json.Models;
import org.netbeans.html.context.spi.Contexts.Id;
-/** An implementation of a binding between model classes (see {@link Model})
+/** * An implementation of a binding between model classes (see {@link Model})
* and particular technology like <a href="http://knockoutjs.com">knockout.js</a>
- * in a browser window, etc.
- * Since introduction of {@link Id technology identifiers} one can choose between
- * different background implementations to handle the conversion and
- * communication requests. The currently known provider is
- * <code>org.netbeans.html:ko4j</code> module which registers
+ * in a browser window, etc.Since introduction of {@link Id technology identifiers} one can choose between
+ different background implementations to handle the conversion and
+ communication requests.
+ * The currently known provider is
+ <code>org.netbeans.html:ko4j</code> module which registers
* a <a href="http://knockoutjs.com" target="_blank">knockout.js</a>
* implementation called <b>ko4j</b>.
*
+ * @param <Data> technology internal type that keeps internal data for each
+ * instance of {@linkplains Model model class}.
+ *
* @author Jaroslav Tulach
*/
public interface Technology<Data> {
@@ -189,4 +192,25 @@ public interface Technology<Data> {
*/
public D wrapModel(Object model, Object copyFrom, PropertyBinding[] propArr, FunctionBinding[] funcArr);
}
+
+ /** Convertor of the internal data type to object suitable as a JavaScript
+ * representation. Certain technologies need to keep some data in Java
+ * and only part of them in JavaScript-ready object. With the help of
+ * {@code ToJavaScript} interface, they can parametrize their
+ * {@link Technology} with the Java type and implement
+ * {@link #toJavaScript(java.lang.Object)}
+ * method to extract the proper JavaScript part from that object.
+ *
+ * @param <D> the internal data type
+ * @since 1.5.1
+ */
+ public static interface ToJavaScript<D> extends Technology<D> {
+ /** Extracts JavaScript ready representation.
+ *
+ * @param data technology's internal data structure
+ * @return object ready to represent the data in JavaScript
+ * @since 1.5.1
+ */
+ public Object toJavaScript(D data);
+ }
}
diff --git a/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java
index 0a17692..c651346 100644
--- a/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java
+++ b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java
@@ -35,6 +35,9 @@ import java.util.concurrent.Executors;
import net.java.html.BrwsrCtx;
import net.java.html.boot.BrowserBuilder;
import net.java.html.js.JavaScriptBody;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.netbeans.html.boot.fx.FXGCPresenter;
import org.netbeans.html.boot.spi.Fn;
import org.netbeans.html.context.spi.Contexts;
import org.netbeans.html.json.spi.Technology;
@@ -42,13 +45,10 @@ import org.netbeans.html.json.spi.Transfer;
import org.netbeans.html.json.spi.WSTransfer;
import org.netbeans.html.json.tck.KOTest;
import org.netbeans.html.json.tck.KnockoutTCK;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.netbeans.html.boot.impl.FnContext;
import org.netbeans.html.ko4j.KO4J;
import org.openide.util.lookup.ServiceProvider;
import org.testng.Assert;
-import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
import org.testng.annotations.Factory;
/**
@@ -75,7 +75,7 @@ public final class TyrusKnockoutTest extends KnockoutTCK {
URI uri = TyrusDynamicHTTP.initServer();
- final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(TyrusKnockoutTest.class).
+ final BrowserBuilder bb = BrowserBuilder.newBrowser(new FXGCPresenter()).loadClass(TyrusKnockoutTest.class).
loadPage(uri.toString()).
invoke("initialized");
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java
index c94e5ae..32f0ea9 100644
--- a/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java
@@ -34,7 +34,8 @@ import org.netbeans.html.json.spi.Technology;
*/
@Contexts.Id("ko4j")
final class KOTech
-implements Technology.BatchCopy<Object>, Technology.ValueMutated<Object>, Technology.ApplyId<Object> {
+implements Technology.BatchCopy<Knockout>, Technology.ValueMutated<Knockout>,
+Technology.ApplyId<Knockout>, Technology.ToJavaScript<Knockout> {
private Object[] jsObjects;
private int jsIndex;
@@ -42,11 +43,11 @@ implements Technology.BatchCopy<Object>, Technology.ValueMutated<Object>, Techno
}
@Override
- public Object wrapModel(Object model, Object copyFrom, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
+ public Knockout wrapModel(Object model, Object copyFrom, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
return createKO(model, copyFrom, propArr, funcArr, null);
}
- final Object createKO(Object model, Object copyFrom, PropertyBinding[] propArr, FunctionBinding[] funcArr, Knockout[] ko) {
+ final Knockout createKO(Object model, Object copyFrom, PropertyBinding[] propArr, FunctionBinding[] funcArr, Knockout[] ko) {
String[] propNames = new String[propArr.length];
Number[] propInfo = new Number[propArr.length];
Object[] propValues = new Object[propArr.length];
@@ -76,7 +77,7 @@ implements Technology.BatchCopy<Object>, Technology.ValueMutated<Object>, Techno
ret, copyFrom,
propNames, propInfo, propValues, funcNames
);
- return ret;
+ return newKO;
}
private Object getJSObject() {
@@ -95,42 +96,43 @@ implements Technology.BatchCopy<Object>, Technology.ValueMutated<Object>, Techno
}
@Override
- public Object wrapModel(Object model) {
+ public Knockout wrapModel(Object model) {
throw new UnsupportedOperationException();
}
@Override
- public void bind(PropertyBinding b, Object model, Object data) {
+ public void bind(PropertyBinding b, Object model, Knockout data) {
throw new UnsupportedOperationException();
}
@Override
- public void valueHasMutated(Object data, String propertyName) {
- Knockout.cleanUp();
- Knockout.valueHasMutated(data, propertyName, null, null);
+ public void valueHasMutated(Knockout data, String propertyName) {
+ valueHasMutated(data, propertyName, null, null);
}
@Override
- public void valueHasMutated(Object data, String propertyName, Object oldValue, Object newValue) {
+ public void valueHasMutated(Knockout data, String propertyName, Object oldValue, Object newValue) {
Knockout.cleanUp();
- if (newValue instanceof Enum) {
- newValue = newValue.toString();
+ if (data != null) {
+ if (newValue instanceof Enum) {
+ newValue = newValue.toString();
+ }
+ Knockout.valueHasMutated(data.js(), propertyName, oldValue, newValue);
}
- Knockout.valueHasMutated(data, propertyName, oldValue, newValue);
}
@Override
- public void expose(FunctionBinding fb, Object model, Object d) {
+ public void expose(FunctionBinding fb, Object model, Knockout data) {
throw new UnsupportedOperationException();
}
@Override
- public void applyBindings(Object data) {
+ public void applyBindings(Knockout data) {
applyBindings(null, data);
}
@Override
- public void applyBindings(String id, Object data) {
- Object ko = Knockout.applyBindings(id, data);
+ public void applyBindings(String id, Knockout data) {
+ Object ko = Knockout.applyBindings(id, data.js());
if (ko instanceof Knockout) {
((Knockout)ko).hold();
applied.add((Knockout) ko);
@@ -153,4 +155,9 @@ implements Technology.BatchCopy<Object>, Technology.ValueMutated<Object>, Techno
public <M> M toModel(Class<M> modelClass, Object data) {
return modelClass.cast(Knockout.toModel(data));
}
+
+ @Override
+ public Object toJavaScript(Knockout data) {
+ return data.js();
+ }
}
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
index 7500715..ae52c39 100644
--- a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
@@ -71,6 +71,10 @@ final class Knockout {
}
}
+ final Object js() {
+ return js;
+ }
+
static void cleanUp() {
for (;;) {
Knockout ko = null;
diff --git a/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java b/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java
index 4306983..8bde691 100644
--- a/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java
+++ b/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java
@@ -34,6 +34,7 @@ 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.fx.FXGCPresenter;
import org.netbeans.html.boot.spi.Fn;
import org.netbeans.html.context.spi.Contexts;
import org.netbeans.html.json.spi.Technology;
@@ -70,7 +71,7 @@ public final class KnockoutFXTest extends KnockoutTCK {
URI uri = DynamicHTTP.initServer();
- final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(KnockoutFXTest.class).
+ final BrowserBuilder bb = BrowserBuilder.newBrowser(new FXGCPresenter()).loadClass(KnockoutFXTest.class).
loadPage(uri.toString()).
invoke("initialized");
diff --git a/src/main/javadoc/overview.html b/src/main/javadoc/overview.html
index 9bdbc8b..b9f066a 100644
--- a/src/main/javadoc/overview.html
+++ b/src/main/javadoc/overview.html
@@ -60,6 +60,9 @@
{@link net.java.html.json.ComputedProperty computing a property}.
Regular subclassing of {@link org.netbeans.html.json.spi.Proto.Type} is
possible.
+ Bugfix <a target="_blank" href="https://issues.apache.org/jira/browse/NETBEANS-99">#99</a>
+ - better garbage collector related behavior of <b>ko4j</b> instances thanks
+ to introduction of {@link org.netbeans.html.json.spi.Technology.ToJavaScript}.
<h3>New in version 1.5</h3>
diff --git a/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonKnockoutTest.java b/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonKnockoutTest.java
index b148218..168de1d 100644
--- a/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonKnockoutTest.java
+++ b/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonKnockoutTest.java
@@ -35,6 +35,7 @@ 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.fx.FXGCPresenter;
import org.netbeans.html.boot.spi.Fn;
import org.netbeans.html.context.spi.Contexts;
import org.netbeans.html.json.spi.Technology;
@@ -69,7 +70,7 @@ public final class JsonKnockoutTest extends KnockoutTCK {
URI uri = JsonDynamicHTTP.initServer();
- final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(JsonKnockoutTest.class).
+ final BrowserBuilder bb = BrowserBuilder.newBrowser(new FXGCPresenter()).loadClass(JsonKnockoutTest.class).
loadPage(uri.toString()).
invoke("initialized");
--
To stop receiving notification emails like this one, please contact
"commits@netbeans.apache.org" <co...@netbeans.apache.org>.