KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > filesys > server > filesys > cache > FilePathCache


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.filesys.server.filesys.cache;
18
19 import java.io.FileNotFoundException JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.concurrent.locks.Lock JavaDoc;
24 import java.util.concurrent.locks.ReadWriteLock JavaDoc;
25 import java.util.concurrent.locks.ReentrantReadWriteLock JavaDoc;
26
27 import org.alfresco.error.AlfrescoRuntimeException;
28 import org.alfresco.repo.cache.SimpleCache;
29 import org.alfresco.repo.node.NodeServicePolicies;
30 import org.alfresco.repo.policy.JavaBehaviour;
31 import org.alfresco.repo.policy.PolicyComponent;
32 import org.alfresco.service.cmr.repository.ChildAssociationRef;
33 import org.alfresco.service.cmr.repository.NodeRef;
34 import org.alfresco.service.namespace.NamespaceService;
35 import org.alfresco.service.namespace.QName;
36 import org.springframework.beans.factory.InitializingBean;
37
38 /**
39  * Thread-safe cache to store the file info of a file or folder against its search path.
40  * <p>
41  * The use of the <tt>java.util.concurrent</tt> package ensures that the reads are not
42  * blocked in what is generally a high ratio of reads to writes.
43  * <p>
44  * This cache listens to the repository for changes to the nodes. Currently
45  * the cache is reset when any change to a node or nodes is detected. In time,
46  * and assuming that the performance benefits are evident, the cache might only
47  * clear out the outdated file info data.
48  *
49  * @author Derek Hulley
50  */

51 public class FilePathCache
52         implements InitializingBean,
53         NodeServicePolicies.OnCreateNodePolicy,
54         NodeServicePolicies.OnUpdateNodePolicy,
55         NodeServicePolicies.OnDeleteNodePolicy
56 {
57     /** the component to register the behaviour with */
58     private PolicyComponent policyComponent;
59     /** the file state cache: for a given node and path, we have a state */
60     private SimpleCache<NodeRef, HashMap JavaDoc<String JavaDoc, FileState>> fileStatesCache;
61     /** the path result cache: for a given node and search, we have a list of results */
62     private SimpleCache<NodeRef, HashMap JavaDoc<String JavaDoc, List JavaDoc<NodeRef>>> pathResultsCache;
63     /** lock for read-only operations */
64     private Lock JavaDoc cacheReadLock;
65     /** lock for write operations */
66     private Lock JavaDoc cacheWriteLock;
67
68     public FilePathCache()
69     {
70         // create lock objects for access to the cache
71
ReadWriteLock JavaDoc cacheLock = new ReentrantReadWriteLock JavaDoc();
72         cacheReadLock = cacheLock.readLock();
73         cacheWriteLock = cacheLock.writeLock();
74     }
75
76     /**
77      * Used to register the behaviours necessary to invalidate the cache
78      * @param policyComponent
79      */

80     public void setPolicyComponent(PolicyComponent policyComponent)
81     {
82         this.policyComponent = policyComponent;
83     }
84
85     /**
86      * Set the cache to be used for storing file state based on a query
87      * @param cache
88      */

89     public void setFileStatesCache(SimpleCache<NodeRef, HashMap JavaDoc<String JavaDoc, FileState>> cache)
90     {
91         this.fileStatesCache = cache;
92     }
93
94     /**
95      * Set the cache used to find a set of results from a path query
96      * @param cache
97      */

98     public void setPathResultsCache(SimpleCache<NodeRef, HashMap JavaDoc<String JavaDoc, List JavaDoc<NodeRef>>> cache)
99     {
100         this.pathResultsCache = cache;
101     }
102
103     /**
104      * Perform checks to ensure that all required properties were set
105      */

106     public void afterPropertiesSet() throws Exception JavaDoc
107     {
108         if (policyComponent == null)
109         {
110             throw new AlfrescoRuntimeException("policyComponent property not set");
111         }
112         if (fileStatesCache == null || pathResultsCache == null)
113         {
114             throw new AlfrescoRuntimeException("fileStatesCache and pathResultsCache properties not set");
115         }
116         // register behaviour
117
policyComponent.bindClassBehaviour(
118                 QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"),
119                 this,
120                 new JavaBehaviour(this, "onCreateNode"));
121         policyComponent.bindClassBehaviour(
122                 QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateNode"),
123                 this,
124                 new JavaBehaviour(this, "onUpdateNode"));
125         policyComponent.bindClassBehaviour(
126                 QName.createQName(NamespaceService.ALFRESCO_URI, "onDeleteNode"),
127                 this,
128                 new JavaBehaviour(this, "onDeleteNode"));
129     }
130
131     /**
132      * Resets the cache.
133      *
134      * @see #reset()
135      */

136     public void onCreateNode(ChildAssociationRef childAssocRef)
137     {
138         //
139
reset();
140     }
141
142     /**
143      * Resets the cache.
144      *
145      * @see #reset()
146      */

147     public void onUpdateNode(NodeRef nodeRef)
148     {
149         reset();
150     }
151
152     /**
153      * Resets the cache.
154      *
155      * @see #reset()
156      */

157     public void onDeleteNode(ChildAssociationRef childAssocRef)
158     {
159         reset();
160     }
161
162     /**
163      * Resets the caches
164      *
165      */

166     public void reset()
167     {
168         cacheWriteLock.lock();
169         try
170         {
171             fileStatesCache.clear();
172             pathResultsCache.clear();
173         }
174         finally
175         {
176             cacheWriteLock.unlock();
177         }
178     }
179     
180     /**
181      * Retrieve the file info associated with with the given path
182      *
183      * @param nodeRef the ancestor node against which the path is valid
184      * @param path the path (not normalized) for which to get the info
185      * @return Returns the state of the file at the given location, or null
186      * if no entry could be found
187      */

188     public FileState getFileState(NodeRef nodeRef, String JavaDoc path)
189     {
190         cacheReadLock.lock();
191         try
192         {
193             Map JavaDoc<String JavaDoc, FileState> fileStatesByPath = fileStatesCache.get(nodeRef);
194             if (fileStatesByPath == null)
195             {
196                 // no state set against the ancestor
197
return null;
198             }
199             return fileStatesByPath.get(path);
200         }
201         finally
202         {
203             cacheReadLock.unlock();
204         }
205     }
206     
207     /**
208      * Supplementary method to ensure that the state retrieved is either null (in case
209      * the cache has no entry) or the file {@link FileState#exists() exists}.
210      *
211      * @param nodeRef the ancestor node against which the path is valid
212      * @param path the path to search
213      * @return Returns the cached file state of an existing file, or null if the cache contained nothing
214      * @throws FileNotFoundException if the cache contained the state of a non-existent file
215      */

216     public FileState getExistingFileState(NodeRef nodeRef, String JavaDoc path) throws FileNotFoundException JavaDoc
217     {
218         FileState fileState = getFileState(nodeRef, path);
219         if (fileState == null)
220         {
221             // no entry
222
return null;
223         }
224         else if (!fileState.exists())
225         {
226             // path represents non-existent file
227
throw new FileNotFoundException JavaDoc(path);
228         }
229         else
230         {
231             // path was cached with existing file
232
return fileState;
233         }
234     }
235     
236     /**
237      * Caches the state associated with a given path
238      *
239      * @param pathRootNodeRef the ancestor node against which the path is valid
240      * @param path the path (not normalized) against which to cache the state
241      * @param fileState the state of the file at the given location
242      */

243     public void setFileState(NodeRef pathRootNodeRef, String JavaDoc path, FileState fileState)
244     {
245         cacheWriteLock.lock();
246         try
247         {
248             HashMap JavaDoc<String JavaDoc, FileState> fileStatesByPath = fileStatesCache.get(pathRootNodeRef);
249             if (fileStatesByPath == null)
250             {
251                 fileStatesByPath = new HashMap JavaDoc<String JavaDoc, FileState>(5);
252                 fileStatesCache.put(pathRootNodeRef, fileStatesByPath);
253             }
254             fileStatesByPath.put(path, fileState);
255         }
256         finally
257         {
258             cacheWriteLock.unlock();
259         }
260     }
261     
262     public List JavaDoc<NodeRef> getPathResults(NodeRef pathRootNodeRef, String JavaDoc path)
263     {
264         cacheReadLock.lock();
265         try
266         {
267             HashMap JavaDoc<String JavaDoc, List JavaDoc<NodeRef>> resultsByPath = pathResultsCache.get(pathRootNodeRef);
268             if (resultsByPath == null)
269             {
270                 // no queries have been made against this search root yet
271
return null;
272             }
273             return resultsByPath.get(path);
274         }
275         finally
276         {
277             cacheReadLock.unlock();
278         }
279     }
280     
281     public void setPathResults(NodeRef pathRootNodeRef, String JavaDoc path, List JavaDoc<NodeRef> results)
282     {
283         cacheWriteLock.lock();
284         try
285         {
286             HashMap JavaDoc<String JavaDoc, List JavaDoc<NodeRef>> resultsByPath = pathResultsCache.get(pathRootNodeRef);
287             if (resultsByPath == null)
288             {
289                 // no queries have been made against this search root yet
290
resultsByPath = new HashMap JavaDoc<String JavaDoc, List JavaDoc<NodeRef>>(5);
291                 pathResultsCache.put(pathRootNodeRef, resultsByPath);
292             }
293             resultsByPath.put(path, results);
294         }
295         finally
296         {
297             cacheWriteLock.unlock();
298         }
299     }
300 }
301
Popular Tags