com.openkm.servlet.admin.JcrRepositoryViewServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.openkm.servlet.admin.JcrRepositoryViewServlet.java

Source

/**
 *  OpenKM, Open Document Management System (http://www.openkm.com)
 *  Copyright (c) 2006-2015  Paco Avila & Josep Llort
 *
 *  No bytes were intentionally harmed during the development of this application.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package com.openkm.servlet.admin;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import javax.jcr.LoginException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.ValueFormatException;
import javax.jcr.lock.Lock;
import javax.jcr.nodetype.PropertyDefinition;
import javax.jcr.util.TraversingItemVisitor;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.core.NodeImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.openkm.api.OKMFolder;
import com.openkm.bean.ContentInfo;
import com.openkm.bean.Document;
import com.openkm.bean.Folder;
import com.openkm.bean.Scripting;
import com.openkm.core.AccessDeniedException;
import com.openkm.core.DatabaseException;
import com.openkm.core.PathNotFoundException;
import com.openkm.dao.LockTokenDAO;
import com.openkm.extractor.RegisteredExtractors;
import com.openkm.module.jcr.stuff.JCRUtils;
import com.openkm.util.FormatUtil;
import com.openkm.util.UserActivity;
import com.openkm.util.WebUtils;

/**
 * RepositoryView servlet
 */
public class JcrRepositoryViewServlet extends BaseServlet {
    private static final long serialVersionUID = 1L;
    private static Logger log = LoggerFactory.getLogger(JcrRepositoryViewServlet.class);
    private static final String[] NODE_TYPE = { "UNDEFINED", "STRING", "BINARY", "LONG", "DOUBLE", "DATE",
            "BOOLEAN", "NAME", "PATH", "REFERENCE" };

    @Override
    public void service(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        String method = request.getMethod();

        if (checkMultipleInstancesAccess(request, response)) {
            if (method.equals(METHOD_GET)) {
                doGet(request, response);
            } else if (method.equals(METHOD_POST)) {
                doPost(request, response);
            }
        }
    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        log.debug("doGet({}, {})", request, response);
        request.setCharacterEncoding("UTF-8");
        String action = WebUtils.getString(request, "action");
        String path = WebUtils.getString(request, "path");
        Session session = null;
        updateSessionManager(request);

        try {
            session = JCRUtils.getSession();

            if (action.equals("unlock")) {
                unlock(session, path, request, response);
            } else if (action.equals("checkin")) {
                checkin(session, path, request, response);
            } else if (action.equals("remove_content")) {
                removeContent(session, path, request, response);
            } else if (action.equals("remove_current")) {
                path = removeCurrent(session, path, request, response);
            } else if (action.equals("remove_mixin")) {
                removeMixin(session, path, request, response);
            } else if (action.equals("edit")) {
                edit(session, path, request, response);
            } else if (action.equals("textExtraction")) {
                textExtraction(session, path, request, response);
            }

            if (!action.equals("edit")) {
                list(session, path, request, response);
            }
        } catch (LoginException e) {
            log.error(e.getMessage(), e);
            sendErrorRedirect(request, response, e);
        } catch (RepositoryException e) {
            log.error(e.getMessage(), e);
            sendErrorRedirect(request, response, e);
        } catch (DatabaseException e) {
            log.error(e.getMessage(), e);
            sendErrorRedirect(request, response, e);
        } finally {
            JCRUtils.logout(session);
        }
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        log.debug("doPost({}, {})", request, response);
        request.setCharacterEncoding("UTF-8");
        String action = WebUtils.getString(request, "action");
        String path = WebUtils.getString(request, "path");
        Session session = null;
        updateSessionManager(request);

        try {
            session = JCRUtils.getSession();

            if ("save".equals(action)) {
                save(session, path, request, response);
                list(session, path, request, response);
            }
        } catch (LoginException e) {
            log.error(e.getMessage(), e);
            sendErrorRedirect(request, response, e);
        } catch (RepositoryException e) {
            log.error(e.getMessage(), e);
            sendErrorRedirect(request, response, e);
        } catch (DatabaseException e) {
            log.error(e.getMessage(), e);
            sendErrorRedirect(request, response, e);
        } finally {
            JCRUtils.logout(session);
        }
    }

    /**
     * Unlock node
     */
    private void unlock(Session session, String path, HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, javax.jcr.PathNotFoundException, RepositoryException,
            DatabaseException {
        log.debug("unlock({}, {}, {}, {})", new Object[] { session, path, request, response });
        Node node = session.getRootNode().getNode(path.substring(1));
        Lock lock = node.getLock();
        String lt = JCRUtils.getLockToken(node.getUUID());

        if (lock.getLockOwner().equals(session.getUserID())) {
            JCRUtils.loadLockTokens(session);

            // If the session contains the lock token of this locked node
            if (Arrays.asList(session.getLockTokens()).contains(lt)) {
                node.unlock();
                JCRUtils.removeLockToken(session, node);
            } else {
                session.addLockToken(lt);
                node.unlock();
                LockTokenDAO.delete(lock.getLockOwner(), lt);
            }
        } else {
            session.addLockToken(lt);
            node.unlock();
            LockTokenDAO.delete(lock.getLockOwner(), lt);
        }

        // Activity log
        UserActivity.log(session.getUserID(), "ADMIN_REPOSITORY_UNLOCK", node.getUUID(), path, null);
        log.debug("unlock: void");
    }

    /**
     * Node check-in
     */
    private void checkin(Session session, String path, HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, javax.jcr.PathNotFoundException, RepositoryException {
        log.debug("checkin({}, {}, {}, {})", new Object[] { session, path, request, response });
        Node node = session.getRootNode().getNode(path.substring(1));
        node.checkin();

        // Activity log
        UserActivity.log(session.getUserID(), "ADMIN_REPOSITORY_CHECKIN", node.getUUID(), path, null);
        log.debug("checkin: void");
    }

    /**
     * Remove children nodes
     */
    private void removeContent(Session session, String path, HttpServletRequest request,
            HttpServletResponse response)
            throws ServletException, IOException, javax.jcr.PathNotFoundException, RepositoryException {
        log.debug("removeCurrent({}, {}, {}, {})", new Object[] { session, path, request, response });
        Node node = session.getRootNode().getNode(path.substring(1));

        for (NodeIterator ni = node.getNodes(); ni.hasNext();) {
            Node child = ni.nextNode();
            child.remove();
            node.save();
        }

        // Activity log
        UserActivity.log(session.getUserID(), "ADMIN_REPOSITORY_REMOVE_CONTENT", node.getUUID(), path, null);
        log.debug("removeCurrent: void");
    }

    /**
     * Remove current node and its children
     */
    private String removeCurrent(Session session, String path, HttpServletRequest request,
            HttpServletResponse response)
            throws ServletException, IOException, javax.jcr.PathNotFoundException, RepositoryException {
        log.debug("removeCurrent({}, {}, {}, {})", new Object[] { session, path, request, response });
        Node node = session.getRootNode().getNode(path.substring(1));
        String uuid = node.getUUID();
        Node parent = node.getParent();
        String parentPath = parent.getPath();
        node.remove();
        parent.save();

        // Activity log
        UserActivity.log(session.getUserID(), "ADMIN_REPOSITORY_REMOVE_CURRENT", uuid, path, null);
        log.debug("removeCurrent: {}", path);
        return parentPath;
    }

    /**
     * Remove mixin
     */
    private void removeMixin(Session session, String path, HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, javax.jcr.PathNotFoundException, RepositoryException {
        log.debug("removeMixin({}, {}, {}, {})", new Object[] { session, path, request, response });
        Node node = session.getRootNode().getNode(path.substring(1));
        String mixin = WebUtils.getString(request, "mixin");
        node.removeMixin(mixin);
        node.save();

        // Activity log
        UserActivity.log(session.getUserID(), "ADMIN_REPOSITORY_REMOVE_MIXIN", node.getUUID(), path, mixin);
        log.debug("removeMixin: {}", path);
    }

    /**
     * Edit property
     */
    private void edit(Session session, String path, HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, javax.jcr.PathNotFoundException, RepositoryException {
        log.debug("edit({}, {}, {}, {})", new Object[] { session, path, request, response });
        String property = WebUtils.getString(request, "property");
        ServletContext sc = getServletContext();
        Node node = session.getRootNode().getNode(path.substring(1));
        Property prop = node.getProperty(property);
        boolean multiple = false;
        String value;

        if (prop.getDefinition().isMultiple()) {
            value = toString(prop.getValues(), "\n");
            multiple = true;
        } else {
            value = prop.getValue().getString();
        }

        // Activity log
        UserActivity.log(session.getUserID(), "ADMIN_REPOSITORY_EDIT", node.getUUID(), path,
                property + ", " + value);

        sc.setAttribute("node", node);
        sc.setAttribute("property", prop);
        sc.setAttribute("multiple", multiple || prop.getName().equals(Scripting.SCRIPT_CODE));
        sc.setAttribute("value", value);
        sc.getRequestDispatcher("/admin/jcr_repository_edit.jsp").forward(request, response);
        log.debug("edit: void");
    }

    /**
     * Save property
     */
    private void save(Session session, String path, HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, javax.jcr.PathNotFoundException, RepositoryException {
        log.debug("save({}, {}, {}, {})", new Object[] { session, path, request, response });
        String value = WebUtils.getString(request, "value");
        String property = WebUtils.getString(request, "property");
        Node node = session.getRootNode().getNode(path.substring(1));
        Property prop = node.getProperty(property);
        ValueFactory vf = session.getValueFactory();

        if (prop.getDefinition().isMultiple()) {
            StringTokenizer st = new StringTokenizer(value, "\n");
            Value[] values = new Value[st.countTokens()];

            for (int i = 0; st.hasMoreTokens(); i++) {
                values[i] = vf.createValue(st.nextToken().trim());
            }

            node.setProperty(property, values);
        } else {
            node.setProperty(property, value);
        }

        node.save();

        // Activity log
        UserActivity.log(session.getUserID(), "ADMIN_REPOSITORY_SAVE", node.getUUID(), path,
                property + ", " + value);
        log.debug("save: void");
    }

    /**
     * Document text extraction
     */
    private void textExtraction(Session session, String path, HttpServletRequest request,
            HttpServletResponse response)
            throws ServletException, IOException, javax.jcr.PathNotFoundException, RepositoryException {
        log.debug("textExtraction({}, {}, {}, {})", new Object[] { session, path, request, response });
        TraversingItemVisitor tiv = new TraversingItemVisitor.Default() {
            @Override
            protected void entering(Node node, int level) throws RepositoryException {
                if (node.isNodeType(Document.CONTENT_TYPE)) {
                    Node docNode = node.getParent();
                    log.info("Document: {}", docNode.getPath());
                    String mimeType = node.getProperty(JcrConstants.JCR_MIMETYPE).getString();

                    if (!node.isLocked()) {
                        try {
                            node.checkout();
                            RegisteredExtractors.index(docNode, node, mimeType);
                            node.setProperty(Document.VERSION_COMMENT, "Text extraction");
                            node.save();
                        } catch (IOException e) {
                            log.error("Error when extracting text: {}", e.getMessage());
                        } finally {
                            if (node.isCheckedOut()) {
                                node.checkin();
                            }
                        }
                    }
                }
            }
        };

        Node node = session.getRootNode().getNode(path.substring(1));
        session.getItem(node.getPath()).accept(tiv);

        // Activity log
        UserActivity.log(session.getUserID(), "ADMIN_REPOSITORY_TEXT_EXTRACTION", node.getUUID(), null, null);
        log.debug("textExtraction: void");
    }

    /**
     * List node properties and children
     */
    private void list(Session session, String path, HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, javax.jcr.PathNotFoundException, RepositoryException {
        log.debug("list({}, {}, {}, {})", new Object[] { session, path, request, response });
        String stats = WebUtils.getString(request, "stats");
        String uuid = WebUtils.getString(request, "uuid");
        ServletContext sc = getServletContext();
        ContentInfo ci = null;
        Node node = null;

        // Respository stats calculation
        if (!stats.equals("")) {
            if (stats.equals("0")) {
                request.getSession().removeAttribute("stats");
            } else {
                request.getSession().setAttribute("stats", true);
            }
        }

        // Handle path or uuid
        if (!path.equals("")) {
            if (path.equals("/")) {
                node = session.getRootNode();
            } else {
                node = session.getRootNode().getNode(path.substring(1));
            }
        } else if (!uuid.equals("")) {
            node = session.getNodeByUUID(uuid);
            path = node.getPath();
        } else {
            node = session.getRootNode();
        }

        if (request.getSession().getAttribute("stats") != null && node.isNodeType(Folder.TYPE)) {
            try {
                ci = OKMFolder.getInstance().getContentInfo(null, node.getPath());
            } catch (AccessDeniedException e) {
                log.warn(e.getMessage(), e);
            } catch (com.openkm.core.RepositoryException e) {
                log.warn(e.getMessage(), e);
            } catch (PathNotFoundException e) {
                log.warn(e.getMessage(), e);
            } catch (DatabaseException e) {
                log.warn(e.getMessage(), e);
            }
        }

        // Activity log
        if (node.isNodeType(JcrConstants.MIX_REFERENCEABLE)) {
            UserActivity.log(session.getUserID(), "ADMIN_REPOSITORY_LIST", node.getUUID(), node.getPath(), null);
        } else {
            UserActivity.log(session.getUserID(), "ADMIN_REPOSITORY_LIST", ((NodeImpl) node).getId().toString(),
                    node.getPath(), null);
        }

        sc.setAttribute("contentInfo", ci);
        sc.setAttribute("node", node);
        sc.setAttribute("isFolder", node.isNodeType(Folder.TYPE));
        sc.setAttribute("isDocument", node.isNodeType(Document.TYPE));
        sc.setAttribute("isDocumentContent", node.isNodeType(Document.CONTENT_TYPE));
        sc.setAttribute("isScripting", node.isNodeType(Scripting.TYPE));
        sc.setAttribute("holdsLock", node.holdsLock());
        sc.setAttribute("breadcrumb", createBreadcrumb(node.getPath()));
        sc.setAttribute("properties", getProperties(node));
        sc.setAttribute("children", getChildren(node));
        sc.getRequestDispatcher("/admin/jcr_repository_list.jsp").forward(request, response);
        log.debug("list: void");
    }

    /**
     * Create bread crumb for easy navigation
     */
    private String createBreadcrumb(String path) throws UnsupportedEncodingException {
        int idx = path.lastIndexOf('/');
        if (idx > 0) {
            String name = path.substring(idx + 1);
            String parent = path.substring(0, idx);
            return createBreadcrumb(parent) + " / <a href=\"JcrRepositoryView?path="
                    + URLEncoder.encode(path, "UTF-8") + "\">" + name + "</a>";
        } else {
            if (!path.substring(1).equals("")) {
                return "<a href=\"JcrRepositoryView?path=\">ROOT</a> / <a href=\"JcrRepositoryView?path="
                        + URLEncoder.encode(path, "UTF-8") + "\">" + path.substring(1) + "</a>";
            } else {
                return "<a href=\"JcrRepositoryView?path=\">ROOT</a> /";
            }
        }
    }

    /**
     * Get children from node
     */
    private Collection<Map<String, Object>> getChildren(Node node) throws RepositoryException {
        ArrayList<Map<String, Object>> al = new ArrayList<Map<String, Object>>();
        Map<String, Object> hm = new HashMap<String, Object>();

        for (NodeIterator ni = node.getNodes(); ni.hasNext();) {
            Node child = ni.nextNode();
            hm = new HashMap<String, Object>();

            if (child.isNodeType(Document.TYPE)) {
                Node contentNode = child.getNode(Document.CONTENT);
                contentNode.isCheckedOut();
                hm.put("checkedOut", contentNode.isCheckedOut());
            } else if (child.isNodeType(Document.CONTENT_TYPE)) {
                hm.put("checkedOut", child.isCheckedOut());
            }

            hm.put("name", child.getName());
            hm.put("path", child.getPath());
            hm.put("locked", child.isLocked());
            hm.put("locked", child.isLocked());
            hm.put("primaryNodeType", child.getPrimaryNodeType().getName());
            hm.put("isFolder", child.isNodeType(Folder.TYPE));
            hm.put("isDocument", child.isNodeType(Document.TYPE));
            hm.put("isDocumentContent", child.isNodeType(Document.CONTENT_TYPE));
            al.add(hm);
        }

        Collections.sort(al, new ChildCmp());
        return al;
    }

    /**
     * Make child node comparable
     */
    protected class ChildCmp implements Comparator<Map<String, Object>> {
        @Override
        public int compare(Map<String, Object> arg0, Map<String, Object> arg1) {
            return ((String) arg0.get("name")).compareTo((String) arg1.get("name"));
        }
    }

    /**
     * Get properties from node
     */
    private Collection<HashMap<String, String>> getProperties(Node node)
            throws ValueFormatException, RepositoryException {
        ArrayList<HashMap<String, String>> al = new ArrayList<HashMap<String, String>>();

        for (PropertyIterator pi = node.getProperties(); pi.hasNext();) {
            HashMap<String, String> hm = new HashMap<String, String>();
            Property p = pi.nextProperty();
            PropertyDefinition pd = p.getDefinition();

            hm.put("pName", p.getName());
            hm.put("pProtected", Boolean.toString(pd.isProtected()));
            hm.put("pMultiple", Boolean.toString(pd.isMultiple()));
            hm.put("pType", NODE_TYPE[pd.getRequiredType()]);

            if (pd.getRequiredType() == PropertyType.BINARY) {
                InputStream is = p.getStream();

                try {
                    hm.put("pValue", "DATA: " + FormatUtil.formatSize(is.available()));
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    IOUtils.closeQuietly(is);
                }
            } else {
                if (pd.isMultiple()) {
                    hm.put("pValue", toString(p.getValues(), "<br/>"));
                } else {
                    if (p.getName().equals(Scripting.SCRIPT_CODE)) {
                        hm.put("pValue", p.getString());
                    } else {
                        hm.put("pValue", p.getString());
                    }
                }
            }

            al.add(hm);
        }

        // Add universal node id
        HashMap<String, String> hm = new HashMap<String, String>();
        hm.put("pName", "jcr:aid");
        hm.put("pProtected", Boolean.toString(true));
        hm.put("pMultiple", Boolean.toString(false));
        hm.put("pType", "VIRTUAL");
        hm.put("pValue", ((NodeImpl) node).getId().toString());
        al.add(hm);

        Collections.sort(al, new PropertyCmp());
        return al;
    }

    /**
     * Make properties comparable
     */
    protected class PropertyCmp implements Comparator<HashMap<String, String>> {
        @Override
        public int compare(HashMap<String, String> arg0, HashMap<String, String> arg1) {
            return arg0.get("pName").compareTo(arg1.get("pName"));
        }
    }

    /**
     * Convert multi-value property to string 
     */
    private String toString(Value[] v, String delim)
            throws ValueFormatException, IllegalStateException, RepositoryException {
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < v.length - 1; i++) {
            sb.append(v[i].getString());
            sb.append(delim);
        }

        if (v.length > 0) {
            sb.append(v[v.length - 1].getString());
        }

        return sb.toString();
    }
}