KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > riotfamily > cachius > CacheItem


1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1
3  * The contents of this file are subject to the Mozilla Public License Version
4  * 1.1 (the "License"); you may not use this file except in compliance with
5  * the License. You may obtain a copy of the License at
6  * http://www.mozilla.org/MPL/
7  *
8  * Software distributed under the License is distributed on an "AS IS" basis,
9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10  * for the specific language governing rights and limitations under the
11  * License.
12  *
13  * The Original Code is Riot.
14  *
15  * The Initial Developer of the Original Code is
16  * Neteye GmbH.
17  * Portions created by the Initial Developer are Copyright (C) 2006
18  * the Initial Developer. All Rights Reserved.
19  *
20  * Contributor(s):
21  * Felix Gnass [fgnass at neteye dot de]
22  *
23  * ***** END LICENSE BLOCK ***** */

24 package org.riotfamily.cachius;
25
26 import java.io.BufferedInputStream JavaDoc;
27 import java.io.BufferedReader JavaDoc;
28 import java.io.File JavaDoc;
29 import java.io.FileInputStream JavaDoc;
30 import java.io.FileNotFoundException JavaDoc;
31 import java.io.IOException JavaDoc;
32 import java.io.InputStream JavaDoc;
33 import java.io.InputStreamReader JavaDoc;
34 import java.io.ObjectInputStream JavaDoc;
35 import java.io.Reader JavaDoc;
36 import java.io.Serializable JavaDoc;
37 import java.io.Writer JavaDoc;
38 import java.util.Arrays JavaDoc;
39
40 import javax.servlet.ServletResponse JavaDoc;
41 import javax.servlet.http.HttpServletRequest JavaDoc;
42
43 import org.apache.commons.logging.Log;
44 import org.apache.commons.logging.LogFactory;
45 import org.riotfamily.cachius.support.ReaderWriterLock;
46 import org.riotfamily.cachius.support.TokenFilterWriter;
47 import org.riotfamily.common.io.IOUtils;
48
49
50 /**
51  * Representation of cached item that is backed by a file. The
52  * <code>lastModified</code> and the <code>contentType</code> properties
53  * are kept in memory and are serialized by the default java serialization
54  * mechanism. The actual content is read from a file to avoid the overhead
55  * of object deserialization on each request.
56  * <br>
57  * If URL rewriting is used to track the session, the sessionId is
58  * replaced by a special token in the cache file. When such an item is
59  * send to a client, the token is replaced with the current sessionId.
60  * <br>
61  * If the sessionId comes from a cookie or the controller outputs binary data,
62  * a direct stream copy is performed instead of using Readers/Writers to
63  * improve performance.
64  *
65  * @author Felix Gnass
66  */

67 public class CacheItem implements Serializable JavaDoc {
68     
69     private static final String JavaDoc ITEM_PREFIX = "item";
70     
71     private static final String JavaDoc TEMP_PREFIX = "tmp";
72     
73     private static final String JavaDoc TEMPFILE_SUFFIX = "";
74                    
75     private static final long NOT_YET = -1L;
76     
77     private static final String JavaDoc FILE_ENCODING = "UTF-8";
78     
79     private Log log = LogFactory.getLog(CacheItem.class);
80     
81     /** The previous item in the linked list */
82     private transient CacheItem previous;
83     
84     /** The next item in the linked list */
85     private transient CacheItem next;
86     
87     /** The key used for lookups */
88     private String JavaDoc key;
89     
90     /** List of tags to categorize the item */
91     private String JavaDoc[] tags;
92     
93     /** Flag indicating whether session IDs are filtered */
94     private boolean filterSessionId;
95     
96     /** The file containing the actual data */
97     private File JavaDoc file = null;
98     
99     /** The content type (may be null) */
100     private String JavaDoc contentType = null;
101     
102     /**
103      * Flag indicating whether the cached content is binary
104      * or character data.
105      */

106     private boolean binary = true;
107     
108     /**
109      * Reader/writer lock to prevent concurrent threads from updating
110      * the cached content while others are reading.
111      */

112     private transient ReaderWriterLock lock = new ReaderWriterLock();
113     
114     /**
115      * Time of the last modification.
116      */

117     private long lastModified;
118     
119     /**
120      * Time of the last up-to-date check.
121      */

122     private long lastCheck;
123     
124     public CacheItem(String JavaDoc key, File JavaDoc cacheDir) throws IOException JavaDoc {
125         this.key = key;
126         file = File.createTempFile(ITEM_PREFIX, TEMPFILE_SUFFIX, cacheDir);
127         lastModified = NOT_YET;
128     }
129         
130     public String JavaDoc getKey() {
131         return key;
132     }
133    
134     public void setKey(String JavaDoc key) {
135         this.key = key;
136     }
137      
138     public void setTags(String JavaDoc[] tags) {
139         if (tags != null) {
140             Arrays.sort(tags);
141         }
142         this.tags = tags;
143     }
144     
145     public String JavaDoc[] getTags() {
146         return tags;
147     }
148     
149     public boolean hasTag(String JavaDoc tag) {
150         return tags != null && Arrays.binarySearch(tags, tag) >= 0;
151     }
152     
153     public CacheItem getPrevious() {
154         return previous;
155     }
156
157    
158     public void setPrevious(CacheItem previous) {
159         this.previous = previous;
160     }
161
162     public CacheItem getNext() {
163         return next;
164     }
165    
166     public void setNext(CacheItem next) {
167         this.next = next;
168     }
169     
170     public int hashCode() {
171         return key.hashCode();
172     }
173
174     public boolean isFilterSessionId() {
175         return filterSessionId;
176     }
177     
178     public void setFilterSessionId(boolean filterSessionId) {
179         this.filterSessionId = filterSessionId;
180     }
181     
182     public void setContentType(String JavaDoc contentType) {
183         this.contentType = contentType;
184     }
185     
186     public String JavaDoc getContentType() {
187         return contentType;
188     }
189         
190     public long getLastModified() {
191         return lastModified;
192     }
193   
194     public void setLastModified(long lastModified) {
195         this.lastModified = lastModified;
196     }
197
198     public long getLastCheck() {
199         return this.lastCheck;
200     }
201
202     public void setLastCheck(long lastCheck) {
203         this.lastCheck = lastCheck;
204     }
205
206     public boolean isNew() {
207         return lastModified == NOT_YET;
208     }
209     
210     /**
211      * Checks whether the cache file exists an is a regular file.
212      */

213     public boolean exists() {
214         return file != null && file.isFile();
215     }
216     
217     public File JavaDoc createTempFile() throws IOException JavaDoc {
218         File JavaDoc dir = file.getParentFile();
219         dir.mkdirs();
220         return File.createTempFile(TEMP_PREFIX, TEMPFILE_SUFFIX, dir);
221     }
222     
223     public void update(File JavaDoc tempFile, boolean binary) {
224         log.debug("Updating cached version of " + key);
225         try {
226             lock.lockForWriting();
227             lastModified = System.currentTimeMillis();
228             delete();
229             IOUtils.move(tempFile, file);
230             this.binary = binary;
231         }
232         finally {
233             lock.releaseWriterLock();
234         }
235     }
236     
237     public void writeTo(HttpServletRequest JavaDoc request,
238             ServletResponse JavaDoc response) throws IOException JavaDoc {
239             
240         log.debug("Serving cached version of " + key);
241         try {
242             lock.lockForReading();
243             if (contentType != null) {
244                 response.setContentType(contentType);
245             }
246             
247             if (binary) {
248                 InputStream JavaDoc in = new BufferedInputStream JavaDoc(
249                         new FileInputStream JavaDoc(file));
250                         
251                 IOUtils.copy(in, response.getOutputStream());
252             }
253             else {
254                 Reader JavaDoc in = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(
255                         new FileInputStream JavaDoc(file), FILE_ENCODING));
256                 
257                 Writer JavaDoc out = response.getWriter();
258                 if (filterSessionId) {
259                     out = new TokenFilterWriter("${jsessionid}",
260                             request.getSession().getId(), out);
261                 }
262                 
263                 IOUtils.copy(in, out);
264             }
265         }
266         catch (FileNotFoundException JavaDoc e) {
267             log.warn("Cache file not found. Resetting modification time " +
268                     "to trigger update on next request.");
269             
270             lastModified = NOT_YET;
271         }
272         finally {
273             lock.releaseReaderLock();
274         }
275     }
276     
277     public void invalidate() {
278         lastModified = NOT_YET;
279         delete();
280     }
281     
282     public void delete() {
283         if (file.exists()) {
284             if (!file.delete()) {
285                 log.warn("Failed to delete cache file: " + file);
286             }
287         }
288     }
289          
290     /**
291      * Calls <code>in.defaultReadObject()</code> and creates a new lock.
292      */

293     private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc,
294             ClassNotFoundException JavaDoc {
295          
296          in.defaultReadObject();
297          lock = new ReaderWriterLock();
298     }
299   
300 }
301
Popular Tags