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 String lockToken = node.getProperty(RepositoryConstants.METADATA_LOCKTOKEN).getString(); 139 140 LockManager lockManager = node.getSession().getWorkspace().getLockManager(); 141 142 lockManager.addLockToken(lockToken); 143 144 lockManager.unlock(node.getPath()); 145 146 // Remove residual properties 147 node.setProperty(RepositoryConstants.METADATA_LOCKTOKEN, (Value) null); 148 node.setProperty(RepositoryConstants.METADATA_LOCKOWNER, (Value) null); 149 node.getSession().save(); 150 151 removeLockedContent(object); 152 } 153 catch (RepositoryException ex) 154 { 155 throw new AmetysRepositoryException("Unable to unlock content", ex); 156 } 157 } 158 159 /** 160 * Test if a {@link JCRAmetysObject} is locked. 161 * @param object the object to test. 162 * @return true if the object is locked, false otherwise. 163 * @throws AmetysRepositoryException if an error occurs. 164 */ 165 public boolean isLocked(JCRAmetysObject object) throws AmetysRepositoryException 166 { 167 try 168 { 169 return getNode(object).isLocked(); 170 } 171 catch (RepositoryException ex) 172 { 173 throw new AmetysRepositoryException("Unable to get lock status on content", ex); 174 } 175 } 176 177 /** 178 * Get the lock owner of a {@link JCRAmetysObject}. 179 * @param object the object of which to get the lock owner. 180 * @return the lock owner or null if there is no lock owner. 181 * @throws AmetysRepositoryException if an error occurs. 182 */ 183 public UserIdentity getLockOwner(JCRAmetysObject object) throws AmetysRepositoryException 184 { 185 try 186 { 187 String userIdentity = getNode(object).getProperty(RepositoryConstants.METADATA_LOCKOWNER).getString(); 188 return UserIdentity.stringToUserIdentity(userIdentity); 189 } 190 catch (PathNotFoundException e) 191 { 192 // No lock owner 193 return null; 194 } 195 catch (RepositoryException ex) 196 { 197 throw new AmetysRepositoryException("Unable to get lock owner on content", ex); 198 } 199 } 200 201 /** 202 * Get an object's base node. 203 * @param object the object which node to get. 204 * @return the object's base node. 205 */ 206 protected Node getNode(JCRAmetysObject object) 207 { 208 Node node = null; 209 210 if (object instanceof DefaultAmetysObject) 211 { 212 node = ((DefaultAmetysObject) object).getBaseNode(); 213 } 214 else 215 { 216 node = object.getNode(); 217 } 218 219 return node; 220 } 221 222}