(lockState, status);
    }
    
    /**
     * @see LockService#getLockType(NodeRef)
     */
    @Extend(traitAPI=LockServiceTrait.class,extensionAPI=LockServiceExtension.class)
    public LockType getLockType(NodeRef nodeRef)
    {
        LockType result = null;
        // Don't disable the lockable aspect interceptor - allow it to fetch the lock type
        // from the correct place (persistent storage or lockStore).
        if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE) == true)
        {
            String lockTypeString = (String) this.nodeService.getProperty(nodeRef, ContentModel.PROP_LOCK_TYPE);
            if (lockTypeString != null)
            {
                result = LockType.valueOf(lockTypeString);
            }
        }
        return result;
    }
    /**
     * Checks for the lock aspect. Adds if missing.
     * 
     * @param nodeRef
     *            the node reference
     */
    private void ensureLockAspect(NodeRef nodeRef)
    {
        if (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE) == false)
        {
            this.nodeService.addAspect(nodeRef, ContentModel.ASPECT_LOCKABLE, null);
        }
    }
    /**
     * {@inheritDoc}
     */
    @Extend(traitAPI=LockServiceTrait.class,extensionAPI=LockServiceExtension.class)
    public void checkForLock(NodeRef nodeRef) throws NodeLockedException
    {
        String userName = getUserName();
        
        nodeRef = tenantService.getName(nodeRef);
 
        // Ensure we have found a node reference
        if (nodeRef != null && userName != null)
        {
            String effectiveUserName = AuthenticationUtil.getRunAsUser();
            // Check to see if should just ignore this node - note: special MT System due to AuditableAspect
            if (! (ignore(nodeRef) || tenantService.getBaseNameUser(effectiveUserName).equals(AuthenticationUtil.getSystemUserName())))
            {
                try
                {
                    // Get the current lock status on the node ref
                    LockStatus currentLockStatus = getLockStatus(nodeRef, userName);
                    LockType lockType = getLockType(nodeRef);
                    if (LockType.WRITE_LOCK.equals(lockType) == true && 
                        LockStatus.LOCKED.equals(currentLockStatus) == true)
                    {
                        // Lock is of type Write Lock and the node is locked by another owner.
                        throw new NodeLockedException(nodeRef);
                    }
                    else if (LockType.READ_ONLY_LOCK.equals(lockType) == true &&
                             (LockStatus.LOCKED.equals(currentLockStatus) == true || LockStatus.LOCK_OWNER.equals(currentLockStatus) == true))
                    {
                        // Error since there is a read only lock on this object and all
                        // modifications are prevented
                        throw new NodeLockedException(nodeRef);
                    }
                    else if (LockType.NODE_LOCK.equals(lockType) == true &&
                            (LockStatus.LOCKED.equals(currentLockStatus) == true || LockStatus.LOCK_OWNER.equals(currentLockStatus) == true))
                    {
                        // Error since there is a read only lock on this object and all
                        // modifications are prevented
                        throw new NodeLockedException(nodeRef);
                    }
                }
                catch (AspectMissingException exception)
                {
                    // Ignore since this indicates that the node does not have the lock aspect applied
                }
            }
        }
    }
    /**
     * Ensures that the parent is not locked.
     * 
     * @see #checkForLock(NodeRef)
     */
    public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode)
    {
        LockType lockType = getLockType(childAssocRef.getParentRef());
        if(lockType != null)
        {
        
            switch (lockType)
            {
                case WRITE_LOCK:
                case READ_ONLY_LOCK:
                    checkForLock(childAssocRef.getParentRef());
                    break;
                case NODE_LOCK:
                // don't check for lock
            }
        }
    }
    /**
     * Ensures that node is not locked.
     * 
     * @see #checkForLock(NodeRef)
     */
    public void beforeUpdateNode(NodeRef nodeRef)
    {
        checkForLock(nodeRef);
    }
    /**
     * Ensures that node is not locked.
     * 
     * @see #checkForLock(NodeRef)
     */
    public void beforeDeleteNode(NodeRef nodeRef)
    {
        checkForLock(nodeRef);
    }
    /**
     * @return              Returns {@link DoNothingCopyBehaviourCallback}
     */
    public CopyBehaviourCallback getCopyCallback(QName classRef, CopyDetails copyDetails)
    {
        return DoNothingCopyBehaviourCallback.getInstance();
    }
    /**
     * OnCreateVersion behaviour for the lock aspect
     * 
     * Ensures that the property values of the lock aspect are not 'frozen' in
     * the version store.
     */
    public void onCreateVersion(
            QName classRef,
            NodeRef versionableNode,
            Map versionProperties,
            PolicyScope nodeDetails)
    {
        // Add the lock aspect, but do not version the property values
        // TODO: disable the LockAspectInterceptor for this thread, re-enable in finally.
        //       (we need to add this aspect for real).
        nodeDetails.addAspect(ContentModel.ASPECT_LOCKABLE);
    }
    /**
     * Get the current user reference
     * 
     * @return the current user reference
     */
    private String getUserName()
    {
        return this.authenticationService.getCurrentUserName();
    }
    /**
     * @deprecated Uses search and does not report on ephemeral locks.
     */
    @Deprecated
    public List getLocks(StoreRef storeRef)
    {
        return getLocks(
                storeRef,
                "ASPECT:\"" + ContentModel.ASPECT_LOCKABLE.toString() + 
                "\" +@\\{http\\://www.alfresco.org/model/content/1.0\\}" + ContentModel.PROP_LOCK_OWNER.getLocalName() + ":\"" + getUserName() + "\"");
    }
    
    /**
     * Get the locks given a store and query string.
     * 
     * @param storeRef      the store reference
     * @param query         the query string
     * @return              the locked nodes
     * @deprecated Uses search and does not report on ephemeral locks.
     */
    @Deprecated
    private List getLocks(StoreRef storeRef, String query)
    {
        List result = new ArrayList();
        ResultSet resultSet = null;
        try
        {
            resultSet = this.searchService.query(
                    storeRef,
                    SearchService.LANGUAGE_LUCENE, 
                    query);
            result = resultSet.getNodeRefs();
        }
        finally
        {
            if (resultSet != null)
            {
                resultSet.close();
            }
        }
        return result;
    }
    /**
     * @deprecated Uses search and does not report on ephemeral locks.
     */
    @Deprecated
    public List getLocks(StoreRef storeRef, LockType lockType)
    {
        return getLocks(
                storeRef,
                "ASPECT:\"" + ContentModel.ASPECT_LOCKABLE.toString() + 
                "\" +@\\{http\\://www.alfresco.org/model/content/1.0\\}" + ContentModel.PROP_LOCK_OWNER.getLocalName() + ":\"" + getUserName() + "\"" +
                " +@\\{http\\://www.alfresco.org/model/content/1.0\\}" + ContentModel.PROP_LOCK_TYPE.getLocalName() + ":\"" + lockType.toString() + "\"");
    }
    @Override
    public void onMoveNode(ChildAssociationRef oldChildAssocRef, ChildAssociationRef newChildAssocRef)
    {
        NodeRef nodeRef = oldChildAssocRef.getChildRef();
        checkForLock(nodeRef);
    }
    @Override
    @Extend(traitAPI=LockServiceTrait.class,extensionAPI=LockServiceExtension.class)
    public void suspendLocks()
    {
       getBehaviourFilter().disableBehaviour(ContentModel.ASPECT_LOCKABLE);
       lockableAspectInterceptor.disableForThread();
    }
    
    @Override
    @Extend(traitAPI=LockServiceTrait.class,extensionAPI=LockServiceExtension.class)
    public void enableLocks()
    {
       getBehaviourFilter().enableBehaviour(ContentModel.ASPECT_LOCKABLE);
       lockableAspectInterceptor.enableForThread();
    }
    @Override
    @Extend(traitAPI=LockServiceTrait.class,extensionAPI=LockServiceExtension.class)
    public String getAdditionalInfo(NodeRef nodeRef)
    {
        LockState lockState = getLockState(nodeRef);
        String additionalInfo = lockState.getAdditionalInfo();
        return additionalInfo;
    }
    @Override
    @Extend(traitAPI=LockServiceTrait.class,extensionAPI=LockServiceExtension.class)
    public LockState getLockState(NodeRef nodeRef)
    {
        // Check in-memory for ephemeral locks first.
        nodeRef = tenantService.getName(nodeRef);
        LockState lockState = lockStore.get(nodeRef);
        
        //ALF-20361: It is possible that a rollback has resulted in a "non-lock" lock state being added to 
        //the lock store. Because of that, we check both whether the retrieved lockState is null and, if it isn't, 
        //whether it represents a real lock
        if (lockState == null || !lockState.isLockInfo())
        {
            // No in-memory state, so get from the DB.
            if (nodeService.exists(nodeRef) && nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE))
            {
                String lockOwner = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_LOCK_OWNER);
                
                Date expiryDate = (Date) nodeService.getProperty(nodeRef, ContentModel.PROP_EXPIRY_DATE);
                String lockTypeStr = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_LOCK_TYPE);
                LockType lockType = lockTypeStr != null ? LockType.valueOf(lockTypeStr) : null;
                String lifetimeStr = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_LOCK_LIFETIME);
                Lifetime lifetime = lifetimeStr != null ? Lifetime.valueOf(lifetimeStr) : null;
                String additionalInfo = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_LOCK_ADDITIONAL_INFO);
                
                // Mark lockstate as PERSISTENT as it was in the persistent storage!
                lockState = LockState.createLock(
                            nodeRef,
                            lockType,
                            lockOwner,
                            expiryDate,
                            lifetime,
                            additionalInfo);
            }
            else
            {
                // There is no lock information
                lockState = LockState.createUnlocked(nodeRef);
            }
        }
        
        // Never return a null LockState
        Assert.notNull(lockState);
        return lockState;
    }
    public void setBehaviourFilter(BehaviourFilter behaviourFilter)
    {
        this.behaviourFilter = behaviourFilter;
    }
    public BehaviourFilter getBehaviourFilter()
    {
        return behaviourFilter;
    }
    public void setNodeIndexer(NodeIndexer nodeIndexer)
    {
        this.nodeIndexer = nodeIndexer;
    }
    @Override
    public void flush()
    {
    }
    @Override
    public void beforeCommit(boolean readOnly)
    {
    }
    @Override
    public void beforeCompletion()
    {
    }
    @Override
    public void afterCommit()
    {
    }
    @Override
    public void afterRollback()
    {
        // As rollback has occurred we are unable to keep hold of any ephemeral locks set during this transaction.
        Map lockedNodes = TransactionalResourceHelper.getMap(KEY_MODIFIED_NODES);
        for (LockState lockInfo : lockedNodes.values())
        {
            lockStore.set(lockInfo.getNodeRef(), lockInfo);
        }
    }
    @Override
    @Extend(traitAPI=LockServiceTrait.class,extensionAPI=LockServiceExtension.class)
    public void setEphemeralExpiryThreshold(int threshSecs)
    {
        ephemeralExpiryThreshold = threshSecs;
    }
    
    public int getEphemeralExpiryThreshold()
    {
        return ephemeralExpiryThreshold;
    }
    @Override
    public  ExtendedTrait getTrait(Class extends M> traitAPI)
    {
        return (ExtendedTrait) lockServiceTrait;
    }
}