You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ad...@apache.org on 2013/09/29 01:06:47 UTC

git commit: JCLOUDS-306. added public acl to openstack-swift

Updated Branches:
  refs/heads/master 2150c8b65 -> 83a1c202e


JCLOUDS-306. added public acl to openstack-swift


Project: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/commit/83a1c202
Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/tree/83a1c202
Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/diff/83a1c202

Branch: refs/heads/master
Commit: 83a1c202ed42612875c00c1b9bf5a8f8df3a3582
Parents: 2150c8b
Author: Adrian Cole <ad...@gmail.com>
Authored: Sat Sep 28 15:35:56 2013 -0700
Committer: Adrian Cole <ad...@gmail.com>
Committed: Sat Sep 28 15:58:37 2013 -0700

----------------------------------------------------------------------
 .../openstack/swift/v1/domain/SwiftObject.java  | 47 ++++++----
 .../swift/v1/features/ContainerApi.java         | 22 ++++-
 .../openstack/swift/v1/features/ObjectApi.java  |  3 +
 .../v1/functions/ParseObjectFromResponse.java   |  5 +
 .../functions/ParseObjectListFromResponse.java  | 99 ++++++++++++++++++++
 .../swift/v1/features/ContainerApiLiveTest.java |  3 +-
 .../swift/v1/features/ContainerApiMockTest.java | 33 +++++--
 .../features/CreatePublicContainerLiveTest.java | 65 +++++++++++++
 .../swift/v1/features/ObjectApiLiveTest.java    | 18 +++-
 .../swift/v1/features/ObjectApiMockTest.java    | 32 ++++---
 10 files changed, 285 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/83a1c202/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/SwiftObject.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/SwiftObject.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/SwiftObject.java
index 6904436..56ceba4 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/SwiftObject.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/SwiftObject.java
@@ -20,13 +20,13 @@ import static com.google.common.base.Objects.equal;
 import static com.google.common.base.Objects.toStringHelper;
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.beans.ConstructorProperties;
+import java.net.URI;
 import java.util.Date;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.io.Payload;
-import org.jclouds.io.Payloads;
 import org.jclouds.openstack.swift.v1.features.ObjectApi;
 
 import com.google.common.base.Objects;
@@ -41,18 +41,16 @@ import com.google.common.collect.ImmutableMap;
 public class SwiftObject implements Comparable<SwiftObject> {
 
    private final String name;
+   private final URI uri;
    private final String hash;
    private final Date lastModified;
    private final Map<String, String> metadata;
    private final Payload payload;
 
-   @ConstructorProperties({ "name", "hash", "bytes", "content_type", "last_modified" })
-   protected SwiftObject(String name, String hash, long bytes, String contentType, Date lastModified) {
-      this(name, hash, lastModified, ImmutableMap.<String, String> of(), payload(bytes, contentType));
-   }
-
-   protected SwiftObject(String name, String hash, Date lastModified, Map<String, String> metadata, Payload payload) {
+   protected SwiftObject(String name, URI uri, String hash, Date lastModified, Map<String, String> metadata,
+         Payload payload) {
       this.name = checkNotNull(name, "name");
+      this.uri = checkNotNull(uri, "uri of %s", uri);
       this.hash = checkNotNull(hash, "hash of %s", name);
       this.lastModified = checkNotNull(lastModified, "lastModified of %s", name);
       this.metadata = metadata == null ? ImmutableMap.<String, String> of() : metadata;
@@ -63,6 +61,14 @@ public class SwiftObject implements Comparable<SwiftObject> {
       return name;
    }
 
+   /**
+    * http location of the object, accessible if its container is
+    * {@link CreateContainerOptions#publicRead}.
+    */
+   public URI uri() {
+      return uri;
+   }
+
    public String hash() {
       return hash;
    }
@@ -100,6 +106,7 @@ public class SwiftObject implements Comparable<SwiftObject> {
       if (object instanceof SwiftObject) {
          final SwiftObject that = SwiftObject.class.cast(object);
          return equal(name(), that.name()) //
+               && equal(uri(), that.uri()) //
                && equal(hash(), that.hash());
       } else {
          return false;
@@ -108,7 +115,7 @@ public class SwiftObject implements Comparable<SwiftObject> {
 
    @Override
    public int hashCode() {
-      return Objects.hashCode(name(), hash());
+      return Objects.hashCode(name(), uri(), hash());
    }
 
    @Override
@@ -119,6 +126,7 @@ public class SwiftObject implements Comparable<SwiftObject> {
    protected ToStringHelper string() {
       return toStringHelper("") //
             .add("name", name()) //
+            .add("uri", uri()) //
             .add("hash", hash()) //
             .add("lastModified", lastModified()) //
             .add("metadata", metadata());
@@ -143,6 +151,7 @@ public class SwiftObject implements Comparable<SwiftObject> {
 
    public static class Builder {
       protected String name;
+      protected URI uri;
       protected String hash;
       protected Date lastModified;
       protected Payload payload;
@@ -157,6 +166,14 @@ public class SwiftObject implements Comparable<SwiftObject> {
       }
 
       /**
+       * @see SwiftObject#uri()
+       */
+      public Builder uri(URI uri) {
+         this.uri = checkNotNull(uri, "uri");
+         return this;
+      }
+
+      /**
        * @see SwiftObject#hash()
        */
       public Builder hash(String hash) {
@@ -196,24 +213,16 @@ public class SwiftObject implements Comparable<SwiftObject> {
       }
 
       public SwiftObject build() {
-         return new SwiftObject(name, hash, lastModified, metadata, payload);
+         return new SwiftObject(name, uri, hash, lastModified, metadata, payload);
       }
 
       public Builder fromObject(SwiftObject from) {
          return name(from.name()) //
+               .uri(from.uri()) //
                .hash(from.hash()) //
                .lastModified(from.lastModified()) //
                .metadata(from.metadata()) //
                .payload(from.payload());
       }
    }
-
-   private static final byte[] NO_CONTENT = new byte[] {};
-
-   private static Payload payload(long bytes, String contentType) {
-      Payload payload = Payloads.newByteArrayPayload(NO_CONTENT);
-      payload.getContentMetadata().setContentLength(bytes);
-      payload.getContentMetadata().setContentType(contentType);
-      return payload;
-   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/83a1c202/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java
index a1b7ae7..e108ab3 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java
@@ -34,6 +34,8 @@ import javax.ws.rs.QueryParam;
 import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404;
 import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
 import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.blobstore.options.CreateContainerOptions;
+import org.jclouds.http.HttpRequest;
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
 import org.jclouds.openstack.swift.v1.binders.BindMetadataToHeaders.BindContainerMetadataToHeaders;
@@ -41,6 +43,7 @@ import org.jclouds.openstack.swift.v1.binders.BindMetadataToHeaders.BindRemoveCo
 import org.jclouds.openstack.swift.v1.domain.Container;
 import org.jclouds.openstack.swift.v1.functions.FalseOnAccepted;
 import org.jclouds.openstack.swift.v1.functions.ParseContainerFromHeaders;
+import org.jclouds.rest.Binder;
 import org.jclouds.rest.annotations.BinderParam;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.QueryParams;
@@ -94,6 +97,10 @@ public interface ContainerApi {
     * 
     * @param containerName
     *           corresponds to {@link Container#name()}.
+    * @param options
+    *           configuration such as <a href=
+    *           "http://docs.openstack.org/api/openstack-object-storage/1.0/content/special-metadata-acls.html"
+    *           >public read access</a>.
     * @see <a
     *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/create-container.html">
     *      Create Container API</a>
@@ -104,7 +111,20 @@ public interface ContainerApi {
    @PUT
    @ResponseParser(FalseOnAccepted.class)
    @Path("/{containerName}")
-   boolean createIfAbsent(@PathParam("containerName") String containerName);
+   boolean createIfAbsent(@PathParam("containerName") String containerName,
+         @BinderParam(ContainerReadHeader.class) CreateContainerOptions options);
+
+   static class ContainerReadHeader implements Binder {
+      @SuppressWarnings("unchecked")
+      @Override
+      public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+         CreateContainerOptions options = CreateContainerOptions.class.cast(input);
+         if (options.isPublicRead()) {
+            return (R) request.toBuilder().addHeader("x-container-read", ".r:*,.rlistings").build();
+         }
+         return request;
+      }
+   }
 
    /**
     * Gets the {@link Container}.

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/83a1c202/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectApi.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectApi.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectApi.java
index 2a3ee1e..05995af 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectApi.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ObjectApi.java
@@ -45,6 +45,7 @@ import org.jclouds.openstack.swift.v1.binders.BindMetadataToHeaders.BindRemoveOb
 import org.jclouds.openstack.swift.v1.domain.SwiftObject;
 import org.jclouds.openstack.swift.v1.functions.ETagHeader;
 import org.jclouds.openstack.swift.v1.functions.ParseObjectFromResponse;
+import org.jclouds.openstack.swift.v1.functions.ParseObjectListFromResponse;
 import org.jclouds.rest.Binder;
 import org.jclouds.rest.annotations.BinderParam;
 import org.jclouds.rest.annotations.Fallback;
@@ -71,6 +72,7 @@ public interface ObjectApi {
    @Named("ListObjects")
    @GET
    @QueryParams(keys = "format", values = "json")
+   @ResponseParser(ParseObjectListFromResponse.class)
    @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
    @Path("/")
    FluentIterable<SwiftObject> listFirstPage();
@@ -86,6 +88,7 @@ public interface ObjectApi {
    @Named("ListObjects")
    @GET
    @QueryParams(keys = "format", values = "json")
+   @ResponseParser(ParseObjectListFromResponse.class)
    @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
    @Path("/")
    FluentIterable<SwiftObject> listAt(@QueryParam("marker") String marker);

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/83a1c202/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java
index c5533a4..36247e1 100644
--- a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectFromResponse.java
@@ -19,6 +19,8 @@ package org.jclouds.openstack.swift.v1.functions;
 import static com.google.common.net.HttpHeaders.ETAG;
 import static com.google.common.net.HttpHeaders.LAST_MODIFIED;
 
+import java.net.URI;
+
 import javax.inject.Inject;
 
 import org.jclouds.date.DateService;
@@ -39,11 +41,13 @@ public class ParseObjectFromResponse implements Function<HttpResponse, SwiftObje
       this.dates = dates;
    }
 
+   private String uri;
    private String name;
 
    @Override
    public SwiftObject apply(HttpResponse from) {
       return SwiftObject.builder() //
+            .uri(URI.create(uri)) //
             .name(name) //
             .hash(from.getFirstHeaderOrNull(ETAG)) //
             .payload(from.getPayload()) //
@@ -53,6 +57,7 @@ public class ParseObjectFromResponse implements Function<HttpResponse, SwiftObje
 
    @Override
    public ParseObjectFromResponse setContext(HttpRequest request) {
+      this.uri = request.getEndpoint().toString();
       this.name = GeneratedHttpRequest.class.cast(request).getInvocation().getArgs().get(0).toString();
       return this;
    }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/83a1c202/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java
new file mode 100644
index 0000000..feb00c8
--- /dev/null
+++ b/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseObjectListFromResponse.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.jclouds.openstack.swift.v1.functions;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+import org.jclouds.openstack.swift.v1.domain.SwiftObject;
+import org.jclouds.rest.InvocationContext;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+
+public class ParseObjectListFromResponse implements Function<HttpResponse, FluentIterable<SwiftObject>>,
+      InvocationContext<ParseObjectListFromResponse> {
+
+   private static final class InternalObject {
+      String name;
+      String hash;
+      long bytes;
+      String content_type;
+      Date last_modified;
+   }
+
+   private final ParseJson<List<InternalObject>> json;
+
+   @Inject
+   ParseObjectListFromResponse(ParseJson<List<InternalObject>> json) {
+      this.json = json;
+   }
+
+   private ToSwiftObject toSwiftObject;
+
+   @Override
+   public FluentIterable<SwiftObject> apply(HttpResponse from) {
+      return FluentIterable.from(json.apply(from)) //
+            .transform(toSwiftObject);
+   }
+
+   static class ToSwiftObject implements Function<InternalObject, SwiftObject> {
+      private final String containerUri;
+
+      ToSwiftObject(String containerUri) {
+         this.containerUri = containerUri;
+      }
+
+      @Override
+      public SwiftObject apply(InternalObject input) {
+         return SwiftObject.builder() //
+               .uri(URI.create(String.format("%s%s", containerUri, input.name))) //
+               .name(input.name) //
+               .hash(input.hash) //
+               .payload(payload(input.bytes, input.content_type)) //
+               .lastModified(input.last_modified).build();
+      }
+   }
+
+   @Override
+   public ParseObjectListFromResponse setContext(HttpRequest request) {
+      String containerUri = request.getEndpoint().toString();
+      int queryIndex = containerUri.indexOf('?');
+      if (queryIndex != -1) {
+         containerUri = containerUri.substring(0, queryIndex);
+      }
+      this.toSwiftObject = new ToSwiftObject(containerUri);
+      return this;
+   }
+
+   private static final byte[] NO_CONTENT = new byte[] {};
+
+   private static Payload payload(long bytes, String contentType) {
+      Payload payload = Payloads.newByteArrayPayload(NO_CONTENT);
+      payload.getContentMetadata().setContentLength(bytes);
+      payload.getContentMetadata().setContentType(contentType);
+      return payload;
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/83a1c202/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
index 973d363..bf0c24c 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
@@ -24,6 +24,7 @@ import static org.testng.Assert.assertTrue;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.openstack.swift.v1.domain.Container;
 import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
 import org.testng.annotations.AfterClass;
@@ -118,7 +119,7 @@ public class ContainerApiLiveTest extends BaseSwiftApiLiveTest {
    public void setup() {
       super.setup();
       for (String regionId : api.configuredRegions()) {
-         api.containerApiInRegion(regionId).createIfAbsent(name);
+         api.containerApiInRegion(regionId).createIfAbsent(name, new CreateContainerOptions());
       }
    }
 

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/83a1c202/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java
index d54530e..b127799 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiMockTest.java
@@ -23,6 +23,7 @@ import static org.testng.Assert.assertTrue;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.openstack.swift.v1.SwiftApi;
 import org.jclouds.openstack.swift.v1.domain.Container;
 import org.jclouds.openstack.swift.v1.internal.BaseSwiftMockTest;
@@ -107,18 +108,38 @@ public class ContainerApiMockTest extends BaseSwiftMockTest {
 
       try {
          SwiftApi api = swiftApi(server.getUrl("/").toString());
-         assertTrue(api.containerApiInRegion("DFW").createIfAbsent("myContainer"));
+         assertTrue(api.containerApiInRegion("DFW").createIfAbsent("myContainer", new CreateContainerOptions()));
 
          assertEquals(server.getRequestCount(), 2);
          assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
-         RecordedRequest deleteRequest = server.takeRequest();
-         assertEquals(deleteRequest.getRequestLine(),
+         RecordedRequest createRequest = server.takeRequest();
+         assertEquals(createRequest.getRequestLine(),
                "PUT /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1");
       } finally {
          server.shutdown();
       }
    }
 
+   public void createPublicRead() throws Exception {
+      MockWebServer server = mockSwiftServer();
+      server.enqueue(new MockResponse().setBody(access));
+      server.enqueue(new MockResponse().setResponseCode(201));
+
+      try {
+         SwiftApi api = swiftApi(server.getUrl("/").toString());
+         assertTrue(api.containerApiInRegion("DFW").createIfAbsent("myContainer", new CreateContainerOptions().publicRead()));
+
+         assertEquals(server.getRequestCount(), 2);
+         assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
+         RecordedRequest createRequest = server.takeRequest();
+         assertEquals(createRequest.getRequestLine(),
+               "PUT /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1");
+         assertEquals(createRequest.getHeader("x-container-read"), ".r:*,.rlistings");
+      } finally {
+         server.shutdown();
+      }
+   }
+
    public void alreadyCreated() throws Exception {
       MockWebServer server = mockSwiftServer();
       server.enqueue(new MockResponse().setBody(access));
@@ -126,12 +147,12 @@ public class ContainerApiMockTest extends BaseSwiftMockTest {
 
       try {
          SwiftApi api = swiftApi(server.getUrl("/").toString());
-         assertFalse(api.containerApiInRegion("DFW").createIfAbsent("myContainer"));
+         assertFalse(api.containerApiInRegion("DFW").createIfAbsent("myContainer", new CreateContainerOptions()));
 
          assertEquals(server.getRequestCount(), 2);
          assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
-         RecordedRequest deleteRequest = server.takeRequest();
-         assertEquals(deleteRequest.getRequestLine(),
+         RecordedRequest createRequest = server.takeRequest();
+         assertEquals(createRequest.getRequestLine(),
                "PUT /v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer HTTP/1.1");
       } finally {
          server.shutdown();

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/83a1c202/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java
new file mode 100644
index 0000000..70a84b9
--- /dev/null
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/CreatePublicContainerLiveTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.jclouds.openstack.swift.v1.features;
+
+import static org.jclouds.blobstore.options.CreateContainerOptions.Builder.publicRead;
+import static org.jclouds.io.Payloads.newStringPayload;
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+
+import org.jclouds.http.options.GetOptions;
+import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
+import org.jclouds.util.Strings2;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "live", testName = "CreatePublicContainerLiveTest")
+public class CreatePublicContainerLiveTest extends BaseSwiftApiLiveTest {
+
+   private String name = getClass().getSimpleName();
+   private String containerName = getClass().getSimpleName() + "Container";
+
+   public void publicReadObjectUri() throws Exception {
+      for (String regionId : api.configuredRegions()) {
+         api.containerApiInRegion(regionId).createIfAbsent(containerName, publicRead());
+         api.containerApiInRegion(regionId).get(containerName);
+
+         ObjectApi objectApi = api.objectApiInRegionForContainer(regionId, containerName);
+         objectApi.createOrUpdate(name, newStringPayload("swifty"), ImmutableMap.<String, String> of());
+
+         InputStream publicStream = objectApi.get(name, new GetOptions()).uri().toURL().openStream();
+
+         assertEquals(Strings2.toStringAndClose(publicStream), "swifty");
+      }
+   }
+
+   @Override
+   @AfterClass(groups = "live")
+   public void tearDown() {
+      for (String regionId : api.configuredRegions()) {
+         api.objectApiInRegionForContainer(regionId, containerName).delete(name);
+         api.containerApiInRegion(regionId).deleteIfEmpty(containerName);
+      }
+      super.tearDown();
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/83a1c202/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java
index 4960fed..4cfa8d3 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiLiveTest.java
@@ -23,11 +23,14 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
+import java.io.IOException;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.TimeUnit;
 
+import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.http.options.GetOptions;
 import org.jclouds.openstack.swift.v1.domain.SwiftObject;
 import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
@@ -61,6 +64,7 @@ public class ObjectApiLiveTest extends BaseSwiftApiLiveTest {
 
    static void checkObject(SwiftObject object) {
       assertNotNull(object.name());
+      assertNotNull(object.uri());
       assertNotNull(object.hash());
       assertTrue(object.lastModified().getTime() <= System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5));
       assertNotNull(object.payload().getContentMetadata().getContentLength());
@@ -85,6 +89,17 @@ public class ObjectApiLiveTest extends BaseSwiftApiLiveTest {
       }
    }
 
+   public void privateByDefault() throws Exception {
+      for (String regionId : api.configuredRegions()) {
+         SwiftObject object = api.objectApiInRegionForContainer(regionId, containerName).head(name);
+         try {
+            object.uri().toURL().openStream();
+            fail("shouldn't be able to access " + object);
+         } catch (IOException expected) {
+         }
+      }
+   }
+
    public void getOptions() throws Exception {
       for (String regionId : api.configuredRegions()) {
          SwiftObject object = api.objectApiInRegionForContainer(regionId, containerName).get(name, tail(1));
@@ -107,7 +122,6 @@ public class ObjectApiLiveTest extends BaseSwiftApiLiveTest {
    public void updateMetadata() throws Exception {
       for (String regionId : api.configuredRegions()) {
          ObjectApi objectApi = api.objectApiInRegionForContainer(regionId, containerName);
-         ;
 
          Map<String, String> meta = ImmutableMap.of("MyAdd1", "foo", "MyAdd2", "bar");
 
@@ -149,7 +163,7 @@ public class ObjectApiLiveTest extends BaseSwiftApiLiveTest {
    public void setup() {
       super.setup();
       for (String regionId : api.configuredRegions()) {
-         api.containerApiInRegion(regionId).createIfAbsent(containerName);
+         api.containerApiInRegion(regionId).createIfAbsent(containerName, new CreateContainerOptions());
          api.objectApiInRegionForContainer(regionId, containerName).createOrUpdate(name, newStringPayload("swifty"),
                ImmutableMap.<String, String> of());
       }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs-openstack/blob/83a1c202/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java
index 63c9974..1cef6fe 100644
--- a/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java
+++ b/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ObjectApiMockTest.java
@@ -23,6 +23,7 @@ import static org.jclouds.io.Payloads.newStringPayload;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 
+import java.net.URI;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -59,17 +60,22 @@ public class ObjectApiMockTest extends BaseSwiftMockTest {
          + "    \"last_modified\":\"2009-02-03T05:26:32.612278\"},\n" //
          + "]";
 
-   ImmutableList<SwiftObject> parsedObjects = ImmutableList.of(//
-         SwiftObject.builder() //
-               .name("test_obj_1") //
-               .hash("4281c348eaf83e70ddce0e07221c3d28") //
-               .payload(payload(14, "application/octet-stream")) //
-               .lastModified(dates.iso8601DateParse("2009-02-03T05:26:32.612278")).build(), //
-         SwiftObject.builder() //
-               .name("test_obj_2") //
-               .hash("b039efe731ad111bc1b0ef221c3849d0") //
-               .payload(payload(64l, "application/octet-stream")) //
-               .lastModified(dates.iso8601DateParse("2009-02-03T05:26:32.612278")).build());
+   protected ImmutableList<SwiftObject> parsedObjectsForUrl(String baseUri) {
+      baseUri += "v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer";
+      return ImmutableList.of(//
+            SwiftObject.builder() //
+                  .name("test_obj_1") //
+                  .uri(URI.create(baseUri + "/test_obj_1")) //
+                  .hash("4281c348eaf83e70ddce0e07221c3d28") //
+                  .payload(payload(14, "application/octet-stream")) //
+                  .lastModified(dates.iso8601DateParse("2009-02-03T05:26:32.612278")).build(), //
+            SwiftObject.builder() //
+                  .name("test_obj_2") //
+                  .uri(URI.create(baseUri + "/test_obj_2")) //
+                  .hash("b039efe731ad111bc1b0ef221c3849d0") //
+                  .payload(payload(64l, "application/octet-stream")) //
+                  .lastModified(dates.iso8601DateParse("2009-02-03T05:26:32.612278")).build());
+   }
 
    public void listFirstPage() throws Exception {
       MockWebServer server = mockSwiftServer();
@@ -80,7 +86,7 @@ public class ObjectApiMockTest extends BaseSwiftMockTest {
          SwiftApi api = swiftApi(server.getUrl("/").toString());
          ImmutableList<SwiftObject> objects = api.objectApiInRegionForContainer("DFW", "myContainer").listFirstPage()
                .toList();
-         assertEquals(objects, parsedObjects);
+         assertEquals(objects, parsedObjectsForUrl(server.getUrl("/").toString()));
 
          assertEquals(server.getRequestCount(), 2);
          assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");
@@ -100,7 +106,7 @@ public class ObjectApiMockTest extends BaseSwiftMockTest {
          SwiftApi api = swiftApi(server.getUrl("/").toString());
          ImmutableList<SwiftObject> objects = api.objectApiInRegionForContainer("DFW", "myContainer").listAt("test")
                .toList();
-         assertEquals(objects, parsedObjects);
+         assertEquals(objects, parsedObjectsForUrl(server.getUrl("/").toString()));
 
          assertEquals(server.getRequestCount(), 2);
          assertEquals(server.takeRequest().getRequestLine(), "POST /tokens HTTP/1.1");