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 35472 - Async thread accessing WebContextObject before it is fully constructed
Summary: Async thread accessing WebContextObject before it is fully constructed
Status: RESOLVED WONTFIX
Alias: None
Product: javaee
Classification: Unclassified
Component: Code (show other bugs)
Version: -S1S-
Hardware: All All
: P2 blocker (vote)
Assignee: issues@javaee
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-08-19 03:26 UTC by Todd Fast
Modified: 2006-09-26 18:15 UTC (History)
3 users (show)

See Also:
Issue Type: TASK
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Todd Fast 2003-08-19 03:26:53 UTC
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.
Comment 1 _ ttran 2003-08-19 07:32:32 UTC
added "zebra" to the status whiteboard field
Comment 2 Petr Jiricka 2003-08-20 16:45:44 UTC
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.
Comment 3 Todd Fast 2003-08-21 01:32:04 UTC
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.
Comment 4 Petr Jiricka 2003-08-21 09:26:15 UTC
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

Comment 5 Pavel Buzek 2004-01-13 21:34:24 UTC
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.
Comment 6 Todd Fast 2006-09-26 18:15:14 UTC
Bug is no longer valid.