001: /*
002: * Copyright 2005-2007 Noelios Consulting.
003: *
004: * The contents of this file are subject to the terms of the Common Development
005: * and Distribution License (the "License"). You may not use this file except in
006: * compliance with the License.
007: *
008: * You can obtain a copy of the license at
009: * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
010: * language governing permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL HEADER in each file and
013: * include the License file at http://www.opensource.org/licenses/cddl1.txt If
014: * applicable, add the following below this CDDL HEADER, with the fields
015: * enclosed by brackets "[]" replaced with your own identifying information:
016: * Portions Copyright [yyyy] [name of copyright owner]
017: */
018:
019: package org.restlet.data;
020:
021: import java.util.logging.Level;
022: import java.util.logging.Logger;
023:
024: /**
025: * Validation tag equivalent to the HTTP entity tag. "A strong entity tag may be
026: * shared by two entities of a resource only if they are equivalent by octet
027: * equality.<br/> A weak entity tag may be shared by two entities of a resource
028: * only if the entities are equivalent and could be substituted for each other
029: * with no significant change in semantics."
030: *
031: * @see <a
032: * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11">HTTP
033: * Entity Tags</a>
034: * @see <a
035: * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3.2">HTTP
036: * Entity Tag Cache Validators</a>
037: * @author Jerome Louvel (contact@noelios.com)
038: */
039: public final class Tag extends Metadata {
040: /** Tag matching any other tag, used in call's condition data. */
041: public static final Tag ALL = Tag.parse("*");
042:
043: /**
044: * Parses a tag formatted as defined by the HTTP standard.
045: *
046: * @param httpTag
047: * The HTTP tag string; if it starts with 'W/' the tag will be
048: * marked as weak and the data following the 'W/' used as the tag;
049: * otherwise it should be surrounded with quotes (e.g.,
050: * "sometag").
051: * @return A new tag instance.
052: * @see <a
053: * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11">HTTP
054: * Entity Tags</a>
055: */
056: public static Tag parse(final String httpTag) {
057: Tag result = null;
058: boolean weak = false;
059: String httpTagCopy = httpTag;
060:
061: if (httpTagCopy.startsWith("W/")) {
062: weak = true;
063: httpTagCopy = httpTagCopy.substring(2);
064: }
065:
066: if (httpTagCopy.startsWith("\"") && httpTagCopy.endsWith("\"")) {
067: result = new Tag(httpTagCopy.substring(1, httpTagCopy
068: .length() - 1), weak);
069: } else if (httpTagCopy.equals("*")) {
070: result = new Tag("*", weak);
071: } else {
072: Logger.getLogger(Tag.class.getCanonicalName()).log(
073: Level.WARNING,
074: "Invalid tag format detected: " + httpTagCopy);
075: }
076:
077: return result;
078: }
079:
080: /** The tag weakness. */
081: private boolean weak;
082:
083: /**
084: * Default constructor. The opaque tag is set to null and the weakness
085: * indicator is set to true.
086: */
087: public Tag() {
088: this (null, true);
089: }
090:
091: /**
092: * Constructor of weak tags.
093: *
094: * @param opaqueTag
095: * The tag value.
096: */
097: public Tag(final String opaqueTag) {
098: this (opaqueTag, true);
099: }
100:
101: /**
102: * Constructor.
103: *
104: * @param opaqueTag
105: * The tag value.
106: * @param weak
107: * The weakness indicator.
108: */
109: public Tag(final String opaqueTag, boolean weak) {
110: super (opaqueTag);
111: this .weak = weak;
112: }
113:
114: /**
115: * Indicates if both tags are equal.
116: *
117: * @param object
118: * The object to compare to.
119: * @return True if both tags are equal.
120: */
121: @Override
122: public boolean equals(final Object object) {
123: return equals(object, true);
124: }
125:
126: /**
127: * Indicates if both tags are equal.
128: *
129: * @param object
130: * The object to compare to.
131: * @param checkWeakness
132: * the equality test takes care or not of the weakness.
133: *
134: * @return True if both tags are equal.
135: */
136: public boolean equals(final Object object, boolean checkWeakness) {
137: boolean result = (object != null) && (object instanceof Tag);
138:
139: if (result) {
140: Tag that = (Tag) object;
141:
142: if (checkWeakness) {
143: result = (that.isWeak() == isWeak());
144: }
145:
146: if (result) {
147: if (getName() == null) {
148: result = (that.getName() == null);
149: } else {
150: result = getName().equals(that.getName());
151: }
152: }
153: }
154:
155: return result;
156: }
157:
158: /**
159: * Returns tag formatted as an HTTP tag string.
160: *
161: * @return The formatted HTTP tag string.
162: * @see <a
163: * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11">HTTP
164: * Entity Tags</a>
165: */
166: public String format() {
167: if (getName().equals("*")) {
168: return "*";
169: } else {
170: StringBuilder sb = new StringBuilder();
171: if (isWeak())
172: sb.append("W/");
173: return sb.append('"').append(getName()).append('"')
174: .toString();
175: }
176: }
177:
178: /**
179: * Returns the description.
180: *
181: * @return The description.
182: */
183: public String getDescription() {
184: return "Validation tag equivalent to an HTTP entity tag";
185: }
186:
187: /**
188: * Returns the name, corresponding to an HTTP opaque tag value.
189: *
190: * @return The name, corresponding to an HTTP opaque tag value.
191: */
192: public String getName() {
193: return super .getName();
194: }
195:
196: /** {@inheritDoc} */
197: @Override
198: public int hashCode() {
199: return format().hashCode();
200: }
201:
202: /**
203: * Indicates if the tag is weak.
204: *
205: * @return True if the tag is weak, false if the tag is strong.
206: */
207: public boolean isWeak() {
208: return this.weak;
209: }
210: }
|