Skip to content

Commit b93f1d3

Browse files
author
Jeremy Boynes
committed
Add an ObjectId class for identifying stored objects
1 parent 0cd6f98 commit b93f1d3

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright 2015 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS-IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
package com.google.gcloud.storage;
18+
19+
import java.net.URI;
20+
import java.util.Objects;
21+
22+
/**
23+
* Identifier for a stored object.
24+
*/
25+
public class ObjectId {
26+
27+
private final String bucketName;
28+
private final String objectName;
29+
private final URI uri;
30+
31+
public ObjectId(String uri) {
32+
this(URI.create(uri));
33+
}
34+
35+
/**
36+
* Constructs an ObjectId from a {@code gsutil} style URI.
37+
*
38+
* @param uri the object's URI
39+
*/
40+
public ObjectId(URI uri) {
41+
Objects.requireNonNull(uri, "uri must not be null");
42+
this.uri = uri;
43+
if (uri.isAbsolute()) {
44+
if (!"gs".equals(uri.getScheme())) {
45+
throw new IllegalArgumentException("uri must use gs: scheme");
46+
}
47+
if (uri.getPath() == null || uri.getPath().length() <= 1) {
48+
throw new IllegalArgumentException("uri must have a path: " + uri);
49+
}
50+
bucketName = uri.getAuthority();
51+
objectName = uri.getPath().substring(1);
52+
} else {
53+
this.bucketName = null;
54+
this.objectName = uri.getPath();
55+
}
56+
}
57+
58+
/**
59+
* Construct an absolute ObjectId from a bucket and object name.
60+
*
61+
* @param bucketName name of the bucket
62+
* @param objectName name of the object; must be a path relative to the bucket i.e. must not start with '/'
63+
*/
64+
public ObjectId(String bucketName, String objectName) {
65+
Objects.requireNonNull(bucketName, "bucketName must not be null");
66+
if (bucketName.isEmpty()) {
67+
throw new IllegalArgumentException("bucketName must not be empty");
68+
}
69+
Objects.requireNonNull(objectName, "objectName must not be null");
70+
if (objectName.isEmpty()) {
71+
throw new IllegalArgumentException("objectName must not be empty");
72+
}
73+
if (objectName.charAt(0) == '/') {
74+
throw new IllegalArgumentException("objectName must be a relative path");
75+
}
76+
this.bucketName = bucketName;
77+
this.objectName = objectName;
78+
this.uri = URI.create("gs://" + bucketName + "/" + objectName);
79+
}
80+
81+
/**
82+
* Returns the name of the bucket containing this object. May be null for object ids that solely define an
83+
* object name independent of bucket.
84+
*
85+
* @return the name of the bucket containing this object; may be null
86+
*/
87+
public String getBucketName() {
88+
return bucketName;
89+
}
90+
91+
/**
92+
* Returns the name of the object within the bucket.
93+
* @return the name of the object within the bucket
94+
*/
95+
public String getObjectName() {
96+
return objectName;
97+
}
98+
99+
/**
100+
* Returns the {@code gsutil} URI for this object.
101+
*
102+
* <p>If a bucketName is defined this will return an absolute URI of the form {@code gs://bucketName/objectName},
103+
* otherwise the objectName will be converted to a relative URI.
104+
*
105+
* @return the uri for this object
106+
*/
107+
public URI toURI() {
108+
return uri;
109+
}
110+
111+
/**
112+
* Returns this objects URI as a String.
113+
* @return this objects URI as a String
114+
*/
115+
@Override
116+
public String toString() {
117+
return uri.toString();
118+
}
119+
120+
@Override
121+
public boolean equals(Object o) {
122+
if (this == o) return true;
123+
if (o == null || getClass() != o.getClass()) return false;
124+
ObjectId other = (ObjectId) o;
125+
return Objects.equals(bucketName, other.bucketName) &&
126+
Objects.equals(objectName, other.objectName);
127+
}
128+
129+
@Override
130+
public int hashCode() {
131+
return Objects.hash(bucketName, objectName);
132+
}
133+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2015 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS-IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
package com.google.gcloud.storage;
18+
19+
import org.junit.Rule;
20+
import org.junit.Test;
21+
import org.junit.rules.ExpectedException;
22+
23+
import java.net.URI;
24+
25+
import static org.junit.Assert.assertEquals;
26+
import static org.junit.Assert.assertNull;
27+
import static org.junit.Assert.assertTrue;
28+
29+
public class ObjectIdTest {
30+
31+
@Rule
32+
public ExpectedException thrown = ExpectedException.none();
33+
34+
@Test
35+
public void createWithBucketAndObjectName() {
36+
ObjectId id = new ObjectId("bucket", "path/to/object.txt");
37+
assertEquals("bucket", id.getBucketName());
38+
assertEquals("path/to/object.txt", id.getObjectName());
39+
assertEquals("gs://bucket/path/to/object.txt", id.toString());
40+
assertEquals(URI.create("gs://bucket/path/to/object.txt"), id.toURI());
41+
}
42+
43+
@Test
44+
public void createFromRelativeURI() {
45+
ObjectId id = new ObjectId("path/to/object.txt");
46+
assertNull(id.getBucketName());
47+
assertEquals("path/to/object.txt", id.getObjectName());
48+
assertEquals("path/to/object.txt", id.toString());
49+
assertEquals(URI.create("path/to/object.txt"), id.toURI());
50+
}
51+
52+
@Test
53+
public void createFromAbsoluteURI() {
54+
ObjectId id = new ObjectId("gs://bucket/path/to/object.txt");
55+
assertEquals("bucket", id.getBucketName());
56+
assertEquals("path/to/object.txt", id.getObjectName());
57+
assertEquals("gs://bucket/path/to/object.txt", id.toString());
58+
assertEquals(URI.create("gs://bucket/path/to/object.txt"), id.toURI());
59+
}
60+
61+
@Test
62+
public void nullBucketNameNotAllowed() {
63+
thrown.expect(NullPointerException.class);
64+
new ObjectId(null, "object");
65+
}
66+
67+
@Test
68+
public void emptyBucketNameNotAllowed() {
69+
thrown.expect(IllegalArgumentException.class);
70+
new ObjectId("", "object");
71+
}
72+
73+
@Test
74+
public void nullObjectNameNotAllowed() {
75+
thrown.expect(NullPointerException.class);
76+
new ObjectId("bucket", null);
77+
}
78+
79+
@Test
80+
public void emptyObjectNameNotAllowed() {
81+
thrown.expect(IllegalArgumentException.class);
82+
new ObjectId("bucket", "");
83+
}
84+
85+
@Test
86+
public void slashObjectNameNotAllowed() {
87+
thrown.expect(IllegalArgumentException.class);
88+
new ObjectId("bucket", "/");
89+
}
90+
91+
@Test
92+
public void checkConsistentHashing() {
93+
ObjectId id1 = new ObjectId("bucket", "object");
94+
ObjectId id2 = new ObjectId("gs://bucket/object");
95+
assertTrue(id1.equals(id2));
96+
assertTrue(id1.hashCode() == id2.hashCode());
97+
}
98+
}

0 commit comments

Comments
 (0)