TreeBaseAppearance Exception

TreeBaseAppearance Exception

Description
I can't provide a test case, but I can try to describe it. I'm filling a TreeGrid using a simple RPC call (so no proxy, loader etc - just simple getStore().add methods after onSuccess). If I change my view before the data was added, I get exactly the same exception, someone posted here already. I also debugged it, and found out, that node = null in TreeBaseAppearance.onJointChange, if I leave the view before adding data. So I overrode the TreeBaseAppearance/BlueTreeAppearance and added a null check:

Thanks for the reminder - a slightly related issue was fixed in 3.0.3, so I'm trying to reproduce this now in 3.0.1 and .3 before applying the fix. There isn't necessarily a problem with adding null checks, but we tend to prefer not adding that small overhead if the fix can be made in another area instead. The linked example too is incomplete - genChildrens isn't provided, so unless simply invoking clear() and add() twice reproduces the issue, I'll need a bit more detail.

Here's a simple entrypoint that I've tried - this keeps out RPC details while still being async. I'm hopefully just missing something silly - browser specific, Web/Dev mode, timing issue, or just not replacing the nodes correctly, but it appears to meet the description here and in the linked thread.

This example is completely self-contained to make it easy to set up and modify. I've only tested with 3.0.1 with this exact case, as that is what your initial report points to, though I have unit test that this is based on that I've confirmed against 3.0.1 and latest in SVN. There are two different ways to make the 'refresh' button replace the nodes, and neither seems to trigger the issue, but I've likely missed the specific case that causes this.

Again, we're not opposed to adding the check you've provided, but we could add null checks everywhere to 'avoid' bugs. Typically we find that those bugs are actually rooted elsewhere, and if we fix the root, then we don't need extra null checks, and other potential bugs are resolved at the same time, so we'd rather find the root cause before applying the fix.

Here's a simple entrypoint that I've tried - this keeps out RPC details while still being async.

How is your example async? After you call one of your replace methods, you can't execute any code in a async way. Or am I missing something?
It took me a while to reproduce the behavior of our code in your example (including RPC). It's not exactly the same exception, but it looks very similar.

As far as I can see, this is causing the problem:
1. Use async way to load data
2. While fetching this data, remove the treegrid from the panel
3. When the async method returns, add an element using add(parent, child). Using add(child) instead is working just fine.

And that's the exception:

com.google.gwt.event.shared.UmbrellaException: One or more exceptions caught, see full set in UmbrellaException#getCauses
at com.google.gwt.event.shared.HandlerManager.fireEvent(HandlerManager.java:129)
at com.sencha.gxt.data.shared.Store.fireEvent(Store.java:609)
at com.sencha.gxt.data.shared.TreeStore.insert(TreeStore.java:996)
at com.sencha.gxt.data.shared.TreeStore.add(TreeStore.java:360)
at nope.client.Test$2.onSuccess(Test.java:81)
at nope.client.Test$2.onSuccess(Test.java:1)
at com.google.gwt.user.client.rpc.impl.RequestCallbackAdapter.onResponseReceived(RequestCallbackAdapter.java:232)
at com.google.gwt.http.client.Request.fireOnResponseReceived(Request.java:287)
at com.google.gwt.http.client.RequestBuilder$1.onReadyStateChange(RequestBuilder.java:395)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:337)
at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:218)
at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:561)
at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:269)
at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:213)
at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:292)
at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:546)
at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:363)
at java.lang.Thread.run(Unknown Source)

Caused by: com.google.gwt.core.client.JavaScriptException: (TypeError): this.insertBefore is not a function
at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:248)
at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:561)
at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:269)
at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
at com.google.gwt.dom.client.Node$.insertBefore$(Node.java)
at com.sencha.gxt.theme.base.client.tree.TreeBaseAppearance.onJointChange(TreeBaseAppearance.java:201)
at com.sencha.gxt.widget.core.client.treegrid.TreeGridView.onJointChange(TreeGridView.java:170)
at com.sencha.gxt.widget.core.client.treegrid.TreeGrid.refresh(TreeGrid.java:610)
at com.sencha.gxt.widget.core.client.treegrid.TreeGrid.onAdd(TreeGrid.java:902)
at com.sencha.gxt.widget.core.client.treegrid.TreeGrid$1.onAdd(TreeGrid.java:246)
at com.sencha.gxt.data.shared.event.StoreAddEvent.dispatch(StoreAddEvent.java:125)
at com.sencha.gxt.data.shared.event.StoreAddEvent.dispatch(StoreAddEvent.java:1)
at com.google.gwt.event.shared.GwtEvent.dispatch(GwtEvent.java:1)
at com.google.web.bindery.event.shared.EventBus.dispatchEvent(EventBus.java:40)
at com.google.web.bindery.event.shared.SimpleEventBus.doFire(SimpleEventBus.java:193)
at com.google.web.bindery.event.shared.SimpleEventBus.fireEvent(SimpleEventBus.java:88)
at com.google.gwt.event.shared.HandlerManager.fireEvent(HandlerManager.java:127)
at com.sencha.gxt.data.shared.Store.fireEvent(Store.java:609)
at com.sencha.gxt.data.shared.TreeStore.insert(TreeStore.java:996)
at com.sencha.gxt.data.shared.TreeStore.add(TreeStore.java:360)
at nope.client.Test$2.onSuccess(Test.java:81)
at nope.client.Test$2.onSuccess(Test.java:1)
at com.google.gwt.user.client.rpc.impl.RequestCallbackAdapter.onResponseReceived(RequestCallbackAdapter.java:232)
at com.google.gwt.http.client.Request.fireOnResponseReceived(Request.java:287)
at com.google.gwt.http.client.RequestBuilder$1.onReadyStateChange(RequestBuilder.java:395)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:337)
at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:218)
at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:561)
at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:269)
at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:213)
at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:292)
at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:546)
at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:363)
at java.lang.Thread.run(Unknown Source)

Again, we're not opposed to adding the check you've provided, but we could add null checks everywhere to 'avoid' bugs. Typically we find that those bugs are actually rooted elsewhere, and if we fix the root, then we don't need extra null checks, and other potential bugs are resolved at the same time, so we'd rather find the root cause before applying the fix.

That's exactly the way I think about null checks. In my case it was just a workaround and I hope you can now find the real cause of this nasty little bug.

It appears that the TreeGrid makes the assumption that after it is attached, if any change is made, it will still be attached. It can be invisible, but removing it from the DOM prevents some code from finding the DOM elements it needs to build the new data. There is a fairly easy change that can be made to fix this in the tree's internals, but it will result in slower element-finding code.

Why does your use case remove the tree before modifying it? If it is for performance sake, consider hiding it instead - you should get nearly the same benefit. If I'm correct, looking up newly built elements will actually be slower when the tree isn't attached at all than when it is merely hidden, but I will investigate further.

I've filed this internally, and we'll update this with any progress or other workarounds.

We have a quite big application containing many views. Imagine something like your GXT Explorer Demo, but instead of adding a tab for each view we are replacing the main content panel. To do so we remove the old view and add a new one. The view should be build each time, so hiding is not really an option.
So that's what happens:
> select menu button 1 > a view with a treegrid opens > load async data > select menu button 2 > exception, when our async callback returns

Makes perfect sense, and that should work, except for the bug you've found. You noted one workaround, hiding it would be another, and here is a third that would prevent the client from handling the data at all:

Cancel the RPC request when the Tree is no longer relevant. There is no way to stop the server from preparing/sending the data without additional wiring on the server, but you can tell the client to ignore the response. First, you can make your RPC async call return Request instead of void, and call cancel on that to stop the RPC call. Second, your AsyncCallback could have a flag in it to avoid doing anything.

As before, this has been filed, and in addition to the workarounds provided both by you and me, we'll update this when we have a fix.