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