KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > vfs > VFSLockManager


1 /*
2  * SSL-Explorer
3  *
4  * Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */

19             
20 package com.sslexplorer.vfs;
21
22 import java.io.IOException JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.HashSet JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.TreeSet JavaDoc;
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 /**
43  *
44  */

45 public class VFSLockManager {
46     /**
47      * A simple class to maintain global locks on files. Locks should only be
48      * requested when a resource is being edited.
49      */

50     private final static Log log = LogFactory.getLog(VFSLockManager.class);
51     private static long HANDLE = 0;
52     private static final Object JavaDoc LOCK = new Object JavaDoc();
53     private static VFSLockManager instance;
54
55     private final Map JavaDoc<String JavaDoc, NonExclusiveLock> nonExclusiveLocks_ = new HashMap JavaDoc<String JavaDoc, NonExclusiveLock>();
56     private final Map JavaDoc<String JavaDoc, ExclusiveLock> exclusiveLocks_ = new HashMap JavaDoc<String JavaDoc, ExclusiveLock>();
57     private final Map JavaDoc<String JavaDoc, Collection JavaDoc<Lock>> locksByHandle_ = new HashMap JavaDoc<String JavaDoc, Collection JavaDoc<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 JavaDoc thread = new Thread JavaDoc() {
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 JavaDoc e) {
100         }
101     }
102
103     /**
104      * Generates a unique handle for a file.
105      *
106      * @return the handle
107      */

108     public static String JavaDoc getNewHandle() {
109         synchronized (LOCK) {
110             return System.currentTimeMillis() + "" + (HANDLE++);
111         }
112     }
113
114     /**
115      * Does what it says on the tin.
116      *
117      * @return the instance
118      */

119     public static VFSLockManager getInstance() {
120         return instance == null ? instance = new VFSLockManager() : instance;
121     }
122
123     /**
124      *
125      * @param resource
126      * @param session
127      * @param exclusive
128      * @param lockParent
129      * @param handle
130      * @throws LockedException
131      * @throws IOException
132      */

133     public synchronized void lock(VFSResource resource, SessionInfo session, boolean exclusive, boolean lockParent, String JavaDoc handle)
134                     throws LockedException, IOException JavaDoc {
135         String JavaDoc key = resource.getWebFolderPath();
136         if (log.isDebugEnabled())
137             log.debug("Attempting to " + (exclusive ? "exclusively" : "non-exclusively") + " lock resource " + key);
138
139         // First of all try to soft lock the parent
140
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 JavaDoc<Lock>());
146
147         Collection JavaDoc<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     /**
173      * @param handle
174      */

175     public synchronized void unlock(String JavaDoc handle) {
176         Collection JavaDoc<Lock> locks = locksByHandle_.get(handle);
177         
178         try {
179             for (Iterator JavaDoc 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     /**
191      * @param session
192      * @param handle
193      */

194     public synchronized void unlock(SessionInfo session, String JavaDoc handle) {
195         Collection JavaDoc<Lock> locks = locksByHandle_.get(handle);
196
197         try {
198             for (Iterator JavaDoc 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 JavaDoc webFolderPath = lock.getResource().getWebFolderPath();
213         Map JavaDoc lockMap = lock instanceof ExclusiveLock ? exclusiveLocks_ : nonExclusiveLocks_;
214         lockMap.remove(webFolderPath);
215     }
216     
217     /**
218      * @return <code>java.util.Collection<VFSFileLock></code> containing all the currently held locks
219      */

220     public synchronized Collection JavaDoc<VFSFileLock> getCurrentLocks () {
221         Collection JavaDoc<VFSFileLock> lockedFiles = new TreeSet JavaDoc<VFSFileLock> ();
222         for (Map.Entry JavaDoc<String JavaDoc, Collection JavaDoc<Lock>> entry : locksByHandle_.entrySet()) {
223             String JavaDoc 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 JavaDoc baseName = name.getBaseName();
231                         String JavaDoc friendlyURI = DAVUtilities.stripUserInfo(name.getURI().toString());
232                         boolean sessionsActive = areSessionsActive(lock);
233                         lockedFiles.add(new VFSFileLock(baseName, friendlyURI, sessionsActive, handle));
234                     }
235                 } catch (IOException JavaDoc e) {
236                     // ignore
237
}
238             }
239         }
240         return lockedFiles;
241     }
242     
243     @SuppressWarnings JavaDoc("unchecked")
244     private static boolean areSessionsActive (Lock lock)
245     {
246         Collection JavaDoc<SessionInfo> lockOwners = lock.getLockOwners();
247         if (lockOwners.isEmpty())
248             return false;
249         
250         LogonController logonController = LogonControllerFactory.getInstance();
251         Collection JavaDoc<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 JavaDoc handle_;
262
263         private ExclusiveLock(VFSResource resource, SessionInfo session, String JavaDoc 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 JavaDoc getHandle() {
278             return handle_;
279         }
280
281         public boolean removeLock(String JavaDoc 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 JavaDoc<SessionInfo> getLockOwners() {
297             Collection JavaDoc<SessionInfo> lockOwners = new HashSet JavaDoc<SessionInfo>(1);
298             lockOwners.add(session_);
299             return lockOwners;
300         }
301
302         @Override JavaDoc
303         public String JavaDoc toString() {
304             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
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 JavaDoc<SessionInfo> sessions_;
316         private final String JavaDoc handle_;
317         
318         NonExclusiveLock(VFSResource resource, SessionInfo session, String JavaDoc handle) {
319             resource_ = resource;
320             sessions_ = new HashSet JavaDoc<SessionInfo>();
321             incrementLock(session);
322             handle_ = handle;
323         }
324
325         @SuppressWarnings JavaDoc("unchecked")
326         private Collection JavaDoc<SessionInfo> getSessions() {
327             return (Collection JavaDoc<SessionInfo>) sessions_.clone();
328         }
329
330         public VFSResource getResource() {
331             return resource_;
332         }
333         
334         private String JavaDoc 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 JavaDoc 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 JavaDoc<SessionInfo> getLockOwners() {
377             return getSessions();
378         }
379
380         @Override JavaDoc
381         public String JavaDoc toString() {
382             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
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         /**
393          * The resource associated with the lock.
394          * @return the resource
395          */

396         VFSResource getResource();
397
398         /**
399          * Removes the lock from the file.
400          * @param handle of the file
401          * @param sessionInfo associated with the lock
402          * @return true if the lock can be removed
403          */

404         boolean removeLock(String JavaDoc handle, SessionInfo sessionInfo);
405
406         /**
407          * Verifies if this lock is owned by the supplied Session.
408          * @param sessionInfo
409          * @return true if this session owns the lock.
410          */

411         boolean isLockOwner(SessionInfo sessionInfo);
412         
413         /**
414          * @return the owners of the lock
415          */

416         Collection JavaDoc<SessionInfo> getLockOwners ();
417     }
418 }
Popular Tags