001: // CachedResource.java
002: // $Id: CachedResource.java,v 1.78 2003/01/24 14:39:59 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:
010: import org.w3c.util.ArrayDictionary;
011: import org.w3c.util.LRUAble;
012:
013: import org.w3c.tools.resources.Attribute;
014: import org.w3c.tools.resources.AttributeHolder;
015: import org.w3c.tools.resources.AttributeRegistry;
016: import org.w3c.tools.resources.DateAttribute;
017: import org.w3c.tools.resources.FileAttribute;
018: import org.w3c.tools.resources.IntegerAttribute;
019: import org.w3c.tools.resources.PropertiesAttribute;
020: import org.w3c.tools.resources.StringArrayAttribute;
021: import org.w3c.tools.resources.StringAttribute;
022:
023: import org.w3c.www.http.HttpEntityTag;
024:
025: import org.w3c.www.protocol.http.HttpException;
026: import org.w3c.www.protocol.http.Reply;
027: import org.w3c.www.protocol.http.Request;
028:
029: import org.w3c.www.mime.MimeType;
030:
031: import org.w3c.jigsaw.frames.MimeTypeAttribute;
032:
033: public abstract class CachedResource extends AttributeHolder implements
034: TeeMonitor, LRUAble {
035:
036: /**
037: * Condition check return code - Condition existed but failed.
038: */
039: public static final int COND_FAILED = 1;
040: /**
041: * Condition check return code - Condition existed and succeeded.
042: */
043: public static final int COND_OK = 2;
044:
045: /**
046: * The download state of the resource, currently not loaded
047: */
048: public static final int STATE_NOT_LOADED = 0;
049:
050: /**
051: * The download state of the resource, complete content
052: */
053: public static final int STATE_LOAD_COMPLETE = 1;
054:
055: /**
056: * The download state of the resource, partial content
057: */
058: public static final int STATE_LOAD_PARTIAL = 2;
059:
060: /**
061: * The download state of the resource, unknown, probably an HTTP/1.0
062: * reply without the Content-Length.
063: */
064: public static final int STATE_LOAD_UNKNOWN = 3;
065: /**
066: * The download state of the resource, erroneous, something weird
067: * happened! but at least we know that :)
068: */
069: public static final int STATE_LOAD_ERROR = 4;
070:
071: /**
072: * Attribute index - The identifier
073: */
074: protected static int ATTR_IDENTIFIER = -1;
075: /**
076: * Attribute index - The resource content length.
077: */
078: protected static int ATTR_CONTENT_LENGTH = -1;
079: /**
080: * Attribute index - The resource current length.
081: */
082: protected static int ATTR_CURRENT_LENGTH = -1;
083: /**
084: * Attribute index - The file
085: */
086: protected static int ATTR_FILE = -1;
087:
088: /**
089: * Attribute name - The resource content length.
090: */
091: protected static final String NAME_CONTENT_LENGTH = "content-length";
092:
093: /**
094: * Attribute name - The resource current length
095: */
096: protected static final String NAME_CURRENT_LENGTH = "current-length";
097:
098: /**
099: * Attribute name - The identifier
100: */
101: protected static final String NAME_IDENTIFIER = "id";
102:
103: /**
104: * Attribute name - The identifier
105: */
106: protected static final String NAME_FILE = "file";
107:
108: /**
109: * Attribute index - The download state
110: */
111: protected static int ATTR_LOAD_STATE = -1;
112: /**
113: * Attribute index - The entity tag (if any) associated with the resource.
114: */
115: protected static int ATTR_ETAG = -1;
116: /**
117: * Attribute index - The reply status.
118: */
119: protected static int ATTR_STATUS = -1;
120: /**
121: * Attribute index - The Last modified of this resource
122: */
123: protected static int ATTR_REPLY_LAST_MODIFIED = -1;
124: /**
125: * Attribute index - The Date of the resource
126: */
127: protected static int ATTR_DATE = -1;
128: /**
129: * Attribute index - The Content MD5 of the resource
130: */
131: protected static int ATTR_CONTENT_MD5 = -1;
132: /**
133: * Attribute index - The Content Encoding of the resource
134: */
135: protected static int ATTR_CONTENT_ENCODING = -1;
136: /**
137: * Attribute index - The Content Language of the resource
138: */
139: protected static int ATTR_CONTENT_LANGUAGE = -1;
140: /**
141: * Attribute index - The Location of this resource
142: */
143: protected static int ATTR_LOCATION = -1;
144: /**
145: * Attribute index - The Vary of this resource
146: */
147: protected static int ATTR_VARY = -1;
148: /**
149: * Attribute index - The extra headers attribute.
150: */
151: protected static int ATTR_EXTRA_HEADERS = -1;
152: /**
153: * Attribute index - The request headers used for content negotiation
154: * as set by the reply Vary header.
155: */
156: protected static int ATTR_CONNEG_HEADERS = -1;
157:
158: static {
159: Attribute a = null;
160: Class c = null;
161: try {
162: c = Class
163: .forName("org.w3c.www.protocol.http.cache.CachedResource");
164: } catch (Exception ex) {
165: ex.printStackTrace();
166: System.exit(1);
167: }
168: // This resource ntity tag:
169: a = new StringAttribute(NAME_IDENTIFIER, null,
170: Attribute.COMPUTED);
171: ATTR_IDENTIFIER = AttributeRegistry.registerAttribute(c, a);
172: // Declare the content length attribuite:
173: a = new IntegerAttribute(NAME_CONTENT_LENGTH, null,
174: Attribute.COMPUTED);
175: ATTR_CONTENT_LENGTH = AttributeRegistry.registerAttribute(c, a);
176: // Declare the currentlength attribuite:
177: a = new IntegerAttribute(NAME_CURRENT_LENGTH, null,
178: Attribute.COMPUTED);
179: ATTR_CURRENT_LENGTH = AttributeRegistry.registerAttribute(c, a);
180: // Declare the file attribute
181: a = new FileAttribute(NAME_FILE, null, Attribute.COMPUTED);
182: ATTR_FILE = AttributeRegistry.registerAttribute(c, a);
183: // Declare the download state value
184: a = new IntegerAttribute("load-state", null, Attribute.COMPUTED);
185: ATTR_LOAD_STATE = AttributeRegistry.registerAttribute(c, a);
186: // This resource entity tag:
187: a = new StringAttribute("etag", null, Attribute.COMPUTED);
188: ATTR_ETAG = AttributeRegistry.registerAttribute(c, a);
189: // Declare the status attribute:
190: a = new IntegerAttribute("status", null, Attribute.COMPUTED);
191: ATTR_STATUS = AttributeRegistry.registerAttribute(c, a);
192: // The last modified attribute:
193: a = new DateAttribute("reply-last-modified", null,
194: Attribute.COMPUTED | Attribute.EDITABLE);
195: ATTR_REPLY_LAST_MODIFIED = AttributeRegistry.registerAttribute(
196: c, a);
197: // The last modified attribute:
198: a = new DateAttribute("reply-date", null, Attribute.COMPUTED
199: | Attribute.EDITABLE);
200: ATTR_DATE = AttributeRegistry.registerAttribute(c, a);
201: // This resource content-md5
202: a = new StringAttribute("content-md5", null, Attribute.COMPUTED);
203: ATTR_CONTENT_MD5 = AttributeRegistry.registerAttribute(c, a);
204: // This resource content encoding
205: a = new StringArrayAttribute("content-encoding", null,
206: Attribute.COMPUTED);
207: ATTR_CONTENT_ENCODING = AttributeRegistry.registerAttribute(c,
208: a);
209: // This resource content-language
210: a = new StringArrayAttribute("content-language", null,
211: Attribute.COMPUTED);
212: ATTR_CONTENT_LANGUAGE = AttributeRegistry.registerAttribute(c,
213: a);
214: // This resource location
215: a = new StringAttribute("location", null, Attribute.COMPUTED);
216: ATTR_LOCATION = AttributeRegistry.registerAttribute(c, a);
217: // This resource location
218: a = new StringArrayAttribute("vary", null, Attribute.COMPUTED);
219: ATTR_VARY = AttributeRegistry.registerAttribute(c, a);
220: // The extra headers attribute:
221: a = new PropertiesAttribute("headers", null, Attribute.COMPUTED);
222: ATTR_EXTRA_HEADERS = AttributeRegistry.registerAttribute(c, a);
223: // The extra headers attribute:
224: a = new PropertiesAttribute("conneg", null, Attribute.COMPUTED);
225: ATTR_CONNEG_HEADERS = AttributeRegistry.registerAttribute(c, a);
226: }
227:
228: /**
229: * The minimal attribute set used to describe a cachedresource without
230: * loading it entirely.
231: */
232: protected static String ATTR_DESCR[] = { NAME_IDENTIFIER,
233: NAME_CURRENT_LENGTH, NAME_FILE };
234:
235: // should we revalidate next time?
236: protected boolean invalidated = false;
237: // our generation
238: protected CacheGeneration generation = null;
239: // Cached Entity tag HTTP list value for this resource.
240: HttpEntityTag etags[] = null;
241: // the extra headers
242: protected ArrayDictionary a = null;
243: // are we uploading or not?
244: protected boolean uploading = false;
245:
246: public void notifyTeeFailure(int size) {
247: };
248:
249: public void notifyTeeSuccess(int size) {
250: };
251:
252: // the filter that is using this resource
253: protected CacheFilter filter;
254: /**
255: * LRU management - previous entry.
256: */
257: protected LRUAble prev = null;
258: /**
259: * LRU management - next entry.
260: */
261: protected LRUAble next = null;
262:
263: /**
264: * LRU management - Get next node.
265: * @return A CvsDirectory instance.
266: */
267:
268: public LRUAble getNext() {
269: return next;
270: }
271:
272: /**
273: * LRU management - Get previous node.
274: * @return A CvsDirectory instance.
275: */
276:
277: public LRUAble getPrev() {
278: return prev;
279: }
280:
281: /**
282: * LRU management - Set next node.
283: * @return A CvsDirectory instance.
284: */
285:
286: public synchronized void setNext(LRUAble next) {
287: this .next = next;
288: }
289:
290: /**
291: * LRU management - Set previous node.
292: * @return A CvsDirectory instance.
293: */
294:
295: public synchronized void setPrev(LRUAble prev) {
296: this .prev = prev;
297: }
298:
299: /**
300: * overrides the default setValue to invalidate the ETag
301: */
302: public void setValue(int idx, Object value) {
303: super .setValue(idx, value);
304: if (idx == ATTR_ETAG)
305: etags = null;
306: }
307:
308: /**
309: * returns the current age of this cached resource
310: * @return an integer, the current age in seconds
311: */
312: public abstract int getCurrentAge();
313:
314: /**
315: * returns the current freshness lifetime of this resource
316: * @return a long, the freshness lifetime, in seconds
317: */
318: public abstract int getFreshnessLifetime();
319:
320: /**
321: * This methods return the CachedResource matching this request
322: * it allows lookup in the cache for alternatives
323: * @return a CachedResource depending on the request
324: */
325: public CachedResource lookupResource(Request request) {
326: return this ;
327: }
328:
329: /**
330: * Get this cached entry identifier
331: * @return a String, usually the URL of the resource
332: */
333: public String getIdentifier() {
334: return (String) getValue(ATTR_IDENTIFIER, null);
335: }
336:
337: /**
338: * Get this cached entry content length.
339: * @return An integer, giving the content length, or <strong>-1</strong>
340: * if undefined.
341: */
342: public int getContentLength() {
343: return getInt(ATTR_CONTENT_LENGTH, -1);
344: }
345:
346: /**
347: * Set the content length of that cached entry.
348: * @param length The new content length of that entry.
349: */
350: public void setContentLength(int length) {
351: setInt(ATTR_CONTENT_LENGTH, length);
352: }
353:
354: /**
355: * Get this cached entry current content length.
356: * @return An integer, giving the current content length, or
357: * <strong>-1</strong> if undefined
358: */
359: public int getCurrentLength() {
360: return getInt(ATTR_CURRENT_LENGTH, -1);
361: }
362:
363: /**
364: * Set the current length of that cached entry.
365: * @param length The current length of that entry.
366: */
367: public void setCurrentLength(int length) {
368: setInt(ATTR_CURRENT_LENGTH, length);
369: }
370:
371: /**
372: * Get the load state value
373: * @return an integer, as defined in CachedResource
374: * @see org.w3c.www.protocol.http.cache.CachedResource
375: * The default is STATE_NOT_LOADED
376: */
377: public int getLoadState() {
378: return getInt(ATTR_LOAD_STATE, STATE_NOT_LOADED);
379: }
380:
381: /**
382: * Set the loading state of this resource
383: * @param an integer, one of the state defined in CachedResource
384: * @see org.w3c.www.protocol.http.cache.CachedResource
385: */
386: public void setLoadState(int state) {
387: setInt(ATTR_LOAD_STATE, state);
388: }
389:
390: /**
391: * Get the HTTP status of that cached entry.
392: * @return An integer HTTP status code, or <strong>-1</strong> if
393: * undefined.
394: */
395: public int getStatus() {
396: return getInt(ATTR_STATUS, -1);
397: }
398:
399: /**
400: * Set the reply status for that entry.
401: * @param status The HTTP status code of that entry, or <strong>-1</strong>
402: * to undefine the previous setting.
403: */
404: public void setStatus(int status) {
405: setInt(ATTR_STATUS, status);
406: }
407:
408: /**
409: * Get this Cached Resource last modification time.
410: * @return A long giving the date of the last modification time, or
411: * <strong>-1</strong> if undefined.
412: */
413: public long getLastModified() {
414: return getLong(ATTR_REPLY_LAST_MODIFIED, (long) -1);
415: }
416:
417: /**
418: * Set the last modified time of that cached entry.
419: * @param lastmodified The last modification date as a number of
420: * milliseconds since Java epoch, or <strong>-1</strong> to undefine
421: * previous setting.
422: */
423: public void setLastModified(long lastmodified) {
424: setLong(ATTR_REPLY_LAST_MODIFIED, lastmodified);
425: }
426:
427: /**
428: * Get the Content-Type of the cached resource of <code>null</code> if
429: * there is no mime type (it should NEVER happen!)
430: * @return a MimeType
431: */
432: public abstract MimeType getContentType();
433:
434: /**
435: * Set the Content-Type of this cached resource
436: * @param a MimeType, the mime type of this resource
437: */
438: public abstract void setContentType(MimeType type);
439:
440: /**
441: * Get state of the resource, did someone ask for revalidation for
442: * the next request?
443: * @return a boolean, <code>true</code> if it will.
444: * -1</strong> if undefined.
445: */
446: public boolean getWillRevalidate() {
447: return invalidated;
448: }
449:
450: /**
451: * Set this cached entry revalidate-on-next-request flag
452: * @param validate, a boolean, <code>true</code> if it will be revalidated
453: * next time.
454: */
455: public void setWillRevalidate(boolean invalidated) {
456: this .invalidated = invalidated;
457: }
458:
459: /**
460: * Get this date, as a long
461: * @return a long, the date
462: * if undefined.
463: */
464: public long getDate() {
465: return getLong(ATTR_DATE, -1);
466: }
467:
468: /**
469: * Set the content length of that cached entry.
470: * @param length The new content length of that entry.
471: */
472: public void setDate(long date) {
473: setLong(ATTR_DATE, date);
474: }
475:
476: /**
477: * Set the cached file
478: * @param file
479: */
480: public void setFile(File file) {
481: setValue(ATTR_FILE, file);
482: }
483:
484: /**
485: * Get the cached File.
486: * @return a File instance
487: */
488: public File getFile() {
489: return (File) getValue(ATTR_FILE, null);
490: }
491:
492: /**
493: * Get the entity tag associated with that cached entry.
494: * @return The String encoded entity tag, or <strong>null</strong> if
495: * undefined.
496: */
497: public String getETag() {
498: return getString(ATTR_ETAG, null);
499: }
500:
501: /**
502: * Associate an entity tag with that cached enrty.
503: * @param etag The entity tag of the entry, or <strong>null</strong>
504: * to reset the value.
505: */
506: public void setETag(String etag) {
507: setValue(ATTR_ETAG, etag);
508: }
509:
510: /**
511: * Get the Content-MD5 associated with that cached entry.
512: * @return The String encoded Content-MD5, or <strong>null</strong> if
513: * undefined.
514: */
515: public String getContentMD5() {
516: return getString(ATTR_CONTENT_MD5, null);
517: }
518:
519: /**
520: * Associate a Content-MD5 with that cached enrty.
521: * @param sum, the md5 sum as a string, see RFC2616,
522: * or <strong>null</strong>
523: * to reset the value.
524: */
525: public void setContentMD5(String sum) {
526: setValue(ATTR_CONTENT_MD5, sum);
527: }
528:
529: /**
530: * Get the Content-Encoding associated with that cached entry.
531: * @return The String Content-Encoding, or <strong>null</strong> if
532: * undefined.
533: */
534: public String[] getContentEncoding() {
535: return (String[]) getValue(ATTR_CONTENT_ENCODING, null);
536: }
537:
538: /**
539: * Associate a Content-Encoding with that cached enrty.
540: * @param sum, the encoding as a string,
541: * or <strong>null</strong>
542: * to reset the value.
543: */
544: public void setContentEncoding(String[] sum) {
545: setValue(ATTR_CONTENT_ENCODING, sum);
546: }
547:
548: /**
549: * Get the Content-Language associated with that cached entry.
550: * @return The String Content-Language, or <strong>null</strong> if
551: * undefined.
552: */
553: public String[] getContentLanguage() {
554: return (String[]) getValue(ATTR_CONTENT_LANGUAGE, null);
555: }
556:
557: /**
558: * Associate a Content-Language with that cached enrty.
559: * @param sum, the encoding as a string,
560: * or <strong>null</strong>
561: * to reset the value.
562: */
563: public void setContentLanguage(String[] language) {
564: setValue(ATTR_CONTENT_LANGUAGE, language);
565: }
566:
567: /**
568: * Get the Vary associated with that cached entry.
569: * @return The String array of Vary, or <strong>null</strong> if
570: * undefined.
571: */
572: public String[] getVary() {
573: return (String[]) getValue(ATTR_VARY, null);
574: }
575:
576: /**
577: * Associate a Vary with that cached enrty.
578: * @param sum, the header involved in the variant check as a string array,
579: * or <strong>null</strong>
580: * to reset the value.
581: */
582: public void setVary(String[] vary) {
583: setValue(ATTR_VARY, vary);
584: }
585:
586: /**
587: * Get the extra headers stored for that resource.
588: * @return An ArrayDictionary with the extra headers, or <strong>null
589: * </strong> if undefined.
590: */
591: public ArrayDictionary getExtraHeaders() {
592: return (ArrayDictionary) getValue(ATTR_EXTRA_HEADERS, null);
593: }
594:
595: /**
596: * Set a new set of extra headers for that resource.
597: * @param headers The new set of headers.
598: */
599: public void setExtraHeaders(ArrayDictionary a) {
600: setValue(ATTR_EXTRA_HEADERS, a);
601: }
602:
603: /**
604: * Get the extra headers stored for that resource.
605: * @return An ArrayDictionary with the extra headers, or <strong>null
606: * </strong> if undefined.
607: */
608: public ArrayDictionary getConnegHeaders() {
609: return (ArrayDictionary) getValue(ATTR_CONNEG_HEADERS, null);
610: }
611:
612: /**
613: * Set a new set of extra headers for that resource.
614: * @param headers The new set of headers.
615: */
616: public void setConnegHeaders(ArrayDictionary a) {
617: setValue(ATTR_CONNEG_HEADERS, a);
618: }
619:
620: /**
621: * Delete this resource (and its associated file).
622: * @return the number of bytes saved.
623: */
624: public long delete() {
625: File file = getFile();
626: if (file != null)
627: file.delete();
628: return getCurrentLength();
629: }
630:
631: /**
632: * This cached entry has been checked valid, perform given request.
633: * @param request The request to perform.
634: * @return An Reply instance.
635: * @exception HttpException If something went wrong.
636: */
637: public abstract Reply perform(Request request) throws HttpException;
638:
639: /**
640: * This cached entry needs revalidation, it will modify the
641: * request to do that.
642: */
643: public abstract Request setRequestRevalidation(Request request);
644:
645: }
|