This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.
I've encountered a problem where the debugging window shows up -twice- on the debugging workspace. The other day I thought I had identified it as a problem between DebuggerWindowPerformer and DebuggerViewAction. But, even after working around that problem I have reproduced the bug. Luckily, this time I had inserted Thread.dumpStack in DebuggerWindow's constructor, so now I can see what the problem is. Here's what happens. The debugger starter action switches to the debugging workspace (by calling DebuggerModule.changeWorkspace) and then starts EnterpriseDebugger.startDebugger. This calls my start debugger, and I call DebuggerWindowPerformer.getDebuggerWindow() to obtain a reference to the debugger window. This causes the debugger window to be created. So far so good. But then shortly thereafter, some window system code kicks in which ALSO creates the debugger window, through reflection (see below stacktrace), presumably from saved window settings or window system XML files defining the debugger window. I'm guessing this is happening because changeWorkspace() call, including all window restoration, has not completed when changeWorkspace() returns, so my startDebugger code is running before the window system is done. Since the window system code is just calling newInstance, it does not use the already-created debugger window that DebuggerWindowPerformer knows about! The end result is that the user sits with two debugger windows on the desktop. I think I can work around this by moving my DebuggerWindowPerfomer.getDebuggerWindow call out to a later point. But the problem is - I don't know how long I have to wait before it is safe. Also, by moving this code out I may introduce new bugs. (I'm adding component listeners to the debugging window to be able to catch window exposure events for the views contained inside the debugger window.) I wasn't sure if this was a debuggercore bug or a window system bug, but I'll start with the debuggercore category since I haven't seen this problem in other areas. Is there some way to "wait" (kind of like a SwingUtilities.invokeAndWait()) for the window system to complete the workspace switch before resuming with my startDebugger code? Here is the stack trace. java.lang.Exception: Stack trace at java.lang.Thread.dumpStack(Thread.java:1071) at org.netbeans.modules.debugger.support.nodes.DebuggerWindow.<init>(DebuggerWindow.java:115) at org.netbeans.modules.debugger.support.actions.DebuggerWindowPerformer.getDebuggerWindow(DebuggerWindowPerformer.java:62) at com.sun.forte.st.ipe.debugger.IpeDebugger.startDebugger(IpeDebugger.java:589) at org.netbeans.modules.debugger.multisession.EnterpriseDebugger.startSession(EnterpriseDebugger.java:406) at org.netbeans.modules.debugger.multisession.EnterpriseDebugger.startDebugger(EnterpriseDebugger.java:202) at com.sun.forte.st.ipe.debugger.AttachProcessDialog.doAttach(AttachProcessDialog.java:209) at com.sun.forte.st.ipe.debugger.AttachProcessDialog.showWindow(AttachProcessDialog.java:437) at com.sun.forte.st.ipe.debugger.actions.AttachToProcessAction.performAction(AttachToProcessAction.java:46) at org.openide.util.actions.CallableSystemAction.actionPerformed(CallableSystemAction.java:69) at org.netbeans.core.ModuleActions$1.run(ModuleActions.java:105) at org.openide.util.Task.run(Task.java:152) at org.openide.util.RequestProcessor$ProcessorThread.run(RequestProcessor.java:622) java.lang.Exception: Stack trace at java.lang.Thread.dumpStack(Thread.java:1071) at org.netbeans.modules.debugger.support.nodes.DebuggerWindow.<init>(DebuggerWindow.java:115) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:274) at java.lang.Class.newInstance0(Class.java:296) at java.lang.Class.newInstance(Class.java:249) at org.openide.loaders.XMLSettingsSupport$SettingsRecognizer.instanceCreate(XMLSettingsSupport.java:455) at org.openide.loaders.InstanceDataObject$SettingsInstance.instanceCreate(InstanceDataObject.java:1215) at org.netbeans.core.windows.PersistenceManager.lookupTCInstance(PersistenceManager.java:350) at org.netbeans.core.windows.WindowManagerImpl.lookupTCInstance(WindowManagerImpl.java:877) at org.netbeans.core.windows.layers.TCRefImpl.getTopComponent(TCRefImpl.java:357) at org.netbeans.core.windows.layers.TCRefImpl.updateMode(TCRefImpl.java:198) at org.netbeans.core.windows.layers.ModeData$CookiesImpl.addComponents(ModeData.java:764) at org.netbeans.core.windows.layers.ModeData$CookiesImpl.updateComponents(ModeData.java:629) at org.netbeans.core.windows.layers.ModeData$CookiesImpl.loadDataSection(ModeData.java:1090) at org.netbeans.core.windows.layers.ModeData$CookiesImpl.updateProperties(ModeData.java:487) at org.netbeans.core.windows.layers.ModeData$CookiesImpl.updateAll(ModeData.java:397) at org.netbeans.core.windows.layers.ModeData$CookiesImpl.createInstance(ModeData.java:341) at org.netbeans.core.windows.layers.ICFolderImpl$R.run(ICFolderImpl.java:261) at org.netbeans.core.windows.layers.ICFolderImpl.instanceCreate(ICFolderImpl.java:123) at org.netbeans.core.windows.layers.WorkspaceData$InstanceCookieImpl.createModes(WorkspaceData.java:470) at org.netbeans.core.windows.layers.WorkspaceData$InstanceCookieImpl.updateModes(WorkspaceData.java:407) at org.netbeans.core.windows.layers.WorkspaceData$InstanceCookieImpl.updateAll(WorkspaceData.java:342) at org.netbeans.core.windows.layers.WorkspaceData$InstanceCookieImpl.loadDataSection(WorkspaceData.java:667) at org.netbeans.core.windows.WorkspaceImpl.ensureSectionLoaded(WorkspaceImpl.java:958) at org.netbeans.core.windows.WorkspaceImpl.setVisible(WorkspaceImpl.java:687) at org.netbeans.core.windows.WindowManagerImpl$1.run(WindowManagerImpl.java:431) at org.netbeans.core.windows.WindowManagerImpl.setCurrentWorkspace(WindowManagerImpl.java:392) at org.netbeans.core.windows.WorkspaceImpl$1.run(WorkspaceImpl.java:468) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:178) at java.awt.EventQueue.dispatchEvent(EventQueue.java:443) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:190) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:144) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:130) at java.awt.EventDispatchThread.run(EventDispatchThread.java:98) (If you need to look at some of the involved source files that are not in NetBeans, the ifdef source files are part of the forte for java closed source repository if you can get to that. If not let me know and I'll send them to you.)
This was using the orion_ea branch (which I think is tied closely to release33), with JDK 1.4 - FCS on Solaris 8. I'm hoping this can be addressed in 3.3.2. The duplicate debugging window is a serious problem for our users because some windows docked in it are inherently singletons (e.g. the terminal emulators to the slave processes, dbx and the user's program) so one window does not work and if the user is trying to use the "wrong" window the product seems completely broken.
One additional note that might be interesting to note: the initial startDebugger is running on the thread "org.netbeans.core.ModuleActions-1", and the second call (the window system reflection) is on "AWT-EventQueue-0".
Looks like really serious problem. Our Debugger Window is definitely not a singleton. We have special instance for each workspace - at least. And for a future we would like to have more "Debugger Window" like component on one workspace too. I think you wanted something like this too. So, you will have probably the same problem, when somebody will open DW on some nonDebugger workspace :(( So what can we do. If you want to force to deserialize Debugger Window before you switch to debuger workspace, you can ask WindowManager for all debugger workspace, and d.workspace for "debugger" mode, and debugger mode for all TopComponents. It should fix your problem. But if you really want to have only one instance of some view, you should create some wrapper component. So you will have one wrapper component for each workspace, you will listen on current one and move your one inner component to it. Hanz
I think the problem is something else. I've earlier identified that DebuggerWindowPerformer and DebuggerViewAction can get "out of sync"; DebuggerWindowPerformer is supposed to enforce that only a single debugger window exists -per workspace-, but DebuggerViewAction can violate that. Today I was able to reproduce the problem again, and this time it's a slightly different flavor. Luckily, I still had my "Thread.dumpStack" and "Thread.currentThread().getName()" output calls in the DebuggerWindow's constructor, so I could see the order and why two debugger windows were created on the same workspace. FIRST, the window system deserializes the saved window state, which in turn results in a DebuggerWindow getting created, on the AWT thread. This is all correct. But THEN, DebuggerWindowPerformer gets called. It checks its map to see if there is a DebuggerWindow stored for the current workspace, and since there isn't, it too creates a new window!!! (I'll show the two stack traces below). The problem is that DebuggerWindowPerformer does not know about the DebuggerWindow which is created by the window system deserialization! I see a couple of different possible solutions here: (1) Instead of DebuggerWindowPerformer.getDebuggerWindow having its own record of debugger windows, just look it up from the window system each time (workspace -> findMode -> getTopComponents) (2) (better) Like the code works today, but in the case where you get null back from the debuggerWindow HashMap, THEN go look in the window system to see if the window exists. (3) In the DebuggerWindow class itself, update the DebuggerWindowPerformer hashmap every time a new debugger window is created. Here's a patch to DebuggerWindowPerformer which implements solution #2: --- DebuggerWindowPerformer.java 4 Jan 2002 13:53:22 -0000 1.9.2.3 +++ DebuggerWindowPerformer.java 8 Mar 2002 22:18:34 -0000 @@ -59,6 +59,23 @@ DebuggerWindow dw = (DebuggerWindow) debuggerWindow.get (w); if (dw == null) { + // Let's make doubly sure that the window has NOT been created. + Workspace ws = TopManager.getDefault().getWindowManager(). + getCurrentWorkspace(); + org.openide.windows.Mode mode = + ws.findMode("debugger"); // NOI18N - from debugger.wsmode + if (mode != null) { + TopComponent[] tcs = mode.getTopComponents(); + for (int i = 0; i < tcs.length; i++) { + if (tcs[i] instanceof DebuggerWindow) { + // Yes, window already exists on workspace! + DebuggerWindow dw = (DebuggerWindow)tcs[i]; + debuggerWindow.put (w, dw); + return dw; + } + } + } + dw = new DebuggerWindow (); debuggerWindow.put (w, dw); //S ystem.out.println ("DebuggerWindowPerformer.getDebuggerWindow (new DW created) return: " + dw.hashCode () + " :for " + w); Here are the trace messages when the problem manifested itself on my system: Name of executing thread is AWT-EventQueue-0 java.lang.Exception: Stack trace at java.lang.Thread.dumpStack(Thread.java:1071) at org.netbeans.modules.debugger.support.nodes.DebuggerWindow.<init>(DebuggerWindow.java:117) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:274) at org.openide.windows.TopComponent$Replacer.readObject(TopComponent.java:757) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:809) at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1733) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1636) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1264) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:322) at org.openide.loaders.XMLSettingsSupport$SettingsRecognizer.readSerial(XMLSettingsSupport.java:400) at org.openide.loaders.XMLSettingsSupport$SettingsRecognizer.instanceCreate(XMLSettingsSupport.java:430) at org.openide.loaders.InstanceDataObject$SettingsInstance.instanceCreate(InstanceDataObject.java:1215) at org.netbeans.core.windows.PersistenceManager.lookupTCInstance(PersistenceManager.java:350) at org.netbeans.core.windows.WindowManagerImpl.lookupTCInstance(WindowManagerImpl.java:877) at org.netbeans.core.windows.layers.TCRefImpl.getTopComponent(TCRefImpl.java:357) at org.netbeans.core.windows.layers.TCRefImpl.updateMode(TCRefImpl.java:198) at org.netbeans.core.windows.layers.ModeData$CookiesImpl.addComponents(ModeData.java:764) at org.netbeans.core.windows.layers.ModeData$CookiesImpl.updateComponents(ModeData.java:629) at org.netbeans.core.windows.layers.ModeData$CookiesImpl.updateAll(ModeData.java:401) at org.netbeans.core.windows.layers.ModeData$CookiesImpl.loadDataSection(ModeData.java:1067) at org.netbeans.core.windows.ModeImpl.ensureSectionLoaded(ModeImpl.java:2099) at org.netbeans.core.windows.ModeImpl.doGetTopComponents(ModeImpl.java:779) at org.netbeans.core.windows.ModeImpl.getTopComponents(ModeImpl.java:766) at org.netbeans.core.windows.WorkspaceImpl.findMode(WorkspaceImpl.java:571) at org.openide.text.CloneableEditor.openOnOtherWorkspaces(CloneableEditor.java:724) at org.openide.text.CloneableEditor.open(CloneableEditor.java:279) at org.openide.windows.TopComponent.open(TopComponent.java:199) at org.openide.windows.CloneableOpenSupport.openCloneableTopComponent(CloneableOpenSupport.java:159) at org.openide.windows.CloneableOpenSupport$1.run(CloneableOpenSupport.java:67) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:178) at java.awt.EventQueue.dispatchEvent(EventQueue.java:443) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:190) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:144) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:130) at java.awt.EventDispatchThread.run(EventDispatchThread.java:98) Name of executing thread is AWT-EventQueue-0 java.lang.Exception: Stack trace at java.lang.Thread.dumpStack(Thread.java:1071) at org.netbeans.modules.debugger.support.nodes.DebuggerWindow.<init>(DebuggerWindow.java:117) at org.netbeans.modules.debugger.support.actions.DebuggerWindowPerformer.getDebuggerWindow(DebuggerWindowPerformer.java:62) at com.sun.forte.st.ipe.debugger.IpeDebugger.continueStartup(IpeDebugger.java:672) at com.sun.forte.st.ipe.debugger.IpeDebugger$2.run(IpeDebugger.java:657) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:178) at java.awt.EventQueue.dispatchEvent(EventQueue.java:443) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:190) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:144) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:130) at java.awt.EventDispatchThread.run(EventDispatchThread.java:98)
P.S. Line 72 of DebuggerWindowPerformer.java (-after- applying the patch) should begin "dw =", not "DebuggerWindow dw =". Sorry.
Can this be fixed for 3.3.2? The bug is causing lots of problems in Orion EE. At JavaOne next week the demo people have been taught to restart the IDE repeatedly until the race condition does not manifest itself. This is obviously not a good situation :-) I believe my suggested fix above works, and that it additionally adds no risk to your debugger - it simply enforces something the code already assumes to be true (which I've observed is not always true, and in that case it takes corrective action; it makes sure there is only one debugger window on a particular workspace.)
fixed in main trunk and orion_fcs
Verified.
Resolved for 3.3.x or earlier, no new info since then -> closing.