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.

5 Antworten auf 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!

Hinterlasse eine Antwort

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


*

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>