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 have found a significant issue with the Web module's WebContextObject class. Our module subclasses this DataObject and overrides its mountLib() method to add additional functionality before delegating to the superclass's implementation. We are occasionally seeing that our overridden version of mountLib() is actually being called before our subclass's constructor has completed, and when the object is not yet completely initialized. The root of the problem is the creation of classesMounterTask in setupContext(). This method is ultimately called by the WebContextObject's constructor in this roundabout fashion: WebContextObject.<init> WebContextObject.init() ProjectViewManager.notifyWebContext() WebContextObject.setupContext() classesMounterTask is an asynchronous task that is immediately scheduled to run on the default request processor thread. This task ultimately calls several methods on WebContextObject, including mountLib(). Occasionally, a race condition results in the classesMounterTask being scheduled to run ahead of the thread constructing our subclass. When this happens, mountLib() is called on our partially initialized object and our logic is affected adversely in subtle ways. The easiest fix for this problem would be to synchronize the constructor of our subclass so that the synchronized mountLib() method could not be called before the subclass is constructed. Unfortunately, it is not possible to synchronize to mountLib() or any other methods in WebContextObject because constructors cannot be declared synchronized in Java. Neither does WebContextObject provide access to its lock objects used to synchronize initialization of the context. These plus the fact that WebContextObject initiates a thread in its constructor makes us conclude that WebContextObject was not written with subclassing in mind. Unfortunately, we have no choice but to subclass this object in order to inherit its behavior in or module. We have been able to work around this particular issue by adding synchronization and a wait/notify mechanism in our constructor and our overridden version of mountLib(). If mountLib() is called before our constructor is complete, that thread wait()s on a sempahore until our constructor is complete and performas a notifyAll(). (A better fix would be to have the superclass provide specific features for subclasses so that elaborate synchronization would not be necessary.) private boolean objectConstructed; public JatoWebContextObject(FileObject fileObject, DataLoader loader) throws IOException { super(fileObject,loader); synchronized (this) { initialize(); objectConstructed=true; notifyAll(); } } public synchronized void mountLib(final FileObject lib) throws IOException { if (!objectConstructed) { try { // Wait a max of 5 seconds for the object to be created. We // should never get anywhere near this length of time, but // just in case it's not good to keep the thread blocked here // for a long time and cause a hang. // This is definitely a HACK--fighting a race condition with // another race condition. wait(5000); } catch (InterruptedException e) { // Ignore } if (!objectConstructed) { throw new IOException("Tried to mount library before "+ "context DataObject was fully constructed"); } } } Finally, let me say that we also have had many issues with the general inability to override significant behavior in the superclass because most of the class's methods are private. This has made our job extremely frustrating and has lead to large number of bugs as we have tried to work around these limitations. For all these reasons and those above, our position is that WebContextObject needs to be modified to account for use by subclasses. Specifically, threading, synchronization, and polymorphism need to be primary considerations in this class going forward.
added "zebra" to the status whiteboard field
Todd, I understand your frustration with WebContextObject. In fact, it has been very frustrating also for us to maintain this class and related code. Historically, there reason why the WebContextObject class and the whole org.netbeans.modules.web.context exists is because of the classpath == filesystems metaphor that the IDE uses. Also, the areas of filesystem mounting and Datasystems in the IDE core used to be very buggy, so we needed to put many hacks and workarounds into our code. It may well be that a lot of that code is no longer necessary, but nevertheless, we are quite reluctant to make changes in this code, as this could introduce regressions. Also, historically we've had many threading problems and deadlocks in this area. To address some of your comments: > ... WebContextObject was not written with subclassing in > mind. That's correct. We never thought anyone would actually want to subclass this. This code is intended to supply end-user functionality, and this works (more or less) in Nevada/NB 3.5; it is much better than in the prior releases. If the purpose of subclassing WebContextObject is to provide special behavior w.r.t. mounting libraries, would not it be possible to achieve this by adding a RepositoryListener to Repository.getDefault() and listen on adding a filesystem which contains WEB-INF/web.xml ? That would IMO be a cleaner way to address such a requirement. Or are there any other reasons why a subclass of WebContextObject exists? > our position is that WebContextObject needs to be > modified to account for use by subclasses. Specifically, > threading, synchronization, and polymorphism need to be > primary considerations in this class going forward. I disagree. I think the WebContextObject class and the related code needs to be thrown away, as it was primarily written as a hack. There should be no need to have the WebContextObject class. More specifically, the solution of the whole problem would be to stabilize the Classpath API that the Java module defines, and use that instead of mounting filesystems. In the short term, I suggest we explore any workarounds on the JATO side, and if we don't have success, we ask the sustaining group to exploit the short term solutions you have suggested on the WebApps side - they all look very reasonable.
Petr-- I'm very understanding of the difficulty of trying to support Web contexts in the Studio given its current metaphor. I respect what you have done to try and make something work that clearly wasn't supposed to work given the original design of the IDE. Our need to subclass WebContextObject is that we need to take advantage of all the behavior it provides in terms of identifying libraries and mounting them, loading the deployment descriptor, nodes, and so on. We could re-write all this ourselves, but historically we have not had the time nor expertise to do so. As you are probably aware, NetBeans makes it incredibly difficult to reuse pieces of other modules without subclassing them, so that was our solution. It has been beneficial more often than not, but I would be lying if I said it was always easy. For what it's worth, the Web module is better designed than most modules when it comes to being able to subclass/extend. In any case, the workaround I described seems to be 100% effective, so I see no reason to try and rebalance your existing code to accomodate us. In fact, it may be better if it remains unchanged so our workarounds don't cause unintentd problems. I consider this bug a closed issue for us at this time. I'm supportive of a plan to throw away the Web module code and start from scratch, but please don't do it without talking to us. <grin> We have several dependencies on that code, some of which may not be obvious. For the forseeable future, we will be dependent on NetBeans'/Studio's capabilities for working with Web contexts as the basis for our work, and we can provide some valuable input if you begin an effort to modernize that support. Thanks.
Ok, looks like we have an agreement. Our new code is in currently in branch prj40_prototype also - you are welcome to look at it and give us feedback. This code depends on other branched modules, so to see the whole thing and to build, please see http://projects.netbeans.org/proposals/prototype/index.html
I am reviewing issues to be fixed for 3.6 and this one does not need to be. I am marking it as a TASK and leaving it open for promo-D to figure out if a better API should/can be introduced.
Bug is no longer valid.