OpenNTF / org.openntf.domino

Open replacement for lotus.domino package in HCL Domino
Apache License 2.0
65 stars 34 forks source link

XPage sessions created with SIGNER* and stored in viewScope cause resurrection problems #149

Closed jesse-gallagher closed 5 years ago

jesse-gallagher commented 8 years ago

Example XPage:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xe="http://www.ibm.com/xsp/coreex">
    <xp:button value="Signer" id="button1">
        <xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="wrapper">
            <xp:this.action><![CDATA[#{javascript:viewScope.test = test.Test.getSessionAsSigner();}]]></xp:this.action>
        </xp:eventHandler>
    </xp:button>
    <xp:div id="wrapper">
        <xp:text id="computedField1">
            <xp:this.value><![CDATA[#{javascript:return viewScope.test ?  viewScope.test.getEffectiveUserName() : "null";}]]></xp:this.value>
        </xp:text>
        <xp:text value="#{javascript:@Now()}">
            <xp:this.converter>
                <xp:convertDateTime type="both"></xp:convertDateTime>
            </xp:this.converter>
        </xp:text>
    </xp:div>
</xp:view>

Java class:

package test;

import org.openntf.domino.Session;
import org.openntf.domino.utils.Factory;
import org.openntf.domino.utils.Factory.SessionType;

public class Test {
    public static Session getSessionAsSigner() {
        return Factory.getSession(SessionType.SIGNER);
    }
}

On first client, this works, but subsequent clicks hit an NPE:

java.lang.NullPointerException
    org.openntf.domino.xsp.session.AbstractXPageSessionFactory.wrapSession(AbstractXPageSessionFactory.java:26)
    org.openntf.domino.xsp.session.XPageSignerSessionFactory.createSession(XPageSignerSessionFactory.java:24)
    org.openntf.domino.utils.Factory.getSession(Factory.java:954)
    org.openntf.domino.impl.Session.recreateSession(Session.java:1616)
    org.openntf.domino.impl.Session.readResolve(Session.java:2069)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
    java.lang.reflect.Method.invoke(Method.java:611)
    java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1136)
    java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1804)
    java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
    java.io.ObjectInputStream.readObject(ObjectInputStream.java:364)
    java.util.HashMap.readObject(HashMap.java:969)
    sun.reflect.GeneratedMethodAccessor34.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
    java.lang.reflect.Method.invoke(Method.java:611)
    java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1049)
    java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1891)
    java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1795)
    java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
    java.io.ObjectInputStream.readUnshared(ObjectInputStream.java:454)
    com.ibm.xsp.application.AbstractSerializingStateManager$FastObjectInputStream.readObjectEx(AbstractSerializingStateManager.java:496)
    com.ibm.xsp.application.AbstractSerializingStateManager$FastObjectInputStream.readObjectEx(AbstractSerializingStateManager.java:503)
    com.ibm.xsp.application.AbstractSerializingStateManager$FastObjectInputStream.readObjectEx(AbstractSerializingStateManager.java:482)
    com.ibm.xsp.application.AbstractSerializingStateManager$FastObjectInputStream.readObjectEx(AbstractSerializingStateManager.java:503)
    com.ibm.xsp.application.AbstractSerializingStateManager$FastObjectInputStream.readObjectEx(AbstractSerializingStateManager.java:503)
    com.ibm.xsp.application.AbstractSerializingStateManager.readSerializedView(AbstractSerializingStateManager.java:215)
    com.ibm.xsp.application.AbstractSerializingStateManager.doRestoreView(AbstractSerializingStateManager.java:127)
    com.ibm.xsp.application.FileStateManager.doRestoreView(FileStateManager.java:249)
    com.ibm.xsp.application.AbstractStateManager.restoreView(AbstractStateManager.java:93)
    com.ibm.xsp.application.StateManagerImpl.restoreView(StateManagerImpl.java:179)
    com.ibm.xsp.application.ViewHandlerExImpl._restoreView(ViewHandlerExImpl.java:386)
    com.ibm.xsp.application.ViewHandlerExImpl.restoreView(ViewHandlerExImpl.java:358)
    com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:168)
    com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:210)
    com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:96)
    com.ibm.xsp.controller.FacesControllerImpl.execute(FacesControllerImpl.java:256)
    com.ibm.xsp.webapp.FacesServlet.serviceView(FacesServlet.java:228)
    com.ibm.xsp.webapp.FacesServletEx.serviceView(FacesServletEx.java:157)
    com.ibm.xsp.webapp.FacesServlet.service(FacesServlet.java:160)
    com.ibm.xsp.webapp.FacesServletEx.service(FacesServletEx.java:138)
    com.ibm.xsp.webapp.DesignerFacesServlet.service(DesignerFacesServlet.java:103)
    com.ibm.designer.runtime.domino.adapter.ComponentModule.invokeServlet(ComponentModule.java:576)
    com.ibm.domino.xsp.module.nsf.NSFComponentModule.invokeServlet(NSFComponentModule.java:1335)
    com.ibm.designer.runtime.domino.adapter.ComponentModule$AdapterInvoker.invokeServlet(ComponentModule.java:853)
    com.ibm.designer.runtime.domino.adapter.ComponentModule$ServletInvoker.doService(ComponentModule.java:796)
    com.ibm.designer.runtime.domino.adapter.ComponentModule.doService(ComponentModule.java:565)
    com.ibm.domino.xsp.module.nsf.NSFComponentModule.doService(NSFComponentModule.java:1319)
    com.ibm.domino.xsp.module.nsf.NSFService.doServiceInternal(NSFService.java:662)
    com.ibm.domino.xsp.module.nsf.NSFService.doService(NSFService.java:482)
    com.ibm.designer.runtime.domino.adapter.LCDEnvironment.doService(LCDEnvironment.java:357)
    com.ibm.designer.runtime.domino.adapter.LCDEnvironment.service(LCDEnvironment.java:313)
    com.ibm.domino.xsp.bridge.http.engine.XspCmdManager.service(XspCmdManager.java:272)

This is a problem during resurrection and is mostly likely due to the signer and signerWithFullAccess sessions not having been created by the time the Session#readResolve method runs. In a newly-created DB with just these design elements and the ODA library enabled, this seems to happen consistently, but there were times during testing when this problem did NOT arise (for example, in a newly-created DB using my framework, as well as in a clean DB after tinkering). I'm not sure what causes this change in behavior, though. I can see four main options:

1) Modify this behavior so that, instead of trying to re-fetch the session via the same path, it will instead create a native named session for the original user/full-access level 2) Modify the session in such a way that it can delay this lookup. This may be difficult, as the lookup happens in a method called by the ObjectStream, not a manual thing on our side, and so it’d probably have to affect basically everything 3) Leave it unchanged and declare view-scoped signer sessions unsupported 4) Figure out what caused the problem to disappear in some of my tests and make that reproducible

4 would certainly be ideal, but otherwise I personally lean towards 3, as I don't put a lot of value in resurrectible sessions.

However, 2 could be implemented through the not-difficult-but-laborious process of having a sanity-check call at the start of each method to check a boolean that indicates that the session was resurrected in this way but had a delayed restoration to avoid the bug.

paulswithers commented 5 years ago

I think we should close this as "unsupported" because Domino objects should not be stored in scopes.

jesse-gallagher commented 5 years ago

Agreed. I think the Resurrectable stuff is more trouble than it’s worth.