Skip to content

Commit 28a13cf

Browse files
authored
[Core] Add ETag Implementation (Azure#24148)
1 parent ae08d30 commit 28a13cf

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.core.util;
5+
6+
import com.azure.core.util.logging.ClientLogger;
7+
8+
import java.util.Objects;
9+
10+
/**
11+
* This class represents an HTTP ETag. A ETag value could be strong or weak ETag.
12+
* More information, check https://en.wikipedia.org/wiki/HTTP_ETag
13+
*/
14+
public final class ETag {
15+
private static final ClientLogger LOGGER = new ClientLogger(ETag.class);
16+
17+
private static final String QUOTE_STRING = "\"";
18+
private static final String WEAK_ETAG_PREFIX_QUOTE = "W/\"";
19+
private static final String ASTERISK = "*";
20+
21+
/**
22+
* The asterisk is a special value representing any resource.
23+
*/
24+
public static final ETag ALL = new ETag(ASTERISK);
25+
26+
private final String eTag;
27+
28+
/**
29+
* Creates a new instance of {@link ETag}.
30+
*
31+
* @param eTag The HTTP entity tag string value.
32+
*/
33+
public ETag(String eTag) {
34+
checkValidETag(eTag);
35+
this.eTag = eTag;
36+
}
37+
38+
@Override
39+
public boolean equals(Object o) {
40+
if (o == this) {
41+
return true;
42+
} else if (o == null) {
43+
return false;
44+
} else if (!(o instanceof ETag)) {
45+
return false;
46+
} else if (eTag == null) {
47+
return ((ETag) o).eTag == null;
48+
} else {
49+
return eTag.equals(((ETag) o).eTag);
50+
}
51+
}
52+
53+
@Override
54+
public int hashCode() {
55+
return Objects.hashCode(eTag);
56+
}
57+
58+
@Override
59+
public String toString() {
60+
return eTag;
61+
}
62+
63+
/**
64+
* Checks if the {@code eTag} a valid ETag value. Valid ETags show below,
65+
* - The special character, '*'.
66+
* - A strong ETag, which the value is wrapped in quotes, ex, "12345".
67+
* - A weak ETag, which value is wrapped in quotes and prefixed by "W/", ex, W/"12345".
68+
*
69+
* @param eTag ETag string value.
70+
*/
71+
private void checkValidETag(String eTag) {
72+
if (eTag == null || ASTERISK.equals(eTag)) {
73+
return;
74+
}
75+
76+
if (!((eTag.startsWith(QUOTE_STRING) || eTag.startsWith(WEAK_ETAG_PREFIX_QUOTE))
77+
&& eTag.endsWith(QUOTE_STRING))) {
78+
throw LOGGER.logExceptionAsError(new IllegalArgumentException(String.format(
79+
"The value=%s should be equal to * , be wrapped in quotes, or be wrapped in quotes prefixed by W/",
80+
eTag)));
81+
}
82+
}
83+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.core.util;
5+
6+
import org.junit.jupiter.api.Test;
7+
8+
import static org.junit.jupiter.api.Assertions.assertEquals;
9+
import static org.junit.jupiter.api.Assertions.assertFalse;
10+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
11+
import static org.junit.jupiter.api.Assertions.assertThrows;
12+
import static org.junit.jupiter.api.Assertions.assertTrue;
13+
14+
/**
15+
* Tests {@link ETag}.
16+
*/
17+
public class ETagTests {
18+
private static final String ETAG_CONTENT = "12345";
19+
private static final String QUOTE_STRING = "\"";
20+
private static final String WEAK_ETAG_PREFIX_QUOTE = "W/\"";
21+
22+
@Test
23+
public void validETag() {
24+
// Valid Strong ETag
25+
String strongETagExpect = QUOTE_STRING + ETAG_CONTENT + QUOTE_STRING;
26+
ETag strongETag = new ETag(strongETagExpect);
27+
assertEquals(strongETagExpect, strongETag.toString());
28+
// Valid Weak ETag
29+
String weakETagExpect = WEAK_ETAG_PREFIX_QUOTE + ETAG_CONTENT + QUOTE_STRING;
30+
ETag weakETag = new ETag(weakETagExpect);
31+
assertEquals(weakETagExpect, weakETag.toString());
32+
// All * ETag
33+
String allETags = "*";
34+
ETag asterisk = new ETag(allETags);
35+
assertEquals(allETags, asterisk.toString());
36+
assertEquals(allETags, ETag.ALL.toString());
37+
}
38+
39+
@Test
40+
public void invalidETag() {
41+
// Invalid Strong ETag
42+
String strongETagExpect = QUOTE_STRING + ETAG_CONTENT;
43+
assertThrows(IllegalArgumentException.class, () -> new ETag(strongETagExpect));
44+
// Valid Weak ETag
45+
String weakETagExpect = WEAK_ETAG_PREFIX_QUOTE + ETAG_CONTENT;
46+
assertThrows(IllegalArgumentException.class, () -> new ETag(weakETagExpect));
47+
}
48+
49+
@Test
50+
public void equalsTest() {
51+
ETag validStrongETag = new ETag(QUOTE_STRING + ETAG_CONTENT + QUOTE_STRING);
52+
assertFalse(validStrongETag.equals(null));
53+
ETag nullETag = new ETag(null);
54+
assertTrue(nullETag.equals(new ETag(null)));
55+
assertFalse(nullETag.equals(validStrongETag));
56+
assertFalse(validStrongETag.equals(nullETag));
57+
assertTrue(validStrongETag.equals(validStrongETag));
58+
59+
ETag validStrongETagCopy = new ETag(QUOTE_STRING + ETAG_CONTENT + QUOTE_STRING);
60+
assertEquals(validStrongETag, validStrongETagCopy);
61+
}
62+
63+
@Test
64+
public void hashCodeTest() {
65+
ETag nullETag = new ETag(null);
66+
ETag validStrongETag = new ETag(QUOTE_STRING + ETAG_CONTENT + QUOTE_STRING);
67+
assertEquals(0, nullETag.hashCode());
68+
assertNotEquals(0, validStrongETag.hashCode());
69+
}
70+
}

0 commit comments

Comments
 (0)