United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4328406 : BC: Removing a BeanContextServices throws NullPointerException

Details
Type:
Bug
Submit Date:
2000-04-06
Status:
Resolved
Updated Date:
2003-04-12
Project Name:
JDK
Resolved Date:
2002-08-12
Component:
client-libs
OS:
windows_nt
Sub-Component:
java.beans
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
1.3.0
Fixed Versions:
1.4.2 (mantis)

Related Reports
Relates:

Sub Tasks

Description

Name: stC104175			Date: 04/06/2000


E:\SiteData\BCSProblem>java -version
java version "1.3.0rc2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0rc2-Y)
Java HotSpot(TM) Client VM (build 1.3.0rc2-Y, mixed mode)

Under very specific circumstances, removing a BeanContextServices that is also a
BeanContextServiceProvider, where the removed bean revokes its service, AND
the removed bean contains a BeanContextChild, will throw a NullPointerException.
Note: This is VERY SIMILAR to the reported bug 4226345 but is present in the 1.3
RC2 release.

The problem seems to have to do with delegated service requests and problems
with the consistency of serviceClasses and serviceRequestors in
BeanContextServicesSupport$BCSSChild. It is a reference to serviceRequestors
that is causing the exception.

The code below demonstrates the problem. Output from the program is included as
well.

=========================  CODE EXAMPLE  ==============================
import java.util.*;
import java.beans.beancontext.*;

public class BCSProblem {
    public static void main(String [] args) {
        BCSProblem bcsp = new BCSProblem();
        try {
            for(int i = 0; i < 10; i++) {
                System.out.println("\nIteration number "+i+":");
                bcsp.createStuff();
                bcsp.removeStuff();
                System.out.println("Done.");
            }
        }
        catch(Exception e) { e.printStackTrace(); }
    }

    BeanContextServices     container;
    BeanContextChild        ms1;
    BeanContextServices     ms2;
    BeanContextChild        mb;

    public void createStuff() {
        container = new BeanContextServicesSupport();
        ms1 = new MyService1();
        ms2 = new MyService2();
        mb  = new MyBean();
        
        container.add(ms1);
        container.add(ms2);
        ms2.add(mb);
    }

    public void removeStuff() {
        container.remove(ms2);
    }
}

class MyService1 extends BeanContextChildSupport
                 implements BeanContextServiceProvider {
    protected void initializeBeanContextResources() {
        super.initializeBeanContextResources();

        System.out.println("    MyService1: initializeBeanContextResources()");
        BeanContextServices bcs = (BeanContextServices) getBeanContext();
        System.out.println("        adding my service: "+this.getClass());
        bcs.addService(this.getClass(), this);
    }

    public Object getService(BeanContextServices bcs, Object requestor, Class
serviceClass, Object serviceSelector)
        { return this; }
    public void releaseService(BeanContextServices bcs, Object requestor, Object
service)
        {}
    public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class
serviceClass)
        { return null; }
}

class MyService2 extends BeanContextServicesSupport
                 implements BeanContextServiceProvider {
    protected void initializeBeanContextResources() {
        super.initializeBeanContextResources();
        
        System.out.println("    MyService2: initializeBeanContextResources()");
        Object service;
        BeanContextServicesSupport bcs = (BeanContextServicesSupport)
getBeanContext();
        
        try {
            service = bcs.getService(this, this, MyService1.class, null, this);
            System.out.println("        obtained service "+service);
        } catch(Exception e) { e.printStackTrace(); }

        System.out.println("        adding my service: "+this.getClass());
        bcs.addService(this.getClass(), this);
    }

    protected void releaseBeanContextResources() {
        super.releaseBeanContextResources();
        
        System.out.println("    MyService2: releaseBeanContextResources()");
        BeanContextServices bcs = (BeanContextServices) getBeanContext();
        System.out.println("        revoking my service: "+this.getClass());
        bcs.revokeService(this.getClass(), this, true);
    }
    
    public Object getService(BeanContextServices bcs, Object requestor, Class
serviceClass, Object serviceSelector)
        { return this; }
    public void releaseService(BeanContextServices bcs, Object requestor, Object
service)
        {}
    public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class
serviceClass)
        { return null; }
}

class MyBean extends BeanContextChildSupport {
    protected void initializeBeanContextResources() {
        super.initializeBeanContextResources();
        
        System.out.println("    MyBean: initializeBeanContextResources()");
        
        Object service;
        BeanContextServices bcs = (BeanContextServices) getBeanContext();

        try {
            service = bcs.getService(this, this, MyService1.class, null, this);
            System.out.println("        obtained service "+service);
        } catch(Exception e) { e.printStackTrace(); }
        try {
            service = bcs.getService(this, this, MyService2.class, null, this);
            System.out.println("        obtained service "+service);
        } catch(Exception e) { e.printStackTrace(); }
    }
}


============================  OUTPUT  =================================
Iteration number 0:
    MyService1: initializeBeanContextResources()
        adding my service: class MyService1
    MyService2: initializeBeanContextResources()
        obtained service MyService1@4eb0a18e
        adding my service: class MyService2
    MyBean: initializeBeanContextResources()
        obtained service MyService1@4eb0a18e
        obtained service MyService2@9be0a189
    MyService2: releaseBeanContextResources()
        revoking my service: class MyService2
java.lang.NullPointerException:
        at
java.beans.beancontext.BeanContextServicesSupport$BCSSChild.revokeService(BeanCo
ntextServicesSupport.java:413)
        at
java.beans.beancontext.BeanContextServicesSupport$BCSSProxyServiceProvider.servi
ceRevoked(BeanContextServicesSupport.java:774)
        at
java.beans.beancontext.BeanContextServicesSupport$BCSSChild.revokeService(BeanCo
ntextServicesSupport.java:435)
        at
java.beans.beancontext.BeanContextServicesSupport.revokeService(BeanContextServi
cesSupport.java:706)
        at MyService2.releaseBeanContextResources(BCSProblem.java:82)
        at
java.beans.beancontext.BeanContextChildSupport.setBeanContext(BeanContextChildSu
pport.java:112)
        at
java.beans.beancontext.BeanContextSupport.remove(BeanContextSupport.java:468)
        at
java.beans.beancontext.BeanContextSupport.remove(BeanContextSupport.java:434)
        at BCSProblem.removeStuff(BCSProblem.java:35, Compiled Code)
        at BCSProblem.main(BCSProblem.java:11, Compiled Code)
(Review ID: 103368) 
======================================================================

                                    

Comments
EVALUATION

Still a problem in the latest JDK (1.4.1 beta).

After looking at this, a simple solution would be to check that the serviceRequestors != null in the while loop of BeanContextServicesSupport$BCSSChild.revokeService().

Will try to fix for 1.4.2

###@###.### 2002-05-29
                                     
2002-05-29
SUGGESTED FIX


------- BeanContextServicesSupport.java -------
406c406
< 	    while (i.hasNext()) {
---
> 	    while (i.hasNext() && serviceRequestors != null) {

###@###.### 2002-05-29
                                     
2002-05-29
WORK AROUND



Name: stC104175			Date: 04/06/2000


A fix is to override the getService() method of BeanContextServicesSupport in
the class MyService2 above. In this method, if the service being requested is
the same service that MyService2 is providing, provide a reference to the
service directly. Otherwise, call the superclass getService() method. See
example below. Note that this will mess up the internal BeanContext framework
with respect to its accounting of delegated services, etc. Thus, service
revokation events are not all generated! Thus, this workaround will get rid of
the exception but has other side effects.

======================== ADD TO MYSERVICE2 ===========================
public Object getService(BeanContextChild child,Object requestor,Class
serviceClass,Object serviceSelector, BeanContextServiceRevokedListener bcsrl)
                  throws TooManyListenersException
{
    if (serviceClass == this.getClass())
        return this;
    else
       return
super.getService(child,requestor,serviceClass,serviceSelector,bcsrl);
}
======================================================================
                                     
2004-06-11
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
mantis
mantis-b02

FIXED IN:
mantis
mantis-b02

INTEGRATED IN:
mantis
mantis-b02


                                     
2004-06-14



Hardware and Software, Engineered to Work Together