diff --git a/remote-api/src/main/java/org/alfresco/repo/webdav/LockInfoImpl.java b/remote-api/src/main/java/org/alfresco/repo/webdav/LockInfoImpl.java index 2f883c2974..10ba2149e3 100644 --- a/remote-api/src/main/java/org/alfresco/repo/webdav/LockInfoImpl.java +++ b/remote-api/src/main/java/org/alfresco/repo/webdav/LockInfoImpl.java @@ -2,7 +2,7 @@ * #%L * Alfresco Remote API * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited + * Copyright (C) 2005 - 2022 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -390,8 +390,9 @@ public class LockInfoImpl implements Serializable, LockInfo else { Date now = dateNow(); - long timeout = ((expires.getTime() - now.getTime()) / 1000); - return timeout; + long remainingTimeoutInSecondsRoundedUp = (Math.max(expires.getTime() - now.getTime(), 0) + 999) / 1000; + + return remainingTimeoutInSecondsRoundedUp; } } diff --git a/remote-api/src/main/java/org/alfresco/repo/webdav/LockMethod.java b/remote-api/src/main/java/org/alfresco/repo/webdav/LockMethod.java index da9c6ed686..ec083d8732 100644 --- a/remote-api/src/main/java/org/alfresco/repo/webdav/LockMethod.java +++ b/remote-api/src/main/java/org/alfresco/repo/webdav/LockMethod.java @@ -1,28 +1,28 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * 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 . - * #L% - */ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2022 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * 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 . + * #L% + */ package org.alfresco.repo.webdav; import java.util.Date; @@ -449,30 +449,18 @@ public class LockMethod extends WebDAVMethod */ protected final void createLock(FileInfo lockNode, String userName) throws WebDAVServerException { - // Create Lock token - lockToken = WebDAV.makeLockToken(lockNode.getNodeRef(), userName); - - if (createExclusive) - { - // Lock the node - lockInfo.setTimeoutSeconds(getLockTimeout()); - lockInfo.setExclusiveLockToken(lockToken); - } - else - { + if (!createExclusive) { // Shared lock creation should already have been prohibited when parsing the request body throw new WebDAVServerException(HttpServletResponse.SC_PRECONDITION_FAILED); } - // Store lock depth + lockToken = WebDAV.makeLockToken(lockNode.getNodeRef(), userName); + lockInfo.setExclusiveLockToken(lockToken); lockInfo.setDepth(WebDAV.getDepthName(m_depth)); - // Store lock scope (shared/exclusive) - String scope = createExclusive ? WebDAV.XML_EXCLUSIVE : WebDAV.XML_SHARED; - lockInfo.setScope(scope); - // Store the owner of this lock + lockInfo.setScope(WebDAV.XML_EXCLUSIVE); lockInfo.setOwner(userName); - // Lock the node - getDAVLockService().lock(lockNode.getNodeRef(), lockInfo); + + getDAVLockService().lock(lockNode.getNodeRef(), lockInfo, getLockTimeout()); if (logger.isDebugEnabled()) { diff --git a/remote-api/src/main/java/org/alfresco/repo/webdav/WebDAVLockService.java b/remote-api/src/main/java/org/alfresco/repo/webdav/WebDAVLockService.java index a826adc6b5..cb474a284e 100644 --- a/remote-api/src/main/java/org/alfresco/repo/webdav/WebDAVLockService.java +++ b/remote-api/src/main/java/org/alfresco/repo/webdav/WebDAVLockService.java @@ -1,28 +1,28 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * 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 . - * #L% - */ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2022 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * 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 . + * #L% + */ package org.alfresco.repo.webdav; @@ -56,7 +56,9 @@ public interface WebDAVLockService void lock(NodeRef nodeRef, String userName, int timeout); void lock(NodeRef nodeRef, LockInfo lockInfo); - + + void lock(NodeRef nodeRef, LockInfo lockInfo, int timeout); + /** * Shared method for webdav/vti to unlock node. Unlocked node is automatically removed from * current sessions's locked resources list. diff --git a/remote-api/src/main/java/org/alfresco/repo/webdav/WebDAVLockServiceImpl.java b/remote-api/src/main/java/org/alfresco/repo/webdav/WebDAVLockServiceImpl.java index ec3ea6b615..d493f28471 100644 --- a/remote-api/src/main/java/org/alfresco/repo/webdav/WebDAVLockServiceImpl.java +++ b/remote-api/src/main/java/org/alfresco/repo/webdav/WebDAVLockServiceImpl.java @@ -2,7 +2,7 @@ * #%L * Alfresco Remote API * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited + * Copyright (C) 2005 - 2022 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -32,7 +32,6 @@ import java.util.List; import javax.servlet.http.HttpSession; import org.alfresco.model.ContentModel; -import org.alfresco.repo.lock.LockUtils; import org.alfresco.repo.lock.mem.Lifetime; import org.alfresco.repo.lock.mem.LockState; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -237,57 +236,15 @@ public class WebDAVLockServiceImpl implements WebDAVLockService } } - public void lock(NodeRef nodeRef, LockInfo lockInfo) - { - boolean performSessionBehavior = false; - long timeout; - - timeout = lockInfo.getRemainingTimeoutSeconds(); - - // ALF-11777 fix, do not lock node for more than 24 hours (webdav and vti) - if (timeout >= WebDAV.TIMEOUT_24_HOURS || timeout == WebDAV.TIMEOUT_INFINITY) - { - timeout = WebDAV.TIMEOUT_24_HOURS; - lockInfo.setTimeoutSeconds((int) timeout); - performSessionBehavior = true; - } - - // TODO: lock children according to depth? lock type? - final String additionalInfo = lockInfo.toJSON(); - lockService.lock(nodeRef, LockType.WRITE_LOCK, (int) timeout, Lifetime.EPHEMERAL, additionalInfo); - - - if (logger.isDebugEnabled()) - { - logger.debug(nodeRef + " was locked for " + timeout + " seconds."); - } - - if (performSessionBehavior) - { - HttpSession session = currentSession.get(); - - if (session == null) - { - if (logger.isDebugEnabled()) - { - logger.debug("Couldn't find current session."); - } - return; - } - - storeObjectInSessionList(session, LOCKED_RESOURCES, new Pair(AuthenticationUtil.getRunAsUser(), nodeRef)); - - if (logger.isDebugEnabled()) - { - logger.debug(nodeRef + " was added to the session " + session.getId() + " for post expiration processing."); - } - } + public void lock(NodeRef nodeRef, LockInfo lockInfo) { + int timeout = (int) lockInfo.getRemainingTimeoutSeconds(); + lock(nodeRef, lockInfo, timeout); } - + /** * Shared method for webdav/vti protocols to lock node. If node is locked for more than 24 hours it is automatically added * to the current session locked resources list. - * + * * @param nodeRef the node to lock * @param userName userName * @param timeout the number of seconds before the locks expires @@ -295,8 +252,68 @@ public class WebDAVLockServiceImpl implements WebDAVLockService @Override public void lock(NodeRef nodeRef, String userName, int timeout) { - LockInfo lockInfo = createLock(nodeRef, userName, true, timeout); - lock(nodeRef, lockInfo); + LockInfo lockInfo = createLock(nodeRef, userName, true); + lock(nodeRef, lockInfo, timeout); + } + + public void lock(NodeRef nodeRef, LockInfo lockInfo, int timeout) + { + // ALF-11777 fix, do not lock node for more than 24 hours (webdav and vti) + boolean performSessionBehavior = false; + if (timeout > WebDAV.TIMEOUT_24_HOURS || timeout == WebDAV.TIMEOUT_INFINITY) + { + timeout = WebDAV.TIMEOUT_24_HOURS; + performSessionBehavior = true; + } + + validateLockTimeout(timeout); + lockInner(nodeRef, lockInfo, timeout); + + if (performSessionBehavior) + { + performLockSessionBehavior(nodeRef); + } + } + + private void validateLockTimeout(int timeout) { + if (timeout != WebDAV.TIMEOUT_INFINITY && timeout == LockService.TIMEOUT_INFINITY) { + throw new IllegalArgumentException("Timeout == " + LockService.TIMEOUT_INFINITY + + " is treated as permanence for locks. For maximum allowed timeout set " + WebDAV.TIMEOUT_INFINITY); + } + } + + private void lockInner(NodeRef nodeRef, LockInfo lockInfo, int timeout) { + //Update/set true expiry date of a lock to be used in additional information + lockInfo.setTimeoutSeconds(timeout); + + // TODO: lock children according to depth? lock type? + final String additionalInfo = lockInfo.toJSON(); + lockService.lock(nodeRef, LockType.WRITE_LOCK, timeout, Lifetime.EPHEMERAL, additionalInfo); + + if (logger.isDebugEnabled()) + { + logger.debug(nodeRef + " was locked for " + timeout + " seconds."); + } + } + + private void performLockSessionBehavior(NodeRef nodeRef) { + HttpSession session = currentSession.get(); + + if (session == null) + { + if (logger.isDebugEnabled()) + { + logger.debug("Couldn't find current session."); + } + return; + } + + storeObjectInSessionList(session, LOCKED_RESOURCES, new Pair(AuthenticationUtil.getRunAsUser(), nodeRef)); + + if (logger.isDebugEnabled()) + { + logger.debug(nodeRef + " was added to the session " + session.getId() + " for post expiration processing."); + } } /** @@ -444,19 +461,15 @@ public class WebDAVLockServiceImpl implements WebDAVLockService * @param nodeRef NodeRef * @param userName String * @param createExclusive boolean - * @param timeoutSecs int */ - private LockInfo createLock(NodeRef nodeRef, String userName, boolean createExclusive, int timeoutSecs) + private LockInfo createLock(NodeRef nodeRef, String userName, boolean createExclusive) { - // Create Lock token String lockToken = WebDAV.makeLockToken(nodeRef, userName); LockInfo lockInfo = new LockInfoImpl(); if (createExclusive) { - // Lock the node - lockInfo.setTimeoutSeconds(timeoutSecs); lockInfo.setExclusiveLockToken(lockToken); } else @@ -464,15 +477,11 @@ public class WebDAVLockServiceImpl implements WebDAVLockService lockInfo.addSharedLockToken(lockToken); } - // Store lock depth lockInfo.setDepth(WebDAV.getDepthName(WebDAV.DEPTH_INFINITY)); - // Store lock scope (shared/exclusive) String scope = createExclusive ? WebDAV.XML_EXCLUSIVE : WebDAV.XML_SHARED; lockInfo.setScope(scope); - // Store the owner of this lock lockInfo.setOwner(userName); - - // TODO: to help with debugging/refactoring (remove later) + String currentUser = AuthenticationUtil.getFullyAuthenticatedUser(); if (!currentUser.equals(userName)) { diff --git a/repository/src/main/java/org/alfresco/repo/lock/LockServiceImpl.java b/repository/src/main/java/org/alfresco/repo/lock/LockServiceImpl.java index a6fcd51645..df0d2ea0b9 100644 --- a/repository/src/main/java/org/alfresco/repo/lock/LockServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/lock/LockServiceImpl.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2018 Alfresco Software Limited + * Copyright (C) 2005 - 2022 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -321,7 +321,7 @@ public class LockServiceImpl implements LockService, public void lock(NodeRef nodeRef, LockType lockType) { // Lock with no expiration - lock(nodeRef, lockType, 0); + lock(nodeRef, lockType, TIMEOUT_INFINITY); } /** @@ -371,16 +371,8 @@ public class LockServiceImpl implements LockService, public void lock(NodeRef nodeRef, LockType lockType, int timeToExpire, Lifetime lifetime, String additionalInfo) { invokeBeforeLock(nodeRef, lockType); - if (lifetime.equals(Lifetime.EPHEMERAL) && (timeToExpire > MAX_EPHEMERAL_LOCK_SECONDS)) - { - throw new IllegalArgumentException("Attempt to create ephemeral lock for " + - timeToExpire + " seconds - exceeds maximum allowed time."); - } - if (lifetime.equals(Lifetime.EPHEMERAL) && (timeToExpire > ephemeralExpiryThreshold)) - { - lifetime = Lifetime.PERSISTENT; - } - + validateTimeToExpire(timeToExpire, lifetime); + lifetime = switchLifetimeMode(timeToExpire, lifetime); nodeRef = tenantService.getName(nodeRef); @@ -442,6 +434,22 @@ public class LockServiceImpl implements LockService, } } } + + private void validateTimeToExpire(int timeToExpire, Lifetime lifetime) { + if (lifetime.equals(Lifetime.EPHEMERAL) && (timeToExpire > MAX_EPHEMERAL_LOCK_SECONDS)) + { + throw new IllegalArgumentException("Attempt to create ephemeral lock for " + + timeToExpire + " seconds - exceeds maximum allowed time."); + } + } + + private Lifetime switchLifetimeMode(int timeToExpire, Lifetime lifetime) { + if (lifetime.equals(Lifetime.EPHEMERAL) && (timeToExpire > ephemeralExpiryThreshold)) + { + return Lifetime.PERSISTENT; + } + return lifetime; + } private void persistLockProps(NodeRef nodeRef, LockType lockType, Lifetime lifetime, String userName, Date expiryDate, String additionalInfo) { @@ -468,16 +476,16 @@ public class LockServiceImpl implements LockService, */ private Date makeExpiryDate(int timeToExpire) { - // Set the expiry date - Date expiryDate = null; - if (timeToExpire > 0) - { - expiryDate = new Date(); - Calendar calendar = Calendar.getInstance(); - calendar.setTime(expiryDate); - calendar.add(Calendar.SECOND, timeToExpire); - expiryDate = calendar.getTime(); + boolean permanent = timeToExpire <= TIMEOUT_INFINITY; + if (permanent) { + return null; } + + Calendar calendar = Calendar.getInstance(); + calendar.setTime(new Date()); + calendar.add(Calendar.SECOND, timeToExpire); + Date expiryDate = calendar.getTime(); + return expiryDate; } diff --git a/repository/src/main/java/org/alfresco/service/cmr/lock/LockService.java b/repository/src/main/java/org/alfresco/service/cmr/lock/LockService.java index 42fc496fe0..b1b2f85da0 100644 --- a/repository/src/main/java/org/alfresco/service/cmr/lock/LockService.java +++ b/repository/src/main/java/org/alfresco/service/cmr/lock/LockService.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited + * Copyright (C) 2005 - 2022 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -42,6 +42,8 @@ import org.alfresco.service.cmr.repository.NodeRef; @AlfrescoPublicApi public interface LockService { + int TIMEOUT_INFINITY = 0; + /** * Places a lock on a node. *