com.surevine.alfresco.webscript.perishable.PerishableWebscript.java Source code

Java tutorial

Introduction

Here is the source code for com.surevine.alfresco.webscript.perishable.PerishableWebscript.java

Source

/*
 * Copyright (C) 2008-2010 Surevine Limited.
 *   
 * Although intended for deployment and use alongside Alfresco this module should
 * be considered 'Not a Contribution' as defined in Alfresco'sstandard contribution agreement, see
 * http://www.alfresco.org/resource/AlfrescoContributionAgreementv2.pdf
 * 
 * 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.surevine.alfresco.webscript.perishable;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.alfresco.model.ContentModel;
import org.alfresco.model.ForumModel;
import org.alfresco.repo.jscript.Scopeable;
import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.preference.PreferenceService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionHistory;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.log4j.Logger;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;

import com.surevine.alfresco.model.ManagedDeletionModel;
import com.surevine.alfresco.presence.PresenceService;
import com.surevine.alfresco.repo.delete.ManagedDeletionService;
import com.surevine.alfresco.repo.delete.NodeArchivalDetails;

public class PerishableWebscript extends DeclarativeWebScript implements Scopeable {
    private static final Logger _logger = Logger.getLogger(PerishableWebscript.class);

    private static final StoreRef STORE_REF = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");

    private static final int MAX_RESULTS = 100;

    private ServiceRegistry _serviceRegistry;
    private SearchService _searchService;
    private PersonService _personService;
    private NodeService _nodeService;
    private PresenceService _presenceService;
    private PreferenceService _preferenceService;
    private VersionService _versionService;
    private ManagedDeletionService _managedDeletionService;
    private Scriptable _scope;

    public void setServiceRegistry(final ServiceRegistry serviceRegistry) {
        _serviceRegistry = serviceRegistry;
        _searchService = _serviceRegistry.getSearchService();
        _personService = _serviceRegistry.getPersonService();
        _nodeService = _serviceRegistry.getNodeService();
        _versionService = _serviceRegistry.getVersionService();
    }

    public void setSearchService(final SearchService searchService) {
        _searchService = searchService;
    }

    public void setPersonService(final PersonService personService) {
        _personService = personService;
    }

    public void setNodeService(final NodeService nodeService) {
        _nodeService = nodeService;
    }

    public void setPresenceService(final PresenceService presenceService) {
        _presenceService = presenceService;
    }

    public void setManagedDeletionService(final ManagedDeletionService managedDeletionService) {
        _managedDeletionService = managedDeletionService;
    }

    public void setPreferenceService(final PreferenceService preferenceService) {
        _logger.debug("Setting preference service to " + preferenceService);
        _preferenceService = preferenceService;
    }

    public void init() {
    }

    @Override
    protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache) {
        final Map<String, Object> model = new HashMap<String, Object>();

        ensureScopePresent();

        ResultSet rs = null;
        try {
            final SearchParameters parameters = new SearchParameters();
            parameters.addStore(STORE_REF);
            parameters.setLanguage(SearchService.LANGUAGE_LUCENE);
            parameters.setQuery(
                    "+PATH:\"/app:company_home//*\" +ASPECT:\"md:perishable\" -ASPECT:\"md:failedToDelete\"");
            parameters.addSort("@md:perishDue", true);

            rs = _searchService.query(parameters);

            final List<NodeRef> untrimmedNodeRefs = rs.getNodeRefs();
            final List<NodeRef> nodeRefs = untrimmedNodeRefs.subList(0,
                    untrimmedNodeRefs.size() > MAX_RESULTS ? MAX_RESULTS : untrimmedNodeRefs.size());

            final ArrayList<Map<String, Object>> results = new ArrayList<Map<String, Object>>();

            final List<ItemApplicabilityVoter> voters = getVoters(
                    _serviceRegistry.getAuthenticationService().getCurrentUserName());

            for (final NodeRef nodeRef : nodeRefs) {
                boolean isApplicable = false;

                ArrayList<String> explanations = new ArrayList<String>();

                for (ItemApplicabilityVoter voter : voters) {
                    if (voter.isItemApplicable(nodeRef)) {
                        isApplicable = true;

                        explanations.add(voter.getApplicabilityString(nodeRef));
                    }
                }

                if (!isApplicable) {
                    continue;
                }

                final String perishRequestedBy = String
                        .valueOf(_nodeService.getProperty(nodeRef, ManagedDeletionModel.PROP_PERISH_REQUESTED_BY));

                NodeArchivalDetails archiveDetails = _managedDeletionService.getArchivalDetails(nodeRef);

                final Map<String, Object> item = new HashMap<String, Object>();
                item.put("node", new ScriptNode(nodeRef, _serviceRegistry, _scope));
                item.put("perishRequestedByUser", _personService.getPerson(perishRequestedBy));
                item.put("perishRequestedByPresence", _presenceService.getUserPresence(perishRequestedBy, false));
                item.put("perishDue", _nodeService.getProperty(nodeRef, ManagedDeletionModel.PROP_PERISH_DUE));
                item.put("perishApplied",
                        _nodeService.getProperty(nodeRef, ManagedDeletionModel.PROP_PERISHED_APPLIED));
                item.put("archiveDue", archiveDetails.archivalDue());
                item.put("explanations", explanations);

                // For an unknown reason node.children[] is returning null so we get the information using
                // the longer syntax
                if (_nodeService.getType(nodeRef).equals(ForumModel.TYPE_TOPIC)) {
                    List<ChildAssociationRef> postAssocRefs = _nodeService.getChildAssocs(nodeRef,
                            ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);

                    if (postAssocRefs.isEmpty()) {
                        // This really shouldn't happen, but if it does, handle it cleanly
                        _logger.warn("Topic node without any posts: " + nodeRef);
                        continue;
                    }

                    item.put("postNode",
                            new ScriptNode(postAssocRefs.get(0).getChildRef(), _serviceRegistry, _scope));
                }

                results.add(item);
            }

            // Re-sort the results as the lucene results are sorted by perishDue
            // (which does not take into account marked for deletion)
            Collections.sort(results, new Comparator<Map<String, Object>>() {
                @Override
                public int compare(Map<String, Object> arg0, Map<String, Object> arg1) {
                    Date archiveDue0 = (Date) arg0.get("archiveDue");
                    Date archiveDue1 = (Date) arg1.get("archiveDue");

                    return archiveDue0.compareTo(archiveDue1);
                }
            });

            model.put("results", results);
        } finally {
            if (rs != null)
                rs.close();
        }

        return model;
    }

    private List<ItemApplicabilityVoter> getVoters(final String userName) {
        List<ItemApplicabilityVoter> applicabilityVoters = new ArrayList<ItemApplicabilityVoter>(5);

        applicabilityVoters = new ArrayList<ItemApplicabilityVoter>();

        applicabilityVoters.add(new IsUserCreatorVoter(userName));
        applicabilityVoters.add(new IsUserEditorVoter(userName));
        applicabilityVoters.add(new IsUserMarkerVoter(userName));
        applicabilityVoters.add(new IsUserCommenterVoter(userName));
        applicabilityVoters.add(new IsUserDiscussionReplierVoter(userName));
        applicabilityVoters.add(new HasUserFavouritedVoter(userName));

        return applicabilityVoters;
    }

    @Override
    public void setScope(Scriptable scope) {
        _scope = scope;
    }

    private void ensureScopePresent() {
        if (_scope == null) {
            // Create a scope for the value conversion. This scope will be an
            // empty scope exposing basic Object and Function, sufficient for
            // value-conversion.
            // In case no context is active for the current thread, we can
            // safely enter end exit one to get hold of a scope
            Context ctx = Context.getCurrentContext();

            boolean closeContext = false;

            if (ctx == null) {
                ctx = Context.enter();
                closeContext = true;
            }

            _scope = ctx.initStandardObjects(null);
            _scope.setParentScope(null);

            if (closeContext) {
                // Only an exit call should be done when context didn't exist
                // before
                Context.exit();
            }
        }
    }

    private interface ItemApplicabilityVoter {
        boolean isItemApplicable(NodeRef nodeRef);

        String getApplicabilityString(NodeRef nodeRef);
    }

    private abstract class AbstractItemApplicabilityVoter implements ItemApplicabilityVoter {
        protected String userName;

        public AbstractItemApplicabilityVoter(final String userName) {
            this.userName = userName;
        }
    }

    /**
     * Did the user create the document?
     */
    private class IsUserCreatorVoter extends AbstractItemApplicabilityVoter {

        public IsUserCreatorVoter(final String userName) {
            super(userName);
        }

        @Override
        public boolean isItemApplicable(NodeRef nodeRef) {
            final Object creator = _nodeService.getProperty(nodeRef, ContentModel.PROP_CREATOR);

            return ((creator != null) && creator.equals(userName));
        }

        @Override
        public String getApplicabilityString(NodeRef nodeRef) {
            return "perish.explanantion.creator";
        }
    }

    /**
     * Did the user create any previous version of the document?
     */
    private class IsUserEditorVoter extends AbstractItemApplicabilityVoter {
        public IsUserEditorVoter(String userName) {
            super(userName);
        }

        @Override
        public boolean isItemApplicable(NodeRef nodeRef) {
            VersionHistory versionHistory = _versionService.getVersionHistory(nodeRef);

            if (versionHistory == null) {
                return false;
            }

            Collection<Version> versions = versionHistory.getAllVersions();

            if (versions == null) {
                return false;
            }

            for (Version version : versions) {
                if (version.getFrozenModifier().equals(userName)) {
                    return true;
                }
            }

            return false;
        }

        @Override
        public String getApplicabilityString(NodeRef nodeRef) {
            return "perish.explanantion.editor";
        }
    }

    /**
     * Did the user mark the document as perishable
     */
    private class IsUserMarkerVoter extends AbstractItemApplicabilityVoter {
        public IsUserMarkerVoter(String userName) {
            super(userName);
        }

        @Override
        public boolean isItemApplicable(NodeRef nodeRef) {
            Object user = _nodeService.getProperty(nodeRef, ManagedDeletionModel.PROP_PERISH_REQUESTED_BY);

            return ((user != null) && user.equals(userName));
        }

        @Override
        public String getApplicabilityString(NodeRef nodeRef) {
            return "perish.explanantion.marker";
        }
    }

    /**
     * Did the user comment on the document?
     */
    private class IsUserCommenterVoter extends AbstractItemApplicabilityVoter {
        public IsUserCommenterVoter(String userName) {
            super(userName);
        }

        @Override
        public boolean isItemApplicable(NodeRef nodeRef) {
            if (!ContentModel.TYPE_CONTENT.equals(_nodeService.getType(nodeRef))) {
                return false;
            }

            List<ChildAssociationRef> forumAssocRefs = _nodeService.getChildAssocs(nodeRef,
                    ForumModel.ASSOC_DISCUSSION, RegexQNamePattern.MATCH_ALL);

            if (forumAssocRefs.size() == 0) {
                return false;
            }

            ChildAssociationRef forumAssocRef = forumAssocRefs.get(0);

            List<ChildAssociationRef> topicNodeAssocRefs = _nodeService.getChildAssocs(forumAssocRef.getChildRef(),
                    ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);

            if (topicNodeAssocRefs.size() == 0) {
                return false;
            }

            ChildAssociationRef topicAssocRef = topicNodeAssocRefs.get(0);

            List<ChildAssociationRef> postAssocRefs = _nodeService.getChildAssocs(topicAssocRef.getChildRef(),
                    ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);

            if (postAssocRefs.size() == 0) {
                return false;
            }

            for (ChildAssociationRef postAssocRef : postAssocRefs) {
                Object creator = _nodeService.getProperty(postAssocRef.getChildRef(), ContentModel.PROP_CREATOR);

                if ((creator != null) && creator.equals(userName)) {
                    return true;
                }
            }

            return false;
        }

        @Override
        public String getApplicabilityString(NodeRef nodeRef) {
            return "perish.explanantion.commenter";
        }
    }

    /**
     * Did the user reply to a discussion?
     */
    private class IsUserDiscussionReplierVoter extends AbstractItemApplicabilityVoter {
        public IsUserDiscussionReplierVoter(String userName) {
            super(userName);
        }

        @Override
        public boolean isItemApplicable(NodeRef nodeRef) {
            if (!ForumModel.TYPE_TOPIC.equals(_nodeService.getType(nodeRef))) {
                return false;
            }

            List<ChildAssociationRef> postAssocRefs = _nodeService.getChildAssocs(nodeRef,
                    ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);

            if (postAssocRefs.size() <= 1) { // Need more than the initial reply.
                return false;
            }

            final String topicName = _nodeService.getProperty(nodeRef, ContentModel.PROP_NAME).toString();

            for (ChildAssociationRef postAssocRef : postAssocRefs) {
                Object creator = _nodeService.getProperty(postAssocRef.getChildRef(), ContentModel.PROP_CREATOR);

                if ((creator != null) && creator.equals(userName)) {
                    final String postName = _nodeService
                            .getProperty(postAssocRef.getChildRef(), ContentModel.PROP_NAME).toString();

                    if (!topicName.equals(postName)) { // Exclude initial reply.
                        return true;
                    }
                }
            }

            return false;
        }

        @Override
        public String getApplicabilityString(NodeRef nodeRef) {
            return "perish.explanantion.replier";
        }
    }

    /**
     * Has the user favourited the document?
     */
    private class HasUserFavouritedVoter extends AbstractItemApplicabilityVoter {
        private HashSet<String> favourites = null;

        public HasUserFavouritedVoter(String userName) {
            super(userName);

            Map<String, Serializable> prefs = _preferenceService.getPreferences(userName,
                    "org.alfresco.share.documents.favourites");

            Object prefsFavourites = prefs.get("org.alfresco.share.documents.favourites");

            if (prefsFavourites == null) {
                return;
            }

            String favouritesString = prefsFavourites.toString();

            if (favouritesString == null) {
                return;
            }

            String[] favouritesArray = favouritesString.split(",");

            favourites = new HashSet<String>();

            for (int i = 0; i < favouritesArray.length; ++i) {
                favourites.add(favouritesArray[i]);
            }

        }

        @Override
        public boolean isItemApplicable(NodeRef nodeRef) {
            return ((favourites != null) && favourites.contains(nodeRef.toString()));
        }

        @Override
        public String getApplicabilityString(NodeRef nodeRef) {
            return "perish.explanantion.favourite";
        }
    }
}