KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jetspeed > cache > disk > JetspeedDiskCacheEntry


1 /*
2  * Copyright 2000-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.jetspeed.cache.disk;
18
19
20 //jetspeed stuff
21
import org.apache.jetspeed.util.URIEncoder;
22 import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
23 import org.apache.jetspeed.services.logging.JetspeedLogger;
24 import org.apache.jetspeed.services.urlmanager.URLFetcher;
25 import org.apache.jetspeed.services.resources.JetspeedResources;
26
27 //standard java stuff
28
import java.io.*;
29 import java.net.*;
30
31 /**
32  *<p>A cache entry represents a data source that can be stored locally for
33  *efficiency.
34  *
35  *<p>It can deliver a string with its contents, but the preferred
36  *way to access to the entry contents is through a Reader
37  *that will get characters from it.
38  *
39  *<p>There are two kinds of entries:
40  *
41  *<ul>
42  * <li>Local: It is not cached.
43  * <li>Remote: It can be cached.
44  *</ul>
45  *
46  *<p>Remote entries can be in the following states:
47  *
48  *<ul>
49  * <li>Invalid: It has no local reference, and the source is transiently or
50  * permanently delivering errors
51  * <li>Stale: It has no local reference, and it is quiet
52  * <li>Loading: It has no local ref yet, and it is loading
53  * <li>Refreshing: It has a local ref (current or expired),
54  * and it is refreshing it
55  * <li>Expired: It has a local ref, but its content is no longer valid
56  * <li>Current: It has a valid local ref
57  *</ul>
58  *
59  *<p>TODO: Some data sources need to be written (i. e., are writable). For those,
60  * a mechanism need to be provided to write back the resource. We currently think
61  * about HTTP PUT as a mechanism.
62  *
63  *@author <a HREF="mailto:burton@apache.org">Kevin A. Burton</a>
64  *@author <a HREF="mailto:sgala@hisitech.com">Santiago Gala</a>
65  *@version $Id: JetspeedDiskCacheEntry.java,v 1.33 2004/02/23 02:45:29 jford Exp $
66  **/

67 public class JetspeedDiskCacheEntry implements DiskCacheEntry {
68
69     /**
70      * <p>Expiration interval that will be used it the remote URL does not
71      * specify one. The contract here is:
72      * <ul>
73      * <li>If we have no hits, we will hit our entry every time DiskCacheDaemon is run to revalidate.</li>
74      * <li>No matter how many hits we get, we will reach our entry at most once per defaultExpirationInterval.</li>
75      * </ul>
76      */

77     private static long defaultExpirationInterval = 1000 *
78         JetspeedResources.getInt( JetspeedResources.DEFAULT_DCE_EXPIRATION_TIME_KEY, 15 * 60 );
79
80     //Used for Local URL writing
81
static String JavaDoc encoding = JetspeedResources.getString(
82                 JetspeedResources.CONTENT_ENCODING_KEY, "iso-8859-1" );
83
84     private File file = null;
85     private String JavaDoc url = null;
86     private String JavaDoc sourceURL = null;
87
88     /**
89      Date (ms since epoch) it was last Modified
90      */

91     private long lastModified = 0;
92     /**
93      Date (ms since epoch) it expires
94      */

95     private long expires = 0;
96     
97     /**
98      * Static initialization of the logger for this class
99      */

100     private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(JetspeedDiskCacheEntry.class.getName());
101     
102     /**
103      *<p>Build a DiskCacheEntry that is based on a cached filesystem entry
104      *
105      *<p>This is used to reconstruct the entries from the cache at boot time
106      *
107      *
108      */

109     protected JetspeedDiskCacheEntry( File file ) {
110         this.setFile( file );
111         this.setURL( this.getSourceURL() );
112     }
113     
114    /**
115     *Build a DiskCacheEntry that is based on a remote URL and may be (or not)
116     *backed on disk.
117     *
118     */

119     public JetspeedDiskCacheEntry( String JavaDoc url ) {
120
121         this.setURL( url );
122         this.init();
123     }
124
125     /**
126      * Initialize the file variable, if it is null & the url
127      * is not local
128      *
129     */

130     public void init() {
131
132         URL url = null;
133
134         // first build the URL object
135
try {
136             url = new URL(this.getURL());
137         } catch (MalformedURLException e) {
138             logger.error("Error in URL", e);
139             return;
140         }
141             
142         //if this is a file:/ based URL then build a file from it.
143
if ( (this.file == null || this.file.exists() == false )
144               && "file".equals( url.getProtocol() ) )
145         {
146             try {
147                 File newfile = new File( url.getFile() );
148                 
149                 this.setFile( newfile );
150                 if( newfile.exists() == false ) {
151                     JetspeedDiskCache.getInstance().add( this.getURL(), true );
152                 }
153             } catch ( IOException e ) {
154                 logger.error("Error building from file", e);
155                 return;
156             }
157
158         }
159
160     }
161     
162     /**
163     */

164     public String JavaDoc getURL() {
165         return this.url;
166     }
167     
168     /**
169     Reconstruct the original URL based on this URL.
170     */

171     public String JavaDoc getSourceURL() {
172         //if getFile() is null then this isn't cached
173
if ( this.getFile() == null ) {
174             return this.getURL();
175         } else {
176             return URIEncoder.decode( this.getFile().getName() );
177         }
178     }
179
180     /**
181     Get the File that this URL obtains within the cache.
182     */

183     public File getFile() {
184         return this.file;
185     }
186     
187     /**
188     Set the file.
189     */

190     public void setFile( File file ) {
191         //now make sure it exists.
192
if ( file.exists() == false ) {
193             String JavaDoc message = "The following file does not exist: " + file.getAbsolutePath();
194             logger.error( message );
195             try {
196                 JetspeedDiskCache.getInstance().add( this.url, true );
197             } catch (Throwable JavaDoc e) {
198             logger.error("Error setting file", e );
199                 }
200         }
201         //file should exist after add in the Cache...
202
this.file = file;
203         this.lastModified = file.lastModified();
204         this.expires = System.currentTimeMillis() +
205             defaultExpirationInterval;
206     }
207     
208     /**
209     Open this URL and read its data, then return it as a string
210     */

211     public String JavaDoc getData() throws IOException {
212
213       Reader is = this.getReader();
214       StringWriter bos = new StringWriter();
215       
216       //now process the Reader...
217
char chars[] = new char[200];
218     
219       int readCount = 0;
220       while( ( readCount = is.read( chars )) > 0 ) {
221       bos.write(chars, 0, readCount);
222       }
223
224       is.close();
225
226       return bos.toString();
227         
228     }
229
230     /**
231     Get an input stream from this entry
232     */

233     public InputStream getInputStream() throws IOException {
234         logger.info( "CacheEntry getInputStream() called: " + this.getURL() );
235         if(this.getFile() != null)
236             {
237                 return new FileInputStream( this.getFile() );
238             }
239
240         if(DiskCacheUtils.isLocal( this.getURL() ) )
241             {
242                 return new URL( this.getURL() ).openConnection().getInputStream();
243             }
244
245         this.lastModified = 0;
246         this.expires = 0;
247         URLFetcher.refresh( this.getURL() );
248         if(this.getFile() != null)
249             return new FileInputStream( this.getFile() );
250         throw new IOException( this.getURL() +
251                                ": is not in cache after forcing" );
252   }
253
254     /**
255     Get a Reader from this entry.
256         ( Patch for handling character encoding sent by
257           Yoshihiro KANNA <y-kanna@bl.jp.nec.com> )
258       For local entries, we assume that the URL coming
259        from the WEB server is allright WRT encoding
260     For remote entries, we assume that the cache saved them in the local store
261         using UTF8 encoding
262     */

263     public Reader getReader() throws IOException {
264
265         if(DiskCacheUtils.isLocal( this.getURL() ) )
266             {
267                 URLConnection conn = new URL( this.getURL() ).openConnection();
268                 // If the URL has a proper encoding, use it
269
String JavaDoc encoding = conn.getContentEncoding();
270                 if(encoding == null) {
271                     // else take it from configuration
272
encoding = JetspeedResources.getString( JetspeedResources.CONTENT_ENCODING_KEY,
273                                                             "iso-8859-1" );
274                 }
275                 //Log.info("Disk Cache Entry: getReader URL -> " +
276
// this.getURL() +
277
// " encoding -> " +
278
// encoding );
279
return new InputStreamReader(conn.getInputStream(),
280                                              encoding );
281             }
282         
283         if(this.getFile() != null)
284             {
285                 InputStreamReader reader = null;
286                 try {
287                     //For cache files, we are assuming UTF8
288
// instead of local encoding
289
reader = new InputStreamReader( new FileInputStream( this.getFile() ), "UTF8" );
290                 } catch (UnsupportedEncodingException e) {
291                     logger.error("Encoding error", e);
292                     reader = new FileReader( this.getFile() );
293                 }
294                 //Log.info("Disk Cache Entry: getReader file -> " +
295
// this.getURL() +
296
// " encoding -> " +
297
// reader.getEncoding() );
298
return reader;
299             }
300
301         this.lastModified = 0;
302         this.expires = 0;
303         URLFetcher.refresh( this.getURL() );
304         // If it is in the cache, call recursively...
305
if(this.getFile() != null)
306             return this.getReader();
307         throw new IOException( this.getURL() +
308                                ": is not in cache after forcing" );
309
310     }
311     
312     /**
313     Get a Writer to update this entry.
314       For local entries, we assume that the URL coming
315        from the WEB server allows PUT
316     For remote entries, we throws a IOException
317
318     */

319     public Writer getWriter() throws IOException {
320
321         if( DiskCacheUtils.isRemote( this.getURL() ) ) {
322             throw new IOException("Cannot write to remote URLs!");
323         }
324
325         if(DiskCacheUtils.isLocal( this.getURL() ) )
326             {
327                 URL url = new URL( this.getURL() );
328
329                 if (url.getProtocol().equalsIgnoreCase("http"))
330                 {
331                     HttpURLConnection conn = (HttpURLConnection) url.openConnection();
332                     conn.setDoOutput(true);
333                     conn.setRequestMethod("PUT");
334                     return new HttpURLWriter( conn );
335                 }
336                 else
337                 {
338                     File file = new File( url.getFile() );
339                     file.getParentFile().mkdirs();
340                     return new FileURLWriter( file );
341                 }
342
343             
344             }
345
346         throw new IOException( this.getURL() +
347                                ": is not local or remote" );
348
349     }
350     
351     /**
352        Return the last modified date of this entry.
353     */

354     public long getLastModified() {
355         if( isLocal() ) {
356             try {
357                 String JavaDoc localfile = this.getURL().substring(5); //remove "file:"
358
this.lastModified = new File( localfile ).lastModified();
359             } catch ( Exception JavaDoc e ) {
360                 if( logger.isDebugEnabled() ) {
361                     logger.debug("Error getLastModified ", e);
362                 }
363                 e.printStackTrace();
364             }
365         }
366         return this.lastModified;
367    
368     }
369
370     /**
371     Set the last modified date of this entry.
372     */

373     public void setLastModified(long time) {
374         this.lastModified = time;
375         
376     }
377
378     /**
379        Set the url on which this is based.
380     */

381     public void setURL( String JavaDoc url ) {
382
383         if ( DiskCacheUtils.isVirtual( url ) ) {
384             url = DiskCacheUtils.getLocalURL( url );
385         }
386         
387         this.url = url;
388     }
389     
390     /**
391     Set the expiration date of this entry.
392     */

393     public long getExpirationTime() {
394         return this.expires;
395     }
396
397     /**
398     Set the expiration date of this entry.
399     */

400     public void setExpirationTime(long time) {
401         this.expires = time;
402         if(this.expires < System.currentTimeMillis())
403             {
404                 this.expires = System.currentTimeMillis() +
405                     defaultExpirationInterval;
406             }
407         
408     }
409
410     /**
411     */

412     public boolean hasExpired() {
413         return this.expires <= 0 ||
414             this.expires < System.currentTimeMillis();
415     }
416
417     /**
418     */

419     public boolean isLocal() {
420
421         return DiskCacheUtils.isLocal(this.getSourceURL());
422     }
423
424     class HttpURLWriter extends OutputStreamWriter
425     {
426         private HttpURLConnection conn;
427
428         public HttpURLWriter( HttpURLConnection conn )
429             throws UnsupportedEncodingException, IOException
430         {
431             super( conn.getOutputStream(), encoding );
432             this.conn = conn;
433             logger.info("HttpURLWriter encoding -> " +
434                      encoding + " method -> " + this.conn.getRequestMethod() );
435         }
436
437         public void close() throws IOException
438         {
439             //We close the stream
440
super.close();
441             //Required to get the real connection sending PUT data
442
this.conn.getResponseCode();
443             logger.info("HttpURLWriter close encoding -> " +
444                      encoding + " method -> " + this.conn.getRequestMethod() +
445                      " Status -> " + this.conn.getResponseCode() );
446             
447         }
448     }
449
450     class FileURLWriter extends FileWriter
451     {
452         private String JavaDoc filename;
453
454         public FileURLWriter( File file )
455             throws UnsupportedEncodingException, IOException
456         {
457             super( file );
458             this.filename = file.getPath();
459             logger.info("FileURLWriter opening file -> " + filename );
460         }
461
462         public void close() throws IOException
463         {
464             //We close the stream
465
super.close();
466             logger.info("FileURLWriter closing file -> " + filename );
467
468         }
469     }
470 }
471
Popular Tags