KickJava   Java API By Example, From Geeks To Geeks.

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


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 //jetspeed
20
import org.apache.jetspeed.util.URIEncoder;
21 import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
22 import org.apache.jetspeed.services.logging.JetspeedLogger;
23 import org.apache.jetspeed.services.threadpool.ThreadPool;
24 import org.apache.jetspeed.services.urlmanager.URLManager;
25 import org.apache.jetspeed.services.urlmanager.URLFetcher;
26 import org.apache.jetspeed.services.urlmanager.URLFetcherDownloader;
27 import org.apache.jetspeed.services.resources.JetspeedResources;
28
29 //standard java stuff
30
import java.io.File JavaDoc;
31 import java.io.FileOutputStream JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.io.Reader JavaDoc;
34 import java.io.OutputStreamWriter JavaDoc;
35 import java.net.MalformedURLException JavaDoc;
36 import java.util.Enumeration JavaDoc;
37 import java.util.Hashtable JavaDoc;
38 import java.util.Vector JavaDoc;
39 import javax.servlet.ServletContext JavaDoc;
40
41 //turbine
42
import org.apache.turbine.services.servlet.TurbineServlet;
43
44
45 /**
46    <p>Sample Implementation of the Disk Cache interface.</p>
47    <p>Entries are updated when DiskCacheDaemon runs</p>
48
49 @see DiskCache
50 @see org.apache.jetspeed.daemon.impl.DiskCacheDaemon
51 @author <A HREF="mailto:burton@apache.org">Kevin A. Burton</A>
52 @author <a HREF="mailto:sgala@hisitech.com">Santiago Gala</a>
53 @version $Id: JetspeedDiskCache.java,v 1.50 2004/02/23 02:45:29 jford Exp $
54 */

55 public class JetspeedDiskCache implements DiskCache {
56
57
58     /**
59     The default cache folder
60     */

61     public static String JavaDoc DEFAULT_CACHE_DIRECTORY =
62         JetspeedResources.getString( JetspeedResources.CACHE_DIRECTORY_KEY, "WEB-INF/cache" );
63    
64     /**
65     Stores instances of JetspeedDiskCaches
66     */

67     private static Hashtable JavaDoc instances = new Hashtable JavaDoc();
68
69     /**
70     This is the directory used to cache the documents.
71     */

72     private String JavaDoc directory;
73
74     /**
75     This is a hashtable with all the entries in this cache.
76     */

77     private Hashtable JavaDoc entries = new Hashtable JavaDoc();
78
79     /**
80      * Static initialization of the logger for this class
81      */

82     private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(JetspeedDiskCache.class.getName());
83     
84     /**
85     Create an instance of the document cache.
86     */

87     private JetspeedDiskCache(String JavaDoc directory) {
88         this.directory = directory;
89
90     if ( DEFAULT_CACHE_DIRECTORY.equals("use-servlet-temp") ) {
91             String JavaDoc tempdir = new String JavaDoc("WEB-INF/cache");
92             try {
93                 ServletContext JavaDoc sc = TurbineServlet.getServletContext();
94                 tempdir = sc.getAttribute("javax.servlet.context.tempdir").toString() + "/jetspeed/cache";
95                 if ( logger.isDebugEnabled() )
96                 {
97                     logger.debug("DISK CACHE: will create cache in servlet temp directory " + tempdir);
98                 }
99             } catch (Exception JavaDoc e) {
100                 logger.error("DISK CACHE: problems creating cache in servlet temp directory "
101                            + " falling back to WEB-INF/cache : " + e);
102             }
103         this.directory = tempdir;
104     } else {
105                 if ( logger.isDebugEnabled() )
106                 {
107                     logger.debug("DISK CACHE: will use cache in user configured directory " + directory);
108                 }
109     }
110     }
111     
112
113     /**
114
115    Create entries in the hashtable corresponding to the cached files...
116     
117     @see DiskCache#getEntries
118     */

119     private void initEntries() {
120         
121         logger.info("Disk Cache init Entries...");
122         //HACK: we need the URLManager started now to avoid locks...
123
//init() acts as a barrier, making our thread wait until
124
//URLManager is done initialization.
125
//This is the long time sought sporadic race condition/lock :-)
126
//To whomever rewrite this code: please change API so the cache is initialized
127
//through the URLManager service *after* the Manager is initialized, and possibly
128
//accessed through URLManager.getReader( url ) or something similar.
129
try {
130             org.apache.turbine.services.TurbineServices
131                 .getInstance()
132                 .getService( org.apache.jetspeed.services.urlmanager.URLManagerService.SERVICE_NAME ).init();
133         }
134         catch (Throwable JavaDoc t)
135         {
136             logger.error( "initEntries: Unable to start URLManagerService", t );
137         }
138
139         File JavaDoc temp = new File JavaDoc( directory );
140         
141         String JavaDoc files[] = temp.list();
142
143
144         if (files == null)
145         {
146             logger.error("DiskCache.initEntries: Error!!! - The cache directory cannot be found: " + directory);
147         }
148
149         for ( int i = 0; i < files.length; ++i ) {
150
151             if ( files[i].indexOf("http_") == 0 ) {
152                 logger.info("Initializing cache entry: " + files[i]);
153                 JetspeedDiskCacheEntry ent = new JetspeedDiskCacheEntry( new File JavaDoc( getRoot(), files[i] ) );
154                 logger.info("Adding cache entry for " + ent.getSourceURL());
155
156                 String JavaDoc interned = ent.getSourceURL().intern();
157                 entries.put( interned, ent);
158                 URLManager.register( interned,
159                                      URLManager.STATUS_OK,
160                                      "Recovered from cache" );
161             }
162             
163         }
164         logger.info("Disk Cache init Entries DONE.");
165         
166     }
167     
168     /**
169     Get a list of all the documents within the cache...
170
171     Modified to create the entries in the hashtable...
172     
173     @see DiskCache#getEntries
174     */

175     public DiskCacheEntry[] getEntries() {
176         
177         Vector JavaDoc diskEntries = new Vector JavaDoc();
178         
179         Enumeration JavaDoc cacheEntries = entries.elements();
180         logger.info("Calling JetspeedDiskCache getEntries");
181         while(cacheEntries.hasMoreElements())
182             {
183                 diskEntries.addElement(cacheEntries.nextElement());
184             }
185         DiskCacheEntry[] found = new DiskCacheEntry[diskEntries.size()];
186         diskEntries.copyInto(found);
187         return found;
188         
189     }
190     
191     /**
192     Return the root of this DiskCache
193     
194     @see DiskCache#getRoot
195     */

196     public String JavaDoc getRoot() {
197         new File JavaDoc( this.directory ).mkdirs();
198         return this.directory;
199     }
200
201     /**
202     @see DiskCache#getEntry( String url )
203     */

204     public DiskCacheEntry getEntry( String JavaDoc url ) throws IOException JavaDoc {
205         return getEntry( url, false );
206     }
207     
208     /**
209     Force this URL to update
210     */

211     public DiskCacheEntry getEntry( String JavaDoc url,
212                                     boolean force ) throws IOException JavaDoc
213     {
214         
215         if ( url == null ) {
216             throw new IllegalArgumentException JavaDoc("You must specify a URL to obtain an entry from the cache");
217         }
218
219         //return right away if the entry exists in the cache...
220
String JavaDoc interned = url.intern();
221         JetspeedDiskCacheEntry entry = (JetspeedDiskCacheEntry)entries.get(interned);
222         if( entry != null)
223             {
224
225                 //Log.info("Returning local URL because it is cached: " + interned );
226
if(force)
227                     {
228                         logger.info("Refreshing local URL!!!" + interned);
229
230                         URLFetcher.refresh(interned);
231                     }
232                 return entry;
233             }
234
235
236         //attempt to see if the user didn't specify a URL if they didn't then
237
//assume it is localhost with the servlet port
238
logger.warn( "Cache getEntry Called with " + url );
239         if ( DiskCacheUtils.isLocal( url ) ) {
240
241             String JavaDoc local = DiskCacheUtils.getLocalURL( url ).intern();
242             JetspeedDiskCacheEntry dce = (JetspeedDiskCacheEntry)entries.get( local );
243             if(dce == null )
244                 {
245
246                     logger.info("Adding Local to cache list: " + local);
247                     dce = new JetspeedDiskCacheEntry( local );
248                     entries.put(local, dce);
249                     URLManager.register( local,
250                                          URLManager.STATUS_OK,
251                                          "Local added" );
252                 }
253             logger.info("Returning local cached URL");
254
255             return dce;
256         }
257         
258                
259         //only return for URLs that are cacheable and that are based on URLs
260
//that are remote
261
if ( DiskCacheUtils.isCacheable( url ) ) {
262         
263             if ( ( DiskCacheUtils.isCached( this, url ) == false ) || force ) {
264
265                 //Log.info( "DiskCache: MISS - fectching document: " + url );
266

267                 //if it doesn't exist then pull it down from a URL and save it to a file
268
// SGP We can arrive here either because force was true or
269
// because force is false and the url is not cached.
270
// We must force load in both cases
271
this.add( url, true );
272
273             }
274             return this.getEntry(url, force);
275             //return new JetspeedDiskCacheEntry( DiskCacheUtils.getFile( this, url ) );
276

277         } else {
278
279             //else it is a remote URL and can not be cached.
280
logger.info( "DiskCache: this URL can't be stored in cache... providing it directly." + url );
281             return new JetspeedDiskCacheEntry( url );
282
283         }
284
285     }
286
287     /**
288      Get an Entry given a Reader and the URL from which it has been fetched.
289     @see DiskCache#getEntry( String url, Reader is )
290     */

291     public DiskCacheEntry getEntry( String JavaDoc url,
292                                     Reader JavaDoc is ) throws IOException JavaDoc {
293
294         String JavaDoc uri = URIEncoder.encode( url );
295         String JavaDoc oldfilename = this.getRoot() + "/old." + uri;
296         String JavaDoc filename = DiskCacheUtils.getFile( this, url ).getAbsolutePath();
297         String JavaDoc newfilename = this.getRoot() + "/new." + uri;
298         File JavaDoc file = new File JavaDoc( DiskCacheUtils.getFile( this, url ).getAbsolutePath() );
299         File JavaDoc newfile = new File JavaDoc( newfilename);
300
301         OutputStreamWriter JavaDoc os = new OutputStreamWriter JavaDoc (new FileOutputStream JavaDoc( newfile ), "utf-8" );
302
303         //now process the InputStream...
304
char chars[] = new char[200];
305
306         int readCount = 0;
307         while( ( readCount = is.read( chars )) > 0 ) {
308             os.write(chars, 0, readCount);
309         }
310
311         is.close();
312         os.close();
313         
314         File JavaDoc oldfile = new File JavaDoc( oldfilename);
315         if(oldfile.exists())
316             oldfile.delete();
317         if(newfile.exists() && newfile.length() > 0) {
318             file = new File JavaDoc( filename );
319             file.renameTo(oldfile);
320             newfile.renameTo(file);
321         }
322         try {
323             if( oldfile.exists() )
324                 oldfile.delete();
325         } catch (Exception JavaDoc e) {
326             logger.info("Exception " +
327                      e.getMessage() +
328                      " while deleting " + oldfilename, e);
329         }
330         JetspeedDiskCacheEntry dce = (JetspeedDiskCacheEntry) entries.get(url.intern());
331         if (dce != null )
332             {
333                 dce.setFile( file );
334                 return dce;
335             } else {
336                 return this.getEntry(url, false);
337             }
338         
339     }
340     
341     
342     /**
343     @see DiskCache#remove( String url )
344     */

345     public void remove( String JavaDoc url ) throws IOException JavaDoc {
346         String JavaDoc uri = URIEncoder.encode( url );
347         if( DiskCacheUtils.isCached( this, url ) ) {
348             entries.remove(url.intern());
349             URLManager.unregister( url.intern() );
350             File JavaDoc file = DiskCacheUtils.getFile( this, url );
351             if(file.exists()) {
352                 file.delete();
353             }
354         }
355         String JavaDoc oldfilename = this.getRoot() + "/old." + uri;
356         File JavaDoc file = new File JavaDoc(oldfilename);
357         if(file.exists()) {
358             file.delete();
359         }
360         String JavaDoc newfilename = this.getRoot() + "/new." + uri;
361         file = new File JavaDoc(newfilename);
362         if(file.exists()) {
363             file.delete();
364         }
365         
366     }
367
368     /**
369     @see DiskCache#add( String url )
370     */

371     public void add( String JavaDoc url ) throws IOException JavaDoc {
372         add( url, false );
373     }
374     
375     /**
376     @see DiskCache#add( String url )
377     */

378     public void add( String JavaDoc url, boolean force ) throws IOException JavaDoc {
379         String JavaDoc interned = url.intern();
380         this.fetch( url,
381                     DiskCacheUtils.getFile( this, url ).getAbsolutePath(),
382                     force );
383         if(entries.get(interned) != null ) return;
384         entries.put(interned, new JetspeedDiskCacheEntry(interned));
385         URLManager.register( interned,
386                              URLManager.STATUS_OK,
387                              "Added by Program" );
388
389     }
390     
391     /**
392
393     @see DiskCache#fetch( String url, String cache )
394     @param url the url to retrieve
395     @param cache what file to store it in.
396     */

397     public String JavaDoc fetch( String JavaDoc url,
398                          String JavaDoc cache ) throws IOException JavaDoc {
399         return fetch( url, cache, false );
400     }
401
402     /**
403     Pulls in the remote URL from the net and saves it to disk
404
405     @see DiskCache#fetch( String url, String cache )
406     @param url the url to retrieve
407     @param cache what file to store it in.
408     */

409     public String JavaDoc fetch( String JavaDoc url,
410                          String JavaDoc cache,
411                          boolean force ) throws IOException JavaDoc {
412
413         if (url == null) {
414             throw new IllegalArgumentException JavaDoc("url cannot be null");
415         }
416         
417         if (cache == null) {
418             throw new IllegalArgumentException JavaDoc("cache cannot be null");
419         }
420
421         try {
422
423             //The URL fecther will try to get the URL or it will throw
424
//an Exception here.
425
Reader JavaDoc is = URLFetcher.fetch( url, force );
426             
427             OutputStreamWriter JavaDoc os = new OutputStreamWriter JavaDoc( new FileOutputStream JavaDoc( cache ),
428                                                            "utf-8" );
429
430             //now process the InputStream...
431
char chars[] = new char[200];
432     
433             int readCount = 0;
434             while( ( readCount = is.read( chars )) > 0 ) {
435                 os.write(chars, 0, readCount);
436             }
437     
438             is.close();
439             os.close();
440     
441         } catch (MalformedURLException JavaDoc e) {
442             logger.error("Error in URL", e );
443         }
444     
445         return cache;
446     
447     }
448
449     /**
450     @see DiskCache#refresh
451     */

452     public void refresh( String JavaDoc url ) {
453         ThreadPool.process( new URLFetcherDownloader( url ) );
454     }
455     
456     /**
457     Return the default instance of the JetspeedDiskCache cache.
458     */

459     public static JetspeedDiskCache getInstance() {
460
461         return JetspeedDiskCache.getInstance( DEFAULT_CACHE_DIRECTORY );
462     }
463
464     /**
465     Return the default instance of the JetspeedDiskCache cache.
466     
467     @param location A directory to store the cache at.
468     */

469     public static JetspeedDiskCache getInstance( String JavaDoc directory ) {
470
471         synchronized(JetspeedDiskCache.instances) {
472         
473             JetspeedDiskCache cache = (JetspeedDiskCache)JetspeedDiskCache.instances.get(directory);
474             
475             if (cache == null) {
476                 cache = new JetspeedDiskCache(directory);
477                 JetspeedDiskCache.instances.put( directory, cache );
478                 logger.info("DISK CACHE: Initing cache for " + directory);
479                 cache.initEntries();
480                 logger.info("DISK CACHE: Inited cache:" + directory);
481             }
482             return cache;
483         }
484     }
485
486     /**
487     */

488     public boolean isCached(String JavaDoc url)
489     {
490         return entries.containsKey(url.intern());
491     }
492     
493 }
494
495
496
Popular Tags