com.ibm.xsp.webdav.resource.DAVResourceDomino.java Source code

Java tutorial

Introduction

Here is the source code for com.ibm.xsp.webdav.resource.DAVResourceDomino.java

Source

/** ========================================================================= *
 * Copyright (C) 2011, 2012 IBM Corporation                                   *
 *           based on work of                                                 *
 * Copyright (C) 2006, 2007 TAO Consulting Pte <http://www.taoconsulting.sg/> *
 *                            All rights reserved.                            *
 * ========================================================================== *
 *                                                                            *
 * Licensed under the  Apache License, Version 2.0  (the "License").  You may *
 * not use this file except in compliance with the License.  You may obtain a *
 * copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>.       *
 *                                                                            *
 * Unless  required  by applicable  law or  agreed  to  in writing,  software *
 * distributed under the License is distributed on an  "AS IS" BASIS, WITHOUT *
 * WARRANTIES OR  CONDITIONS OF ANY KIND, either express or implied.  See the *
 * License for the  specific language  governing permissions  and limitations *
 * under the License.                                                         *
 *                                                                            *
 * ========================================================================== **/
package com.ibm.xsp.webdav.resource;

import java.io.File;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Vector;

import lotus.domino.ACL;
import lotus.domino.Base;
import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.Item;
import lotus.domino.Name;
import lotus.domino.NotesException;
import lotus.domino.Session;
import lotus.domino.View;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import biz.taoconsulting.dominodav.exceptions.DAVNotFoundException;
import biz.taoconsulting.dominodav.interfaces.IDAVAddressInformation;
import biz.taoconsulting.dominodav.interfaces.IDAVRepository;
import biz.taoconsulting.dominodav.resource.DAVAbstractResource;

import com.ibm.xsp.webdav.WebDavManager;
import com.ibm.xsp.webdav.domino.DominoProxy;
import com.ibm.xsp.webdav.repository.DAVRepositoryDomino;
import com.ibm.xsp.webdav.repository.DAVRepositoryMETA;

/**
 * Abstract class that is the base for all Domino related resources:
 * Attachments, Documents, calendar, view etc.
 * 
 * @author Stephan H. Wissel
 * 
 */
public abstract class DAVResourceDomino extends DAVAbstractResource {

    /**
     * The outputstream leading to the temp file or other stream resource
     */
    protected OutputStream out;

    /**
     * Logger for Errors
     */
    private static final Log LOGGER = LogFactory.getLog(DAVResourceDomino.class);

    /**
     * The document UniqueID for document and attachment resources;
     */
    private String documentUniqueID = null;

    public DAVResourceDomino() {
        // Needed for type casting
    }

    /**
     * 
     * @param repository
     *            the repository the Resource is in
     * @param url
     *            the path relative to the repository -- as seen from the
     *            browser
     * @throws DAVNotFoundException
     *             --- if the file is not there
     */
    public DAVResourceDomino(IDAVRepository repository, String url) throws DAVNotFoundException {

        this.setup(repository, url, false);

    }

    /**
     * 
     * @param repository
     *            the repository the Resource is in
     * @param url
     *            the path relative to the repository -- as seen from the
     *            browser
     * @param isMember
     *            : is is a file in a sub directory
     * @throws DAVNotFoundException
     *             --- if the file is not there
     */
    public DAVResourceDomino(IDAVRepository repository, String url, boolean isMember) throws DAVNotFoundException {
        this.setup(repository, url, isMember);
    }

    /**
     * The function checks if a document is read-only for the current user. Step
     * 1: get the user access level, if Reader = ReadOnly, If Editor = ReadWrite
     * if Author = Step 2 Step 2: Get UsernameList for current user and loop
     * through the document to get all items. If a item is an author field, then
     * add it to the list, loop the list to see the access.
     * 
     * @param s
     *            Notessession
     * @param curDoc
     *            Document to evaluate
     * @return true if ReadOnly Access is granted
     */
    protected boolean checkReadOnlyAccess(Document curDoc) {

        boolean result = true; // Readonly until proven better
        HashMap<String, String> allAuthors = new HashMap<String, String>();
        Vector<String> v = null;
        @SuppressWarnings("rawtypes")
        Vector allItems = null;
        String unid = null;

        try {
            unid = curDoc.getUniversalID();
            // Step 1 --- Database access
            @SuppressWarnings("unused")
            Session s = DominoProxy.getUserSession();
            Database db = curDoc.getParentDatabase();
            int accessLevel = db.getCurrentAccessLevel();
            LOGGER.info("Starting check access for docunid=" + unid);
            if (accessLevel == ACL.LEVEL_EDITOR || accessLevel == ACL.LEVEL_DESIGNER
                    || accessLevel == ACL.LEVEL_MANAGER) {
                result = false; // it is not read only, it can be processed
                // // LOGGER.info("Access level is Editor or better");

            } else if (accessLevel == ACL.LEVEL_AUTHOR) {
                // Step 2 --- Document access
                // //
                // LOGGER.info("Access level is Author, checking local access for:"
                // +
                // DominoProxy.getUserName()+"; effective="+s.getEffectiveUserName());

                allItems = curDoc.getItems();
                Item item;
                for (int i = 0; i < allItems.size(); i++) {
                    item = (Item) allItems.get(i);
                    if (item != null && item.isAuthors()) {
                        // Record it to the Map
                        @SuppressWarnings("rawtypes")
                        Vector values = item.getValues();
                        if (values != null) {
                            for (int x = 0; x < values.size(); x++) {
                                if (values.get(x) != null) {
                                    String curAuthor = (String) values.get(x);
                                    // // LOGGER.info("Author found in " +
                                    // item.getName() + ": " + curAuthor);
                                    allAuthors.put(curAuthor.toLowerCase(), curAuthor.toLowerCase());
                                }
                            }
                        }
                    }
                    Item itemO = item;
                    item = null;
                    itemO.recycle();
                }

                // //
                // LOGGER.info("-- Author retrieval completed, now checking usernameslist --");

                // Might not work, if the db is local and consisten acl
                // is not enforced, so we add username and common username
                v = this.getUsernamesList(curDoc);

                if (v == null) {
                    // Get Username list has failed, we can't allow editing of
                    // the file
                    result = true; // READ ONLY
                    // // LOGGER.info("getUsernamesList returned NULL");
                } else {
                    // Now check the userlist
                    for (int i = 0; i < v.size(); i++) {
                        if (v.get(i) != null) {
                            String curName = v.get(i);
                            // // LOGGER.info("Checking access for:" + curName);
                            if (!curName.equals("")) {
                                if (allAuthors.containsKey(curName.toLowerCase())) {
                                    result = false; // We can write!
                                    // // LOGGER.info("Author access found for "
                                    // + curName);
                                    break;
                                }
                            }
                        }
                    }
                }

            }

        } catch (NotesException e) {
            // // LOGGER.info("ReadOnlyAccess Check failed", e);
            result = true; // It is readonly if the check failed
        }
        // // LOGGER.info("Document "+unid+
        // ((result)?" readonly":" normal access"));
        return result;
    }

    /**
     * Extracts the UNID (16) from the internal url. String 16 chars long
     * 
     * @return the UNID
     */
    private String extractUNIDfromInternalAddress() {
        String result = null;
        String[] parts = this.getInternalAddress().split("/");
        for (int i = 0; i < parts.length; i++) {
            if (parts[i].length() == 32) {
                result = parts[i];
                break;
            }
        }
        return result;
    }

    /**
     * Get the members of the Domino resource. Most likely traversing a view
     */
    public abstract void fetchChildren();

    public String getDocumentUniqueID() {
        if (this.documentUniqueID == null || this.documentUniqueID == "") {
            this.documentUniqueID = this.extractUNIDfromInternalAddress();
        }
        return documentUniqueID;
    }

    // This function gets overwritten by sub functions
    protected String getNameFromInternalAddress(String internalName) throws Exception {
        throw new Exception("The function getNameFromInternalAddress must be overwritten");
    }

    /**
     * @return A temp file if we need to write into the file system e.g. for DXL
     *         or attachments. Needs to be overwritten
     */
    public abstract File getTempfile();

    /**
     * Retrieves the current associations with roles and groups
     * 
     * @param s
     *            NotesSession
     * @param doc
     *            NotesDocument
     * @return List of Names and Groups
     */
    @SuppressWarnings("unchecked")
    protected Vector<String> getUsernamesList(Document doc) {
        Vector<String> retVector;
        Name nName = null;
        Session s = DominoProxy.getUserSession();

        try {
            nName = s.createName(s.getEffectiveUserName());
        } catch (NotesException e1) {
            LOGGER.error("getEffectiveUsernamesList Name resolution failed", e1);
        }

        try {
            retVector = s.evaluate("@Usernameslist", doc);
        } catch (NotesException e) {
            LOGGER.error("@Usernameslist failed", e);
            retVector = new Vector<String>();
            retVector.add("");
        }

        try {
            // Eventually retvector has only an empty value, which we consider
            // an error
            if (retVector.get(0).equals("")) {
                LOGGER.equals("@Usernameslist for " + nName.getAbbreviated() + " failed");
            }

        } catch (NotesException e) {
            LOGGER.error("getEffectiveUsername() failed", e);
        }

        try {
            retVector.add(s.getEffectiveUserName());
            retVector.add(nName.getAbbreviated());
        } catch (NotesException e) {
            LOGGER.error("getUsername() failed", e);
        }

        return retVector;
    }

    public void setDocumentUniqueID(String documentUniqueID) {
        this.documentUniqueID = documentUniqueID;
    }

    /**
     * Based on the internal URL we figure the resource type
     */
    protected void setDominoResourceType() {
        String url = this.getInternalAddress().trim();

        String openArgument = null;
        int questPos = url.indexOf("?");

        if (questPos < 0) {
            if (url.endsWith(".nsf") || url.endsWith(".nsf/")) {
                this.setResourceType("NotesDatabase");
            } else if (!(url.indexOf("$File") < 0)) {
                this.setResourceType("NotesAttachment");
                this.setMember(true); // Attachments are always members!
            } else if (this.twoSlashAfterNsf(url)) {
                this.setResourceType("NotesDocument");
            } else {
                this.setResourceType("NotesView");
            }
        } else {
            openArgument = url.substring(questPos + 1) + "&";
            openArgument = openArgument.substring(0, openArgument.indexOf("&"));

            if (openArgument.equals("OpenDatabase")) {
                this.setResourceType("NotesDatabase");
            } else if (openArgument.equals("OpenDocument")) {
                this.setResourceType("NotesDocument");
            } else if (openArgument.equals("OpenView")) {
                this.setResourceType("NotesView");
            }
        }
    }

    /**
     * @param rep
     *            the containing repository
     * @param url
     *            the access to the resource from the browser relative to the
     *            repository
     * @throws DAVNotFoundException
     *             -- we might ask for an non-existing resource
     */
    private void setup(IDAVRepository rep, String url, boolean isMember) throws DAVNotFoundException {

        // Store a link to the repository
        this.setOwner(rep);

        // // LOGGER.info("DAVResouceDomino for "+url);

        // The path can't be null and can't be empty. if it is empty we use "/"
        if (url == null || url.equals("")) {
            url = new String("/");
        }

        if (url.equals("/")) {
            this.setCollection(true);
        } else {
            this.setCollection(false);
        }

        // Memorize the url requested
        this.setPublicHref(url);

        // Get the file-path and a new file
        // // LOGGER.info("Input url="+url);
        String fpath = rep.getInternalAddressFromExternalUrl(url, "DAVREsourceDomino-setup");
        // Keep the address
        this.setInternalAddress(fpath);
        // // LOGGER.info("Output url="+fpath);

        // FIXME XXX TODO Borked code!
        // Next check -- if Repository and Resource have the same path then the
        // resource it top level
        if (fpath.equals(((IDAVAddressInformation) rep).getInternalAddress())) {
            LOGGER.debug("Repository and Resource address match:" + fpath);
            this.setName(((IDAVAddressInformation) rep).getName());
            LOGGER.debug(this.getName() + " is the repository-resource at " + this.getInternalAddress());
            this.setCollection(true);
            this.setResourceType("DominoRepository");
            this.setMember(false);
        } else {
            // It is a notes artifact
            String newName = null;
            try {
                newName = this.getNameFromInternalAddress(this.getInternalAddress());
            } catch (Exception e) {
                LOGGER.error(e);
            }
            this.setName(newName);
            this.setDominoResourceType();
            /*
             * this.setMember(isMember);
             * if(!this.getResourceType().equals("NotesAttachment")){
             * this.setCollection(true); }else{ this.setMember(true);
             * this.setCollection(false); }
             */
            this.validateResourceExists();

            // TODO: figure out read/write access
            this.setReadOnly(false);
            LOGGER.debug(this.getName() + " is a " + this.getResourceType() + " resource at "
                    + this.getInternalAddress());
        }
        // this.setMember(isMember);
        if (!this.isMember()) {
            // search for members (children)
            this.fetchChildren();
        }
    }

    /**
     * Checks if a resource really exists
     * 
     * @throws DAVNotFoundException
     */
    protected void validateResourceExists() throws DAVNotFoundException {

        Session s = DominoProxy.getUserSession();
        String rt = this.getResourceType();

        // TODO: Do we need to check for empty?
        if (rt == null) {
            return;
        }
        String adr = this.getInternalAddress();

        if (rt.equals("NotesAttachment")) {
            adr = adr.substring(0, adr.indexOf("/$File"));
        }

        // If it doesn't resolve it doesn't exist!
        try {
            s.resolve(adr);
        } catch (NotesException e) {
            throw new DAVNotFoundException();
        }

    }

    /**
     * A notes document has two slashes after the .nsf: .nsf/viewname/docid
     * 
     * @param url
     * @return did we find 2 slashes
     */
    private boolean twoSlashAfterNsf(String url) {

        int whereIsNsf = url.indexOf(".nsf");
        if (whereIsNsf < 0) {
            return false;
        }
        String inspect = url.substring(whereIsNsf);
        return (inspect.indexOf("/") != inspect.lastIndexOf("/"));
    }

    public boolean filter() {
        boolean ret = true;
        // // LOGGER.info("Start filter ");
        DAVRepositoryDomino rep = (DAVRepositoryDomino) this.getRepository();
        String filter = rep.getFilter();
        if (filter.equals("")) {
            // LOGGER.info("Filter null");
            return true;
        }
        // LOGGER.info("Filter is "+filter);
        Document doc = getDocument();
        if (doc == null) {
            // LOGGER.info("Get Document is null");
            return ret;
        }
        try {
            DAVRepositoryMETA drm = WebDavManager.getManager(null).getRepositoryMeta();
            if (drm == null) {
                return true;
            }
            Base repDoc = (Base) DominoProxy.resolve(drm.getRepositoryConfigLocation());
            if (repDoc != null) {
                // LOGGER.info("Rep internal address not null; has class="+repDoc.getClass().toString());
                Database db = null;
                if (repDoc instanceof Document) {
                    // LOGGER.info("rep doc is a Document");
                    db = ((Document) repDoc).getParentDatabase();
                }
                if (repDoc instanceof View) {
                    // LOGGER.info("repdoc is a view");
                    View vw = ((View) repDoc);
                    db = (Database) vw.getParent();
                }
                if (db != null) {
                    // LOGGER.info("Parent database not null");
                    Document docP = db.createDocument();
                    // LOGGER.info("Create document parameters...");
                    docP.replaceItemValue("Form", "webDavParameters");
                    docP.computeWithForm(true, false);
                    // LOGGER.info("Compute with form OK!");
                    @SuppressWarnings("rawtypes")
                    Vector items = docP.getItems();
                    for (int i = 0; i < items.size(); i++) {
                        Item itm = (Item) items.get(i);
                        // LOGGER.info("Item "+itm.getName()+"="+itm.getValueString());
                        filter = filter.replaceAll("\\x5B\\x5B" + itm.getName() + "\\x5D\\x5D",
                                "\"" + itm.getValueString() + "\"");
                    }
                    if (!filter.equals("")) {
                        // LOGGER.info("Filter="+filter);
                        Session ses = DominoProxy.getUserSession();
                        @SuppressWarnings("rawtypes")
                        Vector eval = ses.evaluate(filter, doc);
                        if (eval == null) {
                            return true;
                        }
                        String retS = eval.firstElement().toString().toLowerCase();
                        // LOGGER.info("Evaluate result="+retS);
                        if (retS.equals("1.0")) {
                            // LOGGER.info("Filter pass OK!");
                            return true;
                        } else {
                            // LOGGER.info("Filter didn't pass");
                            return false;
                        }
                    }
                }
            }

        } catch (NotesException ne) {
            LOGGER.error("Error on filter;" + ne.getMessage());
            return ret;
        }
        return ret;
    }

    public abstract Document getDocument();
}