Bug 190041 - [69cat] IllegalStateException: The model is not initialized or is broken.
[69cat] IllegalStateException: The model is not initialized or is broken.
Status: VERIFIED FIXED
Product: projects
Classification: Unclassified
Component: Maven
6.x
All All
: P2 (vote)
: 7.0
Assigned To: Jesse Glick
issues@projects
EXCEPTIONS_REPORT
: 70_HR_FIX
: 185975 (view as bug list)
Depends on: 197208
Blocks: 157599
  Show dependency treegraph
 
Reported: 2010-08-31 18:57 UTC by athompson
Modified: 2011-04-14 11:55 UTC (History)
16 users (show)

See Also:
Issue Type: DEFECT
:


Attachments
stacktrace (2.06 KB, text/plain)
2010-08-31 18:57 UTC, athompson
Details
stacktrace (2.06 KB, text/plain)
2010-11-04 11:53 UTC, J Bachorik
Details
stacktrace (2.06 KB, text/plain)
2010-12-27 12:09 UTC, Erno Mononen
Details
stacktrace (2.06 KB, text/plain)
2011-02-08 10:50 UTC, rdelaplante
Details
Patch following all advice in comment #23 which still does not work (4.21 KB, patch)
2011-03-24 23:15 UTC, Jesse Glick
Details | Diff
Patch following advice in comment #25 which also does not work (4.37 KB, patch)
2011-03-28 17:19 UTC, Jesse Glick
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description athompson 2010-08-31 18:57:29 UTC
This bug was originally marked as duplicate of bug 173469, that is already resolved. This bug is still valid, so this seems to be another bug, but it might be related.

Build: NetBeans IDE Dev (Build 201008280001)
VM: Java HotSpot(TM) Client VM, 16.3-b01, Java(TM) SE Runtime Environment, 1.6.0_20-b02
OS: Windows 7

User Comments:
athompson: refreshed an SQL command




Stacktrace: 
java.lang.IllegalStateException: The model is not initialized or is broken.
   at org.netbeans.modules.xml.xdm.XDMModel.checkStableOrParsingState(XDMModel.java:1001)
   at org.netbeans.modules.xml.xdm.XDMModel.getDocument(XDMModel.java:839)
   at org.netbeans.modules.xml.xdm.nodes.NodeImpl.getNamespaceURI(NodeImpl.java:604)
   at org.netbeans.modules.maven.model.pom.impl.POMComponentFactoryImpl.getQName(POMComponentFactoryImpl.java:66)
   at org.netbeans.modules.maven.model.pom.impl.POMComponentFactoryImpl.create(POMComponentFactoryImpl.java:84)
   at org.netbeans.modules.maven.model.pom.impl.POMComponentFactoryImpl.create(POMComponentFactoryImpl.java:54)
Comment 1 athompson 2010-08-31 18:57:33 UTC
Created attachment 101789 [details]
stacktrace
Comment 2 J Bachorik 2010-11-04 11:53:20 UTC
Created attachment 102796 [details]
stacktrace

editing a pom
Comment 3 Erno Mononen 2010-12-27 12:09:44 UTC
Created attachment 104520 [details]
stacktrace

Editing pom.xml - switched to another window for a second, then back to pom.xml and got the exception.
Comment 4 rdelaplante 2011-02-08 10:50:35 UTC
Created attachment 105730 [details]
stacktrace

I'm editing Maven pom.xml and am not finished typing XML so it is incorrect.  I think I switched tabs to look at something else, then came back to this pom.xml editor and got this exception.
Comment 5 Exceptions Reporter 2011-02-08 10:50:50 UTC
This bug already has 20 duplicates 
see http://statistics.netbeans.org/exceptions/detail.do?id=172265
Comment 6 Petr Jiricka 2011-03-09 13:32:43 UTC
Jesse, do you have an idea whether the fix needs to be on the XDM side or the Maven side?
Comment 7 Jesse Glick 2011-03-09 16:47:06 UTC
Don't know. No known way to reproduce; not sure what the error really means, or what the caller is supposed to do about it. Need some advice from the maintainer of XDM, or perhaps XDM can just not throw an exception here - return an empty Document and log a warning, perhaps.
Comment 8 Denis Anisimov 2011-03-14 17:59:44 UTC
This is not XML functionality issue but the client issue .
The client here is : maven.grammar module.
org.netbeans.modules.maven.navigator.POMModelVisitor.visit(Project)  method 
is applied to the invalid model.
As result an exception appears.

Visitor should not be applied at all if model is broken .
So the problem originally in the method rescan of the POMModelVisitor.
Its implementation looks very strange.
Comment 9 Jesse Glick 2011-03-14 22:21:41 UTC
As I am not the author of this code I have little idea what it is doing. The fixes of bug #161559 and bug #160657 may be related. My only guess is that in visit, model.sync() fails and the model is still invalid. I can try to defend against that but I don't really know whether it will solve anything.
Comment 10 Jesse Glick 2011-03-14 22:35:34 UTC
core-main #a39b2899f195
Comment 11 Denis Anisimov 2011-03-15 07:33:22 UTC
>As I am not the author of this code I have little idea what it is doing.
Sure, so am I.

Jesse, sync is not intended to "fix" model .
It could have invalid state before sync and valid state after sync.
It is also possible to have VALID state before sync and invalid state after 
sync.
sync is the method which is called to synchronize the XML model with XML content.
XML content could be invalid in the process of editing : one can start to type 
some text and f.e. don't close some tag.
In this case "sync" will set the state of the model which will differs from valid state.
"sync" is not called each time usually. The model is synced with the underlying
document in the DataObject/editor support code. F.e. on switching between  TopComponents editor/designer or move the focus to the some other UI component.
No need to do it each time in the client.

Visitor could do the sync ( this is not a problem because it uses the "dirty" flag ) but it should check state against VALID value BEFORE call model methods.

About the fix : Level.WARNING will open the special dialog with error message.
Probably this is not a best solution. It fixes the exception dialog but there are 
still a problem: user will get an error each time when it switches between 
different UI component in case its XML file has invalid state.

The common practice in similar situation : this is MVC whith several viewers.
Usually the viewers are Design view , navigator view, ....
Each time when user switches between these views and Editor "sync" should be 
called.
In case of XML model has no valid state Views are marked with some message :
"Model is not well formed" ( or smth. else ) or viewer replace all it content
to the empty content. When model switches back to the VALID state all views 
are rerendered respectively.
Such approach allows to avoid annoying error message which will shown each time
on switching between different UI components with broken XML : yes  the XML 
is broken and user knows about it ( see the comments in the bug ) but user 
don't want to see this error each time .
Comment 12 Denis Anisimov 2011-03-15 07:38:30 UTC
Sorry , this phrase is bad:
>The model is synced with the underlying
document in the DataObject/editor support code. 

I don't know details of the implementation in that case.
But this is the common practice .
So please replace this phrase to the :

The common practice is sync the model with the underlying
document in the DataObject/editor support code.
Comment 13 Quality Engineering 2011-03-15 09:49:05 UTC
Integrated into 'main-golden', will be available in build *201103150400* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)
Changeset: http://hg.netbeans.org/main/rev/a39b2899f195
User: Jesse Glick <jglick@netbeans.org>
Log: #190041: [69cat] IllegalStateException: The model is not initialized or is broken.
Comment 14 Petr Jiricka 2011-03-15 09:50:48 UTC
Thanks a lot Denis and Jesse. As a P2 bug, this should be considered for transplanting to NB 7 release.
Comment 15 Jesse Glick 2011-03-15 20:13:26 UTC
(In reply to comment #11)
> "sync" is not called each time usually. [...]
> No need to do it each time in the client.

I am not sure why it is called here; hg annotate pointed to the two bugs I mentioned in comment #9.

> Level.WARNING will open the special dialog with error message.

It should not open any dialog, since there is no Throwable in the log record. One line will be printed to the log.

> user will get an error each time when it switches between 
> different UI component in case its XML file has invalid state.

I wish they did, because that would mean I could reproduce the original bug and verify a fix! But before making any changes I tried making the XML file (syntactically) invalid and switching to another tab; nothing happened. Now when I try again (after the attempted fix), I get the following strange behavior:

1. Make pom.xml invalid by deleting part of a close tag.

2. Switch to another tab.

3. Switch back to pom.xml. Still shows original content in navigator.

4. Delete the rest of the element affected by #1, so the POM is now valid (still unsaved).

5. Switch to another tab.

6. Switch back to pom.xml. Get ISE from ProjectImpl.getModelVersion again.

Maybe it was valid before the sync and invalid after?
Comment 16 Jesse Glick 2011-03-15 20:55:39 UTC
Checking the state outside of the if-block does not help. It is reported as VALID, and yet immediately afterwards the ISE is thrown.

The only thing I can find which suppresses the exception is actually going ahead and accessing the model, and just catching ISE. But then the POM model navigator is empty or incomplete even after you revert all modifications and save the now-valid POM; getting it to work again without restarting the IDE is tricky (reopening the document does not suffice and you have to make a series of edits).

So this is not a very attractive workaround. But I cannot figure out how to check for the XDMModel.status - which, confusingly, seems to be unrelated to the AbstractModel.state.
Comment 17 Jesse Glick 2011-03-15 20:56:41 UTC
core-main #4017ce92980a
Comment 18 Quality Engineering 2011-03-17 09:56:00 UTC
Integrated into 'main-golden', will be available in build *201103170400* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)
Changeset: http://hg.netbeans.org/main/rev/4017ce92980a
User: Jesse Glick <jglick@netbeans.org>
Log: #190041: [69cat] IllegalStateException: The model is not initialized or is broken.
Crude workaround, pending a way to inspect the model state before trying to use it.
Comment 19 Jesse Glick 2011-03-22 20:31:21 UTC
Denis could you review the fix please?
Comment 20 Denis Anisimov 2011-03-23 05:41:00 UTC
The reason of described confusing behavior could be synchronization 
which is done in the other thread. As result model could be valid at the time
when its state is asked but it will be invalid on the next call.
To exclude such possibility model actions should be called under model lock.

The code in the visitor method performs a number of model request. The model 
could be changed from the other thread before any of such requests.
It means that number of model calls should be atomic from the model point of view.

So the model transaction should be started before asking model state , then model
state should be asked. After this one can ask the model for the data and end transaction.

Probably this will exclude the behavior which you have described about "sync".

So there will be no need to catch ISE. 
But please acquire the model lock in any case:
see AbstractModel.startTransaction()

But please note that "sync" probably should be called outside of transaction
( I don't remember whether XAM transactions could be nested ).
Comment 21 Jesse Glick 2011-03-23 12:39:38 UTC
(In reply to comment #20)
> The reason of described confusing behavior could be synchronization 
> which is done in the other thread.

I do not think that is the cause. The problem is consistently reproducible using the steps given in comment #15, which would not likely be true if the cause were a race condition. (There could be some occurrences of the bug "in the field" which are in fact caused by an unrelated race condition, but I have to assume that the known steps to reproduce are in fact representative.)

> the model transaction should be started before asking model state

I tried this and it seems to have no effect. The transaction is successfully acquired but the ISE continues to be thrown.

diff --git a/maven.grammar/src/org/netbeans/modules/maven/navigator/POMModelVisitor.java b/maven.grammar/src/org/netbeans/modules/maven/navigator/POMModelVisitor.java
--- a/maven.grammar/src/org/netbeans/modules/maven/navigator/POMModelVisitor.java
+++ b/maven.grammar/src/org/netbeans/modules/maven/navigator/POMModelVisitor.java
@@ -107,6 +107,7 @@
 import org.netbeans.modules.maven.model.pom.Scm;
 import org.netbeans.modules.maven.model.pom.Site;
 import org.netbeans.modules.maven.model.pom.StringList;
+import org.netbeans.modules.xml.xam.Component;
 import org.netbeans.modules.xml.xam.Model;
 import org.openide.nodes.AbstractNode;
 import org.openide.nodes.Children;
@@ -1481,7 +1482,11 @@
                         continue;
                     }
                     synchronized (i < models.length ? models[i] : /*#192042*/new Object()) {
+                        Component<?> c = (Component<?>) cut;
+                        boolean gotIt = c.getModel().startTransaction();
+                        System.err.println("XXX startTransaction on " + c + " -> " + gotIt);
                         m.invoke(visitor, cut);
+                        c.getModel().endTransaction();
                     }
                 }
             } catch (Exception x) {
Comment 22 Denis Anisimov 2011-03-23 18:41:00 UTC
OK then.

I've reviewed it and agree with fix.
Comment 23 Denis Anisimov 2011-03-23 20:35:56 UTC
Jesse , I'm sorry but it seems I've understood the problem with ISE.

The XAM/XDM models are used widely and there is no such problem in any 
other domain specific model in case of correct usage.

I believe this is the consequence of the incorrect model usage.

The problem here as I understand : Project element becomes orphaned.
As result it is incorrect to ask it about data.
This is exactly the scenario your have  described :
when model becomes invalid it could be recreated from the scratch on sync() request.
It means that elements from the previous model state could become orphaned 
( the underlying XDM in that case will be replaced with new root reference and 
old XDM could have invalid state). It seems this is exactly the case.

This is consequence of bad POMModelVisitor design : visitor should keep model
reference instead of its root element which could be not valid.

It's not a good time to completely reimplement navigator in appropriate way ,
but I would suggest to do the following :
Component<?> c = (Component<?>) cut;
model = c.getModel();
model.startTransaction();
if ( model.getState() == State.VALID ){
   Project project = (Project)model.getRootComponent(); 
   visit( project );
}
model.endTransaction();

Even if cut is orphaned it should still has the original reference to the 
XML model ( which is always the same ). And then one can get root XML element
which is valid with valid underlying XDM model if XAM model state is VALID.

This approach should work for Project element which is root .
But as I understand the same problem could be with any descendant element.

So before call methods on the element it should be verified via "isInDocumentModel()" method.
Such verification is done in the beginning of the visit(Project) method
but it is supposed that "sync()" and check state of the model will 
give element "in the model". This proposition is wrong.

So as result I object from catching an ISE.
Please review the code from this information perspective.
Comment 24 Jesse Glick 2011-03-24 23:15:22 UTC
Created attachment 107265 [details]
Patch following all advice in comment #23 which still does not work

I think I did every check you recommend, but the ISE continues to be thrown under the same conditions.
Comment 25 Denis Anisimov 2011-03-25 05:26:27 UTC
As I see you didn't modify the visit methods and check the state of the model
before start transaction.

Please move check model state and "isInDocumentModel()" inside transaction.
If you still think there is need in "sync()" method then "isInDocumentModel()" 
should be called AFTER "sync" is called and right before any model access data
methods are called ( i.e. before "t.getModelVersion()" in project case ).
It will exclude race conditions.

In case it will not work I can't imagine other reasons for ISE and let 
use the fix you suggested.
Comment 26 Jesse Glick 2011-03-28 17:19:23 UTC
Created attachment 107344 [details]
Patch following advice in comment #25 which also does not work

Since the bug is easily reproducible, I would appreciate an investigation into the root cause so that I can offer some fix better than catching ISE. I could try to look into it myself, but I guess that you (Denis) know more about XAM/XDM internals even if you are not the original author.

(a) What would cause the XDMModel to be in Status.BROKEN? Obviously that I typed in malformed XML - but then why is the Model in State.VALID? (It is confusing that there are two different kinds of "model", each with its own state enumeration.)

(b) Is there some way that client code can check the XDMModel status other than by trying an operation and catching ISE?
Comment 27 Denis Anisimov 2011-03-28 18:59:21 UTC
(In reply to comment #26)
> Created an attachment (id=107344) [details]
> Patch following advice in comment #25 which also does not work
> 
> Since the bug is easily reproducible,
No I can't reproduce your scenario.
Only once I have been able to get ISE but the steps were different and I can't
repeat them again.
Please provide exact steps : each UI action , what exactly content needs to 
be deleted in the pom.xml , what tabs have been used.
> I would appreciate an investigation into
> the root cause so that I can offer some fix better than catching ISE. I could
> try to look into it myself, but I guess that you (Denis) know more about
> XAM/XDM internals even if you are not the original author.
> 
> (a) What would cause the XDMModel to be in Status.BROKEN? Obviously that I
> typed in malformed XML - but then why is the Model in State.VALID? (It is
> confusing that there are two different kinds of "model", each with its own
> state enumeration.)
I can't say the exact reason but I believe there are design reasons for this:
XDM model is just XML representation ( very close to parser ). It performs 
reading the XML file content.  Its state is parsing state.
XAM state is domain model specific state which is logical level state .
It differs from parsing state.
> 
> (b) Is there some way that client code can check the XDMModel status other than
> by trying an operation and catching ISE?
As I understand XDMModel is not intended for user usage at all. Model client 
should use top level XAM model . Only XAM based model state should be used 
in client code. XDM model iteslf and its status are "implementation" 
which is somehow synchronized with XAM state.
ISE in the XDM is result an incorrect model usage: contract of model API 
is broken ( as I already have mentioned it could f.e. result access to data 
of orphaned model elements ).
Comment 28 Jesse Glick 2011-03-28 19:51:44 UTC
*** Bug 185975 has been marked as a duplicate of this bug. ***
Comment 29 Jesse Glick 2011-03-28 20:00:00 UTC
(In reply to comment #27)
> Please provide exact steps : each UI action , what exactly content needs to 
> be deleted in the pom.xml , what tabs have been used.

As in comment #15, it is easy. Open any Maven project; make sure Navigator is displayed. Under Important Files, open pom.xml and settings.xml (or just any unrelated file). In pom.xml, delete say the '>' at the end of the tag; switch to another file; switch back to pom.xml; delete the entire broken tag; switch to another file; switch back to pom.xml once more -> ISE is thrown (suppressed in trunk but a warning printed to console). It is a little counterintuitive because the ISE occurs when refreshing the navigator view after you have _fixed_ the syntax error.

> ISE in the XDM is result an incorrect model usage: contract of model API 
> is broken (as I already have mentioned it could f.e. result access to data 
> of orphaned model elements).

That is fine but the incorrect model usage needs to somehow be reported more meaningfully; either some way to reliably check that a given model element is orphaned before accessing it (isInDocumentModel does not seem to suffice), or an exception thrown earlier when some mistake was made which corrupted internal state.
Comment 30 Denis Anisimov 2011-03-29 06:30:15 UTC
I'm still not able to reproduce the issue with steps your suggested.
So it is not so easy. Two builds are used : with catching ISE and without.
No console messages and no ISE .

The scenario which I've used:
1) Create Maven Web project.
2) Open pom.xml : it is opened in the editor pane and Navigator is visible
3) Open index.jsp : it is opened in the editor
4) Switch to the pom.xml  and delete ">" in the closing tag for "artifactId" 
element ( "</artifactId>" becomes "</artifactId" ).
5) Switch to the index.jsp.
6) Switch back and delete all broken element "artifactId" ( 
"<artifactId>mavenproject2</artifactId" becomes "" ).
7) Switch to index.jsp
8) Switch back.

No any error in the result.
Comment 31 Jesse Glick 2011-03-29 13:37:52 UTC
(In reply to comment #30)
> The scenario which I've used:
> [...]
> No any error in the result.

Strange. I try these exact steps in a cluster.config=standard dev build on a fresh userdir (Ubuntu, JDK 6) and get

WARNING [org.netbeans.modules.maven.navigator.POMModelVisitor]: #190041: invalid model: java.lang.IllegalStateException: The model is not initialized or is broken.

I do not get anything on XP however. Is there any possible platform difference here? The bug is consistently reproducible for me on Ubuntu so a timing issue seems unlikely.

Since there's not time to investigate further for 7.0, I will just put in the catch-ISE fix for now: releases #4ca91a74ee80 & releases #2693ab3bc160
Comment 32 Denis Anisimov 2011-03-29 13:47:04 UTC
(In reply to comment #31)
> (In reply to comment #30)
> > The scenario which I've used:
> > [...]
> > No any error in the result.
> 
> Strange. I try these exact steps in a cluster.config=standard dev build on a
> fresh userdir (Ubuntu, JDK 6) and get
> 
> WARNING [org.netbeans.modules.maven.navigator.POMModelVisitor]: #190041:
> invalid model: java.lang.IllegalStateException: The model is not initialized or
> is broken.
> 
> I do not get anything on XP however. Is there any possible platform difference
> here? The bug is consistently reproducible for me on Ubuntu so a timing issue
> seems unlikely.
Exactly , I can't reproduce it on Win 7 either.
> 
> Since there's not time to investigate further for 7.0, I will just put in the
> catch-ISE fix for now: releases #4ca91a74ee80 & releases #2693ab3bc160
I agree.
Comment 33 Denis Anisimov 2011-03-29 13:49:12 UTC
(In reply to comment #32)
> > Is there any possible platform difference
> > here? The bug is consistently reproducible for me on Ubuntu so a timing issue
> > seems unlikely.
I can't imagine any platform dependency issue ( except race condition as result
of different Java threads implementation ).
Comment 34 Jesse Glick 2011-03-29 14:48:06 UTC
So setStatus is initially called five times when opening a valid POM: UNPARSED -> PARSING -> UNPARSED -> PARSING -> STABLE. After breaking it and switching to another tab, and back, nothing happens. After fixing it and switching to another tab, it goes -> PARSING -> STABLE -> BROKEN.

(Actually you do not even have to delete the <artifact>...</>; it suffices to just _select_ it, so it is possible to reproduce this without switching editor tabs at all; just necessary to e.g. switch POM model -> POM inheritance and back to trigger refresh of the navigator content.)

Meanwhile, after the XDMModel is set to BROKEN, the POMModelImpl goes from its initial VALID to NOT_WELL_FORMED and immediately back to VALID. The tops of stack traces after the edit is made:

-> PARSING
	at org.netbeans.modules.xml.xdm.XDMModel.setStatus(XDMModel.java:1008)
	at org.netbeans.modules.xml.xdm.XDMModel.prepareSync(XDMModel.java:178)
	at org.netbeans.modules.xml.xdm.XDMModel.sync(XDMModel.java:161)
	at org.netbeans.modules.xml.xdm.xam.XDMAccess.sync(XDMAccess.java:156)
	at org.netbeans.modules.xml.xam.AbstractModel.sync(AbstractModel.java:285)
	at org.netbeans.modules.maven.hints.pom.StatusProvider$StatusProviderImpl.findHints(StatusProvider.java:196)
-> STABLE
	at org.netbeans.modules.xml.xdm.XDMModel.setStatus(XDMModel.java:1008)
	at org.netbeans.modules.xml.xdm.XDMModel.prepareSync(XDMModel.java:198)
-> BROKEN
	at org.netbeans.modules.xml.xdm.XDMModel.setStatus(XDMModel.java:1008)
	at org.netbeans.modules.xml.xdm.XDMModel.finishSync(XDMModel.java:212)
	at org.netbeans.modules.xml.xdm.XDMModel.sync(XDMModel.java:163)
-> NOT_WELL_FORMED
	at org.netbeans.modules.xml.xam.AbstractModel.setState(AbstractModel.java:212)
	at org.netbeans.modules.xml.xam.AbstractModel.sync(AbstractModel.java:289)
-> VALID
	at org.netbeans.modules.xml.xam.AbstractModel.setState(AbstractModel.java:212)
	at org.netbeans.modules.xml.xam.dom.AbstractDocumentModel.refresh(AbstractDocumentModel.java:628)
	at org.netbeans.modules.maven.model.pom.POMModel.refresh(POMModel.java:68)
	at org.netbeans.modules.maven.hints.pom.StatusProvider$StatusProviderImpl.findHints(StatusProvider.java:197)

So the extra call to refresh might be the problem. I suspect that refresh is just not implemented correctly; it sets the XAM model state to valid but does not change the XDM model state.

In fact it looks like bug #157599 was fixed earlier and this bug is just the special case when there is a text selection. I can try to make an analogous fix in trunk; not sure if it ought to be backported to release70 or not: core-main #e1e6dbb60405
Comment 35 Quality Engineering 2011-03-30 08:44:32 UTC
Integrated into 'main-golden', will be available in build *201103300400* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)
Changeset: http://hg.netbeans.org/main/rev/e1e6dbb60405
User: Jesse Glick <jglick@netbeans.org>
Log: Alternate fix of #190041: ISE from POM model navigator.
Comment 36 Tomas Danek 2011-04-14 11:55:39 UTC
not able to reproduce -> verified.

Product Version: NetBeans IDE 7.0 (Build 201104080000)
Java: 1.6.0_24; Java HotSpot(TM) 64-Bit Server VM 19.1-b02-334
System: Mac OS X version 10.6.7 running on x86_64; MacRoman; en_US (nb)
Userdir: /Users/tomas/.netbeans/7.0


By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo