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.

Bug 236401 - TopComponent.Description annotation does not escape TopComponent ID when generating layer entries
Summary: TopComponent.Description annotation does not escape TopComponent ID when gene...
Status: RESOLVED FIXED
Alias: None
Product: platform
Classification: Unclassified
Component: Window System (show other bugs)
Version: 7.3.1
Hardware: PC Windows 7
: P3 normal (vote)
Assignee: Stanislav Aubrecht
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-09-26 07:21 UTC by jmborer
Modified: 2013-09-27 02:12 UTC (History)
0 users

See Also:
Issue Type: DEFECT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description jmborer 2013-09-26 07:21:43 UTC

    
Comment 1 jmborer 2013-09-26 07:23:19 UTC
When you create a new TopComponent, the PersistenceManager creates a
new ID based on the preferredID for later retrieval. It escapes a lot
of reserved chars like " ", "/", "." and so on. Here is the stack:

"AWT-EventQueue-1"
org.openide.loaders.InstanceDataObject.escapeAndCut(InstanceDataObject.java:983)
sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.netbeans.core.windows.persistence.PersistenceManager.escape(PersistenceManager.java:910)
org.netbeans.core.windows.persistence.PersistenceManager.createTopComponentPersistentID(PersistenceManager.java:976)
org.netbeans.core.windows.persistence.PersistenceManager.getGlobalTopComponentID(PersistenceManager.java:498)
org.netbeans.core.windows.WindowManagerImpl.topComponentID(WindowManagerImpl.java:1411)
org.openide.windows.WindowManager.findTopComponentID(WindowManager.java:551)
org.netbeans.core.windows.model.TopComponentSubModel.getID(TopComponentSubModel.java:382)
org.netbeans.core.windows.model.TopComponentSubModel.containsTopComponent(TopComponentSubModel.java:278)
org.netbeans.core.windows.model.DefaultModeModel.containsTopComponent(DefaultModeModel.java:348)
org.netbeans.core.windows.model.DefaultModel.containsModeTopComponent(DefaultModel.java:911)
org.netbeans.core.windows.Central.containsModeTopComponent(Central.java:1558)
org.netbeans.core.windows.ModeImpl.containsTopComponent(ModeImpl.java:431)
org.netbeans.core.windows.WindowManagerImpl.findMode(WindowManagerImpl.java:579)
org.netbeans.core.windows.WindowManagerImpl.getMode(WindowManagerImpl.java:1588)
org.netbeans.core.windows.WindowManagerImpl.topComponentOpenAtTabPosition(WindowManagerImpl.java:1229)
org.netbeans.core.windows.WindowManagerImpl.topComponentOpen(WindowManagerImpl.java:1217)
org.openide.windows.TopComponent.open(TopComponent.java:497)
org.openide.windows.TopComponent.open(TopComponent.java:477)

Later on, when you try to find the component by ID it will, try to
find in a hashmap, if your component exists, but WITHOUT ESCAPING the
ID:

AWT-EventQueue-1"
org.netbeans.core.windows.persistence.PersistenceManager.getTopComponentPersistentForID(PersistenceManager.java:531)
org.netbeans.core.windows.persistence.PersistenceManager.getTopComponentForID(PersistenceManager.java:681)
org.netbeans.core.windows.PersistenceHandler.getTopComponentForID(PersistenceHandler.java:489)
org.netbeans.core.windows.WindowManagerImpl.getTopComponentForID(WindowManagerImpl.java:957)
org.netbeans.core.windows.WindowManagerImpl.findTopComponent(WindowManagerImpl.java:292)
ch.skyguide.nimbus.console.explorer.node.ServiceInstanceNode$5.open(ServiceInstanceNode.java:109)

Unfortunately, my preferredID contained chars that where escaped and
therefore findTopComponent was never able to find my TopComponent
again. When I remove all those chars, it works fine!

I think this is a bug. This will not work with singletons
TopComponents either where their ID contains chars to escape. You can
try to reproduce it: it fails to load your singleton (at least mine
does).

To repeast the problem, try the following: create a singleton TC and set its preferredID to
something that contains "." like "my.preferredTC". It will not work.

WindowManager.findTopCompoentID should lookup the TC not by using the
key you provide, but first escape it like when it is stored in the
map. Otherwise you won't be able to find it, even the singleton...
Comment 2 jmborer 2013-09-26 07:42:09 UTC
Stan, 

I don't know why you want to escape the key provided in the annotation. This won't fix the findTopComponent() issue.

If I create a TopCompnent, say with the following ID: base-service_1-127.0.0.1,
it will be escaped by InstanceDataObject for later persitency to base-service_1_127#002E0#002E0#002E1.

This escaped key is kept in a map in the PersistencyManager. Later on, when you try to find your component through WindowManager.findTopComponent() whith the only key you know which is base-service_1-127.0.0.1, WindowManager will ask the PersistencyManager to return the TC with this ID. Of course it won't find since it is stored in its escape version.
Comment 3 Stanislav Aubrecht 2013-09-26 07:48:46 UTC
(In reply to jmborer from comment #2)
> Stan, 
> 
> I don't know why you want to escape the key provided in the annotation. This
> won't fix the findTopComponent() issue.
> 
> If I create a TopCompnent, say with the following ID:
> base-service_1-127.0.0.1,
> it will be escaped by InstanceDataObject for later persitency to
> base-service_1_127#002E0#002E0#002E1.
> 
> This escaped key is kept in a map in the PersistencyManager. Later on, when
> you try to find your component through WindowManager.findTopComponent()
> whith the only key you know which is base-service_1-127.0.0.1, 
That is not the ID of that component, the real ID is base-service_1_127#002E0#002E0#002E1
Comment 4 jmborer 2013-09-26 07:55:29 UTC
(In reply to Stanislav Aubrecht from comment #3)
> (In reply to jmborer from comment #2)
> > Stan, 
> > 
> > I don't know why you want to escape the key provided in the annotation. This
> > won't fix the findTopComponent() issue.
> > 
> > If I create a TopCompnent, say with the following ID:
> > base-service_1-127.0.0.1,
> > it will be escaped by InstanceDataObject for later persitency to
> > base-service_1_127#002E0#002E0#002E1.
> > 
> > This escaped key is kept in a map in the PersistencyManager. Later on, when
> > you try to find your component through WindowManager.findTopComponent()
> > whith the only key you know which is base-service_1-127.0.0.1, 
> That is not the ID of that component, the real ID is
> base-service_1_127#002E0#002E0#002E1

Sure I agree. But you, in your code, you only know the unescaped ID. 

Again, if I write in my TC:

@TopComponent.Description(
        preferredID = "base-service_1-127.0.0.1",
        persistenceType = TopComponent.PERSISTENCE_ALWAYS)

And later on, for example in an Action I try:

WindowManager.getDefault().findTopComponent("base-service_1-127.0.0.1");

I will get null, since the TC was stored with key base-service_1_127#002E0#002E0#002E1 which I can't know...
Comment 5 Stanislav Aubrecht 2013-09-26 09:08:26 UTC
(In reply to jmborer from comment #4)
> (In reply to Stanislav Aubrecht from comment #3)
> > (In reply to jmborer from comment #2)
> > > Stan, 
> > > 
> > > I don't know why you want to escape the key provided in the annotation. This
> > > won't fix the findTopComponent() issue.
> > > 
> > > If I create a TopCompnent, say with the following ID:
> > > base-service_1-127.0.0.1,
> > > it will be escaped by InstanceDataObject for later persitency to
> > > base-service_1_127#002E0#002E0#002E1.
> > > 
> > > This escaped key is kept in a map in the PersistencyManager. Later on, when
> > > you try to find your component through WindowManager.findTopComponent()
> > > whith the only key you know which is base-service_1-127.0.0.1, 
> > That is not the ID of that component, the real ID is
> > base-service_1_127#002E0#002E0#002E1
> 
> Sure I agree. But you, in your code, you only know the unescaped ID. 
> 
> Again, if I write in my TC:
> 
> @TopComponent.Description(
>         preferredID = "base-service_1-127.0.0.1",
>         persistenceType = TopComponent.PERSISTENCE_ALWAYS)

In this case you should see a warning like this in your IDE log: 

WARNING [org.netbeans.core.windows.persistence]: [WinSys.TCRefParser.handleTcId] Error: Value of attribute "id" of element "tc-id" and configuration file name must be the same: base-service_1-127.0.0.1 x base-service_1-127-0-0-1
INFO [org.netbeans.core.windows.persistence.ModeParser]
org.xml.sax.SAXException: Invalid attribute value
	at org.netbeans.core.windows.persistence.TCRefParser$PropertyHandler.handleTcId(TCRefParser.java:371)
	at org.netbeans.core.windows.persistence.TCRefParser$PropertyHandler.startElement(TCRefParser.java:281)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:506)
	at com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser.emptyElement(AbstractXMLDocumentParser.java:182)


It's because the annotation processor escapes the id for layer file names but does no escaping for the actual id atribute - so the window system complains and derives its own id then.

The annotation should not allow special chars in the preferred id to avoid problems like this.
Comment 6 jmborer 2013-09-26 11:13:50 UTC
(In reply to Stanislav Aubrecht from comment #5)
> (In reply to jmborer from comment #4)
> > (In reply to Stanislav Aubrecht from comment #3)
> > > (In reply to jmborer from comment #2)
> > > > Stan, 
> > > > 
> > > > I don't know why you want to escape the key provided in the annotation. This
> > > > won't fix the findTopComponent() issue.
> > > > 
> > > > If I create a TopCompnent, say with the following ID:
> > > > base-service_1-127.0.0.1,
> > > > it will be escaped by InstanceDataObject for later persitency to
> > > > base-service_1_127#002E0#002E0#002E1.
> > > > 
> > > > This escaped key is kept in a map in the PersistencyManager. Later on, when
> > > > you try to find your component through WindowManager.findTopComponent()
> > > > whith the only key you know which is base-service_1-127.0.0.1, 
> > > That is not the ID of that component, the real ID is
> > > base-service_1_127#002E0#002E0#002E1
> > 
> > Sure I agree. But you, in your code, you only know the unescaped ID. 
> > 
> > Again, if I write in my TC:
> > 
> > @TopComponent.Description(
> >         preferredID = "base-service_1-127.0.0.1",
> >         persistenceType = TopComponent.PERSISTENCE_ALWAYS)
> 
> In this case you should see a warning like this in your IDE log: 
> 
> WARNING [org.netbeans.core.windows.persistence]:
> [WinSys.TCRefParser.handleTcId] Error: Value of attribute "id" of element
> "tc-id" and configuration file name must be the same:
> base-service_1-127.0.0.1 x base-service_1-127-0-0-1
> INFO [org.netbeans.core.windows.persistence.ModeParser]
> org.xml.sax.SAXException: Invalid attribute value
> 	at
> org.netbeans.core.windows.persistence.TCRefParser$PropertyHandler.
> handleTcId(TCRefParser.java:371)
> 	at
> org.netbeans.core.windows.persistence.TCRefParser$PropertyHandler.
> startElement(TCRefParser.java:281)
> 	at
> com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.
> startElement(AbstractSAXParser.java:506)
> 	at
> com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser.
> emptyElement(AbstractXMLDocumentParser.java:182)
> 
> 
> It's because the annotation processor escapes the id for layer file names
> but does no escaping for the actual id atribute - so the window system
> complains and derives its own id then.
> 
> The annotation should not allow special chars in the preferred id to avoid
> problems like this.

It should also be clearly documented that findTopComponent() can and must only be used to find singleton TCs! Otherwise the result may not be predictable.

I am actually able to find a unique TC (say an editor TC), by building my own unique id and returning it through TC.preferredId(). It works when I use only valid chars. 

I know that I shouldn't do that if I want some persistency even though I think it can work at deserialization.

I am bit surprised that find an editor TC is not better documented or has appropriate APIs in NB. There are of course alternives (see our long thread) but any way, I still think there is lack in the API.
Comment 7 jmborer 2013-09-26 11:17:40 UTC
Stan,

Could you please explain why it would be wrong to escape the string you provide in WindowManager.findTopComponent()? Does it really hurt something? At least it would make things work better, no?
Comment 8 Stanislav Aubrecht 2013-09-26 12:12:12 UTC
core-main 946bdb69df5b
Comment 9 Stanislav Aubrecht 2013-09-26 12:18:28 UTC
(In reply to jmborer from comment #6)
> 
> It should also be clearly documented that findTopComponent() can and must
> only be used to find singleton TCs! Otherwise the result may not be
> predictable.
No, it works for any TopComponent but you must provide the actual ID obtained from WindowManager.findTopComponentID()

> 
> I am actually able to find a unique TC (say an editor TC), by building my
> own unique id and returning it through TC.preferredId(). It works when I use
> only valid chars. 
The fix for this issue does not allow special chars in TopComponent annotations.
> 
> I know that I shouldn't do that if I want some persistency even though I
> think it can work at deserialization.
> 
> I am bit surprised that find an editor TC is not better documented or has
> appropriate APIs in NB. There are of course alternives (see our long thread)
> but any way, I still think there is lack in the API.
Editor TCs are documents mostly so there's no need to know their exact winsys id. Just refer to the document file their displaying/editing to access that editor.
Comment 10 jmborer 2013-09-26 12:49:09 UTC
(In reply to Stanislav Aubrecht from comment #9)
> (In reply to jmborer from comment #6)
> > 
> > It should also be clearly documented that findTopComponent() can and must
> > only be used to find singleton TCs! Otherwise the result may not be
> > predictable.
> No, it works for any TopComponent but you must provide the actual ID
> obtained from WindowManager.findTopComponentID()

Only if you have a reference to TC to find, well you don't need to find it when you already have a reference to it, no? ;)

> 
> > 
> > I am actually able to find a unique TC (say an editor TC), by building my
> > own unique id and returning it through TC.preferredId(). It works when I use
> > only valid chars. 
> The fix for this issue does not allow special chars in TopComponent
> annotations.

Again, I am not complaining about the annotation, just the handling of WindowManager.findTopComponent(String). I am convinced it would fix the issue I describe (I reverse engineered the code).

> > 
> > I know that I shouldn't do that if I want some persistency even though I
> > think it can work at deserialization.
> > 
> > I am bit surprised that find an editor TC is not better documented or has
> > appropriate APIs in NB. There are of course alternives (see our long thread)
> > but any way, I still think there is lack in the API.
> Editor TCs are documents mostly so there's no need to know their exact
> winsys id. Just refer to the document file their displaying/editing to
> access that editor.

Yes, if your are working around a document, but when you build a NB RCP, it not always the case: you open one TC per data to edit or view. Looking for this data object is not always a good solution because the object might be exposed by another TC. For example in my case the active node on wich I double click also contains the object in its lookup and injects it into a new "editor" TC. Do you see my point?

Again. I know that I have alternatives. I am using them. It should be clearly documented that WindowManager.findTopComponent(String) should only be used with singleton then.
Comment 11 Quality Engineering 2013-09-27 02:12:29 UTC
Integrated into 'main-silver', will be available in build *201309270002* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)

Changeset: http://hg.netbeans.org/main-silver/rev/946bdb69df5b
User: S. Aubrecht <saubrecht@netbeans.org>
Log: #236401 - don't allow special chars in preferred id in TopComponent registration annotations