1 19 20 package com.sslexplorer.vfs; 21 22 import java.io.IOException ; 23 import java.util.ArrayList ; 24 import java.util.Collection ; 25 import java.util.HashMap ; 26 import java.util.HashSet ; 27 import java.util.Iterator ; 28 import java.util.Map ; 29 import java.util.TreeSet ; 30 31 import org.apache.commons.logging.Log; 32 import org.apache.commons.logging.LogFactory; 33 import org.apache.commons.vfs.FileName; 34 import org.apache.commons.vfs.FileObject; 35 36 import com.sslexplorer.security.LogonController; 37 import com.sslexplorer.security.LogonControllerFactory; 38 import com.sslexplorer.security.SessionInfo; 39 import com.sslexplorer.vfs.webdav.DAVUtilities; 40 import com.sslexplorer.vfs.webdav.LockedException; 41 42 45 public class VFSLockManager { 46 50 private final static Log log = LogFactory.getLog(VFSLockManager.class); 51 private static long HANDLE = 0; 52 private static final Object LOCK = new Object (); 53 private static VFSLockManager instance; 54 55 private final Map <String , NonExclusiveLock> nonExclusiveLocks_ = new HashMap <String , NonExclusiveLock>(); 56 private final Map <String , ExclusiveLock> exclusiveLocks_ = new HashMap <String , ExclusiveLock>(); 57 private final Map <String , Collection <Lock>> locksByHandle_ = new HashMap <String , Collection <Lock>>(); 58 private final boolean debug_ = false; 59 60 VFSLockManager() { 61 addLogging(); 62 } 63 64 private void addLogging() { 65 if (!log.isDebugEnabled() && !debug_) 66 return; 67 68 Thread thread = new Thread () { 69 public void run() { 70 while (true) { 71 sleepPlease(); 72 73 if (exclusiveLocks_.size() > 0) { 74 log.debug("***Exclusive Locks***"); 75 for (ExclusiveLock lock : exclusiveLocks_.values()) 76 log.debug(" " + lock.getSession() + " - " + lock.getResource().getFullPath()); 77 } else { 78 log.debug("***No outstanding exclusive locks***"); 79 } 80 if (nonExclusiveLocks_.size() > 0) { 81 log.debug("***Non-exclusive Locks***"); 82 for (NonExclusiveLock lock : nonExclusiveLocks_.values()) { 83 log.debug(" " + lock.getResource().getFullPath() + " open by "); 84 for (SessionInfo sessionInfo : lock.getSessions()) 85 log.debug(" - " + sessionInfo.toString()); 86 } 87 } else { 88 log.debug("***No outstanding non-exclusive locks***"); 89 } 90 } 91 } 92 }; 93 thread.start(); 94 } 95 96 private static void sleepPlease() { 97 try { 98 Thread.sleep(30000); 99 } catch (InterruptedException e) { 100 } 101 } 102 103 108 public static String getNewHandle() { 109 synchronized (LOCK) { 110 return System.currentTimeMillis() + "" + (HANDLE++); 111 } 112 } 113 114 119 public static VFSLockManager getInstance() { 120 return instance == null ? instance = new VFSLockManager() : instance; 121 } 122 123 133 public synchronized void lock(VFSResource resource, SessionInfo session, boolean exclusive, boolean lockParent, String handle) 134 throws LockedException, IOException { 135 String key = resource.getWebFolderPath(); 136 if (log.isDebugEnabled()) 137 log.debug("Attempting to " + (exclusive ? "exclusively" : "non-exclusively") + " lock resource " + key); 138 139 if (lockParent && resource.getParent() != null) { 141 lock(resource.getParent(), session, false, false, handle); 142 } 143 144 if (!locksByHandle_.containsKey(handle)) 145 locksByHandle_.put(handle, new ArrayList <Lock>()); 146 147 Collection <Lock> locks = locksByHandle_.get(handle); 148 if (exclusive && exclusiveLocks_.containsKey(key)) { 149 ExclusiveLock lock = exclusiveLocks_.get(key); 150 if (!lock.isLockOwner(session)) 151 throw new LockedException("File is currently locked exclusively by session " + lock.getSession()); 152 } else if (nonExclusiveLocks_.containsKey(key)) { 153 NonExclusiveLock lock = nonExclusiveLocks_.get(key); 154 if (exclusive && !lock.isLockOwner(session)) 155 throw new LockedException("Cannot lock file exclusivley; there are currently " + lock.getSessions().size() 156 + " sessions using it non-exclusivley"); 157 lock.incrementLock(session); 158 } else if (exclusive) { 159 ExclusiveLock lock = new ExclusiveLock(resource, session, handle); 160 exclusiveLocks_.put(key, lock); 161 locks.add(lock); 162 } else { 163 NonExclusiveLock lock = new NonExclusiveLock(resource, session, handle); 164 nonExclusiveLocks_.put(key, lock); 165 locks.add(lock); 166 } 167 168 if (log.isDebugEnabled()) 169 log.debug((exclusive ? "Exclusively" : "Non-exclusively") + " locked " + key); 170 } 171 172 175 public synchronized void unlock(String handle) { 176 Collection <Lock> locks = locksByHandle_.get(handle); 177 178 try { 179 for (Iterator itr = locks.iterator(); itr.hasNext();) { 180 Lock lock = (Lock) itr.next(); 181 unlock(lock); 182 itr.remove(); 183 } 184 } finally { 185 if(locks.isEmpty()) 186 locksByHandle_.remove(handle); 187 } 188 } 189 190 194 public synchronized void unlock(SessionInfo session, String handle) { 195 Collection <Lock> locks = locksByHandle_.get(handle); 196 197 try { 198 for (Iterator itr = locks.iterator(); itr.hasNext();) { 199 Lock lock = (Lock) itr.next(); 200 if (lock.removeLock(handle, session)) { 201 unlock(lock); 202 itr.remove(); 203 } 204 } 205 } finally { 206 if(locks.isEmpty()) 207 locksByHandle_.remove(handle); 208 } 209 } 210 211 private void unlock(Lock lock) { 212 String webFolderPath = lock.getResource().getWebFolderPath(); 213 Map lockMap = lock instanceof ExclusiveLock ? exclusiveLocks_ : nonExclusiveLocks_; 214 lockMap.remove(webFolderPath); 215 } 216 217 220 public synchronized Collection <VFSFileLock> getCurrentLocks () { 221 Collection <VFSFileLock> lockedFiles = new TreeSet <VFSFileLock> (); 222 for (Map.Entry <String , Collection <Lock>> entry : locksByHandle_.entrySet()) { 223 String handle = entry.getKey(); 224 for (Lock lock : entry.getValue()) { 225 try { 226 FileObject file = lock.getResource().getFile(); 227 if(file!=null) 228 { 229 FileName name = file.getName(); 230 String baseName = name.getBaseName(); 231 String friendlyURI = DAVUtilities.stripUserInfo(name.getURI().toString()); 232 boolean sessionsActive = areSessionsActive(lock); 233 lockedFiles.add(new VFSFileLock(baseName, friendlyURI, sessionsActive, handle)); 234 } 235 } catch (IOException e) { 236 } 238 } 239 } 240 return lockedFiles; 241 } 242 243 @SuppressWarnings ("unchecked") 244 private static boolean areSessionsActive (Lock lock) 245 { 246 Collection <SessionInfo> lockOwners = lock.getLockOwners(); 247 if (lockOwners.isEmpty()) 248 return false; 249 250 LogonController logonController = LogonControllerFactory.getInstance(); 251 Collection <SessionInfo> sessions = logonController.getActiveSessions().values(); 252 253 int lockOwnerCount = lockOwners.size(); 254 lockOwners.removeAll(sessions); 255 return lockOwners.isEmpty() || (lockOwners.size() != lockOwnerCount); 256 } 257 258 private static final class ExclusiveLock implements Lock { 259 private final VFSResource resource_; 260 private final SessionInfo session_; 261 private final String handle_; 262 263 private ExclusiveLock(VFSResource resource, SessionInfo session, String handle) { 264 resource_ = resource; 265 session_ = session; 266 handle_ = handle; 267 } 268 269 public VFSResource getResource() { 270 return resource_; 271 } 272 273 private SessionInfo getSession() { 274 return session_; 275 } 276 277 private String getHandle() { 278 return handle_; 279 } 280 281 public boolean removeLock(String handle, SessionInfo sessionInfo) { 282 if (!getHandle().equals(handle)) { 283 log.error("User attempting to unlock resource is not the lock owner"); 284 return false; 285 } 286 287 if (log.isDebugEnabled()) 288 log.debug("Exclusive lock for " + getResource().getWebFolderPath() + " has been removed"); 289 return true; 290 } 291 292 public boolean isLockOwner(SessionInfo sessionInfo) { 293 return session_.getUser().equals(sessionInfo.getUser()); 294 } 295 296 public Collection <SessionInfo> getLockOwners() { 297 Collection <SessionInfo> lockOwners = new HashSet <SessionInfo>(1); 298 lockOwners.add(session_); 299 return lockOwners; 300 } 301 302 @Override 303 public String toString() { 304 StringBuffer buffer = new StringBuffer (); 305 buffer.append("ExclusiveLock@"); 306 buffer.append("[").append("Resource='").append(resource_.toString()).append("', "); 307 buffer.append("Session='").append(getSession().toString()).append("', "); 308 buffer.append("Handle='").append(getHandle()).append("']"); 309 return buffer.toString(); 310 } 311 } 312 313 private static final class NonExclusiveLock implements Lock { 314 private final VFSResource resource_; 315 private final HashSet <SessionInfo> sessions_; 316 private final String handle_; 317 318 NonExclusiveLock(VFSResource resource, SessionInfo session, String handle) { 319 resource_ = resource; 320 sessions_ = new HashSet <SessionInfo>(); 321 incrementLock(session); 322 handle_ = handle; 323 } 324 325 @SuppressWarnings ("unchecked") 326 private Collection <SessionInfo> getSessions() { 327 return (Collection <SessionInfo>) sessions_.clone(); 328 } 329 330 public VFSResource getResource() { 331 return resource_; 332 } 333 334 private String getHandle() { 335 return handle_; 336 } 337 338 private int getCount() { 339 return sessions_.size(); 340 } 341 342 private void incrementLock(SessionInfo session) { 343 sessions_.add(session); 344 } 345 346 private boolean decrementLock(SessionInfo session) { 347 if (sessions_.isEmpty()) 348 return true; 349 sessions_.remove(session); 350 return sessions_.isEmpty(); 351 } 352 353 public boolean removeLock(String handle, SessionInfo sessionInfo) { 354 if (!getHandle().equals(handle)) { 355 log.error("User attempting to unlock resource is not the lock owner"); 356 return false; 357 } 358 359 if (log.isDebugEnabled()) 360 log.debug("There are " + getCount() + " non-exclusive locks remaining.. decrementing by 1"); 361 362 boolean decrementLock = decrementLock(sessionInfo); 363 if (decrementLock && log.isDebugEnabled()) 364 log.debug("All non-exclusive locks for " + getResource().getWebFolderPath() + " have been removed"); 365 return decrementLock; 366 } 367 368 public boolean isLockOwner(SessionInfo sessionInfo) { 369 for (SessionInfo session : sessions_) { 370 if (!session.getUser().equals(sessionInfo.getUser())) 371 return false; 372 } 373 return true; 374 } 375 376 public Collection <SessionInfo> getLockOwners() { 377 return getSessions(); 378 } 379 380 @Override 381 public String toString() { 382 StringBuffer buffer = new StringBuffer (); 383 buffer.append("NonExclusiveLock@"); 384 buffer.append("[").append("Resource='").append(resource_.toString()).append("', "); 385 buffer.append("Sessions='").append(getCount()).append("', "); 386 buffer.append("Handle='").append(getHandle()).append("']"); 387 return buffer.toString(); 388 } 389 } 390 391 private interface Lock { 392 396 VFSResource getResource(); 397 398 404 boolean removeLock(String handle, SessionInfo sessionInfo); 405 406 411 boolean isLockOwner(SessionInfo sessionInfo); 412 413 416 Collection <SessionInfo> getLockOwners (); 417 } 418 } | Popular Tags |