001/*
002 *  Copyright 2016 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.workflow.store;
017
018import java.util.ArrayList;
019import java.util.List;
020
021import javax.jcr.Node;
022import javax.jcr.Repository;
023import javax.jcr.RepositoryException;
024import javax.jcr.Session;
025
026import org.apache.cocoon.util.HashUtil;
027import org.apache.commons.lang.StringUtils;
028
029import org.ametys.plugins.workflow.support.WorkflowProvider;
030
031/**
032 * The generic workflow store.
033 * @see WorkflowProvider
034 */
035public class GenericWorkflowStore extends AbstractJackrabbitWorkflowStore
036{
037    /** Internal hash tree node type. */
038    static final String __HTREE_NT = __NM_PREFIX + "hashSegment";
039    
040    /**
041     * Generic workflow store constructor
042     * @param repository The repository
043     */
044    public GenericWorkflowStore(Repository repository)
045    {
046        super(repository);
047    }
048
049    @Override
050    public boolean shouldClearHistory()
051    {
052        return true;
053    }
054    
055    @Override
056    protected void _createRootNode() throws RepositoryException
057    {
058        Session session = null;
059        try
060        {
061            session = _getSession();
062            
063            Node root = session.getRootNode();
064            if (!root.hasNode(__ROOT_NODE))
065            {
066                if (_log.isDebugEnabled())
067                {
068                    _log.debug("Creating osworkflow root node");
069                }
070                
071                root.addNode(__ROOT_NODE, __ROOT_NT);
072                
073                session.save();
074            }
075            else
076            {
077                if (_log.isDebugEnabled())
078                {
079                    _log.debug("Existing osworkflow root node, skipping creation.");
080                }
081            }
082        }
083        finally
084        {
085            _release(session);
086        }
087    }
088    
089    @Override
090    protected Node _getRootNode(Session session) throws RepositoryException
091    {
092        return session.getRootNode().getNode(__ROOT_NODE);
093    }
094    /**
095     * Retrieve the hash used for an entry id.
096     * @param entryId the entry id.
097     * @return the hash parts.
098     */
099    protected List<String> _getEntryHash(long entryId)
100    {
101        long hash = Math.abs(HashUtil.hash(String.valueOf(entryId)));
102        // Prepend 0 for having same length hash parts
103        String hashHexa = StringUtils.leftPad(Long.toString(hash, 16), 4, "0");
104
105        List<String> hashSegments = new ArrayList<>();
106        
107        hashSegments.add(hashHexa.substring(0, 2));
108        hashSegments.add(hashHexa.substring(2, 4));
109        
110        return hashSegments;
111    }
112    
113    @Override
114    protected Node _getOrCreateParentEntryNode(Node root, long id) throws RepositoryException
115    {
116        // Balanced tree management
117        Node htree = root;
118        List<String> hashSegments = _getEntryHash(id);
119        for (String hashSegment : hashSegments)
120        {
121            if (htree.hasNode(hashSegment))
122            {
123                // Go down to a leaf of the hash tree
124                htree = htree.getNode(hashSegment);
125            }
126            else
127            {
128                // Add a new leaf to the hash tree
129                htree = htree.addNode(hashSegment, __HTREE_NT);
130            }
131        }
132        
133        return htree;
134    }
135}