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.
When dock in to Mode works incorrectly and led unexpected behavior Steps 1 Create Module Project and add Window system API and UI Utilities API as dependencies 2 Add Action to it (Name = Mode Issue) 3 fill performAction() method with this code //get the Project TC TopComponent projectTC = WindowManager.getDefault().findTopComponent("projectTabLogical_tc"); //get before Id String beforId = WindowManager.getDefault().findTopComponentID(projectTC); System.out.println("Before Project TC ID : " + beforId); //find the output mode final Mode findMode = WindowManager.getDefault().findMode("output"); //dock in findMode.dockInto(projectTC); /*may be issue topcomponent need to open becouse dock in close the topcomponent */ projectTC.open(); //get after Id String afterId = WindowManager.getDefault().findTopComponentID(projectTC); System.out.println("After Project TC ID : " + afterId); 4 Run Application and invoke the Action Note that topcomponent Id change after Dock in and it will close (may be issue).Now close the application and restart Two Project Tc will Open I Create the Module Project I will attach it with this Issue
Created attachment 44802 [details] Project
P1 is reserved for crashes and data loss, lowering the priority. How do you run the application when it is not an application but netbeans module? Do you install the module into running NetBeans system? It's very strange use case to move with 'live' top components from another modules, why do you need it? Please describe your steps and motivation in exact details, thanks.
AFAIK Application or NetBeans system make no deference .I Just pick Project TC as a example what I have many Module in Platform Application that Providing different functionalities. The use case is One Module will handle window Layouts and allow user to create Custom views and switch between different views as needed. Even this is very strange use case Window System Is Core API and must react to specification. Doc says dockInto boolean dockInto(TopComponent c) Attaches a component to a mode for this workspace. If the component is in different mode on this workspace, it is removed from the original and moved to this one. Parameters: c - component Returns: true if top component was successfully docked to this mode, false otherwise so it must provide functionality what it documented right and even TopComponent unique ID can't be change after calling dockInto right .Here the steps again Steps 1 Create Module Project and add Window system API and UI Utilities API as dependencies 2 Add Action to it (Name = Mode Issue) 3 fill performAction() method with this code //get the Project TC TopComponent projectTC = WindowManager.getDefault().findTopComponent("projectTabLogical_tc"); //get before Id String beforId = WindowManager.getDefault().findTopComponentID(projectTC); System.out.println("Before Project TC ID : " + beforId); //find the output mode final Mode findMode = WindowManager.getDefault().findMode("output"); //dock in findMode.dockInto(projectTC); /*may be issue topcomponent need to open becouse dock in close the topcomponent */ projectTC.open(); //get after Id String afterId = WindowManager.getDefault().findTopComponentID(projectTC); System.out.println("After Project TC ID : " + afterId); 4 Run Module it will open new NetBeans system right then invoke the Action that we create Look at output window sop details unique ID got changed and after close and run module again will open two Project topcomponents that really unexpected behavior
I found the bug in Nb source (I think) whan calling dockInto() it calls its IMPL class "SOURCE_PATH"\core\windows\src\org\netbeans\core\windows\ModeImpl.java dockIntoImpl(final TopComponent tc, final boolean select) method. before dock it close TopComponent and remove from previous mode. to remove from previous mode it call method removeModeTopComponent(ModeImpl mode, TopComponent tc) in "SOURCE_PATH"\core\windows\src\org\netbeans\core\windows\Central.java In that method it call removeGlobalTopComponentID(String id) in "SOURCE_PATH"\core\windows\src\org\netbeans\core\windows\persistence\PersistenceManager.java that method clearly say "make sure you call this only on TCs that are NOT TC.PERSISTENT_ALWAYS" so thats the mistake so we need to make sure you call this only on TCs that are NOT TC.PERSISTENT_ALWAYS . So I create diff patch to Central.java .I'll attach that. (PS I didn't fill a Contributor Agreement. I'll do it today :))
Created attachment 46102 [details] PACH
Created attachment 46103 [details] PATCH
Created attachment 46104 [details] PATCH
sorry for mistake use last patch and ignore previous ones sorry
Created attachment 46150 [details] PATCH
I just attach better patch.I did find all usage go removeGlobalTopComponentID(String id) and make sure to call this only on TCs that are NOT TC.PERSISTENT_ALWAYS
Wow, thanks for the patch, it appears that it may be right one, I just need to verify and understand the code a bit more before integration. Ccing Marek who knows perhaps more about TopComponent IDs.
Created attachment 46215 [details] my version of the patch
theanuradha, it seems your findings were exact and good. I just simplified the patch a bit, because there is already a method WindowManagerImpl.isTopComponentPersistentWhenClosed which does the test. I verified that the patch works. I'm leaving on vacation right now, so Marek feel free to integrate if you want. But maybe the best solution would be also to add a check, perhaps even assertion into removeGlobalTopComponentID, to never call it on persistent TCs.
So Marek any comments about integrate the Patch ?
Do I understand problem correctly that TC ID generated for given TC instance is different second time it is registered in winsys? This is all wrong. Original issue #41272 introduced removeGlobalTopComponentID to avoid memory leak. (Internal map <String,WeakReference<TopComponent>> was not cleared when TopComponent instance was garbage collected. BUT this way is wrong as map should be cleared AFTER TopComponent instance was gc'ed. In current situation we remove ID from map and cache BEFORE TC is gc'ed. It can result in this behavior: ID assigned to TC second time is different from original TC ID because removeGlobalTopComponentID was called between. If this is the case I will close this issue, reopen issue #41272 and fix memory another way.
This issue will be solved with fix of #41272. I will close this issue as I verify this using provided test case. Probably I will write test for it too.
I think this issue #41272 introduced removeGlobalTopComponentID nothing to do with this issue because removeGlobalTopComponentID clearly say "make sure you call this only on TCs that are NOT TC.PERSISTENT_ALWAYS" so that's the mistake so we need to make sure you call this only on TCs that are NOT TC.PERSISTENT_ALWAYS .I think TC.PERSISTENT_ALWAYS Tc must hold reference to persist regardless of open or not .So My suggest is just make sure you call this only on TCs that are NOT TC.PERSISTENT_ALWAYS .
I explain issue in mode detail as it is closely related to TC instance lifecycle. Requirements for TC ID: 1.TC ID must be unique. 2.TC ID assigned to TC must stay fixed once it is assigned. This requirement is not so strong we could live without it but I believe this is reasonable and makes things clearer for user of Window System API. For always persistent TC it is quite simple. Usually such TC is singleton so once instantiated it is never gc'ed because singleton keeps strong reference to TC instance in its private static field. So this is root and TC cannot be gc'ed. For non persistent and peristent only opened it is more complex. Look at this use case: 1.Create TC instance at runtime. 2.You must somehow register TC instance with winsys eg. open TC or dock and open. 3.When you now close this TC removeGlobalTopComponentID will be invoked. It will deregister TC in winsys. 4.When you now open this TC again it will be again registered and possibly new TC ID different from previous one will be assigned by winsys to this TC even if this TC is not persistent. This is I want to avoid. My fix will release used TC ID AFTER Tc instance is gc'ed. I hope it is clearer now and you understand why I belive yoyur patch is not sufficient and it will solve problem only for persistent TC. In addition current impl of removeGlobalTopComponentID says it should be called only for non persistent TC but of course there is no check for it. Really error prone.
I explain issue in mode detail as it is closely related to TC instance lifecycle. Requirements for TC ID: 1.TC ID must be unique. 2.TC ID assigned to TC must stay fixed once it is assigned. This requirement is not so strong we could live without it but I believe this is reasonable and makes things clearer for user of Window System API. For always persistent TC it is quite simple. Usually such TC is singleton so once instantiated it is never gc'ed because singleton keeps strong reference to TC instance in its private static field. So this is root and TC cannot be gc'ed. For non persistent and peristent only opened it is more complex. Look at this use case: 1.Create TC instance at runtime. 2.You must somehow register TC instance with winsys eg. open TC or dock and open. 3.When you now close this TC removeGlobalTopComponentID will be invoked. It will deregister TC in winsys. 4.When you now open this TC again it will be again registered and possibly new TC ID different from previous one will be assigned by winsys to this TC even if this TC is not persistent. This is I want to avoid. My fix will release used TC ID AFTER Tc instance is gc'ed. I hope it is clearer now and you understand why I believe your patch is not sufficient and it will solve problem only for persistent TC. In addition current impl of removeGlobalTopComponentID says it should be called only for non persistent TC but of course there is no check for it. Really error prone.
Thanks For details. Now I got the issue.
Issue #41272 is fixed. I also run your test case and it works fine now. Please verify. Let me know if you find any problem. Thanks for catching this tricky issue.
verifyed