Source Code Cross Referenced for EntityCachedResource.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:        // EntityCachedResource.java
002:        // $Id: EntityCachedResource.java,v 1.37 2003/02/24 14:13:08 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.net.URL;
009:
010:        import java.util.Enumeration;
011:
012:        import java.io.BufferedInputStream;
013:        import java.io.FileInputStream;
014:        import java.io.FileOutputStream;
015:        import java.io.IOException;
016:        import java.io.InputStream;
017:        import java.io.OutputStream;
018:        import java.io.PrintStream;
019:
020:        import org.w3c.util.ArrayDictionary;
021:        import org.w3c.tools.resources.Attribute;
022:        import org.w3c.tools.resources.AttributeRegistry;
023:        import org.w3c.tools.resources.BooleanAttribute;
024:        import org.w3c.tools.resources.IntegerAttribute;
025:        import org.w3c.tools.resources.LongAttribute;
026:        import org.w3c.tools.resources.StringAttribute;
027:        import org.w3c.www.http.HeaderDescription;
028:        import org.w3c.www.http.HTTP;
029:        import org.w3c.www.http.HttpCacheControl;
030:        import org.w3c.www.http.HttpContentRange;
031:        import org.w3c.www.http.HttpRange;
032:        import org.w3c.www.http.HttpEntityTag;
033:        import org.w3c.www.http.HttpFactory;
034:        import org.w3c.www.http.ByteRangeOutputStream;
035:        import org.w3c.www.protocol.http.HttpException;
036:        import org.w3c.www.protocol.http.Reply;
037:        import org.w3c.www.protocol.http.Request;
038:        import org.w3c.www.mime.MimeType;
039:        import org.w3c.jigsaw.frames.MimeTypeAttribute;
040:
041:        /**
042:         * A cached resource with an entity
043:         */
044:        public class EntityCachedResource extends CachedResource {
045:
046:            /**
047:             * Condition check return code - Condition existed but failed.
048:             */
049:            public static final int COND_FAILED = 1;
050:            /**
051:             * Condition check return code - Condition existed and succeeded.
052:             */
053:            public static final int COND_OK = 2;
054:            /**
055:             * Condition check return code - Condition existed and succeeded 
056:             *                               but is a weak validation.
057:             */
058:            public static final int COND_WEAK = 3;
059:
060:            /**
061:             * Attribute index - The Content-Type of the resource
062:             */
063:            protected static int ATTR_CONTENT_TYPE = -1;
064:            /**
065:             * Attribute index - The resource's max age.
066:             */
067:            protected static int ATTR_FRESHNESS_LIFETIME = -1;
068:            /**
069:             * Attribute index - The initial age of this resource.
070:             */
071:            protected static int ATTR_INITIAL_AGE = -1;
072:            /**
073:             * Attribute index - The response time
074:             */
075:            protected static int ATTR_RESPONSE_TIME = -1;
076:            /**
077:             * Attribute index - Revalidate flag
078:             */
079:            protected static int ATTR_REVALIDATE = -1;
080:            /**
081:             * Attribute index - The download state
082:             */
083:            protected static int ATTR_LOAD_STATE = -1;
084:
085:            static {
086:                Attribute a = null;
087:                Class c = null;
088:                try {
089:                    c = Class
090:                            .forName("org.w3c.www.protocol.http.cache.EntityCachedResource");
091:                } catch (Exception ex) {
092:                    ex.printStackTrace();
093:                    System.exit(1);
094:                }
095:                // Declare the contenht type attribute:
096:                a = new MimeTypeAttribute("content-type", null,
097:                        Attribute.COMPUTED);
098:                ATTR_CONTENT_TYPE = AttributeRegistry.registerAttribute(c, a);
099:                // Declare the max-age (freshness lifetime) value.
100:                a = new IntegerAttribute("freshness-lifetime", null,
101:                        Attribute.COMPUTED);
102:                ATTR_FRESHNESS_LIFETIME = AttributeRegistry.registerAttribute(
103:                        c, a);
104:                // Declare the initial age value.
105:                a = new IntegerAttribute("initial-age", null,
106:                        Attribute.COMPUTED);
107:                ATTR_INITIAL_AGE = AttributeRegistry.registerAttribute(c, a);
108:                // Declare the response time value.
109:                a = new LongAttribute("response-time", null, Attribute.COMPUTED);
110:                ATTR_RESPONSE_TIME = AttributeRegistry.registerAttribute(c, a);
111:                // Declare the response time value.
112:                a = new BooleanAttribute("revalidate", Boolean.FALSE,
113:                        Attribute.COMPUTED);
114:                ATTR_REVALIDATE = AttributeRegistry.registerAttribute(c, a);
115:            }
116:
117:            // some download specific variables
118:            protected boolean revalidating = false;
119:            protected boolean regetting = false;
120:            protected boolean hasEntity = false;
121:            protected int oldsize = -1;
122:            protected int wantedsize = -1;
123:            // our cache filter, if we need to notify it
124:            protected CacheFilter filter;
125:
126:            /**
127:             * Get the Content-Type of the cached resource of <code>null</code> if
128:             * there is no mime type (it should NEVER happen!)
129:             * @return a MimeType
130:             */
131:            public MimeType getContentType() {
132:                return (MimeType) getValue(ATTR_CONTENT_TYPE, null);
133:            }
134:
135:            /**
136:             * Set the Content-Type of this cached resource
137:             * @param a MimeType, the mime type of this resource
138:             */
139:            public void setContentType(MimeType type) {
140:                setValue(ATTR_CONTENT_TYPE, type);
141:            }
142:
143:            /**
144:             * Get this resource's freshness lifetime (RFC2616: 13.2.4).
145:             * @return A long number of seconds for which that entry will remain
146:             * valid, or <strong>-1</strong> if undefined.
147:             */
148:            public int getFreshnessLifetime() {
149:                return getInt(ATTR_FRESHNESS_LIFETIME, -1);
150:            }
151:
152:            /**
153:             * Set this cached entry . freshness lifetime (RFC2616: 13.2.4).
154:             * @param maxage A number of seconds during which the entry will 
155:             * remain valid, or <strong>-1</strong> to undefine previous setting.
156:             */
157:            public void setFreshnessLifetime(int freshnessLifetime) {
158:                setInt(ATTR_FRESHNESS_LIFETIME, freshnessLifetime);
159:            }
160:
161:            /**
162:             * Get this cached entry initial age.
163:             * @return A long number of seconds giving the initial age
164:             * or <strong>-1</strong> if undefined.
165:             */
166:            public int getInitialAge() {
167:                return getInt(ATTR_INITIAL_AGE, -1);
168:            }
169:
170:            /**
171:             * Set this resource's initial age.
172:             * @param initage The initial age as a number of seconds
173:             * or <strong>-1</strong> to undefine previous setting.
174:             */
175:            public void setInitialAge(int initage) {
176:                setInt(ATTR_INITIAL_AGE, initage);
177:            }
178:
179:            /**
180:             * Get the time of the response used to cached that entry.
181:             * @return A long number of milliseconds since Java epoch, or <strong>
182:             * -1</strong> if undefined.
183:             */
184:            public long getResponseTime() {
185:                return getLong(ATTR_RESPONSE_TIME, -1);
186:            }
187:
188:            /**
189:             * Set this cached entry response time.
190:             * @param responsetime A long number of milliseconds indicating the 
191:             * response time relative to Java epoch, or <strong>-1</strong> to 
192:             * undefined previous setting.
193:             */
194:            public void setResponseTime(long responsetime) {
195:                setLong(ATTR_RESPONSE_TIME, responsetime);
196:            }
197:
198:            /**
199:             * Get the revalidate flag
200:             * @return a boolean, <code>true</code> if the proxy must revalidate
201:             * stale entries
202:             * -1</strong> if undefined.
203:             */
204:            public boolean getRevalidate() {
205:                return getBoolean(ATTR_REVALIDATE, false);
206:            }
207:
208:            /**
209:             * Set this cached entry revalidate flag.
210:             * @param validate, a boolean, <code>true</code> if this entry needs
211:             * to be revalidated while stale.
212:             */
213:            public void setRevalidate(boolean validate) {
214:                setBoolean(ATTR_REVALIDATE, validate);
215:            }
216:
217:            /**
218:             * Get the entity tag associated with that cached entry
219:             * @return the entity tag or <strong>null</strong> if undefined
220:             */
221:            public HttpEntityTag getHETag() {
222:                if (definesAttribute(ATTR_ETAG)) {
223:                    if (etags == null) {
224:                        etags = new HttpEntityTag[1];
225:                        etags[0] = HttpFactory.parseETag(getETag());
226:                    }
227:                    return etags[0];
228:                }
229:                return null;
230:            }
231:
232:            // FIXME add entity tag here
233:
234:            // end of the basic accessors
235:
236:            /**
237:             * Get the cached data for that cached entry.
238:             * @return A <em>non-buffered</em> output stream.
239:             */
240:            public synchronized InputStream getInputStream() throws IOException {
241:                return new BufferedInputStream(new FileInputStream(getFile()));
242:            }
243:
244:            /**
245:             * Get the current age of this resource
246:             * @return a long the current age of this resource
247:             */
248:            public int getCurrentAge() {
249:                long now = System.currentTimeMillis();
250:                // RFC2616: 13.2.3 Age Calculation
251:                return (int) (getInitialAge() + ((now - getResponseTime()) / 1000));
252:            }
253:
254:            /**
255:             * Try to validate an <code>If-Modified-Since</code> request.
256:             * @param request The request to validate.
257:             * @return An integer, <code>COND_FAILED</code>, if the condition  was
258:             * checked, but failed; <code>COND_OK</code> of condition was checked
259:             * and succeeded, <strong>0</strong> otherwise.
260:             */
261:
262:            public int checkIfModifiedSince(Request request) {
263:                // Check for an If-Modified-Since conditional:
264:                long ims = request.getIfModifiedSince();
265:                long cmt = getLastModified();
266:                if (ims >= 0) {
267:                    if (cmt > 0) {
268:                        long s_cmt = cmt / 1000;
269:                        long s_ims = ims / 1000;
270:                        if (s_cmt < s_ims) {
271:                            return COND_FAILED;
272:                        } else if (s_cmt == s_ims) {
273:                            return COND_WEAK;
274:                        }
275:                        return COND_OK;
276:                    }
277:                }
278:                return 0;
279:            }
280:
281:            /**
282:             * Try to validate an <code>If-Unmodified-Since</code> request.
283:             * @param request The request to validate.
284:             * @return An integer, <code>COND_FAILED</code>, if the condition  was
285:             * checked, but failed; <code>COND_OK</code> of condition was checked
286:             * and succeeded, <strong>0</strong> otherwise.
287:             */
288:
289:            public int checkIfUnmodifiedSince(Request request) {
290:                // Check for an If-Unmodified-Since conditional:
291:                long iums = request.getIfUnmodifiedSince();
292:                long cmt = getLastModified();
293:                if (iums >= 0)
294:                    return ((cmt > 0) && (cmt - 1000) >= iums) ? COND_FAILED
295:                            : COND_OK;
296:                return 0;
297:            }
298:
299:            /**
300:             * Try to validate an <code>If-Match</code> request.
301:             * @param request The request to validate.
302:             * @return An integer, <code>COND_FAILED</code>, if the condition  was
303:             * checked, but failed; <code>COND_OK</code> of condition was checked
304:             * and succeeded, <strong>0</strong> otherwise.
305:             */
306:
307:            public int checkIfMatch(Request request) {
308:                HttpEntityTag tags[] = request.getIfMatch();
309:                if (tags != null) {
310:                    HttpEntityTag etag = getHETag();
311:                    // Good, real validators in use:
312:                    if (etag != null) {
313:                        for (int i = 0; i < tags.length; i++) {
314:                            HttpEntityTag t = tags[i];
315:                            if (t.getTag().equals(etag.getTag())) {
316:                                if (t.isWeak() || etag.isWeak()) {
317:                                    return COND_WEAK;
318:                                } else {
319:                                    return COND_OK;
320:                                }
321:                            }
322:                        }
323:                    }
324:                    return COND_FAILED;
325:                }
326:                return 0;
327:            }
328:
329:            /**
330:             * Try to validate an <code>If-None-Match</code> request.
331:             * @param request The request to validate.
332:             * @return An integer, <code>COND_FAILED</code>, if the condition  was
333:             * checked, but failed; <code>COND_OK</code> of condition was checked
334:             * and succeeded, <strong>0</strong> otherwise.
335:             */
336:
337:            public int checkIfNoneMatch(Request request) {
338:                String setag = getETag();
339:                HttpEntityTag etag = null;
340:                // Check for an If-None-Match conditional:
341:                HttpEntityTag tags[] = request.getIfNoneMatch();
342:                if (setag != null) {
343:                    etag = HttpFactory.parseETag(getETag());
344:                }
345:                if (tags != null) {
346:                    if (etag == null) {
347:                        return COND_OK;
348:                    }
349:                    int status = COND_OK;
350:                    for (int i = 0; i < tags.length; i++) {
351:                        HttpEntityTag t = tags[i];
352:                        if (t.getTag().equals(etag.getTag())) {
353:                            //		    if (t.isWeak() && !etag.isWeak()) {
354:                            if (t.isWeak() || etag.isWeak()) {
355:                                status = COND_WEAK;
356:                            } else {
357:                                return COND_FAILED;
358:                            }
359:                        }
360:                        if (t.getTag().equals("*")) {
361:                            return COND_FAILED;
362:                        }
363:                    }
364:                    return status;
365:                }
366:                return 0;
367:            }
368:
369:            /**
370:             * Called when the tee succeed, it allows you to notify a listener of the 
371:             * Tee that the download completed succesfully with a specific size
372:             * @parameter the size received, an integer
373:             */
374:            public synchronized void notifyTeeSuccess(int size) {
375:                int state = getLoadState();
376:                try {
377:                    if (wantedsize > 0) {
378:                        if (!regetting) {
379:                            // sanity check
380:                            if (state == STATE_NOT_LOADED) {
381:                                if (size == wantedsize) {
382:                                    // cool! the right size and it was the first 
383:                                    // download!
384:                                    setCurrentLength(size);
385:                                    setLoadState(STATE_LOAD_COMPLETE);
386:                                } else {
387:                                    // argh! wrong size and a success hum...
388:                                    setCurrentLength(size);
389:                                    setLoadState(STATE_LOAD_ERROR);
390:                                    System.out.println(getIdentifier()
391:                                            + ": tee stream mismatch, "
392:                                            + "bytes(adv/got)=" + wantedsize
393:                                            + "/" + size);
394:                                }
395:                            } else {
396:                                // how can we end up here, I frankly don't know
397:                                setCurrentLength(size);
398:                                setLoadState(STATE_LOAD_ERROR);
399:                                System.out.println(getIdentifier()
400:                                        + ": UNKNOWN STATE for "
401:                                        + "tee stream!, bytes(adv/got)="
402:                                        + wantedsize + "/" + size);
403:                            }
404:                        } else {
405:                            // we asked for the diff, and we have it!!!
406:                            if (size == wantedsize) {
407:                                setCurrentLength(oldsize + wantedsize);
408:                                setLoadState(STATE_LOAD_COMPLETE);
409:                            } else {
410:                                // argh! wrong size and a success hum...
411:                                setCurrentLength(size);
412:                                setLoadState(STATE_LOAD_ERROR);
413:                                System.out.println(getIdentifier()
414:                                        + ": tee stream mismatch in reget, "
415:                                        + "bytes(adv/got)=" + wantedsize + "/"
416:                                        + size);
417:                            }
418:                        }
419:                    } else {
420:                        // we didn't knew the size, we should trust what we got
421:                        // (unless it is HTTP/1.0)
422:                        setCurrentLength(size);
423:                        // FIXME (a trust flag to select btw COMPLETE and UNKNOWN
424:                        setLoadState(STATE_LOAD_COMPLETE);
425:                    }
426:                    // Update cache filter space usage:
427:                    //	    filter.markUsed(this, oldsize, wantedsize);
428:
429:                } finally {
430:                    cleanUpload();
431:                }
432:            }
433:
434:            public void notifyTeeFailure(int size) {
435:                System.out
436:                        .println(getIdentifier() + ": tee streaming failed !");
437:                int state = getLoadState();
438:
439:                setCurrentLength(size);
440:                setLoadState(STATE_LOAD_ERROR);
441:                System.out.println(getIdentifier() + ": tee stream mismatch, "
442:                        + "bytes(adv/got)=" + wantedsize + "/" + size);
443:                // and finish the thing!
444:                cleanUpload();
445:            }
446:
447:            // FIXME should be called after every upload
448:            protected synchronized void cleanUpload() {
449:                // FIXME reset a whole bunch of stuff
450:                uploading = false;
451:                filter.cleanUpload(this );
452:                notifyAll();
453:            }
454:
455:            /**
456:             * FIXME Will be replaced soon, so that multiple people may share 
457:             * the same temporary resource.
458:             * Wait for the upload to finish, if needed.
459:             */
460:            protected final synchronized void waitUpload() {
461:                while (uploading) {
462:                    try {
463:                        wait();
464:                    } catch (InterruptedException ex) {
465:                    }
466:                }
467:            }
468:
469:            /**
470:             * handle a range request, according to the first range or the
471:             * request FIXME we should handle all the ranges at some point...
472:             */
473:            protected Reply handleRangeRequest(Request request, HttpRange r) {
474:                // Should we check against a IfRange header ?
475:                HttpEntityTag t = request.getIfRange();
476:                if (t != null) {
477:                    if (t.isWeak() || !t.getTag().equals(getHETag().getTag()))
478:                        return null;
479:                }
480:                // Check the range:
481:                int cl = getContentLength();
482:                int fb = r.getFirstPosition();
483:                int lb = r.getLastPosition();
484:                int sz;
485:                if (fb > cl - 1) { // first byte already out of range
486:                    HttpContentRange cr = HttpFactory.makeContentRange("bytes",
487:                            0, cl - 1, cl);
488:                    Reply rr;
489:                    rr = request
490:                            .makeReply(HTTP.REQUESTED_RANGE_NOT_SATISFIABLE);
491:                    rr.setContentLength(-1);
492:                    rr.setHeaderValue(rr.H_CONTENT_RANGE, cr);
493:                    rr.setContentMD5(null);
494:                    return rr;
495:                }
496:                if ((fb < 0) && (lb >= 0)) { // ex: bytes=-20 final 20 bytes
497:                    if (lb >= cl) // cut the end
498:                        lb = cl;
499:                    sz = lb;
500:                    fb = cl - lb;
501:                    lb = cl - 1;
502:                } else if (lb < 0) { // ex: bytes=10- the last size - 10
503:                    lb = cl - 1;
504:                    sz = lb - fb + 1;
505:                } else { // ex: bytes=10-20
506:                    if (lb >= cl) // cut the end
507:                        lb = cl - 1;
508:                    sz = lb - fb + 1;
509:                }
510:                if ((fb < 0) || (lb < 0) || (fb <= lb)) {
511:                    HttpContentRange cr = null;
512:                    fb = (fb < 0) ? 0 : fb;
513:                    lb = ((lb > cl) || (lb < 0)) ? cl : lb;
514:                    cr = HttpFactory.makeContentRange("bytes", fb, lb, cl);
515:                    // Emit reply:
516:                    Reply rr = request.makeReply(HTTP.PARTIAL_CONTENT);
517:                    try {
518:                        rr.setContentMD5(null); // just in case :)
519:                        rr.setContentLength(sz);
520:                        rr.setHeaderValue(rr.H_CONTENT_RANGE, cr);
521:                        rr.setStream(new ByteRangeOutputStream(getFile(), fb,
522:                                lb + 1));
523:                        return rr;
524:                    } catch (IOException ex) {
525:                    }
526:                }
527:                return null;
528:            }
529:
530:            /**
531:             * decorate the reply header with some meta information taken
532:             * from the cached resource
533:             * @return a reply, the one we just updated
534:             */
535:            protected Reply setReplyHeaders(Reply reply) {
536:                int status = reply.getStatus();
537:                if (status != HTTP.NOT_MODIFIED) {
538:                    // FIXME check for byte range replies
539:                    reply.setContentLength(getContentLength());
540:                    // dump the headers we know.
541:                    reply.setContentMD5(getContentMD5());
542:                    reply.setContentLanguage(getContentLanguage());
543:                    reply.setContentEncoding(getContentEncoding());
544:                    reply.setContentType(getContentType());
545:                    reply.setLastModified(getLastModified());
546:                    reply.setVary(getVary());
547:                }
548:                reply.setETag(getHETag());
549:                long date = getDate();
550:                if (date > 0)
551:                    reply.setDate(getDate());
552:                reply.setAge(getCurrentAge());
553:                ArrayDictionary a = getExtraHeaders();
554:                if (a != null) {
555:                    // This is the slowest operation of the whole cache :-(
556:                    Enumeration e = a.keys();
557:                    while (e.hasMoreElements()) {
558:                        String hname = (String) e.nextElement();
559:                        String hvalue = (String) a.get(hname);
560:                        reply.setValue(hname, hvalue);
561:                    }
562:                }
563:                if ((filter != null) && filter.isShared()) {
564:                    HttpCacheControl hcc = reply.getCacheControl();
565:                    if (hcc != null) {
566:                        String priv[] = hcc.getPrivate();
567:                        if (priv != null) {
568:                            for (int i = 0; i < priv.length; i++) {
569:                                // remove headers that are private if we are
570:                                // a shared cache (rfc2616#14.9, rfc2616#14.9.1)
571:                                reply.setHeaderValue(priv[i], null);
572:                            }
573:                        }
574:                    }
575:                }
576:                return reply;
577:            }
578:
579:            /**
580:             * check the validators namely LMT/Etags according to rfc2616 rules
581:             * @return An integer, either <code>COND_FAILED</cond> if condition
582:             * was checked, but failed, <code>COND_OK</code> if condition was checked
583:             * and succeeded, or <strong>0</strong> if the condition was not checked
584:             * at all (eg because the resource or the request didn't support it).
585:             */
586:            public int checkValidators(Request request) {
587:                int v_inm = checkIfNoneMatch(request);
588:                int v_ims = checkIfModifiedSince(request);
589:
590:                if ((v_inm == COND_OK) || (v_ims == COND_OK)) {
591:                    return COND_OK;
592:                }
593:                if ((v_inm == COND_FAILED) || (v_ims == COND_FAILED)) {
594:                    return COND_FAILED;
595:                }
596:                if ((v_inm == COND_WEAK) || (v_ims == COND_WEAK)) {
597:                    return COND_FAILED;
598:                }
599:                return 0;
600:            }
601:
602:            /**
603:             * This cached entry has been checked valid, perform given request.
604:             * @param request The request to perform.
605:             * @return An Reply instance.
606:             * @exception HttpException If something went wrong.
607:             */
608:            public Reply perform(Request request) throws HttpException {
609:                // If the resource is currently being uploaded, wait:
610:                waitUpload();
611:                // Now perform the request:
612:                try {
613:                    Reply reply = null;
614:                    boolean needsEntity = true;
615:                    // Handle range requests:
616:                    HttpRange ranges[] = request.getRange();
617:                    if ((ranges != null) && (ranges.length == 1))
618:                        reply = handleRangeRequest(request, ranges[0]);
619:                    // Handle full retreivals:
620:                    if (reply == null) {
621:                        int status = getStatus();
622:                        // Try validating first 
623:                        // NOTE: We know we are only dealing with GETs and HEADs here
624:                        // otherwise the cache wouldn't be used...
625:                        int cim = checkIfMatch(request);
626:                        if ((cim == COND_FAILED) || (cim == COND_WEAK)) {
627:                            status = HTTP.PRECONDITION_FAILED;
628:                            needsEntity = false;
629:                            reply = request.makeReply(status);
630:                            reply.setContent("Pre-conditions failed.");
631:                            throw new HttpException(request, reply,
632:                                    "pre-condition");
633:                        } else if (checkIfUnmodifiedSince(request) == COND_FAILED) {
634:                            status = HTTP.PRECONDITION_FAILED;
635:                            reply = request.makeReply(status);
636:                            reply.setContent("Pre-conditions failed.");
637:                            throw new HttpException(request, reply,
638:                                    "pre-condition");
639:                        } else if (checkValidators(request) == COND_FAILED) {
640:                            status = HTTP.NOT_MODIFIED;
641:                            needsEntity = false;
642:                        }
643:                        // Emit reply:
644:                        reply = request.makeReply(status);
645:                        if (needsEntity) {
646:                            reply.setStream(getInputStream());
647:                        }
648:                    }
649:                    setReplyHeaders(reply);
650:                    // Check if entity is needed:
651:                    String mth = request.getMethod();
652:                    if (mth.equals("HEAD") || mth.equals("OPTIONS"))
653:                        reply.setStream(null);
654:                    //	    filter.markUsed(this);
655:                    return reply;
656:                } catch (IOException ex) {
657:                    //	    if (debug)
658:                    //		ex.printStackTrace();
659:                    // Some exception occured, delete that resource (no longer usefull)
660:                    //	    delete();
661:                }
662:                return null;
663:            }
664:
665:            /**
666:             * Try using an active stream to cache the content.
667:             * Byte size usage is taken care of only at the end of the download
668:             * to make sure we get the right sizes (might different from the
669:             * advertized ones).
670:             * @return An InputStream instance if active caching was possible,
671:             * <strong>null</strong> otherwise.
672:             */
673:            public synchronized InputStream tryActiveCacheContent(InputStream in)
674:                    throws IOException {
675:                // If we don't return null, we *are* responsible for cleaning up
676:                // the upload *whatever* happens ...
677:                InputStream tee = null;
678:                OutputStream out = null;
679:                uploading = true;
680:                // Open the output stream:
681:                try {
682:                    out = new FileOutputStream(getFile());
683:                } catch (IOException ex) {
684:                    //	    if (debug)
685:                    ex.printStackTrace();
686:                    // We'll let cacheContent take care of that situation:
687:                    return null;
688:                }
689:                // We might be able to use active streams:
690:                //	if (upnewsize > ACTIVE_STREAM_THRESOLD ) {
691:                tee = ActiveStream.createTee(this , in, out);
692:                if (tee != null)
693:                    return tee;
694:                //	} 
695:                // We were not able to active stream:
696:                try {
697:                    out.close();
698:                } catch (IOException ex) {
699:                }
700:                return null;
701:            }
702:
703:            /**
704:             * The basic initialization
705:             */
706:            public void initialize(Object values[]) {
707:                super .initialize(values);
708:            }
709:
710:            /**
711:             * sets some useful information about the entity
712:             * @param the request that requested this entity
713:             * @param the reply triggered by this request
714:             */
715:            protected void updateInfo(Request request, Reply rep) {
716:                String mth = request.getMethod();
717:                Reply reply = (Reply) rep.getClone();
718:                boolean hasEntity = !(mth.equals("HEAD") || mth
719:                        .equals("OPTIONS"));
720:                // is it a revalidation?
721:                if (!request.hasState(CacheState.STATE_REVALIDATION)) {
722:                    // no, go for it!
723:                    HttpCacheControl hcc = reply.getCacheControl();
724:                    // first we should NOT cache headers protected by a no-cache
725:                    // per rfc2616@14.9
726:                    if (hcc != null) {
727:                        String nocache[] = hcc.getNoCache();
728:                        if (nocache != null) {
729:                            for (int i = 0; i < nocache.length; i++) {
730:                                reply.setHeaderValue(nocache[i], null);
731:                            }
732:                        }
733:                    }
734:                    setStatus(reply.getStatus());
735:                    setContentType(reply.getContentType());
736:                    setContentLength(reply.getContentLength());
737:                    setLastModified(reply.getLastModified());
738:                    setContentMD5(reply.getContentMD5());
739:                    String vary[] = reply.getVary();
740:                    setVary(vary);
741:                    if (vary != null) {
742:                        // update the conneg headers
743:                        ArrayDictionary a = null;
744:                        for (int i = 0; i < vary.length; i++) {
745:                            if (vary[i].equals("*")) {
746:                                continue;
747:                            }
748:                            if (a == null) {
749:                                a = new ArrayDictionary(vary.length);
750:                            }
751:                            a.put(vary[i].toLowerCase(), request
752:                                    .getValue(vary[i]));
753:                        }
754:                        // FIXME we should be able to update to save multiple
755:                        // matches, but with a limitation of course
756:                        if (a != null) {
757:                            setConnegHeaders(a);
758:                        }
759:                    }
760:                    if (reply.hasHeader(reply.H_ETAG)) {
761:                        setETag(reply.getETag().toString());
762:                    } else {
763:                        // be safe here!
764:                        setETag(null);
765:                    }
766:                    ArrayDictionary a = new ArrayDictionary(5, 5);
767:                    Enumeration e = reply.enumerateHeaderDescriptions();
768:                    while (e.hasMoreElements()) {
769:                        HeaderDescription d = (HeaderDescription) e
770:                                .nextElement();
771:                        // Skip all well-known headers:
772:                        if (d.isHeader(Reply.H_CONTENT_TYPE)
773:                                || d.isHeader(Reply.H_CONTENT_LENGTH)
774:                                || d.isHeader(Reply.H_LAST_MODIFIED)
775:                                || d.isHeader(Reply.H_ETAG)
776:                                || d.isHeader(Reply.H_AGE)
777:                                || d.isHeader(Reply.H_DATE)
778:                                || d.isHeader(Reply.H_VARY)
779:                                || d.isHeader(Reply.H_CONNECTION)
780:                                || d.isHeader(Reply.H_PROXY_CONNECTION)
781:                                || d.isHeader(Reply.H_TRANSFER_ENCODING)
782:                                || d.isHeader(Reply.H_CONTENT_MD5)
783:                                || d.getName().equalsIgnoreCase("keep-alive"))
784:                            continue;
785:                        // This is an extra header:
786:                        a.put(d.getName(), reply.getValue(d));
787:                    }
788:                    setExtraHeaders(a);
789:                    // FIXME add the headers ;)
790:
791:                }
792:            }
793:
794:            /**
795:             * This cached entry needs revalidation, it will modify the 
796:             * request to do that.
797:             */
798:            public Request setRequestRevalidation(Request request) {
799:                Request origreq = (Request) request.getClone();
800:                request.setState(CacheState.STATE_RESOURCE, this );
801:                request.setState(CacheState.STATE_ORIGREQ, origreq);
802:                // At this point, we use the suggested way of using date as etag:
803:                request.setIfModifiedSince(getLastModified());
804:                // But if we do have an etag, we also uses it, as recommended:
805:                if ((etags == null) && (getETag() != null)) {
806:                    etags = new HttpEntityTag[1];
807:                    etags[0] = HttpFactory.parseETag(getETag());
808:                }
809:                request.setIfNoneMatch(etags);
810:                // We have to remove all other conditionals here:
811:                request.setIfRange(null);
812:                request.setRange(null);
813:                request.setIfUnmodifiedSince(-1);
814:                request.setIfMatch(null);
815:                return request;
816:            }
817:
818:            /**
819:             * A constructor for new resources that will get some data
820:             * directly
821:             * FIXME params
822:             */
823:            public EntityCachedResource(CacheFilter filter, Request req,
824:                    Reply rep) {
825:                invalidated = false;
826:                setValue(ATTR_IDENTIFIER, req.getURL().toExternalForm());
827:                // Keep fast track of the filter:
828:                this .filter = filter;
829:                // update the headers
830:                updateInfo(req, rep);
831:                // and do some calculation according to the validator
832:                filter.getValidator().updateExpirationInfo(this , req, rep);
833:                // Save the content of resource into the content cache:
834:                setFile(filter.getStore().getNewEntryFile());
835:                wantedsize = rep.getContentLength();
836:                InputStream in;
837:                try {
838:                    in = tryActiveCacheContent(rep.getInputStream());
839:                    if (in == null) {
840:                        // something bad happened
841:                        // in = cacheContent(reply.getInputStream());
842:                    }
843:                    rep.setStream(in);
844:                } catch (IOException ex) {
845:                    // FIXME
846:                }
847:            }
848:
849:            public EntityCachedResource() {
850:                super();
851:            }
852:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.