001/* 002 * Copyright 2012 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.repository.jcr; 017 018import javax.jcr.Node; 019import javax.jcr.PathNotFoundException; 020import javax.jcr.RepositoryException; 021import javax.jcr.Value; 022import javax.jcr.lock.Lock; 023import javax.jcr.lock.LockManager; 024 025import org.apache.avalon.framework.component.Component; 026import org.apache.avalon.framework.logger.AbstractLogEnabled; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030 031import org.ametys.core.user.CurrentUserProvider; 032import org.ametys.core.user.UserIdentity; 033import org.ametys.plugins.repository.AmetysObject; 034import org.ametys.plugins.repository.AmetysRepositoryException; 035import org.ametys.plugins.repository.RepositoryConstants; 036import org.ametys.plugins.repository.lock.UnlockHelper; 037 038/** 039 * Component that provides methods for lock management on {@link JCRAmetysObject}s. 040 */ 041public class LockComponent extends AbstractLogEnabled implements Serviceable, Component 042{ 043 044 /** The avalon component role. */ 045 public static final String ROLE = LockComponent.class.getName(); 046 047 /** The unlock helper. */ 048 protected UnlockHelper _unlockHelper; 049 050 /** The current user provider. */ 051 protected CurrentUserProvider _currentUserProvider; 052 053 @Override 054 public void service(ServiceManager manager) throws ServiceException 055 { 056 _unlockHelper = (UnlockHelper) manager.lookup(UnlockHelper.ROLE); 057 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 058 } 059 060 /** 061 * Register a locked content for automatic unlocking 062 * @param object the locked {@link AmetysObject} 063 */ 064 public void addLockedContent(AmetysObject object) 065 { 066 _unlockHelper.scheduleUnlocking(object); 067 } 068 069 /** 070 * Unregister a locked content for automatic unlocking 071 * @param object the locked {@link AmetysObject} 072 */ 073 public void removeLockedContent(AmetysObject object) 074 { 075 _unlockHelper.cancelUnlocking(object); 076 } 077 078 /** 079 * Provides the current user. 080 * @return the current user. 081 */ 082 public UserIdentity getCurrentUser() 083 { 084 return _currentUserProvider.getUser(); 085 } 086 087 /** 088 * Lock a {@link JCRAmetysObject}. 089 * @param object the object to lock. 090 * @throws AmetysRepositoryException if an error occurs. 091 */ 092 public void lock(JCRAmetysObject object) throws AmetysRepositoryException 093 { 094 try 095 { 096 Node node = getNode(object); 097 098 if (!node.isCheckedOut()) 099 { 100 throw new AmetysRepositoryException("Unable to lock a checked-in Node"); 101 } 102 103 LockManager lockManager = node.getSession().getWorkspace().getLockManager(); 104 105 Lock lock = lockManager.lock(node.getPath(), false, false, Long.MAX_VALUE, null); 106 node.setProperty(RepositoryConstants.METADATA_LOCKTOKEN, lock.getLockToken()); 107 108 UserIdentity currentUser = getCurrentUser(); 109 if (currentUser != null) 110 { 111 node.setProperty(RepositoryConstants.METADATA_LOCKOWNER, UserIdentity.userIdentityToString(currentUser)); 112 } 113 node.getSession().save(); 114 115 // On détache immédiatement le lock de la session, pour permettre 116 // les utilisations concurrentes 117 lockManager.removeLockToken(lock.getLockToken()); 118 119 addLockedContent(object); 120 } 121 catch (RepositoryException ex) 122 { 123 throw new AmetysRepositoryException("Unable to lock object " + object, ex); 124 } 125 } 126 127 /** 128 * Unlock a {@link JCRAmetysObject}. 129 * @param object the object to unlock. 130 * @throws AmetysRepositoryException if an error occurs. 131 */ 132 public void unlock(JCRAmetysObject object) throws AmetysRepositoryException 133 { 134 try 135 { 136 Node node = getNode(object); 137 138 LockManager lockManager = node.getSession().getWorkspace().getLockManager(); 139 140 Lock lock = lockManager.getLock(node.getPath()); 141 Node lockHolder = lock.getNode(); 142 String lockToken = lockHolder.getProperty(RepositoryConstants.METADATA_LOCKTOKEN).getString(); 143 144 lockManager.addLockToken(lockToken); 145 146 lockManager.unlock(node.getPath()); 147 148 // Remove residual properties 149 node.setProperty(RepositoryConstants.METADATA_LOCKTOKEN, (Value) null); 150 node.setProperty(RepositoryConstants.METADATA_LOCKOWNER, (Value) null); 151 node.getSession().save(); 152 153 removeLockedContent(object); 154 } 155 catch (RepositoryException ex) 156 { 157 throw new AmetysRepositoryException("Unable to unlock object " + object, ex); 158 } 159 } 160 161 /** 162 * Sets a lock token on the current session for the given {@link JCRAmetysObject} 163 * @param object the object for which the lock token is set. 164 * @throws AmetysRepositoryException if an error occurs 165 */ 166 public void setLockTokenOnCurrentSession(JCRAmetysObject object) throws AmetysRepositoryException 167 { 168 try 169 { 170 Node node = getNode(object); 171 if (node.isLocked()) 172 { 173 LockManager lockManager = node.getSession().getWorkspace().getLockManager(); 174 175 Lock lock = lockManager.getLock(node.getPath()); 176 Node lockHolder = lock.getNode(); 177 String lockToken = lockHolder.getProperty(RepositoryConstants.METADATA_LOCKTOKEN).getString(); 178 179 lockManager.addLockToken(lockToken); 180 } 181 } 182 catch (RepositoryException ex) 183 { 184 throw new AmetysRepositoryException("Unable to add the lock token on object " + object, ex); 185 } 186 } 187 188 /** 189 * Test if a {@link JCRAmetysObject} is locked. 190 * @param object the object to test. 191 * @return true if the object is locked, false otherwise. 192 * @throws AmetysRepositoryException if an error occurs. 193 */ 194 public boolean isLocked(JCRAmetysObject object) throws AmetysRepositoryException 195 { 196 try 197 { 198 return getNode(object).isLocked(); 199 } 200 catch (RepositoryException ex) 201 { 202 throw new AmetysRepositoryException("Unable to get lock status on object " + object, ex); 203 } 204 } 205 206 /** 207 * Get the lock owner of a {@link JCRAmetysObject}. 208 * @param object the object of which to get the lock owner. 209 * @return the lock owner or null if there is no lock owner. 210 * @throws AmetysRepositoryException if an error occurs. 211 */ 212 public UserIdentity getLockOwner(JCRAmetysObject object) throws AmetysRepositoryException 213 { 214 try 215 { 216 String userIdentity = getNode(object).getProperty(RepositoryConstants.METADATA_LOCKOWNER).getString(); 217 return UserIdentity.stringToUserIdentity(userIdentity); 218 } 219 catch (PathNotFoundException e) 220 { 221 // No lock owner 222 return null; 223 } 224 catch (RepositoryException ex) 225 { 226 throw new AmetysRepositoryException("Unable to get lock owner on object " + object, ex); 227 } 228 } 229 230 /** 231 * Get an object's base node. 232 * @param object the object which node to get. 233 * @return the object's base node. 234 */ 235 protected Node getNode(JCRAmetysObject object) 236 { 237 return object instanceof DefaultAmetysObject defaultAmetysObject 238 ? defaultAmetysObject.getBaseNode() 239 : object.getNode(); 240 } 241 242}