Skip to content

Commit

Permalink
Add an ObjectId class for identifying stored objects
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeremy Boynes committed Jun 5, 2015
1 parent 0cd6f98 commit b93f1d3
Show file tree
Hide file tree
Showing 2 changed files with 231 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.google.gcloud.storage;

import java.net.URI;
import java.util.Objects;

/**
* Identifier for a stored object.
*/
public class ObjectId {

private final String bucketName;
private final String objectName;
private final URI uri;

public ObjectId(String uri) {
this(URI.create(uri));
}

/**
* Constructs an ObjectId from a {@code gsutil} style URI.
*
* @param uri the object's URI
*/
public ObjectId(URI uri) {
Objects.requireNonNull(uri, "uri must not be null");
this.uri = uri;
if (uri.isAbsolute()) {
if (!"gs".equals(uri.getScheme())) {
throw new IllegalArgumentException("uri must use gs: scheme");
}
if (uri.getPath() == null || uri.getPath().length() <= 1) {
throw new IllegalArgumentException("uri must have a path: " + uri);
}
bucketName = uri.getAuthority();
objectName = uri.getPath().substring(1);
} else {
this.bucketName = null;
this.objectName = uri.getPath();
}
}

/**
* Construct an absolute ObjectId from a bucket and object name.
*
* @param bucketName name of the bucket
* @param objectName name of the object; must be a path relative to the bucket i.e. must not start with '/'
*/
public ObjectId(String bucketName, String objectName) {
Objects.requireNonNull(bucketName, "bucketName must not be null");
if (bucketName.isEmpty()) {
throw new IllegalArgumentException("bucketName must not be empty");
}
Objects.requireNonNull(objectName, "objectName must not be null");
if (objectName.isEmpty()) {
throw new IllegalArgumentException("objectName must not be empty");
}
if (objectName.charAt(0) == '/') {
throw new IllegalArgumentException("objectName must be a relative path");
}
this.bucketName = bucketName;
this.objectName = objectName;
this.uri = URI.create("gs://" + bucketName + "/" + objectName);
}

/**
* Returns the name of the bucket containing this object. May be null for object ids that solely define an
* object name independent of bucket.
*
* @return the name of the bucket containing this object; may be null
*/
public String getBucketName() {
return bucketName;
}

/**
* Returns the name of the object within the bucket.
* @return the name of the object within the bucket
*/
public String getObjectName() {
return objectName;
}

/**
* Returns the {@code gsutil} URI for this object.
*
* <p>If a bucketName is defined this will return an absolute URI of the form {@code gs://bucketName/objectName},
* otherwise the objectName will be converted to a relative URI.
*
* @return the uri for this object
*/
public URI toURI() {
return uri;
}

/**
* Returns this objects URI as a String.
* @return this objects URI as a String
*/
@Override
public String toString() {
return uri.toString();
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ObjectId other = (ObjectId) o;
return Objects.equals(bucketName, other.bucketName) &&
Objects.equals(objectName, other.objectName);
}

@Override
public int hashCode() {
return Objects.hash(bucketName, objectName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.google.gcloud.storage;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import java.net.URI;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

public class ObjectIdTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void createWithBucketAndObjectName() {
ObjectId id = new ObjectId("bucket", "path/to/object.txt");
assertEquals("bucket", id.getBucketName());
assertEquals("path/to/object.txt", id.getObjectName());
assertEquals("gs://bucket/path/to/object.txt", id.toString());
assertEquals(URI.create("gs://bucket/path/to/object.txt"), id.toURI());
}

@Test
public void createFromRelativeURI() {
ObjectId id = new ObjectId("path/to/object.txt");
assertNull(id.getBucketName());
assertEquals("path/to/object.txt", id.getObjectName());
assertEquals("path/to/object.txt", id.toString());
assertEquals(URI.create("path/to/object.txt"), id.toURI());
}

@Test
public void createFromAbsoluteURI() {
ObjectId id = new ObjectId("gs://bucket/path/to/object.txt");
assertEquals("bucket", id.getBucketName());
assertEquals("path/to/object.txt", id.getObjectName());
assertEquals("gs://bucket/path/to/object.txt", id.toString());
assertEquals(URI.create("gs://bucket/path/to/object.txt"), id.toURI());
}

@Test
public void nullBucketNameNotAllowed() {
thrown.expect(NullPointerException.class);
new ObjectId(null, "object");
}

@Test
public void emptyBucketNameNotAllowed() {
thrown.expect(IllegalArgumentException.class);
new ObjectId("", "object");
}

@Test
public void nullObjectNameNotAllowed() {
thrown.expect(NullPointerException.class);
new ObjectId("bucket", null);
}

@Test
public void emptyObjectNameNotAllowed() {
thrown.expect(IllegalArgumentException.class);
new ObjectId("bucket", "");
}

@Test
public void slashObjectNameNotAllowed() {
thrown.expect(IllegalArgumentException.class);
new ObjectId("bucket", "/");
}

@Test
public void checkConsistentHashing() {
ObjectId id1 = new ObjectId("bucket", "object");
ObjectId id2 = new ObjectId("gs://bucket/object");
assertTrue(id1.equals(id2));
assertTrue(id1.hashCode() == id2.hashCode());
}
}

0 comments on commit b93f1d3

Please sign in to comment.