DefaultConcurrencyManager.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
12 
28 
29 /**
30  * Default ConcurrencyManager implementation.
31  *
32  * @author ingo herwig <ingo@wemove.com>
33  */
35 
36  private $persistenceFacade = null;
37  private $lockHandler = null;
38  private $session = null;
39 
40  private static $logger = null;
41 
42  /**
43  * Constructor
44  * @param $persistenceFacade
45  * @param $lockHandler
46  * @param $session
47  */
48  public function __construct(PersistenceFacade $persistenceFacade,
49  LockHandler $lockHandler,
50  Session $session) {
51  $this->persistenceFacade = $persistenceFacade;
52  $this->lockHandler = $lockHandler;
53  $this->session = $session;
54  if (self::$logger == null) {
55  self::$logger = LogManager::getLogger(__CLASS__);
56  }
57  }
58 
59  /**
60  * @see ConcurrencyManager::aquireLock()
61  */
62  public function aquireLock(ObjectId $oid, $type, PersistentObject $currentState=null) {
63  if (!ObjectId::isValid($oid) || ($type != Lock::TYPE_OPTIMISTIC &&
64  $type != Lock::TYPE_PESSIMISTIC)) {
65  throw new IllegalArgumentException("Invalid object id or locktype given");
66  }
67 
68  // load the current state if not provided
69  if ($type == Lock::TYPE_OPTIMISTIC && $currentState == null) {
70  $currentState = $this->persistenceFacade->load($oid, BuildDepth::SINGLE);
71  }
72 
73  $this->lockHandler->aquireLock($oid, $type, $currentState);
74  }
75 
76  /**
77  * @see ConcurrencyManager::releaseLock()
78  */
79  public function releaseLock(ObjectId $oid, $type=null) {
80  if (!ObjectId::isValid($oid)) {
81  throw new IllegalArgumentException("Invalid object id given");
82  }
83  $this->lockHandler->releaseLock($oid, $type);
84  }
85 
86  /**
87  * @see ConcurrencyManager::releaseLocks()
88  */
89  public function releaseLocks(ObjectId $oid) {
90  if (!ObjectId::isValid($oid)) {
91  throw new IllegalArgumentException("Invalid object id given");
92  }
93  $this->lockHandler->releaseLocks($oid);
94  }
95 
96  /**
97  * @see ConcurrencyManager::releaseAllLocks()
98  */
99  public function releaseAllLocks() {
100  $this->lockHandler->releaseAllLocks();
101  }
102 
103  /**
104  * @see ConcurrencyManager::getLock()
105  */
106  public function getLock(ObjectId $oid) {
107  return $this->lockHandler->getLock($oid);
108  }
109 
110  /**
111  * @see ConcurrencyManager::checkPersist()
112  */
113  public function checkPersist(PersistentObject $object) {
114  $oid = $object->getOID();
115  $lock = $this->lockHandler->getLock($oid);
116  if ($lock != null) {
117  $type = $lock->getType();
118 
119  // if there is a pessimistic lock on the object and it's not
120  // owned by the current user, throw a PessimisticLockException
121  if ($type == Lock::TYPE_PESSIMISTIC) {
122  $authUserLogin = $this->session->getAuthUser();
123  if ($lock->getLogin() != $authUserLogin) {
124  throw new PessimisticLockException($lock);
125  }
126  }
127 
128  // if there is an optimistic lock on the object and the object was updated
129  // in the meantime, throw a OptimisticLockException
130  if ($type == Lock::TYPE_OPTIMISTIC) {
131  $originalState = $lock->getCurrentState();
132  // temporarily detach the object from the transaction in order to get
133  // the latest version from the store
134  $transaction = $this->persistenceFacade->getTransaction();
135  $transaction->detach($object->getOID());
136  $currentState = $this->persistenceFacade->load($oid, BuildDepth::SINGLE);
137  // check for deletion
138  if ($currentState == null) {
139  throw new OptimisticLockException(null);
140  }
141  // check for modifications
142  $mapper = $this->persistenceFacade->getMapper($object->getType());
143  $it = new NodeValueIterator($originalState, false);
144  foreach($it as $valueName => $originalValue) {
145  $attribute = $mapper->hasAttribute($valueName) ? $mapper->getAttribute($valueName) : null;
146  // ignore references and transient values
147  if ($attribute && !($attribute instanceof ReferenceDescription) && !($attribute instanceof TransientAttributeDescription)) {
148  $currentValue = $currentState->getValue($valueName);
149  if (strval($currentValue) != strval($originalValue)) {
150  if (self::$logger->isDebugEnabled()) {
151  self::$logger->debug("Current state is different to original state: ".$object->getOID()."-".$valueName.": current[".
152  serialize($currentValue)."], original[".serialize($originalValue)."]");
153  }
154  throw new OptimisticLockException($currentState);
155  }
156  }
157  }
158  // if there was no concurrent update, attach the object again
159  $transaction->attach($object);
160  }
161  }
162  // everything is ok
163  }
164 
165  /**
166  * @see ConcurrencyManager::updateLock()
167  */
168  public function updateLock(ObjectId $oid, PersistentObject $object) {
169  return $this->lockHandler->updateLock($oid, $object);
170  }
171 }
172 ?>
Session is the interface for session implementations and defines access to session variables.
Definition: Session.php:19
getType()
Get the type of the object.
aquireLock(ObjectId $oid, $type, PersistentObject $currentState=null)
OptimisticLockException signals an exception when trying to create an optimistic lock.
NodeValueIterator is used to iterate over all persistent values of a Node (not including relations).
getOID()
Get the object id of the PersistentObject.
IllegalArgumentException signals an exception in method arguments.
PessimisticLockException signals an exception when trying to create an pessimistic lock.
ObjectId is the unique identifier of an object.
Definition: ObjectId.php:28
LockHandler defines the interface for LockHandler implementations.
Definition: LockHandler.php:21
BuildDepth values are used to define the depth when loading object trees.
Definition: BuildDepth.php:19
Instances of ReferenceDescription describe reference attributes of PersistentObjects.
Lock represents a lock on an object.
Definition: Lock.php:18
PersistenceFacade defines the interface for PersistenceFacade implementations.
ConcurrencyManager is used to handle concurrency for objects.
static getLogger($name)
Get the logger with the given name.
Definition: LogManager.php:37
__construct(PersistenceFacade $persistenceFacade, LockHandler $lockHandler, Session $session)
Constructor.
PersistentObject defines the interface of all persistent objects.
static isValid($oid)
Check if a serialized ObjectId has a valid syntax, the type is known and if the number of primary key...
Definition: ObjectId.php:123
LogManager is used to retrieve Logger instances.
Definition: LogManager.php:20
Instances of TransientAttributeDescription describe transient attributes of PersistentObjects.