NPE when calling node.getBaseVersion() within the transaction.
--------------------------------------------------------------

                 Key: JCR-2382
                 URL: https://issues.apache.org/jira/browse/JCR-2382
             Project: Jackrabbit Content Repository
          Issue Type: Bug
          Components: jackrabbit-core
    Affects Versions: 1.6.0
         Environment: winxp
            Reporter: Cele Liu


We try to get the base version from a versionable node in the transaction, but 
if we didn't check in the node, the NPE will throw out. We used the jr-jcr to 
support XA transaction.
the code likes:
        UserTransaction ut = null;
        InitialContext tx = new InitialContext();
        ut = (UserTransaction) tx.lookup("UserTransaction");
        ut.begin();
        try {
            Session session = getJcrSession();
            Node root = session.getRootNode();
            Node child = root.addNode("testchild");
            root.save();
            child.addMixin(JcrConstants.MIX_VERSIONABLE);
            child.save();
            session.save();
            //child.checkin();
            javax.jcr.version.Version v = child.getBaseVersion();
            session.logout();
            ut.commit();
        }catch(Exception e){
            ut.rollback();
            e.printStackTrace(System.err);
            fail("failed with " + e.getMessage());
        }
The exception stack:
java.lang.NullPointerException
      at org.apache.jackrabbit.core.NodeImpl.getBaseVersion(NodeImpl.java:3659)
      at 
com.vitria.modeling.repository.sapi.JcrTransactionTest.testBaseVersionableSample(JcrTransac
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

If we did not run the code in XA transaction or check-in the code before 
calling the child.getBaseVersion(), the NPE will be gone.
JR1.5.0 doesn't have this issue.

I compare the code between JR1.5.0 and JR 1.6.0. and get some clue.

Please check the code snippet for JR 1.6.0. Looks like in JR 1.6.0, it always 
look up the node from the version manager.
The NPE happens if the versioned node doesn't exist, v is null and then JR try 
to get node by the v.getId().

public Version getBaseVersion() throws UnsupportedRepositoryOperationException, 
RepositoryException {
        // check state of this instance
        sanityCheck();
        boolean isFull = checkVersionable();
        InternalVersion v;
        if (isFull) {
            NodeId id = 
NodeId.valueOf(getProperty(NameConstants.JCR_BASEVERSION).getString());
            v = session.getVersionManager().getVersion(id);
        } else {
            // note, that the method currently only works for linear version
            // graphs (i.e. simple versioning)
            v = session.getVersionManager().getHeadVersionOfNode(((NodeId) id));
        }
        return (Version) session.getNodeById(v.getId());
}

And there is the code snippet for JR 1.5.0, JR doesn't depends on the version 
manager, it always get the version from the property.

public Version getBaseVersion() throws UnsupportedRepositoryOperationException, 
RepositoryException {
        // check state of this instance
        sanityCheck();
        checkVersionable();
       // transactions workaround.
        NodeId id = 
NodeId.valueOf(getProperty(NameConstants.JCR_BASEVERSION).getString());
        session.getVersionManager().getVersion(id);
        return (Version) getProperty(NameConstants.JCR_BASEVERSION).getNode();
}

Notice: For JR 1.5.0 and JR 1.6.0, if you didn't check in the node in XA 
transaction, the API session.getVersionManager().getVersion(id); both will 
return null.
The difference is 1.6.0 will use the return to perform the look-up, and 1.5.0 
doesn't. 

After I patch the code to below, the getBaseVersion() cases got passed:
public Version getBaseVersion() throws UnsupportedRepositoryOperationException, 
RepositoryException {
        // check state of this instance
        sanityCheck();
        boolean isFull = checkVersionable();
        InternalVersion v;
        if (isFull) {
            NodeId id = 
NodeId.valueOf(getProperty(NameConstants.JCR_BASEVERSION).getString());
            v = session.getVersionManager().getVersion(id);
        } else {
            // note, that the method currently only works for linear version
            // graphs (i.e. simple versioning)
            v = session.getVersionManager().getHeadVersionOfNode(((NodeId) id));
        }
        if (v == null){
            return (Version) 
getProperty(NameConstants.JCR_BASEVERSION).getNode();
        }else{
            return (Version) session.getNodeById(v.getId());    
        }
}




-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to