JDK-4328406 : BC: Removing a BeanContextServices throws NullPointerException
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.beans
  • Affected Version: 1.3.0
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_nt
  • CPU: x86
  • Submitted: 2000-04-06
  • Updated: 2003-04-12
  • Resolved: 2002-08-12
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.2 mantisFixed
Related Reports
Relates :  
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
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis mantis-b02 FIXED IN: mantis mantis-b02 INTEGRATED IN: mantis mantis-b02
14-06-2004

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); } ======================================================================
11-06-2004

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
29-05-2002

SUGGESTED FIX ------- BeanContextServicesSupport.java ------- 406c406 < while (i.hasNext()) { --- > while (i.hasNext() && serviceRequestors != null) { ###@###.### 2002-05-29
29-05-2002