1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.validator;
29
30 import org.apache.hc.core5.annotation.Contract;
31 import org.apache.hc.core5.annotation.Internal;
32 import org.apache.hc.core5.annotation.ThreadingBehavior;
33 import org.apache.hc.core5.http.Header;
34 import org.apache.hc.core5.http.HttpHeaders;
35 import org.apache.hc.core5.http.MessageHeaders;
36 import org.apache.hc.core5.util.Args;
37 import org.apache.hc.core5.util.CharArrayBuffer;
38 import org.apache.hc.core5.util.LangUtils;
39 import org.apache.hc.core5.util.Tokenizer;
40
41
42
43
44
45
46 @Contract(threading = ThreadingBehavior.IMMUTABLE)
47 public final class ETag {
48
49 private final String value;
50 private final ValidatorType type;
51
52 public ETag(final String value, final ValidatorType type) {
53 this.value = Args.notNull(value, "Value");
54 this.type = Args.notNull(type, "Validator type");
55 }
56
57 public ETag(final String value) {
58 this(value, ValidatorType.STRONG);
59 }
60
61 public ValidatorType getType() {
62 return type;
63 }
64
65 public String getValue() {
66 return value;
67 }
68
69 public static boolean strongCompare(final ETag t1, final ETag t2) {
70 if (t1 == null || t2 == null) {
71 return false;
72 }
73 return t1.type == ValidatorType.STRONG && t1.type == t2.type && t1.value.equals(t2.value);
74 }
75
76 public static boolean weakCompare(final ETag t1, final ETag t2) {
77 if (t1 == null || t2 == null) {
78 return false;
79 }
80 return t1.value.equals(t2.value);
81 }
82
83 static ETag parse(final CharSequence buf, final Tokenizer.Cursor cursor) {
84 final Tokenizer tokenizer = Tokenizer.INSTANCE;
85 tokenizer.skipWhiteSpace(buf, cursor);
86
87 ValidatorType type = ValidatorType.STRONG;
88
89 if (!cursor.atEnd() && buf.charAt(cursor.getPos()) == 'W') {
90 cursor.updatePos(cursor.getPos() + 1);
91 if (!cursor.atEnd() && buf.charAt(cursor.getPos()) == '/') {
92 type = ValidatorType.WEAK;
93 cursor.updatePos(cursor.getPos() + 1);
94 } else {
95 return null;
96 }
97 }
98
99 String value = null;
100 if (!cursor.atEnd() && buf.charAt(cursor.getPos()) == '"') {
101 cursor.updatePos(cursor.getPos() + 1);
102 final StringBuilder sb = new StringBuilder();
103 for (;;) {
104 if (cursor.atEnd()) {
105 return null;
106 }
107 final char ch = buf.charAt(cursor.getPos());
108 cursor.updatePos(cursor.getPos() + 1);
109 if (ch == '"') {
110 break;
111 } else {
112 sb.append(ch);
113 }
114 }
115 value = sb.toString();
116 }
117
118 tokenizer.skipWhiteSpace(buf, cursor);
119 if (!cursor.atEnd()) {
120 return null;
121 }
122
123 return new ETag(value, type);
124 }
125
126 public static ETag parse(final String s) {
127 if (s == null) {
128 return null;
129 }
130 final Tokenizer.Cursor cursor = new Tokenizer.Cursor(0, s.length());
131 return parse(s, cursor);
132 }
133
134 public static ETag parse(final Header h) {
135 if (h == null) {
136 return null;
137 }
138 final String value = h.getValue();
139 if (value == null) {
140 return null;
141 }
142 return parse(value);
143 }
144
145 public static ETag get(final MessageHeaders message) {
146 if (message == null) {
147 return null;
148 }
149 return parse(message.getFirstHeader(HttpHeaders.ETAG));
150 }
151
152 @Internal
153 public void format(final CharArrayBuffer buf) {
154 if (buf == null) {
155 return;
156 }
157 if (type == ValidatorType.WEAK) {
158 buf.append("W/");
159 }
160 buf.append('"');
161 buf.append(value);
162 buf.append('"');
163 }
164
165 @Override
166 public boolean equals(final Object o) {
167 if (this == o) {
168 return true;
169 }
170 if (o instanceof ETag) {
171 final ETag that = (ETag) o;
172 return this.type == that.type && this.value.equals(that.value);
173 }
174 return false;
175 }
176
177 @Override
178 public int hashCode() {
179 int hash = LangUtils.HASH_SEED;
180 hash = LangUtils.hashCode(hash, type);
181 hash = LangUtils.hashCode(hash, value);
182 return hash;
183 }
184
185 @Override
186 public String toString() {
187 final CharArrayBuffer buf = new CharArrayBuffer(64);
188 format(buf);
189 return buf.toString();
190 }
191
192 }