DocumentDataSource with Signer/SignerWithFullAccess-Rights

Yesterday I read the very interessting question from Daniele Grillo at stackoverflow.com: Is a datasource available for XPages who can access the underlying document with different access levels?

I have never seen one before, so I decided to do some tests and tried to find a workaround / hack for this problem. But after a while and a some lines of coding, I was unable to get a solution, so I decided to create a new datasource: A datasource which can access the documents in the backend with different access levels: sessionAsSigner and sessionAsSignerWithFullAccess.

The datasource is still in beta version, there are some limitations because I have implemented the basic functionallity only. It must be added programmatically, I have no ambitions to create a design element of it, but perhaps I will create a XSnippet.

To use this datasource, you can add it to a XPage and control it via URL parameters.

  • Open document as current user
XPage.xsp?documentId=<DocUNID>
  • Open document as Signer
XPage.xsp?documentId=<DocUNID>&access=sessionAsSigner
  • Open document as Signer with Full Access
XPage.xsp?documentId=<DocUNID>&access=sessionAsSignerWithFullAccess

To use this datasource in your XPage, you have to add some SSJS code:

<xp:this.beforePageLoad>
   <![CDATA[#{javascript:
      importPackage(ch.hasselba.xpages.jsf.core);
      var ds = new 
         ch.hasselba.xpages.jsf.core.AccessDocDataSource();
      ds.setVar( "document1" );
      ds.setConcurrencyMode( "force" );
      view.addData(ds);
   }]]>
</xp:this.beforePageLoad>

[You can change the name of the datasource (marked red) to fit your requirements.]

The datasource can be used like a normal document datasource:

<xp:inputText id="inputText1" value="#{document1.Test}" />

To save the document you have to call the save method directly (The default actions are currently not working. Maybe because the actions check the object type. I am trying to figure this out):

<xp:button value="Save" id="button1">
   <xp:eventHandler event="onclick" submit="true"
      refreshMode="complete">
      <xp:this.action>
         <![CDATA[#{javascript:document1.save()}]]>
      </xp:this.action>
   </xp:eventHandler>
</xp:button>

Here is the Java code:

package ch.hasselba.xpages.jsf.core;

import com.ibm.xsp.FacesExceptionEx;
import com.ibm.xsp.model.AbstractDocumentDataSource;
import com.ibm.xsp.model.DocDataSource;
import com.ibm.xsp.model.DocumentDataContainer;
import com.ibm.xsp.model.domino.wrapped.DominoDocument;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import lotus.domino.Document;
import lotus.domino.NotesException;
import lotus.domino.Session;
import java.util.Map;

public class AccessDocDataSource extends AbstractDocumentDataSource
   implements DocDataSource {

    private final static String DEFAULT_CONCURRENCYMODE = "force";
    private final static String CONCURRENCYMODE = "concurrencyMode";
    private final static String ACTION = "action";
    private final static String ACCESS = "access";
    private final static String DOCUMENTID = "documentId";
    private final static String CONST_SESSION = "session";
    private final static String CONST_SESSIONASSIGNER = "sessionAsSigner";
    private final static String CONST_SESSIONASSIGNERFULLACCESS = "sessionAsSignerWithFullAccess";
    private final static String MSG_DOCSAVE_FAILED = "doSaveDocument failed!";

    private String _docId;
    private String _action;
    private String _concurrencyMode;
    private String _access;

    private DominoDocument _doc;

    private static boolean isStrEmpty(final String str) {
        if (str == null)
            return true;
        if (str.length() == 0)
            return true;

        return false;
    }

    private static Object getVariableValue(String varName) {

        FacesContext context = FacesContext.getCurrentInstance();
        return context.getApplication().getVariableResolver().resolveVariable(
                context, varName);
    }

    @Override
    public void readRequestParams(FacesContext paramFacesContext,
            Map<String, Object> pMap) {

        String tmpStr = (String) pMap.get(prefixRequestParam(DOCUMENTID));
        if (!isStrEmpty(tmpStr))
            this._docId = tmpStr;

        tmpStr = (String) pMap.get(prefixRequestParam(ACTION));
        if (!isStrEmpty(tmpStr))
            this._action = tmpStr;

        tmpStr = (String) pMap.get(prefixRequestParam(ACCESS));
        if (!isStrEmpty(tmpStr))
            this._access = tmpStr;
    }

    @Override
    public Object getDataObject() {

        return this._doc;
    }

    @Override
    public boolean isReadonly() {

        DominoDocument doc = getDocument();
        if (doc == null)
            return true;
        return isReadOnly( doc );

    }
    @Override
    public boolean isReadOnly(Object paramObject) {

        return !((DominoDocument) paramObject).isEditable();
    }
    @SuppressWarnings("deprecation")
    public DominoDocument getDocument() {

        Document d = null;
        DominoDocument doc = null;
        if (this._doc != null)
            return this._doc;

        try {
            Session s = (Session) getVariableValue(getAccess());

            d = s.getCurrentDatabase().getDocumentByUNID(getDocumentId());
            doc = com.ibm.xsp.model.domino.wrapped.DominoDocument.wrap(d
                    .getParentDatabase().getFilePath(), d, null,
                    getConcurrencyMode(), false, null);
            this._doc = doc;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return doc;
    }

    public String getConcurrencyMode() {

        if (this._concurrencyMode != null) {
            return this._concurrencyMode;
        }

        ValueBinding vb = getValueBinding(CONCURRENCYMODE);
        if (vb != null) {
            return (String) vb.getValue(FacesContext.getCurrentInstance());
        }
        return DEFAULT_CONCURRENCYMODE;
    }

    public void setConcurrencyMode(String pString) {

        this._concurrencyMode = pString;
    }

    public String getDocumentId() {

        if (this._docId != null) {
            return this._docId;
        }

        ValueBinding vb = getValueBinding(DOCUMENTID);
        if (vb != null) {
            return (String) vb.getValue(FacesContext.getCurrentInstance());
        }

        return null;
    }

    public void setDocumentId(String pString) {

        this._docId = pString;
    }

    public String getAccess(){
        if (this._access != null) {
            return this._access;
        }

        ValueBinding vb = getValueBinding(ACCESS);
        if (vb != null) {
            return (String) vb.getValue(FacesContext.getCurrentInstance());
        }

        return null;
    }
    public void setAccess( String pString ){
        if( isStrEmpty( pString ) ){
            this._access = CONST_SESSION;
            return;
        }

        if( pString.equals( CONST_SESSIONASSIGNER ) ){
            this._access = CONST_SESSIONASSIGNER;
            return;
        }

        if( pString.equals( CONST_SESSIONASSIGNERFULLACCESS  ) ){
            this._access = CONST_SESSIONASSIGNERFULLACCESS ;
            return;
        }

        this._access = CONST_SESSION;

    }
    @Override
    public boolean doSaveDocument(FacesContext paramFacesContext, Object paramObject)
            throws FacesExceptionEx {

        try {
            return ((DominoDocument) paramObject).save();
        } catch (NotesException ne) {
            ne.printStackTrace();
        }
        throw new FacesExceptionEx( MSG_DOCSAVE_FAILED , null);
    }

    @Override
    public Object saveState(FacesContext paramFacesContext) {

        Object[] objArr = new Object[5];
        objArr[0] = super.saveState(paramFacesContext);
        objArr[1] = this._docId;
        objArr[2] = this._concurrencyMode;
        objArr[3] = this._action;
        objArr[4] = this._access;

        return objArr;
    }

    @Override
    public void restoreState(FacesContext paramFacesContext, Object paramObject) {

        Object[] objArr = (Object[]) paramObject;
        super.restoreState(paramFacesContext, objArr[0]);
        this._docId = ((String) objArr[1]);
        this._concurrencyMode = ((String) objArr[2]);
        this._action = ((String) objArr[3]);
        this._access = ((String) objArr[4]);
    }

    @Override
    public DocumentDataContainer doNewDocument(FacesContext paramFacesContext)
            throws FacesExceptionEx {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public DocumentDataContainer doOpenDocument(FacesContext paramFacesContext)
            throws FacesExceptionEx {
        // TODO Auto-generated method stub
        return null;
    }

    public boolean isNewDocument(FacesContext paramFacesContext) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void doComputeDocument(FacesContext paramFacesContext, Object paramObject)
            throws FacesExceptionEx {
        // TODO Auto-generated method stub

    }

    @Override
    public void doDeleteDocument(FacesContext paramFacesContext, Object paramObject)
            throws FacesExceptionEx {
        // TODO Auto-generated method stub

    }

    @Override
    protected String composeUniqueId() {
        // TODO Auto-generated method stub
        return null;
    }

    public boolean isDocument(Object paramObject) {
        // TODO Auto-generated method stub
        return false;
    }

}
Dieser Beitrag wurde unter Java, JSF, Security, ServerSide JavaScript, XPages abgelegt und mit , , , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

7 Kommentare zu DocumentDataSource with Signer/SignerWithFullAccess-Rights

  1. Daniele Grillo sagt:

    Woooww, wonderful work!!!

    Tnx you very much!

  2. Fredrik sagt:

    Scary, get full access to database and pass domino security using url param.
    However, a nice example of XPages possibilites.

  3. Bill Hanson sagt:

    This looks like it will solve an issue for me, but I am getting a 505 error when testing. Do you have any idea why I get a 505 when the new data source is constructed in the SSJS beforePageLoad event?

  4. Bill Hanson sagt:

    Oops, sorry. The error was actually: Error 500 – HTTP Web Server: Command Not Handled Exception.

    In the server logs, the exception is: NoClassDefFoundError: com.ibm.xsp.model.DocDataSource, but that is never displayed in the browser even though I have the error page enabled.

    Any ideas would be much appreciated. This idea opens up some great possibilities!

  5. Hi Sven,
    I the R9 release seem that when you save the document..now generate error 500…
    Into the specific the problem is that loose the java bean to the field

    Have you the same problem?

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.