001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.lock; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsProject; 032import org.opencms.file.CmsUser; 033import org.opencms.util.CmsUUID; 034 035/** 036 * Represents the lock state of a VFS resource.<p> 037 * 038 * The lock state is combination of how, by whom and in which project 039 * a resource is currently locked.<p> 040 * 041 * @since 6.0.0 042 * 043 * @see org.opencms.file.CmsObject#getLock(org.opencms.file.CmsResource) 044 * @see org.opencms.lock.CmsLockManager 045 */ 046public class CmsLock implements Comparable<CmsLock> { 047 048 /** The shared null lock object. */ 049 private static final CmsLock NULL_LOCK = new CmsLock( 050 "", 051 CmsUUID.getNullUUID(), 052 new CmsProject(), 053 CmsLockType.UNLOCKED); 054 055 /** The project where the resource is locked. */ 056 private CmsProject m_project; 057 058 /** The related lock. */ 059 private CmsLock m_relatedLock; 060 061 /** The name of the locked resource. */ 062 private String m_resourceName; 063 064 /** Indicates how the resource is locked. */ 065 private CmsLockType m_type; 066 067 /** The ID of the user who locked the resource. */ 068 private CmsUUID m_userId; 069 070 /** 071 * Constructor for a new Cms lock.<p> 072 * 073 * @param resourceName the full resource name including the site root 074 * @param userId the ID of the user who locked the resource 075 * @param project the project where the resource is locked 076 * @param type flag indicating how the resource is locked 077 */ 078 public CmsLock(String resourceName, CmsUUID userId, CmsProject project, CmsLockType type) { 079 080 m_resourceName = resourceName; 081 m_userId = userId; 082 m_project = project; 083 m_type = type; 084 } 085 086 /** 087 * Returns the shared Null CmsLock.<p> 088 * 089 * @return the shared Null CmsLock 090 */ 091 public static CmsLock getNullLock() { 092 093 return CmsLock.NULL_LOCK; 094 } 095 096 /** 097 * @see java.lang.Comparable#compareTo(java.lang.Object) 098 */ 099 public int compareTo(CmsLock other) { 100 101 return m_resourceName.compareTo(other.m_resourceName); 102 } 103 104 /** 105 * Compares this lock to the specified object.<p> 106 * 107 * @param obj the object to compare to 108 * @return true if and only if member values of this CmsLock are the same with the compared CmsLock 109 */ 110 @Override 111 public boolean equals(Object obj) { 112 113 if (obj == this) { 114 return true; 115 } 116 if (obj instanceof CmsLock) { 117 CmsLock other = (CmsLock)obj; 118 return other.m_resourceName.equals(m_resourceName) 119 && other.m_userId.equals(m_userId) 120 && other.m_project.equals(m_project) 121 && other.m_type.equals(m_type); 122 } 123 return false; 124 } 125 126 /** 127 * Returns the edition lock.<p> 128 * 129 * @return the edition lock 130 */ 131 public CmsLock getEditionLock() { 132 133 if (isSystemLock()) { 134 return getRelatedLock(); 135 } 136 return this; 137 } 138 139 /** 140 * Returns the project where the resource is currently locked.<p> 141 * 142 * @return the project where the resource is currently locked 143 */ 144 public CmsProject getProject() { 145 146 return m_project; 147 } 148 149 /** 150 * Returns the ID of the project where the resource is currently locked.<p> 151 * 152 * @return the ID of the project 153 */ 154 public CmsUUID getProjectId() { 155 156 return m_project.getUuid(); 157 } 158 159 /** 160 * Returns the name of the locked resource.<p> 161 * 162 * @return the name of the locked resource 163 */ 164 public String getResourceName() { 165 166 return m_resourceName; 167 } 168 169 /** 170 * Returns the system lock.<p> 171 * 172 * @return the system lock 173 */ 174 public CmsLock getSystemLock() { 175 176 if (!isSystemLock()) { 177 return getRelatedLock(); 178 } 179 return this; 180 } 181 182 /** 183 * Returns the type about how the resource is locked.<p> 184 * 185 * @return the type of the lock 186 */ 187 public CmsLockType getType() { 188 189 return m_type; 190 } 191 192 /** 193 * Returns the ID of the user who currently locked the resource.<p> 194 * 195 * @return the ID of the user 196 */ 197 public CmsUUID getUserId() { 198 199 return m_userId; 200 } 201 202 /** 203 * @see java.lang.Object#hashCode() 204 */ 205 @Override 206 public int hashCode() { 207 208 return m_project.hashCode() + m_resourceName.hashCode() + m_userId.hashCode() + m_type.hashCode(); 209 } 210 211 /** 212 * Returns <code>true</code> if this is an directly inherited lock.<p> 213 * 214 * @return <code>true</code> if this is an directly inherited lock 215 */ 216 public boolean isDirectlyInherited() { 217 218 return m_type.isDirectlyInherited(); 219 } 220 221 /** 222 * Returns <code>true</code> if this is an exclusive, temporary exclusive, or 223 * directly inherited lock, and the given user is the owner of this lock.<p> 224 * 225 * @param user the user to compare to the owner of this lock 226 * 227 * @return <code>true</code> if this is an exclusive, temporary exclusive, or 228 * directly inherited lock, and the given user is the owner of this lock 229 */ 230 public boolean isDirectlyOwnedBy(CmsUser user) { 231 232 return (isExclusive() || isDirectlyInherited()) && isOwnedBy(user); 233 } 234 235 /** 236 * Returns <code>true</code> if this is an exclusive, temporary exclusive, or 237 * directly inherited lock, and the current user is the owner of this lock, 238 * checking also the project of the lock.<p> 239 * 240 * @param cms the CMS context to check 241 * 242 * @return <code>true</code> if this is an exclusive, temporary exclusive, or 243 * directly inherited lock, and the current user is the owner of this lock 244 */ 245 public boolean isDirectlyOwnedInProjectBy(CmsObject cms) { 246 247 return (isExclusive() || isDirectlyInherited()) 248 && isOwnedInProjectBy( 249 cms.getRequestContext().getCurrentUser(), 250 cms.getRequestContext().getCurrentProject()); 251 } 252 253 /** 254 * Returns <code>true</code> if this is an exclusive, temporary exclusive, or 255 * directly inherited lock, and the given user is the owner of this lock, 256 * checking also the project of the lock.<p> 257 * 258 * @param user the user to compare to the owner of this lock 259 * @param project the project to compare to the project of this lock 260 * 261 * @return <code>true</code> if this is an exclusive, temporary exclusive, or 262 * directly inherited lock, and the given user is the owner of this lock 263 */ 264 public boolean isDirectlyOwnedInProjectBy(CmsUser user, CmsProject project) { 265 266 return (isExclusive() || isDirectlyInherited()) && isOwnedInProjectBy(user, project); 267 } 268 269 /** 270 * Returns <code>true</code> if this is an exclusive (or temporary exclusive) lock.<p> 271 * 272 * @return <code>true</code> if this is an exclusive (or temporary exclusive) lock 273 */ 274 public boolean isExclusive() { 275 276 return m_type.isExclusive(); 277 } 278 279 /** 280 * Returns <code>true</code> if this is an exclusive (or temporary exclusive) lock, 281 * and the given user is the owner of this lock.<p> 282 * 283 * @param user the user to compare to the owner of this lock 284 * 285 * @return <code>true</code> if this is an exclusive (or temporary exclusive) lock, 286 * and the given user is the owner of this lock 287 */ 288 public boolean isExclusiveOwnedBy(CmsUser user) { 289 290 return isExclusive() && isOwnedBy(user); 291 } 292 293 /** 294 * Returns <code>true</code> if this is an exclusive (or temporary exclusive) lock, 295 * and the given user is the owner and the given project is the project of this lock.<p> 296 * 297 * @param user the user to compare to the owner of this lock 298 * @param project the project to compare to the project of this lock 299 * 300 * @return <code>true</code> if this is an exclusive (or temporary exclusive) lock, 301 * and the given user is the owner and the given project is the project of this lock 302 */ 303 public boolean isExclusiveOwnedInProjectBy(CmsUser user, CmsProject project) { 304 305 return isExclusive() && isOwnedInProjectBy(user, project); 306 } 307 308 /** 309 * Returns <code>true</code> if this is an inherited lock, which may either be directly or shared inherited.<p> 310 * 311 * @return <code>true</code> if this is an inherited lock, which may either be directly or shared inherited 312 */ 313 public boolean isInherited() { 314 315 return m_type.isInherited(); 316 } 317 318 /** 319 * Returns <code>true</code> if the given project is the project of this lock.<p> 320 * 321 * @param project the project to compare to the project of this lock 322 * 323 * @return <code>true</code> if the given project is the project of this lock 324 */ 325 public boolean isInProject(CmsProject project) { 326 327 return m_project.equals(project); 328 } 329 330 /** 331 * Checks if a resource can be locked by a user.<p> 332 * 333 * The resource is not lockable if it already has a lock of type {@link CmsLockType#PUBLISH}.<p> 334 * 335 * The resource is lockable either 336 * - if it is currently unlocked 337 * - if it has a lock of another type set and the user is the lock owner 338 * 339 * @param user the user to test lockeability for 340 * 341 * @return <code>true</code> if this lock blocks any operation on the locked resource until it is unlocked 342 */ 343 public boolean isLockableBy(CmsUser user) { 344 345 if (getSystemLock().isPublish()) { 346 return false; 347 } 348 if (getEditionLock().isUnlocked() && getSystemLock().isUnlocked()) { 349 return true; 350 } 351 return getEditionLock().isOwnedBy(user); 352 } 353 354 /** 355 * Returns <code>true</code> if this lock is the <code>NULL</code> lock which can 356 * be obtained by {@link #getNullLock()}.<p> 357 * 358 * Only for the <code>NULL</code> lock, {@link #isUnlocked()} is <code>true</code>.<p> 359 * 360 * @return <code>true</code> if this lock is the <code>NULL</code> lock 361 */ 362 public boolean isNullLock() { 363 364 return isUnlocked(); 365 } 366 367 /** 368 * Returns <code>true</code> if the given user is the owner of this lock.<p> 369 * 370 * @param user the user to compare to the owner of this lock 371 * 372 * @return <code>true</code> if the given user is the owner of this lock 373 */ 374 public boolean isOwnedBy(CmsUser user) { 375 376 return m_userId.equals(user.getId()); 377 } 378 379 /** 380 * Returns <code>true</code> if the given user is the owner of this lock, 381 * and this lock belongs to the given project.<p> 382 * 383 * @param user the user to compare to the owner of this lock 384 * @param project the project to compare to the project of this lock 385 * 386 * @return <code>true</code> if the given user is the owner of this lock, 387 * and this lock belongs to the given project 388 */ 389 public boolean isOwnedInProjectBy(CmsUser user, CmsProject project) { 390 391 return isOwnedBy(user) && isInProject(project); 392 } 393 394 /** 395 * Returns <code>true</code> if this is a persistent lock that should be saved when the systems shuts down.<p> 396 * 397 * @return <code>true</code> if this is a persistent lock that should be saved when the systems shuts down 398 */ 399 public boolean isPersistent() { 400 401 return m_type.isPersistent(); 402 } 403 404 /** 405 * Returns <code>true</code> if this is a publish lock.<p> 406 * 407 * @return <code>true</code> if this is a publish lock 408 */ 409 public boolean isPublish() { 410 411 return m_type.isPublish(); 412 } 413 414 /** 415 * Returns <code>true</code> if this is a shared lock.<p> 416 * 417 * @return <code>true</code> if this is a shared lock 418 */ 419 public boolean isShared() { 420 421 return m_type.isShared(); 422 } 423 424 /** 425 * Returns <code>true</code> if this is a system (2nd level) lock.<p> 426 * 427 * @return <code>true</code> if this is a system (2nd level) lock 428 */ 429 public boolean isSystemLock() { 430 431 return m_type.isSystem(); 432 } 433 434 /** 435 * Returns <code>true</code> if this is a temporary lock.<p> 436 * 437 * @return <code>true</code> if this is a temporary lock 438 */ 439 public boolean isTemporary() { 440 441 return m_type.isTemporary(); 442 } 443 444 /** 445 * Returns <code>true</code> if this lock is in fact unlocked.<p> 446 * 447 * Only if this is <code>true</code>, the result lock is equal to the <code>NULL</code> lock, 448 * which can be obtained by {@link #getNullLock()}.<p> 449 * 450 * @return <code>true</code> if this lock is in fact unlocked 451 */ 452 public boolean isUnlocked() { 453 454 return m_type.isUnlocked(); 455 } 456 457 /** 458 * Builds a string representation of the current state.<p> 459 * 460 * @see java.lang.Object#toString() 461 */ 462 @Override 463 public String toString() { 464 465 StringBuffer buf = new StringBuffer(); 466 467 buf.append("[CmsLock: resource: "); 468 buf.append(getResourceName()); 469 buf.append(", type: "); 470 buf.append(getType()); 471 buf.append(", project: "); 472 buf.append(getProjectId()); 473 buf.append(", user: "); 474 buf.append(getUserId()); 475 if (getRelatedLock() != null) { 476 buf.append(", related lock: "); 477 buf.append(getRelatedLock().getType()); 478 } 479 buf.append("]"); 480 481 return buf.toString(); 482 } 483 484 /** 485 * @see java.lang.Object#clone() 486 */ 487 @Override 488 protected Object clone() { 489 490 CmsLock lock = new CmsLock(m_resourceName, m_userId, m_project, m_type); 491 if ((m_relatedLock != null) && !m_relatedLock.isNullLock()) { 492 lock.setRelatedLock( 493 new CmsLock( 494 m_relatedLock.m_resourceName, 495 m_relatedLock.m_userId, 496 m_relatedLock.m_project, 497 m_relatedLock.m_type)); 498 } 499 return lock; 500 } 501 502 /** 503 * Returns the related Lock.<p> 504 * 505 * @return the related Lock 506 */ 507 protected CmsLock getRelatedLock() { 508 509 if (m_relatedLock == null) { 510 CmsLockType type; 511 if (isSystemLock()) { 512 type = CmsLockType.UNLOCKED; 513 } else { 514 type = CmsLockType.SYSTEM_UNLOCKED; 515 } 516 CmsLock lock = new CmsLock(getResourceName(), getUserId(), getProject(), type); 517 lock.setRelatedLock(this); 518 if (isUnlocked()) { 519 // prevent the null lock gets modified 520 return lock; 521 } 522 m_relatedLock = lock; 523 } 524 return m_relatedLock; 525 } 526 527 /** 528 * Sets the related Lock.<p> 529 * 530 * @param relatedLock the related Lock to set 531 */ 532 protected void setRelatedLock(CmsLock relatedLock) { 533 534 if (this == NULL_LOCK) { 535 throw new RuntimeException("null lock"); 536 } 537 if ((relatedLock == null) || relatedLock.isUnlocked()) { 538 m_relatedLock = null; 539 } else { 540 m_relatedLock = relatedLock; 541 m_relatedLock.m_relatedLock = this; 542 } 543 } 544}