1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.cache.disk;
18
19
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
30 import java.io.File;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.Reader;
34 import java.io.OutputStreamWriter;
35 import java.net.MalformedURLException;
36 import java.util.Enumeration;
37 import java.util.Hashtable;
38 import java.util.Vector;
39 import javax.servlet.ServletContext;
40
41
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 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 instances = new Hashtable();
68
69 /***
70 This is the directory used to cache the documents.
71 */
72 private String directory;
73
74 /***
75 This is a hashtable with all the entries in this cache.
76 */
77 private Hashtable entries = new Hashtable();
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 directory) {
88 this.directory = directory;
89
90 if ( DEFAULT_CACHE_DIRECTORY.equals("use-servlet-temp") ) {
91 String tempdir = new String("WEB-INF/cache");
92 try {
93 ServletContext 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 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
123
124
125
126
127
128
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 t)
135 {
136 logger.error( "initEntries: Unable to start URLManagerService", t );
137 }
138
139 File temp = new File( directory );
140
141 String 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( getRoot(), files[i] ) );
154 logger.info("Adding cache entry for " + ent.getSourceURL());
155
156 String 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 diskEntries = new Vector();
178
179 Enumeration 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 getRoot() {
197 new File( this.directory ).mkdirs();
198 return this.directory;
199 }
200
201 /***
202 @see DiskCache#getEntry( String url )
203 */
204 public DiskCacheEntry getEntry( String url ) throws IOException {
205 return getEntry( url, false );
206 }
207
208 /***
209 Force this URL to update
210 */
211 public DiskCacheEntry getEntry( String url,
212 boolean force ) throws IOException
213 {
214
215 if ( url == null ) {
216 throw new IllegalArgumentException("You must specify a URL to obtain an entry from the cache");
217 }
218
219
220 String interned = url.intern();
221 JetspeedDiskCacheEntry entry = (JetspeedDiskCacheEntry)entries.get(interned);
222 if( entry != null)
223 {
224
225
226 if(force)
227 {
228 logger.info("Refreshing local URL!!!" + interned);
229
230 URLFetcher.refresh(interned);
231 }
232 return entry;
233 }
234
235
236
237
238 logger.warn( "Cache getEntry Called with " + url );
239 if ( DiskCacheUtils.isLocal( url ) ) {
240
241 String 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
260
261 if ( DiskCacheUtils.isCacheable( url ) ) {
262
263 if ( ( DiskCacheUtils.isCached( this, url ) == false ) || force ) {
264
265
266
267
268
269
270
271 this.add( url, true );
272
273 }
274 return this.getEntry(url, force);
275
276
277 } else {
278
279
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 url,
292 Reader is ) throws IOException {
293
294 String uri = URIEncoder.encode( url );
295 String oldfilename = this.getRoot() + "/old." + uri;
296 String filename = DiskCacheUtils.getFile( this, url ).getAbsolutePath();
297 String newfilename = this.getRoot() + "/new." + uri;
298 File file = new File( DiskCacheUtils.getFile( this, url ).getAbsolutePath() );
299 File newfile = new File( newfilename);
300
301 OutputStreamWriter os = new OutputStreamWriter (new FileOutputStream( newfile ), "utf-8" );
302
303
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 oldfile = new File( oldfilename);
315 if(oldfile.exists())
316 oldfile.delete();
317 if(newfile.exists() && newfile.length() > 0) {
318 file = new File( filename );
319 file.renameTo(oldfile);
320 newfile.renameTo(file);
321 }
322 try {
323 if( oldfile.exists() )
324 oldfile.delete();
325 } catch (Exception 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 url ) throws IOException {
346 String uri = URIEncoder.encode( url );
347 if( DiskCacheUtils.isCached( this, url ) ) {
348 entries.remove(url.intern());
349 URLManager.unregister( url.intern() );
350 File file = DiskCacheUtils.getFile( this, url );
351 if(file.exists()) {
352 file.delete();
353 }
354 }
355 String oldfilename = this.getRoot() + "/old." + uri;
356 File file = new File(oldfilename);
357 if(file.exists()) {
358 file.delete();
359 }
360 String newfilename = this.getRoot() + "/new." + uri;
361 file = new File(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 url ) throws IOException {
372 add( url, false );
373 }
374
375 /***
376 @see DiskCache#add( String url )
377 */
378 public void add( String url, boolean force ) throws IOException {
379 String 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 fetch( String url,
398 String cache ) throws IOException {
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 fetch( String url,
410 String cache,
411 boolean force ) throws IOException {
412
413 if (url == null) {
414 throw new IllegalArgumentException("url cannot be null");
415 }
416
417 if (cache == null) {
418 throw new IllegalArgumentException("cache cannot be null");
419 }
420
421 try {
422
423
424
425 Reader is = URLFetcher.fetch( url, force );
426
427 OutputStreamWriter os = new OutputStreamWriter( new FileOutputStream( cache ),
428 "utf-8" );
429
430
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 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 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 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 url)
489 {
490 return entries.containsKey(url.intern());
491 }
492
493 }
494
495