001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.naming.resources;
019:
020: import java.text.ParseException;
021: import java.text.SimpleDateFormat;
022: import java.util.Date;
023: import java.util.Locale;
024: import java.util.TimeZone;
025: import java.util.Vector;
026:
027: import javax.naming.NamingEnumeration;
028: import javax.naming.NamingException;
029: import javax.naming.directory.Attribute;
030: import javax.naming.directory.Attributes;
031: import javax.naming.directory.BasicAttribute;
032:
033: /**
034: * Attributes implementation.
035: *
036: * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
037: * @version $Revision: 467222 $
038: */
039: public class ResourceAttributes implements Attributes {
040:
041: // -------------------------------------------------------------- Constants
042:
043: // Default attribute names
044:
045: /**
046: * Creation date.
047: */
048: public static final String CREATION_DATE = "creationdate";
049:
050: /**
051: * Creation date.
052: */
053: public static final String ALTERNATE_CREATION_DATE = "creation-date";
054:
055: /**
056: * Last modification date.
057: */
058: public static final String LAST_MODIFIED = "getlastmodified";
059:
060: /**
061: * Last modification date.
062: */
063: public static final String ALTERNATE_LAST_MODIFIED = "last-modified";
064:
065: /**
066: * Name.
067: */
068: public static final String NAME = "displayname";
069:
070: /**
071: * Type.
072: */
073: public static final String TYPE = "resourcetype";
074:
075: /**
076: * Type.
077: */
078: public static final String ALTERNATE_TYPE = "content-type";
079:
080: /**
081: * Source.
082: */
083: public static final String SOURCE = "source";
084:
085: /**
086: * MIME type of the content.
087: */
088: public static final String CONTENT_TYPE = "getcontenttype";
089:
090: /**
091: * Content language.
092: */
093: public static final String CONTENT_LANGUAGE = "getcontentlanguage";
094:
095: /**
096: * Content length.
097: */
098: public static final String CONTENT_LENGTH = "getcontentlength";
099:
100: /**
101: * Content length.
102: */
103: public static final String ALTERNATE_CONTENT_LENGTH = "content-length";
104:
105: /**
106: * ETag.
107: */
108: public static final String ETAG = "getetag";
109:
110: /**
111: * Collection type.
112: */
113: public static final String COLLECTION_TYPE = "<collection/>";
114:
115: /**
116: * HTTP date format.
117: */
118: protected static final SimpleDateFormat format = new SimpleDateFormat(
119: "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
120:
121: /**
122: * Date formats using for Date parsing.
123: */
124: protected static final SimpleDateFormat formats[] = {
125: new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz",
126: Locale.US),
127: new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz",
128: Locale.US),
129: new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
130:
131: protected final static TimeZone gmtZone = TimeZone
132: .getTimeZone("GMT");
133:
134: /**
135: * GMT timezone - all HTTP dates are on GMT
136: */
137: static {
138:
139: format.setTimeZone(gmtZone);
140:
141: formats[0].setTimeZone(gmtZone);
142: formats[1].setTimeZone(gmtZone);
143: formats[2].setTimeZone(gmtZone);
144:
145: }
146:
147: // ----------------------------------------------------------- Constructors
148:
149: /**
150: * Default constructor.
151: */
152: public ResourceAttributes() {
153: }
154:
155: /**
156: * Merges with another attribute set.
157: */
158: public ResourceAttributes(Attributes attributes) {
159: this .attributes = attributes;
160: }
161:
162: // ----------------------------------------------------- Instance Variables
163:
164: /**
165: * Collection flag.
166: */
167: protected boolean collection = false;
168:
169: /**
170: * Content length.
171: */
172: protected long contentLength = -1;
173:
174: /**
175: * Creation time.
176: */
177: protected long creation = -1;
178:
179: /**
180: * Creation date.
181: */
182: protected Date creationDate = null;
183:
184: /**
185: * Last modified time.
186: */
187: protected long lastModified = -1;
188:
189: /**
190: * Last modified date.
191: */
192: protected Date lastModifiedDate = null;
193:
194: /**
195: * Last modified date in HTTP format.
196: */
197: protected String lastModifiedHttp = null;
198:
199: /**
200: * MIME type.
201: */
202: protected String mimeType = null;
203:
204: /**
205: * Name.
206: */
207: protected String name = null;
208:
209: /**
210: * Weak ETag.
211: */
212: protected String weakETag = null;
213:
214: /**
215: * Strong ETag.
216: */
217: protected String strongETag = null;
218:
219: /**
220: * External attributes.
221: */
222: protected Attributes attributes = null;
223:
224: // ------------------------------------------------------------- Properties
225:
226: /**
227: * Is collection.
228: */
229: public boolean isCollection() {
230: if (attributes != null) {
231: return (getResourceType().equals(COLLECTION_TYPE));
232: } else {
233: return (collection);
234: }
235: }
236:
237: /**
238: * Set collection flag.
239: *
240: * @param collection New flag value
241: */
242: public void setCollection(boolean collection) {
243: this .collection = collection;
244: if (attributes != null) {
245: String value = "";
246: if (collection)
247: value = COLLECTION_TYPE;
248: attributes.put(TYPE, value);
249: }
250: }
251:
252: /**
253: * Get content length.
254: *
255: * @return content length value
256: */
257: public long getContentLength() {
258: if (contentLength != -1L)
259: return contentLength;
260: if (attributes != null) {
261: Attribute attribute = attributes.get(CONTENT_LENGTH);
262: if (attribute != null) {
263: try {
264: Object value = attribute.get();
265: if (value instanceof Long) {
266: contentLength = ((Long) value).longValue();
267: } else {
268: try {
269: contentLength = Long.parseLong(value
270: .toString());
271: } catch (NumberFormatException e) {
272: ; // Ignore
273: }
274: }
275: } catch (NamingException e) {
276: ; // No value for the attribute
277: }
278: }
279: }
280: return contentLength;
281: }
282:
283: /**
284: * Set content length.
285: *
286: * @param contentLength New content length value
287: */
288: public void setContentLength(long contentLength) {
289: this .contentLength = contentLength;
290: if (attributes != null)
291: attributes.put(CONTENT_LENGTH, new Long(contentLength));
292: }
293:
294: /**
295: * Get creation time.
296: *
297: * @return creation time value
298: */
299: public long getCreation() {
300: if (creation != -1L)
301: return creation;
302: if (creationDate != null)
303: return creationDate.getTime();
304: if (attributes != null) {
305: Attribute attribute = attributes.get(CREATION_DATE);
306: if (attribute != null) {
307: try {
308: Object value = attribute.get();
309: if (value instanceof Long) {
310: creation = ((Long) value).longValue();
311: } else if (value instanceof Date) {
312: creation = ((Date) value).getTime();
313: creationDate = (Date) value;
314: } else {
315: String creationDateValue = value.toString();
316: Date result = null;
317: // Parsing the HTTP Date
318: for (int i = 0; (result == null)
319: && (i < formats.length); i++) {
320: try {
321: result = formats[i]
322: .parse(creationDateValue);
323: } catch (ParseException e) {
324: ;
325: }
326: }
327: if (result != null) {
328: creation = result.getTime();
329: creationDate = result;
330: }
331: }
332: } catch (NamingException e) {
333: ; // No value for the attribute
334: }
335: }
336: }
337: return creation;
338: }
339:
340: /**
341: * Set creation.
342: *
343: * @param creation New creation value
344: */
345: public void setCreation(long creation) {
346: this .creation = creation;
347: this .creationDate = null;
348: if (attributes != null)
349: attributes.put(CREATION_DATE, new Date(creation));
350: }
351:
352: /**
353: * Get creation date.
354: *
355: * @return Creation date value
356: */
357: public Date getCreationDate() {
358: if (creationDate != null)
359: return creationDate;
360: if (creation != -1L) {
361: creationDate = new Date(creation);
362: return creationDate;
363: }
364: if (attributes != null) {
365: Attribute attribute = attributes.get(CREATION_DATE);
366: if (attribute != null) {
367: try {
368: Object value = attribute.get();
369: if (value instanceof Long) {
370: creation = ((Long) value).longValue();
371: creationDate = new Date(creation);
372: } else if (value instanceof Date) {
373: creation = ((Date) value).getTime();
374: creationDate = (Date) value;
375: } else {
376: String creationDateValue = value.toString();
377: Date result = null;
378: // Parsing the HTTP Date
379: for (int i = 0; (result == null)
380: && (i < formats.length); i++) {
381: try {
382: result = formats[i]
383: .parse(creationDateValue);
384: } catch (ParseException e) {
385: ;
386: }
387: }
388: if (result != null) {
389: creation = result.getTime();
390: creationDate = result;
391: }
392: }
393: } catch (NamingException e) {
394: ; // No value for the attribute
395: }
396: }
397: }
398: return creationDate;
399: }
400:
401: /**
402: * Creation date mutator.
403: *
404: * @param creationDate New creation date
405: */
406: public void setCreationDate(Date creationDate) {
407: this .creation = creationDate.getTime();
408: this .creationDate = creationDate;
409: if (attributes != null)
410: attributes.put(CREATION_DATE, creationDate);
411: }
412:
413: /**
414: * Get last modified time.
415: *
416: * @return lastModified time value
417: */
418: public long getLastModified() {
419: if (lastModified != -1L)
420: return lastModified;
421: if (lastModifiedDate != null)
422: return lastModifiedDate.getTime();
423: if (attributes != null) {
424: Attribute attribute = attributes.get(LAST_MODIFIED);
425: if (attribute != null) {
426: try {
427: Object value = attribute.get();
428: if (value instanceof Long) {
429: lastModified = ((Long) value).longValue();
430: } else if (value instanceof Date) {
431: lastModified = ((Date) value).getTime();
432: lastModifiedDate = (Date) value;
433: } else {
434: String lastModifiedDateValue = value.toString();
435: Date result = null;
436: // Parsing the HTTP Date
437: for (int i = 0; (result == null)
438: && (i < formats.length); i++) {
439: try {
440: result = formats[i]
441: .parse(lastModifiedDateValue);
442: } catch (ParseException e) {
443: ;
444: }
445: }
446: if (result != null) {
447: lastModified = result.getTime();
448: lastModifiedDate = result;
449: }
450: }
451: } catch (NamingException e) {
452: ; // No value for the attribute
453: }
454: }
455: }
456: return lastModified;
457: }
458:
459: /**
460: * Set last modified.
461: *
462: * @param lastModified New last modified value
463: */
464: public void setLastModified(long lastModified) {
465: this .lastModified = lastModified;
466: this .lastModifiedDate = null;
467: if (attributes != null)
468: attributes.put(LAST_MODIFIED, new Date(lastModified));
469: }
470:
471: /**
472: * Set last modified date.
473: *
474: * @param lastModified New last modified date value
475: * @deprecated
476: */
477: public void setLastModified(Date lastModified) {
478: setLastModifiedDate(lastModified);
479: }
480:
481: /**
482: * Get lastModified date.
483: *
484: * @return LastModified date value
485: */
486: public Date getLastModifiedDate() {
487: if (lastModifiedDate != null)
488: return lastModifiedDate;
489: if (lastModified != -1L) {
490: lastModifiedDate = new Date(lastModified);
491: return lastModifiedDate;
492: }
493: if (attributes != null) {
494: Attribute attribute = attributes.get(LAST_MODIFIED);
495: if (attribute != null) {
496: try {
497: Object value = attribute.get();
498: if (value instanceof Long) {
499: lastModified = ((Long) value).longValue();
500: lastModifiedDate = new Date(lastModified);
501: } else if (value instanceof Date) {
502: lastModified = ((Date) value).getTime();
503: lastModifiedDate = (Date) value;
504: } else {
505: String lastModifiedDateValue = value.toString();
506: Date result = null;
507: // Parsing the HTTP Date
508: for (int i = 0; (result == null)
509: && (i < formats.length); i++) {
510: try {
511: result = formats[i]
512: .parse(lastModifiedDateValue);
513: } catch (ParseException e) {
514: ;
515: }
516: }
517: if (result != null) {
518: lastModified = result.getTime();
519: lastModifiedDate = result;
520: }
521: }
522: } catch (NamingException e) {
523: ; // No value for the attribute
524: }
525: }
526: }
527: return lastModifiedDate;
528: }
529:
530: /**
531: * Last modified date mutator.
532: *
533: * @param lastModifiedDate New last modified date
534: */
535: public void setLastModifiedDate(Date lastModifiedDate) {
536: this .lastModified = lastModifiedDate.getTime();
537: this .lastModifiedDate = lastModifiedDate;
538: if (attributes != null)
539: attributes.put(LAST_MODIFIED, lastModifiedDate);
540: }
541:
542: /**
543: * @return Returns the lastModifiedHttp.
544: */
545: public String getLastModifiedHttp() {
546: if (lastModifiedHttp != null)
547: return lastModifiedHttp;
548: Date modifiedDate = getLastModifiedDate();
549: if (modifiedDate == null) {
550: modifiedDate = getCreationDate();
551: }
552: if (modifiedDate == null) {
553: modifiedDate = new Date();
554: }
555: synchronized (format) {
556: lastModifiedHttp = format.format(modifiedDate);
557: }
558: return lastModifiedHttp;
559: }
560:
561: /**
562: * @param lastModifiedHttp The lastModifiedHttp to set.
563: */
564: public void setLastModifiedHttp(String lastModifiedHttp) {
565: this .lastModifiedHttp = lastModifiedHttp;
566: }
567:
568: /**
569: * @return Returns the mimeType.
570: */
571: public String getMimeType() {
572: return mimeType;
573: }
574:
575: /**
576: * @param mimeType The mimeType to set.
577: */
578: public void setMimeType(String mimeType) {
579: this .mimeType = mimeType;
580: }
581:
582: /**
583: * Get name.
584: *
585: * @return Name value
586: */
587: public String getName() {
588: if (name != null)
589: return name;
590: if (attributes != null) {
591: Attribute attribute = attributes.get(NAME);
592: if (attribute != null) {
593: try {
594: name = attribute.get().toString();
595: } catch (NamingException e) {
596: ; // No value for the attribute
597: }
598: }
599: }
600: return name;
601: }
602:
603: /**
604: * Set name.
605: *
606: * @param name New name value
607: */
608: public void setName(String name) {
609: this .name = name;
610: if (attributes != null)
611: attributes.put(NAME, name);
612: }
613:
614: /**
615: * Get resource type.
616: *
617: * @return String resource type
618: */
619: public String getResourceType() {
620: String result = null;
621: if (attributes != null) {
622: Attribute attribute = attributes.get(TYPE);
623: if (attribute != null) {
624: try {
625: result = attribute.get().toString();
626: } catch (NamingException e) {
627: ; // No value for the attribute
628: }
629: }
630: }
631: if (result == null) {
632: if (collection)
633: result = COLLECTION_TYPE;
634: else
635: result = "";
636: }
637: return result;
638: }
639:
640: /**
641: * Type mutator.
642: *
643: * @param resourceType New resource type
644: */
645: public void setResourceType(String resourceType) {
646: collection = resourceType.equals(COLLECTION_TYPE);
647: if (attributes != null)
648: attributes.put(TYPE, resourceType);
649: }
650:
651: /**
652: * Get ETag.
653: *
654: * @return Weak ETag
655: */
656: public String getETag() {
657: return getETag(false);
658: }
659:
660: /**
661: * Get ETag.
662: *
663: * @param strong If true, the strong ETag will be returned
664: * @return ETag
665: */
666: public String getETag(boolean strong) {
667: String result = null;
668: if (attributes != null) {
669: Attribute attribute = attributes.get(ETAG);
670: if (attribute != null) {
671: try {
672: result = attribute.get().toString();
673: } catch (NamingException e) {
674: ; // No value for the attribute
675: }
676: }
677: }
678: if (strong) {
679: // The strong ETag must always be calculated by the resources
680: result = strongETag;
681: } else {
682: // The weakETag is contentLenght + lastModified
683: if (weakETag == null) {
684: weakETag = "W/\"" + getContentLength() + "-"
685: + getLastModified() + "\"";
686: }
687: result = weakETag;
688: }
689: return result;
690: }
691:
692: /**
693: * Set strong ETag.
694: */
695: public void setETag(String eTag) {
696: this .strongETag = eTag;
697: if (attributes != null)
698: attributes.put(ETAG, eTag);
699: }
700:
701: /**
702: * Return the canonical path of the resource, to possibly be used for
703: * direct file serving. Implementations which support this should override
704: * it to return the file path.
705: *
706: * @return The canonical path of the resource
707: */
708: public String getCanonicalPath() {
709: return null;
710: }
711:
712: // ----------------------------------------------------- Attributes Methods
713:
714: /**
715: * Get attribute.
716: */
717: public Attribute get(String attrID) {
718: if (attributes == null) {
719: if (attrID.equals(CREATION_DATE)) {
720: return new BasicAttribute(CREATION_DATE,
721: getCreationDate());
722: } else if (attrID.equals(ALTERNATE_CREATION_DATE)) {
723: return new BasicAttribute(ALTERNATE_CREATION_DATE,
724: getCreationDate());
725: } else if (attrID.equals(LAST_MODIFIED)) {
726: return new BasicAttribute(LAST_MODIFIED,
727: getLastModifiedDate());
728: } else if (attrID.equals(ALTERNATE_LAST_MODIFIED)) {
729: return new BasicAttribute(ALTERNATE_LAST_MODIFIED,
730: getLastModifiedDate());
731: } else if (attrID.equals(NAME)) {
732: return new BasicAttribute(NAME, getName());
733: } else if (attrID.equals(TYPE)) {
734: return new BasicAttribute(TYPE, getResourceType());
735: } else if (attrID.equals(ALTERNATE_TYPE)) {
736: return new BasicAttribute(ALTERNATE_TYPE,
737: getResourceType());
738: } else if (attrID.equals(CONTENT_LENGTH)) {
739: return new BasicAttribute(CONTENT_LENGTH, new Long(
740: getContentLength()));
741: } else if (attrID.equals(ALTERNATE_CONTENT_LENGTH)) {
742: return new BasicAttribute(ALTERNATE_CONTENT_LENGTH,
743: new Long(getContentLength()));
744: }
745: } else {
746: return attributes.get(attrID);
747: }
748: return null;
749: }
750:
751: /**
752: * Put attribute.
753: */
754: public Attribute put(Attribute attribute) {
755: if (attributes == null) {
756: try {
757: return put(attribute.getID(), attribute.get());
758: } catch (NamingException e) {
759: return null;
760: }
761: } else {
762: return attributes.put(attribute);
763: }
764: }
765:
766: /**
767: * Put attribute.
768: */
769: public Attribute put(String attrID, Object val) {
770: if (attributes == null) {
771: return null; // No reason to implement this
772: } else {
773: return attributes.put(attrID, val);
774: }
775: }
776:
777: /**
778: * Remove attribute.
779: */
780: public Attribute remove(String attrID) {
781: if (attributes == null) {
782: return null; // No reason to implement this
783: } else {
784: return attributes.remove(attrID);
785: }
786: }
787:
788: /**
789: * Get all attributes.
790: */
791: public NamingEnumeration getAll() {
792: if (attributes == null) {
793: Vector attributes = new Vector();
794: attributes.addElement(new BasicAttribute(CREATION_DATE,
795: getCreationDate()));
796: attributes.addElement(new BasicAttribute(LAST_MODIFIED,
797: getLastModifiedDate()));
798: attributes.addElement(new BasicAttribute(NAME, getName()));
799: attributes.addElement(new BasicAttribute(TYPE,
800: getResourceType()));
801: attributes.addElement(new BasicAttribute(CONTENT_LENGTH,
802: new Long(getContentLength())));
803: return new RecyclableNamingEnumeration(attributes);
804: } else {
805: return attributes.getAll();
806: }
807: }
808:
809: /**
810: * Get all attribute IDs.
811: */
812: public NamingEnumeration getIDs() {
813: if (attributes == null) {
814: Vector attributeIDs = new Vector();
815: attributeIDs.addElement(CREATION_DATE);
816: attributeIDs.addElement(LAST_MODIFIED);
817: attributeIDs.addElement(NAME);
818: attributeIDs.addElement(TYPE);
819: attributeIDs.addElement(CONTENT_LENGTH);
820: return new RecyclableNamingEnumeration(attributeIDs);
821: } else {
822: return attributes.getIDs();
823: }
824: }
825:
826: /**
827: * Retrieves the number of attributes in the attribute set.
828: */
829: public int size() {
830: if (attributes == null) {
831: return 5;
832: } else {
833: return attributes.size();
834: }
835: }
836:
837: /**
838: * Clone the attributes object (WARNING: fake cloning).
839: */
840: public Object clone() {
841: return this ;
842: }
843:
844: /**
845: * Case sensitivity.
846: */
847: public boolean isCaseIgnored() {
848: return false;
849: }
850:
851: }
|