Source Code Cross Referenced for CacheFilter.java in  » Web-Server » Jigsaw » org » w3c » www » protocol » http » cache » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Server » Jigsaw » org.w3c.www.protocol.http.cache 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        // CacheFilter.java
002:        // $Id: CacheFilter.java,v 1.92 2003/04/02 19:08:09 ylafon Exp $
003:        // (c) COPYRIGHT MIT, INRIA and Keio, 1999.
004:        // Please first read the full copyright statement in file COPYRIGHT.html
005:
006:        package org.w3c.www.protocol.http.cache;
007:
008:        import java.io.File;
009:        import java.lang.reflect.Method;
010:        import java.lang.reflect.InvocationTargetException;
011:        import java.net.URL;
012:        import java.net.MalformedURLException;
013:        import java.util.Vector;
014:        import java.util.Hashtable;
015:
016:        import org.w3c.util.ObservableProperties;
017:        import org.w3c.util.PropertyMonitoring;
018:        import org.w3c.util.URLUtils;
019:
020:        import org.w3c.www.protocol.http.HttpException;
021:        import org.w3c.www.protocol.http.HttpManager;
022:        import org.w3c.www.protocol.http.PropRequestFilter;
023:        import org.w3c.www.protocol.http.PropRequestFilterException;
024:        import org.w3c.www.protocol.http.Reply;
025:        import org.w3c.www.protocol.http.Request;
026:        import org.w3c.www.protocol.http.RequestFilter;
027:
028:        import org.w3c.www.http.HTTP;
029:        import org.w3c.www.http.HttpCacheControl;
030:        import org.w3c.www.http.HttpEntityMessage;
031:        import org.w3c.www.http.HttpFactory;
032:        import org.w3c.www.http.HttpInvalidValueException;
033:        import org.w3c.www.http.HttpMessage;
034:        import org.w3c.www.http.HttpReplyMessage;
035:        import org.w3c.www.http.HttpRequestMessage;
036:        import org.w3c.www.http.HttpSetCookieList;
037:        import org.w3c.www.http.HttpWarning;
038:
039:        public class CacheFilter implements  PropRequestFilter,
040:                PropertyMonitoring {
041:            // serializer class
042:            public static final String SERIALIZER_P = "org.w3c.www.protocol.http.cache.serializerclass";
043:            // sweeper class
044:            public static final String SWEEPER_P = "org.w3c.www.protocol.http.cache.sweeperclass";
045:            // validator class
046:            public static final String VALIDATOR_P = "org.w3c.www.protocol.http.cache.validatorclass";
047:
048:            /**
049:             * Name of the property enabling the connected/disconnected mode
050:             */
051:            public static final String CACHE_CONNECTED_P = "org.w3c.www.protocol.http.cache.connected";
052:            /**
053:             * Name of the property indicating if this cache is shared.
054:             * <p>This property defaults to <strong>true</strong>.
055:             */
056:            public static final String SHARED_P = "org.w3c.www.protocol.http.cache.shared";
057:
058:            /**
059:             * The name of the properties indicating the size of the cache (in bytes).
060:             * This property will give the value of the disk-based cache size. This
061:             * value only takes into account the size of the entities saved, not
062:             * the size of the associated headers, and not the physical size on the
063:             * disc.
064:             * <p>This property defaults to <strong>5000000</strong> bytes.
065:             */
066:            public static final String CACHE_SIZE_P = "org.w3c.www.protocol.http.cache.size";
067:
068:            /**
069:             * Name of the property indicating if the cache is in debug mode.
070:             * <p>This property defaults to <strong>false</strong>.
071:             */
072:            public static final String DEBUG_P = "org.w3c.www.protocol.http.cache.debug";
073:
074:            /**
075:             * The state used to disable that filter per request. Also set by the cache
076:             * if the request cannot be fullfilled by caches, as detected by this 
077:             * filter.
078:             */
079:            public final static String STATE_NOCACHE = "org.w3c.www.protocol.http.cache.dont";
080:            /**
081:             * Name of the request state used to collect warnings.
082:             */
083:            public final static String STATE_WARNINGS = "org.w3c.www.protocol.http.cache.CacheFilter.warns";
084:            /**
085:             * Name of the request state used tokeep track of original request
086:             */
087:            public final static String STATE_ORIGREQ = "org.w3c.www.protocol.http.cache.CacheFilter.origreq";
088:            /**
089:             * Name of the request state that marks a request as being a revalidation.
090:             */
091:            public final static String STATE_REVALIDATION = "org.w3c.www.protocol.http.cache.revalidation";
092:
093:            /**
094:             * The HTTP warning used to notify of a disconnected cache.
095:             */
096:            protected static HttpWarning WARN_DISCONNECTED = null;
097:            /**
098:             * The HTTP warning used to mark invalid entries
099:             */
100:            protected static HttpWarning WARN_STALE = null;
101:            /**
102:             * The HTTP warning used to indicate a heuristic expiration time.
103:             */
104:            protected static HttpWarning WARN_HEURISTIC = null;
105:
106:            static {
107:                // Build the std "disconnected" warning
108:                HttpWarning w = null;
109:                w = HttpFactory.makeWarning(HttpWarning.DISCONNECTED_OPERATION);
110:                w.setAgent("Jigsaw");
111:                w.setText("The required cached resource is stale.");
112:                WARN_DISCONNECTED = w;
113:                // Build the stale std warning
114:                w = HttpFactory.makeWarning(HttpWarning.STALE);
115:                w.setAgent("Jigsaw");
116:                w.setText("The returned entry is stale.");
117:                WARN_STALE = w;
118:                // Build the heuristic expiration warning:
119:                w = HttpFactory.makeWarning(HttpWarning.HEURISTIC_EXPIRATION);
120:                w.setAgent("Jigsaw");
121:                w.setText("Heuristic expiration time used on this entry.");
122:                WARN_HEURISTIC = w;
123:            }
124:
125:            /**
126:             * The properties we initialized ourself from.
127:             */
128:            protected ObservableProperties props = null;
129:            // our validator
130:            protected CacheValidator validator;
131:            // our caches tore
132:            protected CacheStore store;
133:            // our cache sweeper
134:            protected CacheSweeper sweeper;
135:            // our cache serializer
136:            protected CacheSerializer serializer;
137:            // is the cache connected?
138:            protected boolean connected = true;
139:            // is the cache shared?
140:            protected boolean shared = true;
141:            // The cache size
142:            protected long size = 20971520; // 20Mo is the default
143:            protected File directory = null;
144:            // should ew debug this?
145:            protected boolean debug = false;
146:            // the hastable of not downloaded resources
147:            protected Hashtable precache = new Hashtable(10);
148:            // the hastable of the URI to be downloaded
149:            protected Hashtable uritable = new Hashtable(10);
150:
151:            /**
152:             * return the cache sweeper used by the cache
153:             * @return an instance of CacheSweeper
154:             */
155:            public CacheSweeper getSweeper() {
156:                return sweeper;
157:            }
158:
159:            /**
160:             * return the serializer used by the cache
161:             * @return an instance of Serializer
162:             */
163:            public CacheSerializer getSerializer() {
164:                return serializer;
165:            }
166:
167:            /**
168:             * return the cache validator used by the cache
169:             * @return an instance of CacheValidator
170:             */
171:            public CacheValidator getValidator() {
172:                return validator;
173:            }
174:
175:            /**
176:             * is the cache shared?
177:             * @return a boolean, true if the cache is shared
178:             */
179:            public boolean isShared() {
180:                return shared;
181:            }
182:
183:            /**
184:             * is the cache connected?
185:             * @return a boolean, true if the cache is connected
186:             */
187:            public boolean isConnected() {
188:                return connected;
189:            }
190:
191:            /**
192:             * Display some output, related to the request (used for debugging)
193:             */
194:            protected final void trace(Request request, String msg) {
195:                System.out.println(request.getURL() + ": " + msg);
196:            }
197:
198:            /**
199:             * Add a warning, to be emitted at reply time.
200:             * The cache filter keeps track, through a specific piece of request state
201:             * of the warnings to be emitted at reply time (if any).
202:             * <p>During request processing, cached resources can add any kind
203:             * of warnings, which will be collected and forwarded back to the reply.
204:             * @param request The request being process, and whose reply requires
205:             * some warnings.
206:             * @param warning The warning to be emitted if ever we use the cache
207:             * filter to answer the above request.
208:             */
209:            protected void addWarning(Request request, HttpWarning warning) {
210:                Vector vw = (Vector) request.getState(STATE_WARNINGS);
211:                if (vw == null) {
212:                    vw = new Vector(4);
213:                    request.setState(STATE_WARNINGS, vw);
214:                }
215:                vw.addElement(warning);
216:            }
217:
218:            /**
219:             * Copy all warnings colllected into the given reply.
220:             * This method collects all HTTP warnings saved during request processing
221:             * and create (if needed) the approporiate warning header in the given
222:             * reply.
223:             * @param request The request that has been processed by the cache filter.
224:             * @param reply The reply that has been constructed from the cache.
225:             * @see #addWarning
226:             */
227:            protected final void setWarnings(Request request, Reply reply) {
228:                Vector vw = (Vector) request.getState(STATE_WARNINGS);
229:                if (vw == null)
230:                    return;
231:                HttpWarning ws[] = new HttpWarning[vw.size()];
232:                vw.copyInto(ws);
233:                reply.setWarning(ws);
234:            }
235:
236:            /**
237:             * check if we can use the cache or not for this request
238:             * It marks the request as being not cachable if false.
239:             * @param a request, the incoming client-side request
240:             * @return a boolean, true if we can use the cache
241:             */
242:            public boolean canUseCache(Request req) {
243:                // RFC2616: 14.32 Cache-Control equivalence of Pragma: no-cache
244:                // RFC2616: 14.9.2 no-store directive
245:                // RFC2616: 14.9.4 End-to-end reload
246:                if (req.hasPragma("no-cache") || (req.getNoCache() != null)) {
247:                    req.setState(CacheState.STATE_NOCACHE, Boolean.TRUE);
248:                    return false;
249:                }
250:                if (req.checkNoStore()) {
251:                    req.setState(CacheState.STATE_STORABLE, Boolean.FALSE);
252:                    return false;
253:                }
254:                String method = req.getMethod();
255:                if (!method.equals("GET") && !method.equals("HEAD")) {
256:                    req.setState(CacheState.STATE_NOCACHE, Boolean.TRUE);
257:                    return false;
258:                }
259:                return true;
260:            }
261:
262:            /**
263:             * Checks if, according to the headers of the reply, an entity may
264:             * be cached or not, it decorates also the reply
265:             * @param a request, the client side request
266:             * @param a reply, the client side reply
267:             * @return a boolean, true if the resource can be cached
268:             */
269:            public boolean canCache(Request req, Reply rep) {
270:                String method = req.getMethod();
271:                // only cache GET and HEAD
272:                if (!method.equals("GET") /* FIXME && !method.equals("HEAD")*/) {
273:                    rep.setState(CacheState.STATE_CACHABLE, Boolean.FALSE);
274:                    return false;
275:                }
276:                // don't cache HTTP/0.9 replies for now
277:                if (req.getMajorVersion() == 0) {
278:                    rep.setState(CacheState.STATE_CACHABLE, Boolean.FALSE);
279:                    return false;
280:                }
281:                // Ugly Hack for lame cookies
282:                if (rep.getSetCookie() != null) {
283:                    rep.setState(CacheState.STATE_CACHABLE, Boolean.FALSE);
284:                    return false;
285:                }
286:                // RFC2616: 13.4 Response cacheability
287:                int status = rep.getStatus();
288:                if ((status != HTTP.OK)
289:                        && (status != HTTP.NON_AUTHORITATIVE_INFORMATION)
290:                        && (status != HTTP.PARTIAL_CONTENT)
291:                        && (status != HTTP.MULTIPLE_CHOICE)
292:                        && (status != HTTP.MOVED_PERMANENTLY)
293:                        && (status != HTTP.GONE)) {
294:                    rep.setState(CacheState.STATE_CACHABLE, Boolean.FALSE);
295:                    return false;
296:                }
297:                HttpCacheControl repcc = null;
298:                try {
299:                    repcc = rep.getCacheControl();
300:                } catch (HttpInvalidValueException ex) {
301:                    // invalid header, be safe and avoid caching
302:                    repcc = HttpFactory.parseCacheControl("no-cache");
303:                    rep.setCacheControl(repcc);
304:                }
305:                // first check if we are told that we can cache the resource
306:                if (repcc != null) {
307:                    // RFC2616: 14.9.1 Cache-Control: public overrides everything
308:                    if (repcc.checkPublic()) {
309:                        rep.setState(CacheState.STATE_CACHABLE, Boolean.TRUE);
310:                        return true;
311:                    }
312:                    // RFC2616: 14.9.1 Cache-Control: private
313:                    // We are not handling for now the field names that may be
314:                    // associated
315:                    if (isShared() && (repcc.getPrivate() != null)) {
316:                        rep.setState(CacheState.STATE_CACHABLE, Boolean.FALSE);
317:                        return false;
318:                    }
319:                }
320:                // RFC2616: 14.9.1 no-cache, note that we are not using
321:                // the optional field-names (it is a MAY)
322:                if (rep.getNoCache() != null) {
323:                    rep.setState(CacheState.STATE_CACHABLE, Boolean.FALSE);
324:                    return false;
325:                }
326:                // HTTP/1.[01] Pragma no-cache RFC2616: 14.32 Cache-Control equivalence
327:                if (rep.hasPragma("no-cache")) {
328:                    rep.setState(CacheState.STATE_CACHABLE, Boolean.FALSE);
329:                    return false;
330:                }
331:                // Now check for URI and HTTP/1.0, 
332:                // RFC2616: 13.9 HTTP/1.0 with ? in the URI and no Expires should not
333:                // be cached.
334:                if ((req.getURL().getFile().indexOf('?') != -1)
335:                        && ((rep.getMajorVersion() == 1) && (rep
336:                                .getMinorVersion() == 0))
337:                        && (rep.getExpires() == -1)) {
338:                    rep.setState(CacheState.STATE_CACHABLE, Boolean.FALSE);
339:                    return false;
340:                }
341:                // Do we have an authentication?
342:                // without a cache-control, we deny caching for now.
343:                if (req.hasAuthorization()) {
344:                    rep.setState(CacheState.STATE_CACHABLE, Boolean.FALSE);
345:                    return false;
346:                }
347:                // by default, it is cacheable
348:                rep.setState(CacheState.STATE_CACHABLE, Boolean.TRUE);
349:                return true;
350:            }
351:
352:            /**
353:             * Checks if, according to the headers of a reply we can store
354:             * the resource.
355:             * Note that a resource may be cachable, but not storable (memory cache)
356:             * although is MUST do its best to get rid of it asap, in our case we just
357:             * don't store it!
358:             * @param a request, the client side request
359:             * @param a reply, the client side reply
360:             * @return a boolean, true if the resource can be stored by the cache
361:             */
362:            public boolean canStore(Request req, Reply rep) {
363:                // RFC2616: 14.9.2 What can be stored...
364:                if (req.checkNoStore() || rep.checkNoStore()) {
365:                    rep.setState(CacheState.STATE_STORABLE, Boolean.FALSE);
366:                    return false;
367:                }
368:                rep.setState(CacheState.STATE_CACHABLE, Boolean.TRUE);
369:                return true;
370:            }
371:
372:            /**
373:             * Modify a request to ask for a revalidation
374:             * @param the resource to be revalidated
375:             * @param request, the original request to be modified
376:             */
377:            protected Request setRequestRevalidation(CachedResource res,
378:                    Request req) {
379:                try {
380:                    return store.getCachedResource(res).setRequestRevalidation(
381:                            req);
382:                } catch (InvalidCacheException ex) {
383:                    // should never happen as we know it is in the cache
384:                }
385:                return null;
386:            }
387:
388:            /**
389:             * The request pre-processing hook.
390:             * Before each request is launched, all filters will be called back through
391:             * this method. They will generally set up additional request header
392:             * fields to enhance the request.
393:             * @param request The request that is about to be launched.
394:             * @return An instance of Reply if the filter could handle the request,
395:             * or <strong>null</strong> if processing should continue normally.
396:             * @exception HttpException If the filter is supposed to fulfill the
397:             * request, but some error happened during that processing.
398:             */
399:            public Reply ingoingFilter(Request request) throws HttpException {
400:                // can we use the cache?
401:                if (!canUseCache(request)) {
402:                    if (debug) {
403:                        trace(request, "*** Can't use cache");
404:                    }
405:                    // we will invalidate this resource, will do that only
406:                    // on real entity resource, not on negotiated ones
407:                    if (connected) {
408:                        CachedResource res = null;
409:                        EntityCachedResource invalidRes = null;
410:                        try {
411:                            URL _ru = request.getURL();
412:                            String requrl = URLUtils.normalize(_ru)
413:                                    .toExternalForm();
414:                            res = store.getCachedResourceReference(requrl);
415:                            if (res != null) {
416:                                invalidRes = (EntityCachedResource) res
417:                                        .lookupResource(request);
418:                            }
419:                        } catch (InvalidCacheException ex) {
420:                            invalidRes = null;
421:                        }
422:                        if (invalidRes != null) {
423:                            invalidRes.setWillRevalidate(true);
424:                        }
425:                        request.setState(STATE_NOCACHE, Boolean.TRUE);
426:                        return null;
427:                    } else {
428:                        // disconnected, abort now!
429:                        Reply reply = request.makeReply(HTTP.GATEWAY_TIMEOUT);
430:                        reply.setContent("The cache cannot be use for "
431:                                + "<p><code>" + request.getMethod()
432:                                + "</code> " + "<strong>" + request.getURL()
433:                                + "</strong>" + ". <p>It is disconnected.");
434:                        return reply;
435:                    }
436:                }
437:                // let's try to get the resource!
438:                URL _ru = request.getURL();
439:                String requrl = URLUtils.normalize(_ru).toExternalForm();
440:                // in the pre-cache, wait for full download
441:                // FIXME should be better than this behaviour...
442:                // see EntityCachedResource perform's FIXME ;)
443:                if (precache.containsKey(requrl)) {
444:                    if (debug)
445:                        System.out
446:                                .println("*** Already downloading: " + requrl);
447:                    try {
448:                        CachedResource cr = (CachedResource) precache
449:                                .get(requrl);
450:                        return cr.perform(request);
451:                    } catch (Exception ex) {
452:                        // there was a problem with the previous request, 
453:                        // it may be better to do it by ourself
454:                    }
455:                }
456:
457:                CachedResource res = null;
458:                try {
459:                    res = store.getCachedResourceReference(requrl);
460:                } catch (InvalidCacheException ex) {
461:                    res = null;
462:                }
463:                // are we disconnected?
464:                if (request.checkOnlyIfCached() || !connected) {
465:                    // and no entries...
466:                    EntityCachedResource ecr = null;
467:                    if (res != null) {
468:                        ecr = (EntityCachedResource) res
469:                                .lookupResource(request);
470:                    }
471:                    if ((res == null) || (ecr == null)) {
472:                        if (debug)
473:                            trace(request, "unavailable (disconnected).");
474:                        Reply reply = request.makeReply(HTTP.GATEWAY_TIMEOUT);
475:                        reply.setContent("The cache doesn't have an entry for "
476:                                + "<p><strong>" + request.getURL()
477:                                + "</strong>" + ". <p>And it is disconnected.");
478:                        return reply;
479:                    }
480:                    // yeah!
481:                    if (debug) {
482:                        trace(request, (connected) ? " hit - only if cached"
483:                                : " hit while disconneced");
484:                    }
485:                    if (!validator.isValid(ecr, request)) {
486:                        addWarning(request, WARN_STALE);
487:                    }
488:                    addWarning(request, WARN_DISCONNECTED);
489:                    Reply reply = ecr.perform(request);
490:                    // Add any warnings collected during processing to the reply:
491:                    setWarnings(request, reply);
492:                    //FIXME	    request.setState(STATE_HOW, HOW_HIT);
493:                    return reply;
494:                }
495:                // in connected mode, we should now take care of revalidation and such
496:                if (res != null) {
497:                    // if not fully loaded, ask for a revalidation FIXME
498:                    if ((res.getLoadState() == CachedResource.STATE_LOAD_PARTIAL)
499:                            || (res.getLoadState() == CachedResource.STATE_LOAD_ERROR)) {
500:                        setRequestRevalidation(res, request);
501:                        return null;
502:                    }
503:                    if (validator.isValid(res, request)) {
504:                        try {
505:                            store.updateResourceGeneration(res);
506:                        } catch (InvalidCacheException ex) {
507:                            // should be ok so...
508:                        }
509:                        //FIXME	    request.setState(STATE_HOW, HOW_HIT);
510:                        Reply rep = res.perform(request);
511:                        return rep;
512:                    } else {
513:                        if (debug) {
514:                            System.out.println("*** Revalidation asked for "
515:                                    + requrl);
516:                        }
517:                        // ask for a revalidation
518:                        setRequestRevalidation(res, request);
519:                        return null;
520:                    }
521:                }
522:                // lock here while we are waiting for the download
523:                while (uritable.containsKey(requrl)) {
524:                    synchronized (uritable) {
525:                        try {
526:                            uritable.wait();
527:                        } catch (InterruptedException ex) {
528:                        }
529:                    }
530:                    if (precache.containsKey(requrl)) {
531:                        if (debug)
532:                            System.out.println("*** Already downloading: "
533:                                    + requrl);
534:                        CachedResource cr = (CachedResource) precache
535:                                .get(requrl);
536:                        return cr.perform(request);
537:                    }
538:                    uritable.put(requrl, requrl);
539:                }
540:                return null;
541:            }
542:
543:            /**
544:             * This filter  handle exceptions.
545:             * @param request The request that triggered the exception.
546:             * @param ex The triggered exception.
547:             * @return Always <strong>false</strong>.
548:             */
549:            public boolean exceptionFilter(Request request, HttpException ex) {
550:                URL _ru;
551:                _ru = request.getURL();
552:                String requrl = URLUtils.normalize(_ru).toExternalForm();
553:                synchronized (uritable) {
554:                    uritable.remove(requrl);
555:                    uritable.notifyAll();
556:                }
557:                return false;
558:            }
559:
560:            /**
561:             * The request post-processing hook.
562:             * After each request has been replied to by the target server (be it a 
563:             * proxy or the actual origin server), each filter's outgoingFilter
564:             * method is called.
565:             * <p>It gets the original request, and the actual reply as a parameter,
566:             * and should return whatever reply it wants the caller to get.
567:             * @param request The original (handled) request.
568:             * @param reply The reply, as emited by the target server, or constructed
569:             * by some other filter.
570:             * @exception HttpException If the reply emitted by the server is not
571:             * a valid HTTP reply.
572:             */
573:            public Reply outgoingFilter(Request request, Reply reply)
574:                    throws HttpException {
575:                URL url = URLUtils.normalize(request.getURL());
576:                // Yeah ! We win:
577:                CachedResource c;
578:                c = (CachedResource) request
579:                        .getState(CacheState.STATE_RESOURCE);
580:                if (c != null) {
581:                    if (debug)
582:                        trace(request, "revalidated " + reply.getStatus());
583:                    //		request.setState(STATE_HOW
584:                    //				 , ((reply.getStatus() == HTTP.NOT_MODIFIED)
585:                    //				    ? HOW_REVALIDATION_SUCCESS
586:                    //				    : HOW_REVALIDATION_FAILURE));
587:                    //		Reply valrep = c.validate(request, reply);
588:                    // Client or Server error, ask for revalidation
589:                    //		if (valrep.getStatus()/100 >= 4) {
590:                    //		    c.setWillRevalidate(true);
591:                    //		}
592:                    if (reply.getStatus() == HTTP.NOT_MODIFIED) {
593:                        // FIXME revalidateResource(request, reply)
594:                        validator.revalidateResource(c, request, reply);
595:                        try {
596:                            store.storeCachedResource(c, c.getCurrentLength());
597:                        } catch (InvalidCacheException ex) {
598:                            if (debug) {
599:                                ex.printStackTrace();
600:                            }
601:                        }
602:                        // extract the original request
603:                        Request origreq;
604:                        origreq = (Request) request
605:                                .getState(CacheState.STATE_ORIGREQ);
606:                        return c.perform(origreq);
607:                    } else {
608:                        // delete it
609:                        c.delete();
610:                        store.getState().notifyResourceDeleted(c);
611:                    }
612:                }
613:                // don't use cache, exit asap
614:                if (!canCache(request, reply)) {
615:                    request.setState(STATE_NOCACHE, Boolean.TRUE);
616:                    if (debug) {
617:                        System.out.println("*** Can't cache reply");
618:                    }
619:                    String requrl = url.toExternalForm();
620:                    precache.remove(requrl);
621:                    synchronized (uritable) {
622:                        uritable.remove(requrl);
623:                        uritable.notifyAll();
624:                    }
625:                    invalidateOnReply(request, reply);
626:                    return null;
627:                }
628:                if (!canStore(request, reply)) {
629:                    //	    request.setState(STATE_NOSTORE, Boolean.TRUE);
630:                    if (debug) {
631:                        System.out.println("*** Can't store reply");
632:                    }
633:                    String requrl = url.toExternalForm();
634:                    precache.remove(requrl);
635:                    synchronized (uritable) {
636:                        uritable.remove(requrl);
637:                        uritable.notifyAll();
638:                    }
639:                    invalidateOnReply(request, reply);
640:                    return null;
641:                }
642:                pushDocument(request, reply);
643:                return null;
644:            }
645:
646:            private void invalidateOnReply(Request request, Reply reply) {
647:                URL url = request.getURL();
648:                // now invalidate the entities per rfc2616#13.11
649:                if ((request.getMethod() == HTTP.POST)
650:                        || (request.getMethod() == HTTP.PUT)
651:                        || (request.getMethod() == HTTP.DELETE)) {
652:                    String rloc = reply.getLocation();
653:                    String rcloc = reply.getContentLocation();
654:                    URL urloc, urcloc;
655:                    // FIXME use a private method instead of duplicating
656:                    if (rloc != null) {
657:                        try {
658:                            urloc = new URL(rloc);
659:                            // only if host match
660:                            if (URLUtils.equalsProtocolHostPort(url, urloc)) {
661:                                CachedResource res = null;
662:                                try {
663:                                    res = store
664:                                            .getCachedResourceReference(rloc);
665:                                    if (res != null) {
666:                                        res.setWillRevalidate(true);
667:                                    }
668:                                } catch (InvalidCacheException ex) {
669:                                    // weird, but it won't stop us :)
670:                                }
671:                            }
672:                        } catch (MalformedURLException mule) {
673:                            // nothing to do
674:                        }
675:                    }
676:                    if (rcloc != null) {
677:                        try {
678:                            urcloc = new URL(url, rcloc);
679:                            // only if host match
680:                            if (URLUtils.equalsProtocolHostPort(url, urcloc)) {
681:                                CachedResource res = null;
682:                                try {
683:                                    String surcloc = urcloc.toExternalForm();
684:                                    res = store
685:                                            .getCachedResourceReference(surcloc);
686:                                    if (res != null) {
687:                                        res.setWillRevalidate(true);
688:                                    }
689:                                } catch (InvalidCacheException ex) {
690:                                    // weird, but it won't stop us :)
691:                                }
692:                            }
693:                        } catch (MalformedURLException mule) {
694:                            // nothing to do
695:                        }
696:                    }
697:                }
698:            }
699:
700:            public void sync() {
701:                if (debug) {
702:                    System.out.println("*** Synching the CacheFilter");
703:                }
704:                try {
705:                    store.sync();
706:                } catch (Exception ex) {
707:                    System.err.println(getClass().getName()
708:                            + ": Unable to save cache.");
709:                }
710:            }
711:
712:            /**
713:             * Property monitoring for the CacheFilter.
714:             * The CacheFilter allows you to dynamically (typically through the 
715:             * property setter) change the class of the sweeper, the validator, 
716:             * the size...
717:             * @param name The name of the property that has changed.
718:             * @return A boolean, <strong>true</strong> if the change was made, 
719:             *    <strong>false</strong> otherwise.
720:             */
721:            public boolean propertyChanged(String name) {
722:                if (name.equals(SERIALIZER_P)) {
723:                    CacheSerializer cs = null;
724:                    try {
725:                        Class c;
726:                        c = Class.forName(props.getString(name, null));
727:                        cs = (CacheSerializer) c.newInstance();
728:                    } catch (Exception ex) {
729:                        return false;
730:                    }
731:                    serializer = cs;
732:                    return true;
733:                } else if (name.equals(SWEEPER_P)) {
734:                    CacheSweeper cs = null;
735:                    try {
736:                        Class c;
737:                        c = Class.forName(props.getString(name, null));
738:                        cs = (CacheSweeper) c.newInstance();
739:                    } catch (Exception ex) {
740:                        return false;
741:                    }
742:                    // looks good, let's restart with this one!
743:                    sweeper.destroy();
744:                    sweeper = cs;
745:                    sweeper.start();
746:                    return true;
747:                } else if (name.equals(VALIDATOR_P)) {
748:                    CacheValidator cv = null;
749:                    try {
750:                        Class c;
751:                        c = Class.forName(props.getString(name, null));
752:                        cv = (CacheValidator) c.newInstance();
753:                    } catch (Exception ex) {
754:                        return false;
755:                    }
756:                    validator = cv;
757:                    return true;
758:                } else if (name.equals(DEBUG_P)) {
759:                    debug = props.getBoolean(name, debug);
760:                    return true;
761:                } else if (name.equals(SHARED_P)) {
762:                    shared = props.getBoolean(name, shared);
763:                    return true;
764:                } else if (name.equals(CACHE_CONNECTED_P)) {
765:                    connected = props.getBoolean(name, true);
766:                    return true;
767:                }
768:                // ask the store if it can do something
769:                return store.propertyChanged(name);
770:            }
771:
772:            /**
773:             * Push a document in the cache.
774:             * The caller has to forge a a request and a reply before being able
775:             * to make something
776:             * enter the cache. 
777:             * The request should provide at least:
778:             * <dl>
779:             * <dt>URL<dl>The URL (key for cache lookups)
780:             * <dt>Method<dl>The method that was "applied" to URL to get forged
781:             * reply.
782:             * </dl>
783:             * <p>It is recommended that the reply provides at least
784:             * the following informations:
785:             * <dl>
786:             * <dt>Status Code</dl>A valid HTTP/1.1 status code (probably <strong>
787:             * 200</code>)
788:             * <dt>InputStream<dl>Containing the entity to be cached,
789:             * <dt>EntityTag<dl>A valid entity tag for the document,
790:             * <dt>CacheControl<dl>Appropriate HTTP/1.1 cache controls for that
791:             *     document,
792:             * <dt>Mime headers<dl>At least a valid content type, and probably a
793:             *     content length (to check consistency with the reply body).
794:             * </dt>
795:             */
796:            public void pushDocument(Request request, Reply reply) {
797:                URL url = URLUtils.normalize(request.getURL());
798:                try {
799:                    synchronized (uritable) {
800:                        CachedResource r = null;
801:                        String requrl = url.toExternalForm();
802:                        r = CachedResourceFactory.createResource(this , request,
803:                                reply);
804:                        if (r.uploading)
805:                            precache.put(requrl, r);
806:                        uritable.remove(requrl);
807:                        uritable.notifyAll();
808:                    }
809:                    if (debug)
810:                        trace(request, "enters cache.");
811:                } catch (Exception ex) {
812:                    ex.printStackTrace();
813:                }
814:            }
815:
816:            /**
817:             * do what is needed when an upload is done!
818:             * ie: remove from the precache and put in the store
819:             * @param the CachedResource to be moved.
820:             */
821:            protected synchronized void cleanUpload(CachedResource cr) {
822:                // FIXME we should check the state!
823:                precache.remove(cr.getIdentifier());
824:                try {
825:                    store.storeCachedResource(cr);
826:                } catch (InvalidCacheException ex) {
827:                    if (debug) {
828:                        ex.printStackTrace();
829:                    }
830:                }
831:            }
832:
833:            /**
834:             * @return the store used a CacheStore
835:             */
836:            public CacheStore getStore() {
837:                return store;
838:            }
839:
840:            public void initialize(HttpManager manager)
841:                    throws PropRequestFilterException {
842:                String validator_c;
843:                String sweeper_c;
844:                String serializer_c;
845:                props = manager.getProperties();
846:
847:                shared = props.getBoolean(SHARED_P, true);
848:                connected = props.getBoolean(CACHE_CONNECTED_P, true);
849:                debug = props.getBoolean(DEBUG_P, false);
850:                // now create the add-on classes
851:                validator_c = props.getString(VALIDATOR_P,
852:                        "org.w3c.www.protocol.http.cache.SimpleCacheValidator");
853:                sweeper_c = props.getString(SWEEPER_P,
854:                        "org.w3c.www.protocol.http.cache.SimpleCacheSweeper");
855:                serializer_c = props
856:                        .getString(SERIALIZER_P,
857:                                "org.w3c.www.protocol.http.cache.SimpleCacheSerializer");
858:                try {
859:                    Class c;
860:                    c = Class.forName(validator_c);
861:                    validator = (CacheValidator) c.newInstance();
862:                    validator.initialize(this );
863:                    c = Class.forName(sweeper_c);
864:                    sweeper = (CacheSweeper) c.newInstance();
865:                    sweeper.initialize(this );
866:                    c = Class.forName(serializer_c);
867:                    serializer = (CacheSerializer) c.newInstance();
868:                } catch (Exception ex) {
869:                    // a fatal error! The cache won't be loaded...
870:                    ex.printStackTrace();
871:                    throw new PropRequestFilterException(
872:                            "Unable to start cache");
873:                }
874:                // now create the store as we have the basic things here
875:                store = new CacheStore();
876:                try {
877:                    store.initialize(this );
878:                } catch (InvalidCacheException ex) {
879:                    // hum no worky, should do some action there!
880:                    if (debug) {
881:                        ex.printStackTrace();
882:                    }
883:                }
884:                // now start the sweeper
885:                sweeper.start();
886:                // Start the ActiveStream handler:
887:                ActiveStream.initialize();
888:                // Register for property changes:
889:                props.registerObserver(this );
890:                // Now, we are ready, register that filter:
891:                manager.setFilter(this);
892:            }
893:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.