View Javadoc

1   /*
2    * Copyright (c) 2006-2007 Creative Sphere Limited.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *
10   *   Creative Sphere - initial API and implementation
11   *
12   */
13  package org.abstracthorizon.danube.webdav.lock.impl;
14  
15  import org.abstracthorizon.danube.webdav.lock.Lock;
16  import org.abstracthorizon.danube.webdav.lock.LockingMechanism;
17  import org.abstracthorizon.danube.webdav.util.Timeout;
18  
19  import java.util.Collection;
20  import java.util.HashMap;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.Map;
24  
25  /**
26   * Simple, in-memory locking mechanism
27   *
28   * @author Daniel Sendula
29   */
30  public class SimpleInMemoryLockingMechanism implements LockingMechanism {
31  
32      /** Map of tokens to locks */
33      protected Map<String, Lock> tokenLocks = new HashMap<String, Lock>();
34  
35      /** Map of locks to resources */
36      protected Map<Lock, Collection<Object>> lockResources = new HashMap<Lock, Collection<Object>>();
37  
38      /** Map of resources to locks */
39      protected Map<Object, Collection<Lock>> resourcesLocks = new HashMap<Object, Collection<Lock>>();
40  
41      /** Minimal interval timed out locks are removed. Defaulted to 10 seconds */
42      protected int harvestMinimumInterval = 10000; // 10 seconds
43  
44      /** Time locks can be harvesed as the earliest */
45      protected long nextHarvested;
46  
47      /**
48       * Constructor
49       */
50      public SimpleInMemoryLockingMechanism() {
51      }
52  
53      /**
54       * Creates the lock
55       * @param type lock type
56       * @param scope lock type
57       * @param owner lock owner
58       * @param timeout lock timeout
59       * @param depth lock depth
60       */
61      public synchronized Lock createLock(int type, int scope, Object owner, Timeout timeout, int depth) {
62          Lock lock = createLockImpl(type, scope, owner, timeout, depth);
63          tokenLocks.put(lock.getToken(), lock);
64          harvestLocks();
65          return lock;
66      }
67  
68      /**
69       * Constructs lock object
70       * @param type lock type
71       * @param scope lock scope
72       * @param owner lock owner
73       * @param timeout lock timeout
74       * @param depth lock depth
75       * @return
76       */
77      protected Lock createLockImpl(int type, int scope, Object owner, Timeout timeout, int depth) {
78          return new Lock(type, scope, owner, timeout, depth);
79      }
80  
81      /**
82       * Retunrs the lock with the given token or <code>null</code>
83       * @param token token
84       * @return the lock with the given token or <code>null</code>
85       */
86      public synchronized Lock findLock(String token) {
87          return tokenLocks.get(token);
88      }
89  
90      /**
91       * Locks reource
92       * @param lock lock
93       * @param resource resource
94       * @return <code>true</code> if lock succeded
95       */
96      public synchronized boolean lockResource(Lock lock, Object resource) {
97          Collection<Lock> locks = resourcesLocks.get(resource);
98          if ((locks != null) && locks.contains(lock)) {
99              return false;
100         }
101         Collection<Object> rs = lockResources.get(lock);
102         if (rs == null) {
103             rs = new HashSet<Object>();
104             lockResources.put(lock, rs);
105         }
106         rs.add(resource);
107         if (locks == null) {
108            locks = new HashSet<Lock>();
109            resourcesLocks.put(resource, locks);
110         }
111         locks.add(lock);
112         return true;
113     }
114 
115     /**
116      * Unlocks resource
117      * @param lock lock
118      */
119     public synchronized void unlockResources(Lock lock) {
120         tokenLocks.remove(lock.getToken());
121         removeLock(lock);
122     }
123 
124     /**
125      * Removes locks form the given resource
126      * @param resource resource
127      */
128     public void removeLocks(Object resource) {
129         Collection<Lock> locks = resourcesLocks.remove(resource);
130         if (locks != null) {
131             for (Lock lock : locks) {
132                 Collection<Object> resources = lockResources.get(lock);
133                 resources.remove(resource);
134                 if (resources.size() == 0) {
135                     tokenLocks.remove(lock);
136                     lockResources.remove(lock);
137                 }
138             }
139         }
140     }
141 
142     /**
143      * Returns locks for the given resource
144      * @param resource resource
145      * @return locks array
146      */
147     public Lock[] getLocks(Object resource) {
148         Collection<Lock> locks = resourcesLocks.get(resource);
149         if ((locks != null) && (locks.size() > 0)) {
150             Lock[] res = new Lock[locks.size()];
151             return locks.toArray(res);
152         }
153         return null;
154     }
155 
156     /**
157      * Returns an array of resources for the given lock
158      * @param lock lock
159      * @return an array of resources
160      */
161     public Object[] getResources(Lock lock) {
162         Collection<Object> resources = lockResources.get(lock);
163         if ((resources != null) && (resources.size() > 0)) {
164             Object[] res = new Object[resources.size()];
165             return resources.toArray(res);
166         }
167         return null;
168     }
169 
170     /**
171      * Returns <code>true</code> if resource is locked
172      * @param resource resource
173      * @return <code>true</code> if resource is locked
174      */
175     public synchronized boolean isLocked(Object resource) {
176         harvestLocks();
177         Collection<Lock> locks = resourcesLocks.get(resource);
178         return ((locks != null) && (locks.size() > 0));
179     }
180 
181     /**
182      * Returns <code>true</code> if access to the resource is allowed
183      * @param resource resource
184      * @param token token
185      * @return <code>true</code> if access to the resource is allowed
186      */
187     public synchronized boolean isAccessAllowed(Object resource, String token) {
188         harvestLocks();
189         Collection<Lock> locks = resourcesLocks.get(resource);
190         if ((locks != null) && (locks.size() > 0)) {
191             if (token != null) {
192                 for (Lock lock : locks) {
193                     if (lock.getToken().equals(token)) {
194                         return true;
195                     }
196                 }
197             }
198             return false;
199         } else {
200             return true;
201         }
202     }
203 
204     /**
205      * Returns array with {@link LockingMechanism#SCOPE_EXCLUSIVE} and {@link LockingMechanism#SCOPE_SHARED}
206      * @return array with {@link LockingMechanism#SCOPE_EXCLUSIVE} and {@link LockingMechanism#SCOPE_SHARED}
207      */
208     public int[] getSupportedLockScopes(Object resource) {
209         return new int[]{LockingMechanism.SCOPE_EXCLUSIVE, LockingMechanism.SCOPE_SHARED};
210     }
211 
212     /**
213      * Removes all locks that are not valid anymore (due to timeout)
214      */
215     protected synchronized void harvestLocks() {
216         long now = System.currentTimeMillis();
217         if (nextHarvested  < now) {
218             nextHarvested = now + harvestMinimumInterval;
219 
220             Iterator<Lock> iterator = tokenLocks.values().iterator();
221             while (iterator.hasNext()) {
222                 Lock lock = iterator.next();
223                 if (lock.getValidUntil() < now) {
224                     iterator.remove();
225                     removeLock(lock);
226                 }
227             }
228 
229         }
230     }
231 
232     /**
233      * Removes a lock
234      * @param lock lock
235      */
236     protected void removeLock(Lock lock) {
237         Collection<Object> resources = lockResources.get(lock);
238         if (resources != null) {
239             for (Object resource : resources) {
240                 Collection<Lock> locks = resourcesLocks.get(resource);
241                 if (locks != null) {
242                     locks.remove(lock);
243                     if (locks.size() == 0) {
244                         resourcesLocks.remove(resource);
245                     }
246                 }
247             }
248         }
249         lockResources.remove(lock);
250         lock.freeLock();
251     }
252 
253     /**
254      * Returns minimal harvest interval in miliseconds
255      * @return minimal harvest interval in miliseconds
256      */
257     public int getHarvestMinimumInterval() {
258         return harvestMinimumInterval;
259     }
260 
261     /**
262      * Sets minimal harvest interval in miliseconds
263      * @return minimal harvest interval in miliseconds
264      */
265     public void setHarvestMinimumInterval(int harvestMinimumInterval) {
266         this.harvestMinimumInterval = harvestMinimumInterval;
267     }
268 }