mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
ALF-12866: WebDAV should use in-memory locking for transient locks
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@34167 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.alfresco.repo.webdav;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -27,10 +29,12 @@ import java.util.Set;
|
||||
* @author Ivan Rybnikov
|
||||
*
|
||||
*/
|
||||
public class LockInfo
|
||||
public final class LockInfo implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// Exclusive lock token
|
||||
private String token = null;
|
||||
private String exclusiveLockToken = null;
|
||||
|
||||
// Lock scope
|
||||
private String scope = null;
|
||||
@@ -38,14 +42,14 @@ public class LockInfo
|
||||
// Lock depth
|
||||
private String depth = null;
|
||||
|
||||
// If lock is shared
|
||||
private boolean shared = false;
|
||||
|
||||
// Shared lock tokens
|
||||
private Set<String> sharedLockTokens = null;
|
||||
private final Set<String> sharedLockTokens = new HashSet<String>(3);
|
||||
|
||||
// Shared lock token separator
|
||||
private static final String SHARED_LOCK_TOKEN_SEPARATOR = ",";
|
||||
// User name of the lock's owner
|
||||
private String owner;
|
||||
|
||||
// When does the lock expire?
|
||||
private Date expires;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
@@ -64,7 +68,7 @@ public class LockInfo
|
||||
*/
|
||||
public LockInfo(String token, String scope, String depth)
|
||||
{
|
||||
this.token = token;
|
||||
this.exclusiveLockToken = token;
|
||||
this.scope = scope;
|
||||
this.depth = depth;
|
||||
}
|
||||
@@ -76,11 +80,7 @@ public class LockInfo
|
||||
*/
|
||||
public boolean isLocked()
|
||||
{
|
||||
if (token != null || (sharedLockTokens != null && !sharedLockTokens.isEmpty()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return (isExclusive() || isShared());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,18 +88,20 @@ public class LockInfo
|
||||
*
|
||||
* @param token Lock token
|
||||
*/
|
||||
public void setToken(String token)
|
||||
public void setExclusiveLockToken(String token)
|
||||
{
|
||||
this.token = token;
|
||||
this.exclusiveLockToken = token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for exclusive lock token
|
||||
* @return
|
||||
* Getter for exclusive lock token.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String getToken()
|
||||
public String getExclusiveLockToken()
|
||||
{
|
||||
return token;
|
||||
checkLockState();
|
||||
return exclusiveLockToken;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,110 +145,48 @@ public class LockInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms shared lock tokens string to list.
|
||||
*
|
||||
* @param sharedLockTokens String contains all node's shared lock tokens
|
||||
* divided with SHARED_LOCK_TOKEN_SEPARATOR value.
|
||||
* @return List of shared lock tokens
|
||||
*/
|
||||
public static Set<String> parseSharedLockTokens(String sharedLockTokens)
|
||||
{
|
||||
if (sharedLockTokens == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] sl = sharedLockTokens.split(SHARED_LOCK_TOKEN_SEPARATOR);
|
||||
Set<String> result = new HashSet<String>(sl.length * 2);
|
||||
for (int i = 0; i < sl.length; i++)
|
||||
{
|
||||
result.add(sl[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for sharedLockTokens list
|
||||
* Getter for sharedLockTokens list.
|
||||
*
|
||||
* @return LinkedList<String>
|
||||
*/
|
||||
public Set<String> getSharedLockTokens()
|
||||
{
|
||||
checkLockState();
|
||||
return sharedLockTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for sharedLockTokens list
|
||||
* Setter for sharedLockTokens list.
|
||||
*
|
||||
* @param sharedLockTokens
|
||||
*/
|
||||
public void setSharedLockTokens(Set<String> sharedLockTokens)
|
||||
{
|
||||
this.sharedLockTokens = sharedLockTokens;
|
||||
this.sharedLockTokens.clear();
|
||||
this.sharedLockTokens.addAll(sharedLockTokens);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new shared lock token to sharedLockTokens list
|
||||
* Adds new shared lock token to sharedLockTokens list.
|
||||
*
|
||||
* @param token new token
|
||||
* @param token The token to add.
|
||||
*/
|
||||
public void addSharedLockToken(String token)
|
||||
{
|
||||
if (sharedLockTokens == null)
|
||||
{
|
||||
sharedLockTokens = new HashSet<String>(3);
|
||||
}
|
||||
sharedLockTokens.add(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms list of shared locks to string.
|
||||
* Lock tokens separated with SHARED_LOCK_TOKEN_SEPARATOR value.
|
||||
* Is it a shared lock?
|
||||
*
|
||||
* @param lockTokens list of shared locks
|
||||
* @return String
|
||||
*/
|
||||
public static String makeSharedLockTokensString(Set<String> lockTokens)
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
boolean first = true;
|
||||
for (String token : lockTokens)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
str.append(SHARED_LOCK_TOKEN_SEPARATOR);
|
||||
}
|
||||
else
|
||||
{
|
||||
first = false;
|
||||
}
|
||||
str.append(token);
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for shared property
|
||||
*
|
||||
* @param shared
|
||||
*/
|
||||
public void setShared(boolean shared)
|
||||
{
|
||||
this.shared = shared;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true is lock is shared
|
||||
*
|
||||
* @return boolean
|
||||
* @return true if shared.
|
||||
*/
|
||||
public boolean isShared()
|
||||
{
|
||||
return shared;
|
||||
return (!sharedLockTokens.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the lock info as a string
|
||||
*
|
||||
@@ -256,20 +196,113 @@ public class LockInfo
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
str.append("[");
|
||||
str.append("LockInfo[");
|
||||
|
||||
str.append("token=");
|
||||
str.append(getToken());
|
||||
str.append(",scope=");
|
||||
str.append("exclusiveLockToken=");
|
||||
str.append(getExclusiveLockToken());
|
||||
str.append(", scope=");
|
||||
str.append(getScope());
|
||||
str.append(",depth=");
|
||||
str.append(", depth=");
|
||||
str.append(getDepth());
|
||||
str.append(",shared locks=");
|
||||
str.append(", sharedLockTokens=");
|
||||
str.append(getSharedLockTokens());
|
||||
str.append(", owner=");
|
||||
str.append(owner);
|
||||
str.append(", expires=");
|
||||
str.append(expires);
|
||||
|
||||
str.append("]");
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this lock has expired. If no expiry is set (i.e. expires is null)
|
||||
* then false is always returned.
|
||||
*
|
||||
* @return true if expired.
|
||||
*/
|
||||
public boolean isExpired()
|
||||
{
|
||||
if (expires == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Date now = new Date();
|
||||
return now.after(expires);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is it an exclusive lock?
|
||||
*
|
||||
* @return true if exclusive.
|
||||
*/
|
||||
public boolean isExclusive()
|
||||
{
|
||||
return (exclusiveLockToken != null && exclusiveLockToken.length() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Who owns the lock?
|
||||
*
|
||||
* @return the owner
|
||||
*/
|
||||
public String getOwner()
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username of who owns the lock.
|
||||
*
|
||||
* @param owner Owner's username
|
||||
*/
|
||||
public void setOwner(String owner)
|
||||
{
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expiry date/time for this lock. Set to null for never expires.
|
||||
*
|
||||
* @param expires the expires to set
|
||||
*/
|
||||
public void setExpires(Date expires)
|
||||
{
|
||||
this.expires = expires;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the expiry date/time for this lock, or null if it never expires.
|
||||
*
|
||||
* @return the expires
|
||||
*/
|
||||
public Date getExpires()
|
||||
{
|
||||
return expires;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanity check the state of this LockInfo.
|
||||
*/
|
||||
private void checkLockState()
|
||||
{
|
||||
if (isShared() && isExclusive())
|
||||
{
|
||||
throw new IllegalStateException("Lock cannot be both shared and exclusive: " + toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expiry date/time to lockTimeout seconds into the future.
|
||||
*
|
||||
* @param lockTimeout
|
||||
*/
|
||||
public void setTimeoutSeconds(int lockTimeout)
|
||||
{
|
||||
int timeoutMillis = (lockTimeout * 60 * 1000);
|
||||
Date now = new Date();
|
||||
Date nextExpiry = new Date(now.getTime() + timeoutMillis);
|
||||
setExpires(nextExpiry);
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.alfresco.repo.webdav;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -27,12 +28,9 @@ import java.util.TimerTask;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.WebDAVModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.lock.LockService;
|
||||
import org.alfresco.service.cmr.lock.LockType;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileFolderUtil;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
@@ -390,40 +388,34 @@ public class LockMethod extends WebDAVMethod
|
||||
*/
|
||||
protected final void createLock(FileInfo lockNode, String userName) throws WebDAVServerException
|
||||
{
|
||||
LockService lockService = getLockService();
|
||||
|
||||
// Create Lock token
|
||||
lockToken = WebDAV.makeLockToken(lockNode.getNodeRef(), userName);
|
||||
|
||||
if (this.createExclusive)
|
||||
if (createExclusive)
|
||||
{
|
||||
// Lock the node
|
||||
lockService.lock(lockNode.getNodeRef(), LockType.WRITE_LOCK, getLockTimeout());
|
||||
|
||||
// update local cache (will be read back when generating the response)
|
||||
lockNode.getProperties().put(ContentModel.PROP_LOCK_OWNER, userName);
|
||||
// ALF-3681, we should also cache the expiryDate for correct response generation
|
||||
lockNode.getProperties().put(ContentModel.PROP_EXPIRY_DATE,
|
||||
getNodeService().getProperty(lockNode.getNodeRef(), ContentModel.PROP_EXPIRY_DATE));
|
||||
|
||||
//this.lockInfo.setToken(lockToken);
|
||||
getNodeService().setProperty(lockNode.getNodeRef(), WebDAVModel.PROP_OPAQUE_LOCK_TOKEN, lockToken);
|
||||
lockInfo.setTimeoutSeconds(getLockTimeout());
|
||||
lockInfo.setExclusiveLockToken(lockToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.lockInfo.addSharedLockToken(lockToken);
|
||||
String sharedLockTokens = LockInfo.makeSharedLockTokensString(this.lockInfo.getSharedLockTokens());
|
||||
getNodeService().setProperty(lockNode.getNodeRef(), WebDAVModel.PROP_SHARED_LOCK_TOKENS, sharedLockTokens);
|
||||
|
||||
lockInfo.addSharedLockToken(lockToken);
|
||||
}
|
||||
|
||||
// Store lock depth
|
||||
getNodeService().setProperty(lockNode.getNodeRef(), WebDAVModel.PROP_LOCK_DEPTH, WebDAV.getDepthName(m_depth));
|
||||
|
||||
lockInfo.setDepth(WebDAV.getDepthName(m_depth));
|
||||
// Store lock scope (shared/exclusive)
|
||||
getNodeService().setProperty(lockNode.getNodeRef(), WebDAVModel.PROP_LOCK_SCOPE, this.createExclusive ? WebDAV.XML_EXCLUSIVE : WebDAV.XML_SHARED);
|
||||
String scope = createExclusive ? WebDAV.XML_EXCLUSIVE : WebDAV.XML_SHARED;
|
||||
lockInfo.setScope(scope);
|
||||
// Store the owner of this lock
|
||||
lockInfo.setOwner(userName);
|
||||
// Lock the node
|
||||
getLockStore().put(lockNode.getNodeRef(), lockInfo);
|
||||
|
||||
logger.debug("Properties of the " + lockNode + " was changed");
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Locked node " + lockNode + ": " + lockInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -438,7 +430,10 @@ public class LockMethod extends WebDAVMethod
|
||||
if (this.createExclusive)
|
||||
{
|
||||
// Update the expiry for the lock
|
||||
getLockService().lock(lockNode.getNodeRef(), LockType.WRITE_LOCK, getLockTimeout());
|
||||
if (lockInfo.getExpires() != null)
|
||||
{
|
||||
lockInfo.setTimeoutSeconds(getLockTimeout());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,9 +456,9 @@ public class LockMethod extends WebDAVMethod
|
||||
// In case of lock refreshing take the scope from previously stored lock
|
||||
scope = this.lockInfo.getScope();
|
||||
// Output refreshed lock
|
||||
lt = this.lockInfo.getToken();
|
||||
lt = this.lockInfo.getExclusiveLockToken();
|
||||
}
|
||||
String owner = (String) lockNodeInfo.getProperties().get(ContentModel.PROP_LOCK_OWNER);
|
||||
String owner = lockInfo.getOwner();
|
||||
|
||||
XMLWriter xml = createXMLWriter();
|
||||
|
||||
@@ -473,7 +468,8 @@ public class LockMethod extends WebDAVMethod
|
||||
xml.startElement(WebDAV.DAV_NS, WebDAV.XML_PROP + nsdec, WebDAV.XML_NS_PROP + nsdec, getDAVHelper().getNullAttributes());
|
||||
|
||||
// Output the lock details
|
||||
generateLockDiscoveryXML(xml, lockNodeInfo, false, scope, WebDAV.getDepthName(m_depth), lt, owner);
|
||||
Date expiry = lockInfo.getExpires();
|
||||
generateLockDiscoveryXML(xml, lockNodeInfo, false, scope, WebDAV.getDepthName(m_depth), lt, owner, expiry);
|
||||
|
||||
// Close off the XML
|
||||
xml.endElement(WebDAV.DAV_NS, WebDAV.XML_PROP, WebDAV.XML_NS_PROP);
|
||||
|
58
source/java/org/alfresco/repo/webdav/LockStore.java
Normal file
58
source/java/org/alfresco/repo/webdav/LockStore.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.webdav;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
/**
|
||||
* Provides storage for WebDAV {@link LockInfo lock information}.
|
||||
* <p>
|
||||
* Note: the existence of LockInfo does NOT mean that a node is necessarily locked. It may have timed-out,
|
||||
* been unlocked, or be left in an invalid state for some reason. The LockInfo is a record of a requested lock -
|
||||
* the actual values should be examined as necessary.
|
||||
* <p>
|
||||
* Implementations of this interface should be fast, ideally an in-memory map. Implementations should also be thread-
|
||||
* and cluster-safe.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public interface LockStore
|
||||
{
|
||||
/**
|
||||
* Provide LockInfo about a specific node to the LockStore.
|
||||
*
|
||||
* @param nodeToLock
|
||||
* @param lockInfo
|
||||
*/
|
||||
void put(NodeRef nodeToLock, LockInfo lockInfo);
|
||||
|
||||
/**
|
||||
* Retrieves LockInfo for as given nodeRef. The LockInfo may specify that a node is
|
||||
* <strong>NOT</strong> locked, so the LockInfo should always be checked for validity.
|
||||
* <p>
|
||||
* The presence of LockInfo does not imply that a node is locked.
|
||||
*
|
||||
* @param nodeRef
|
||||
* @return
|
||||
*/
|
||||
LockInfo get(NodeRef nodeRef);
|
||||
|
||||
|
||||
void remove(NodeRef nodeRef);
|
||||
}
|
30
source/java/org/alfresco/repo/webdav/LockStoreFactory.java
Normal file
30
source/java/org/alfresco/repo/webdav/LockStoreFactory.java
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.webdav;
|
||||
|
||||
|
||||
/**
|
||||
* Factory to create {@link LockStore} instances.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public interface LockStoreFactory
|
||||
{
|
||||
LockStore getLockStore();
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.webdav;
|
||||
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link LockStoreFactory} interface. Creates {@link LockStore}s
|
||||
* backed by a Hazelcast distributed {@link java.util.Map Map}.
|
||||
*
|
||||
* @see LockStoreFactory
|
||||
* @see LockStoreImpl
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class LockStoreFactoryImpl implements LockStoreFactory
|
||||
{
|
||||
private HazelcastInstance hazelcast;
|
||||
|
||||
@Override
|
||||
public LockStore getLockStore()
|
||||
{
|
||||
ConcurrentMap<NodeRef, LockInfo> map = hazelcast.getMap("webdav-locks");
|
||||
return new LockStoreImpl(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hazelcast the hazelcast to set
|
||||
*/
|
||||
public void setHazelcast(HazelcastInstance hazelcast)
|
||||
{
|
||||
this.hazelcast = hazelcast;
|
||||
}
|
||||
}
|
59
source/java/org/alfresco/repo/webdav/LockStoreImpl.java
Normal file
59
source/java/org/alfresco/repo/webdav/LockStoreImpl.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.webdav;
|
||||
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
|
||||
|
||||
/**
|
||||
* The default {@link LockStore} implementation. This is based upon a ConcurrentMap intended to be supplied by
|
||||
* Hazelcast (or a similar, distributed data structure library).
|
||||
*
|
||||
* @see LockStore
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class LockStoreImpl implements LockStore
|
||||
{
|
||||
private final ConcurrentMap<NodeRef, LockInfo> lockInfoMap;
|
||||
|
||||
public LockStoreImpl(ConcurrentMap<NodeRef, LockInfo> lockInfoMap)
|
||||
{
|
||||
this.lockInfoMap = lockInfoMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(NodeRef nodeToLock, LockInfo lockInfo)
|
||||
{
|
||||
lockInfoMap.put(nodeToLock, lockInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockInfo get(NodeRef nodeRef)
|
||||
{
|
||||
return lockInfoMap.get(nodeRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(NodeRef nodeRef)
|
||||
{
|
||||
lockInfoMap.remove(nodeRef);
|
||||
}
|
||||
}
|
@@ -24,10 +24,9 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.action.executer.ContentMetadataExtracter;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.lock.LockStatus;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.model.FileExistsException;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
@@ -44,7 +43,6 @@ import org.springframework.dao.ConcurrencyFailureException;
|
||||
public class PutMethod extends WebDAVMethod
|
||||
{
|
||||
// Request parameters
|
||||
private String m_strLockToken = null;
|
||||
private String m_strContentType = null;
|
||||
private boolean m_expectHeaderPresent = false;
|
||||
|
||||
@@ -189,12 +187,17 @@ public class PutMethod extends WebDAVMethod
|
||||
}
|
||||
}
|
||||
|
||||
LockStatus lockSts = getLockService().getLockStatus(contentNodeInfo.getNodeRef());
|
||||
String userName = getDAVHelper().getAuthenticationService().getCurrentUserName();
|
||||
String owner = (String) getNodeService().getProperty(contentNodeInfo.getNodeRef(), ContentModel.PROP_LOCK_OWNER);
|
||||
LockInfo lockInfo = getLockStore().get(contentNodeInfo.getNodeRef());
|
||||
|
||||
if (lockSts == LockStatus.LOCKED || (lockSts == LockStatus.LOCK_OWNER && !userName.equals(owner)))
|
||||
if (lockInfo != null && lockInfo.isLocked() && !lockInfo.getOwner().equals(userName))
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
String path = getPath();
|
||||
String owner = lockInfo.getOwner();
|
||||
logger.debug("Node locked: path=["+path+"], owner=["+owner+"], current user=["+userName+"]");
|
||||
}
|
||||
// Indicate that the resource is locked
|
||||
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
||||
}
|
||||
|
@@ -23,13 +23,9 @@ import java.util.Set;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.WebDAVModel;
|
||||
import org.alfresco.service.cmr.lock.LockService;
|
||||
import org.alfresco.service.cmr.lock.LockStatus;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
|
||||
/**
|
||||
* Implements the WebDAV UNLOCK method
|
||||
@@ -126,37 +122,42 @@ public class UnlockMethod extends WebDAVMethod
|
||||
}
|
||||
|
||||
// Parse the lock token
|
||||
String[] lockInfo = WebDAV.parseLockToken(getLockToken());
|
||||
if (lockInfo == null)
|
||||
String[] lockInfoFromRequest = WebDAV.parseLockToken(getLockToken());
|
||||
if (lockInfoFromRequest == null)
|
||||
{
|
||||
// Bad lock token
|
||||
throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED);
|
||||
}
|
||||
|
||||
// Get the lock status for the node
|
||||
LockService lockService = getDAVHelper().getLockService();
|
||||
NodeService nodeService = getNodeService();
|
||||
// String nodeId = lockInfo[0];
|
||||
// String userName = lockInfo[1];
|
||||
|
||||
NodeRef nodeRef = lockNodeInfo.getNodeRef();
|
||||
LockStatus lockSts = lockService.getLockStatus(nodeRef);
|
||||
if (lockSts == LockStatus.LOCK_OWNER)
|
||||
{
|
||||
if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY))
|
||||
lockService.unlock(nodeRef);
|
||||
nodeService.removeProperty(nodeRef, WebDAVModel.PROP_OPAQUE_LOCK_TOKEN);
|
||||
nodeService.removeProperty(nodeRef, WebDAVModel.PROP_LOCK_DEPTH);
|
||||
nodeService.removeProperty(nodeRef, WebDAVModel.PROP_LOCK_SCOPE);
|
||||
LockInfo lockInfo = getLockStore().get(nodeRef);
|
||||
|
||||
// Return the cm:lockable aspect to working copy (ALF-4479, ALF-7079)
|
||||
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY))
|
||||
if (lockInfo == null || !lockInfo.isLocked())
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
nodeService.addAspect(nodeRef, ContentModel.ASPECT_LOCKABLE, null);
|
||||
logger.debug("Unlock token=" + getLockToken() + " Not locked");
|
||||
}
|
||||
// Node is not locked
|
||||
throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED);
|
||||
}
|
||||
else if (lockInfo.isExpired())
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Unlock token=" + getLockToken() + " Lock expired");
|
||||
}
|
||||
// Return a success status
|
||||
m_response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||
removeNoContentAspect(nodeRef);
|
||||
}
|
||||
else if (lockInfo.isExclusive() /* && user is lock-owner */)
|
||||
{
|
||||
getLockStore().remove(nodeRef);
|
||||
|
||||
// Indicate that the unlock was successful
|
||||
m_response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||
|
||||
removeNoContentAspect(nodeRef);
|
||||
|
||||
// DEBUG
|
||||
@@ -165,57 +166,27 @@ public class UnlockMethod extends WebDAVMethod
|
||||
logger.debug("Unlock token=" + getLockToken() + " Successful");
|
||||
}
|
||||
}
|
||||
else if (lockSts == LockStatus.NO_LOCK)
|
||||
else if (lockInfo.isShared())
|
||||
{
|
||||
String sharedLocks = (String) nodeService.getProperty(nodeRef, WebDAVModel.PROP_SHARED_LOCK_TOKENS);
|
||||
if (sharedLocks != null)
|
||||
Set<String> sharedLocks = lockInfo.getSharedLockTokens();
|
||||
if (sharedLocks.contains(m_strLockToken))
|
||||
{
|
||||
Set<String> locks = LockInfo.parseSharedLockTokens(sharedLocks);
|
||||
sharedLocks.remove(m_strLockToken);
|
||||
|
||||
if (locks != null && locks.contains(m_strLockToken))
|
||||
{
|
||||
locks.remove(m_strLockToken);
|
||||
nodeService.setProperty(nodeRef, WebDAVModel.PROP_SHARED_LOCK_TOKENS, LockInfo.makeSharedLockTokensString(locks));
|
||||
// Indicate that the unlock was successful
|
||||
m_response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||
removeNoContentAspect(nodeRef);
|
||||
|
||||
// Indicate that the unlock was successful
|
||||
m_response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||
removeNoContentAspect(nodeRef);
|
||||
|
||||
// DEBUG
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Unlock token=" + getLockToken() + " Successful");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// DEBUG
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Unlock token=" + getLockToken() + " Not locked");
|
||||
|
||||
// Node is not locked
|
||||
throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED);
|
||||
{
|
||||
logger.debug("Unlock token=" + getLockToken() + " Successful");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (lockSts == LockStatus.LOCKED)
|
||||
else
|
||||
{
|
||||
// DEBUG
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Unlock token=" + getLockToken() + " Not lock owner");
|
||||
|
||||
// Node is locked but not by this user
|
||||
throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED);
|
||||
}
|
||||
else if (lockSts == LockStatus.LOCK_EXPIRED)
|
||||
{
|
||||
// DEBUG
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Unlock token=" + getLockToken() + " Lock expired");
|
||||
|
||||
// Return a success status
|
||||
m_response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||
removeNoContentAspect(nodeRef);
|
||||
throw new IllegalStateException("Invalid LockInfo state: " + lockInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -77,6 +77,7 @@ public class WebDAVHelper
|
||||
private DictionaryService m_dictionaryService;
|
||||
private MimetypeService m_mimetypeService;
|
||||
private LockService m_lockService;
|
||||
private LockStore m_lockStore;
|
||||
private ActionService m_actionService;
|
||||
private AuthenticationService m_authService;
|
||||
private PermissionService m_permissionService;
|
||||
@@ -88,7 +89,7 @@ public class WebDAVHelper
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
protected WebDAVHelper(ServiceRegistry serviceRegistry, AuthenticationService authService)
|
||||
protected WebDAVHelper(ServiceRegistry serviceRegistry, LockStore lockStore, AuthenticationService authService)
|
||||
{
|
||||
m_serviceRegistry = serviceRegistry;
|
||||
|
||||
@@ -103,6 +104,8 @@ public class WebDAVHelper
|
||||
m_permissionService = m_serviceRegistry.getPermissionService();
|
||||
|
||||
m_authService = authService;
|
||||
|
||||
m_lockStore = lockStore;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,6 +177,14 @@ public class WebDAVHelper
|
||||
return m_lockService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Return the {@link LockStore lock store}.
|
||||
*/
|
||||
public final LockStore getLockStore()
|
||||
{
|
||||
return m_lockStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Return the action service
|
||||
*/
|
||||
|
@@ -25,15 +25,14 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
@@ -45,16 +44,12 @@ import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.WebDAVModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.action.ActionService;
|
||||
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
||||
import org.alfresco.service.cmr.lock.LockService;
|
||||
import org.alfresco.service.cmr.lock.LockStatus;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||
@@ -654,13 +649,13 @@ public abstract class WebDAVMethod
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to return the lock service
|
||||
* Retrieve the (WebDAV protocol-level) {@link LockStore lock store}.
|
||||
*
|
||||
* @return LockService
|
||||
* @return LockStore
|
||||
*/
|
||||
protected final LockService getLockService()
|
||||
protected final LockStore getLockStore()
|
||||
{
|
||||
return m_davHelper.getLockService();
|
||||
return m_davHelper.getLockStore();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -747,16 +742,19 @@ public abstract class WebDAVMethod
|
||||
return writer;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Generates the lock discovery XML response
|
||||
*
|
||||
* @param xml XMLWriter
|
||||
* @param lockNode NodeRef
|
||||
* @param lockInfo
|
||||
*/
|
||||
protected void generateLockDiscoveryXML(XMLWriter xml, FileInfo lockNodeInfo, LockInfo lockInfo) throws Exception
|
||||
{
|
||||
String owner = (String) lockNodeInfo.getProperties().get(ContentModel.PROP_LOCK_OWNER);
|
||||
generateLockDiscoveryXML(xml, lockNodeInfo, false, lockInfo.getScope(), lockInfo.getDepth(), WebDAV.makeLockToken(lockNodeInfo.getNodeRef(), owner), owner);
|
||||
String owner = lockInfo.getOwner();
|
||||
Date expiry = lockInfo.getExpires();
|
||||
generateLockDiscoveryXML(xml, lockNodeInfo, false, lockInfo.getScope(), lockInfo.getDepth(),
|
||||
WebDAV.makeLockToken(lockNodeInfo.getNodeRef(), owner), owner, expiry);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -769,17 +767,15 @@ public abstract class WebDAVMethod
|
||||
* @param depth String lock depth
|
||||
* @param lToken String locktoken
|
||||
* @param owner String lock owner
|
||||
*
|
||||
* @param expiryDate the date/time the lock should expire
|
||||
*/
|
||||
protected void generateLockDiscoveryXML(XMLWriter xml, FileInfo lockNodeInfo, boolean emptyNamespace, String scope, String depth, String lToken, String owner) throws Exception
|
||||
protected void generateLockDiscoveryXML(XMLWriter xml, FileInfo lockNodeInfo, boolean emptyNamespace,
|
||||
String scope, String depth, String lToken, String owner, Date expiryDate) throws Exception
|
||||
{
|
||||
Attributes nullAttr= getDAVHelper().getNullAttributes();
|
||||
String ns = emptyNamespace ? "" : WebDAV.DAV_NS;
|
||||
if (lockNodeInfo != null)
|
||||
{
|
||||
// Get the lock details
|
||||
Date expiryDate = (Date) lockNodeInfo.getProperties().get(ContentModel.PROP_EXPIRY_DATE);
|
||||
|
||||
// Output the XML response
|
||||
|
||||
xml.startElement(ns, WebDAV.XML_LOCK_DISCOVERY, emptyNamespace ? WebDAV.XML_LOCK_DISCOVERY : WebDAV.XML_NS_LOCK_DISCOVERY, nullAttr);
|
||||
@@ -882,15 +878,22 @@ public abstract class WebDAVMethod
|
||||
|
||||
if (m_conditions == null)
|
||||
{
|
||||
if (nodeLockInfo.getToken() == null)
|
||||
if (!nodeLockInfo.isLocked())
|
||||
{
|
||||
CheckOutCheckInService checkOutCheckInService = m_davHelper.getServiceRegistry().getCheckOutCheckInService();
|
||||
if (nodeLockInfo.getSharedLockTokens() == null && checkOutCheckInService.getWorkingCopy(fileInfo.getNodeRef()) == null)
|
||||
// Not locked
|
||||
return nodeLockInfo;
|
||||
}
|
||||
|
||||
if (nodeLockInfo.isShared())
|
||||
{
|
||||
if (nodeLockInfo.getSharedLockTokens().isEmpty())
|
||||
{
|
||||
// Although flagged as shared - no shared locks.
|
||||
return nodeLockInfo;
|
||||
}
|
||||
if (!ignoreShared)
|
||||
{
|
||||
// Shared locks exist
|
||||
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
||||
}
|
||||
}
|
||||
@@ -900,15 +903,16 @@ public abstract class WebDAVMethod
|
||||
if (m_userAgent != null && m_userAgent.equals(WebDAV.AGENT_MICROSOFT_DATA_ACCESS_INTERNET_PUBLISHING_PROVIDER_DAV))
|
||||
{
|
||||
String currentUser = getAuthenticationService().getCurrentUserName();
|
||||
Serializable lockOwner = fileInfo.getProperties().get(ContentModel.PROP_LOCK_OWNER);
|
||||
|
||||
String lockOwner = nodeLockInfo.getOwner();
|
||||
if (lockOwner.equals(currentUser))
|
||||
{
|
||||
// OK to write - lock is owned by current user.
|
||||
return nodeLockInfo;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Exclusive lock, owned by someone else
|
||||
throw new WebDAVServerException(WebDAV.WEBDAV_SC_LOCKED);
|
||||
}
|
||||
}
|
||||
@@ -920,7 +924,7 @@ public abstract class WebDAVMethod
|
||||
// but request must fail with 423 Locked response because node is locked.
|
||||
// 2. Check if ANY of the conditions in If header true.
|
||||
checkLockToken(nodeLockInfo, ignoreShared, lockMethod);
|
||||
checkConditions(nodeLockInfo.getToken(), nodeETag);
|
||||
checkConditions(nodeLockInfo.getExclusiveLockToken(), nodeETag);
|
||||
|
||||
return nodeLockInfo;
|
||||
}
|
||||
@@ -949,7 +953,7 @@ public abstract class WebDAVMethod
|
||||
*/
|
||||
private void checkLockToken(LockInfo lockInfo, boolean ignoreShared, boolean lockMethod) throws WebDAVServerException
|
||||
{
|
||||
String nodeLockToken = lockInfo.getToken();
|
||||
String nodeLockToken = lockInfo.getExclusiveLockToken();
|
||||
Set<String> sharedLockTokens = lockInfo.getSharedLockTokens();
|
||||
|
||||
if (m_conditions != null)
|
||||
@@ -959,7 +963,7 @@ public abstract class WebDAVMethod
|
||||
{
|
||||
// Node has shared lock. Check if conditions contains lock token of the node.
|
||||
// If not throw exception
|
||||
if (sharedLockTokens != null)
|
||||
if (!sharedLockTokens.isEmpty())
|
||||
{
|
||||
if (!ignoreShared)
|
||||
{
|
||||
@@ -1096,44 +1100,15 @@ public abstract class WebDAVMethod
|
||||
private LockInfo getNodeLockInfoImpl(FileInfo nodeInfo)
|
||||
{
|
||||
// Check if node is locked directly.
|
||||
|
||||
LockInfo lockInfo = getNodeLockInfoDirect(nodeInfo);
|
||||
if (lockInfo != null)
|
||||
{
|
||||
return lockInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No has no exclusive lock but can be locked with shared lock
|
||||
String sharedLocks = (String) nodeInfo.getProperties().get(WebDAVModel.PROP_SHARED_LOCK_TOKENS);
|
||||
if (sharedLocks != null)
|
||||
{
|
||||
// Get lock depth
|
||||
String depth = (String) nodeInfo.getProperties().get(WebDAVModel.PROP_LOCK_DEPTH);
|
||||
//Get lock scope
|
||||
String scope = (String) nodeInfo.getProperties().get(WebDAVModel.PROP_LOCK_SCOPE);
|
||||
|
||||
// Node has it's own Lock token.
|
||||
// Store lock information to the lockInfo object
|
||||
|
||||
lockInfo = new LockInfo();
|
||||
|
||||
lockInfo.setDepth(depth);
|
||||
lockInfo.setScope(scope);
|
||||
lockInfo.setSharedLockTokens(LockInfo.parseSharedLockTokens(sharedLocks));
|
||||
lockInfo.setShared(true);
|
||||
|
||||
return lockInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// Node isn't locked directly and has no it's own Lock token.
|
||||
// Try to search indirect lock.
|
||||
|
||||
// Node isn't locked directly, try to search for an indirect lock.
|
||||
NodeService nodeService = getNodeService();
|
||||
|
||||
NodeRef nodeRef = nodeInfo.getNodeRef();
|
||||
NodeRef node = nodeRef;
|
||||
NodeRef node = nodeInfo.getNodeRef();
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -1175,41 +1150,13 @@ public abstract class WebDAVMethod
|
||||
{
|
||||
return lockInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO - I assume this should be parent not nodeRef (see ALF-6224) ?
|
||||
|
||||
lockInfo = new LockInfo();
|
||||
|
||||
// Node has no exclusive lock but can be locked with shared lock
|
||||
String sharedLocks = (String) nodeService.getProperty(parent, WebDAVModel.PROP_SHARED_LOCK_TOKENS);
|
||||
if (sharedLocks != null)
|
||||
{
|
||||
// Check node lock depth.
|
||||
// If depth is WebDAV.INFINITY then return this node's Lock token.
|
||||
String depth = (String) nodeService.getProperty(parent, WebDAVModel.PROP_LOCK_DEPTH);
|
||||
if (WebDAV.INFINITY.equals(depth))
|
||||
{
|
||||
// In this case node is locked indirectly.
|
||||
|
||||
//Get lock scope
|
||||
String scope = (String) nodeService.getProperty(parent, WebDAVModel.PROP_LOCK_SCOPE);
|
||||
|
||||
// Node has it's own Lock token.
|
||||
|
||||
lockInfo.setDepth(depth);
|
||||
lockInfo.setScope(scope);
|
||||
lockInfo.setSharedLockTokens(LockInfo.parseSharedLockTokens(sharedLocks));
|
||||
|
||||
lockInfo.setShared(true);
|
||||
|
||||
return lockInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockInfo == null)
|
||||
{
|
||||
lockInfo = new LockInfo();
|
||||
}
|
||||
// temporarily cache - for this request
|
||||
m_parentLockInfo.put(parent, lockInfo);
|
||||
}
|
||||
@@ -1221,32 +1168,11 @@ public abstract class WebDAVMethod
|
||||
|
||||
private LockInfo getNodeLockInfoDirect(FileInfo nodeInfo)
|
||||
{
|
||||
String propOpaqueLockToken = (String) nodeInfo.getProperties().get(WebDAVModel.PROP_OPAQUE_LOCK_TOKEN);
|
||||
if (propOpaqueLockToken != null)
|
||||
LockInfo lock = getLockStore().get(nodeInfo.getNodeRef());
|
||||
|
||||
if (lock != null && lock.isLocked())
|
||||
{
|
||||
// now check for lock status ...
|
||||
LockStatus lockSts = getLockService().getLockStatus(nodeInfo.getNodeRef());
|
||||
if (lockSts == LockStatus.LOCKED || lockSts == LockStatus.LOCK_OWNER)
|
||||
{
|
||||
// Get lock depth
|
||||
String depth = (String) nodeInfo.getProperties().get(WebDAVModel.PROP_LOCK_DEPTH);
|
||||
//Get lock scope
|
||||
String scope = (String) nodeInfo.getProperties().get(WebDAVModel.PROP_LOCK_SCOPE);
|
||||
// Get shared lock tokens
|
||||
String sharedLocks = (String) nodeInfo.getProperties().get(WebDAVModel.PROP_SHARED_LOCK_TOKENS);
|
||||
|
||||
// Node has it's own Lock token.
|
||||
// Store lock information to the lockInfo object
|
||||
|
||||
LockInfo lockInfo = new LockInfo();
|
||||
|
||||
lockInfo.setToken(propOpaqueLockToken);
|
||||
lockInfo.setDepth(depth);
|
||||
lockInfo.setScope(scope);
|
||||
lockInfo.setSharedLockTokens(LockInfo.parseSharedLockTokens(sharedLocks));
|
||||
|
||||
return lockInfo;
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -1254,37 +1180,15 @@ public abstract class WebDAVMethod
|
||||
|
||||
private LockInfo getNodeLockInfoIndirect(FileInfo nodeInfo, NodeRef parent)
|
||||
{
|
||||
NodeService nodeService = getNodeService();
|
||||
LockInfo parentLock = getLockStore().get(parent);
|
||||
|
||||
// Check node lock depth.
|
||||
// If depth is WebDAV.INFINITY then return this node's Lock token.
|
||||
String depth = (String) nodeService.getProperty(parent, WebDAVModel.PROP_LOCK_DEPTH);
|
||||
if (WebDAV.INFINITY.equals(depth))
|
||||
if (parentLock != null && WebDAV.INFINITY.equals(parentLock.getDepth()))
|
||||
{
|
||||
// now check for lock status ...
|
||||
LockStatus lockSts = getLockService().getLockStatus(parent);
|
||||
if (lockSts == LockStatus.LOCKED || lockSts == LockStatus.LOCK_OWNER)
|
||||
if (parentLock.isLocked())
|
||||
{
|
||||
// In this case node is locked indirectly.
|
||||
|
||||
//Get lock scope
|
||||
String scope = (String) nodeInfo.getProperties().get(WebDAVModel.PROP_LOCK_SCOPE);
|
||||
// Get shared lock tokens
|
||||
String sharedLocks = (String) nodeInfo.getProperties().get(WebDAVModel.PROP_SHARED_LOCK_TOKENS);
|
||||
|
||||
// Store lock information to the lockInfo object
|
||||
|
||||
// Get lock token of the locked node - this is indirect lock token.
|
||||
String propOpaqueLockToken = (String) nodeService.getProperty(parent, WebDAVModel.PROP_OPAQUE_LOCK_TOKEN);
|
||||
|
||||
LockInfo lockInfo = new LockInfo();
|
||||
|
||||
lockInfo.setToken(propOpaqueLockToken);
|
||||
lockInfo.setDepth(depth);
|
||||
lockInfo.setScope(scope);
|
||||
lockInfo.setSharedLockTokens(LockInfo.parseSharedLockTokens(sharedLocks));
|
||||
|
||||
return lockInfo;
|
||||
return parentLock;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -280,9 +280,11 @@ public class WebDAVServlet extends HttpServlet
|
||||
NodeService nodeService = (NodeService) context.getBean("NodeService");
|
||||
SearchService searchService = (SearchService) context.getBean("SearchService");
|
||||
NamespaceService namespaceService = (NamespaceService) context.getBean("NamespaceService");
|
||||
LockStoreFactory lockStoreFactory = (LockStoreFactory) context.getBean("webdavLockStoreFactory");
|
||||
LockStore lockStore = lockStoreFactory.getLockStore();
|
||||
|
||||
// Create the WebDAV helper
|
||||
m_davHelper = new WebDAVHelper(m_serviceRegistry, authService);
|
||||
m_davHelper = new WebDAVHelper(m_serviceRegistry, lockStore, authService);
|
||||
|
||||
// Initialize the root node
|
||||
|
||||
|
Reference in New Issue
Block a user