diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNConnection.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNConnection.java new file mode 100644 index 0000000000..9f7c9e79fc --- /dev/null +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNConnection.java @@ -0,0 +1,98 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles; + +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.HEAD; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata; +import org.jclouds.rackspace.cloudfiles.functions.ParseCdnUriFromHeaders; +import org.jclouds.rackspace.cloudfiles.functions.ParseContainerCDNMetadataFromHeaders; +import org.jclouds.rackspace.cloudfiles.functions.ParseContainerCDNMetadataListFromGsonResponse; +import org.jclouds.rackspace.cloudfiles.functions.ReturnContainerCDNMetadataNotFoundOn404; +import org.jclouds.rackspace.cloudfiles.functions.ReturnTrueOn202FalseOtherwise; +import org.jclouds.rackspace.cloudfiles.options.ListCdnContainerOptions; +import org.jclouds.rackspace.cloudfiles.reference.CloudFilesHeaders; +import org.jclouds.rackspace.filters.AuthenticateRequest; +import org.jclouds.rest.ExceptionParser; +import org.jclouds.rest.Header; +import org.jclouds.rest.Query; +import org.jclouds.rest.RequestFilters; +import org.jclouds.rest.ResponseParser; +import org.jclouds.rest.SkipEncoding; + +/** + * Provides access to the Cloud Files service's CDN offering via their REST API. + * + * @see + * @author James Murty + */ +@SkipEncoding('/') +@RequestFilters(AuthenticateRequest.class) +public interface CloudFilesCDNConnection { + + @GET + @ResponseParser(ParseContainerCDNMetadataListFromGsonResponse.class) + @Query(key = "format", value = "json") + @Path("/") + List listCDNContainers(ListCdnContainerOptions ... options); + + // TODO: Container name is not included in CDN HEAD response headers, so we cannot populate it here. + @HEAD + @ResponseParser(ParseContainerCDNMetadataFromHeaders.class) + @ExceptionParser(ReturnContainerCDNMetadataNotFoundOn404.class) + @Path("{container}") + ContainerCDNMetadata getCDNMetadata(@PathParam("container") String container); + + @PUT + @Path("{container}") + @ResponseParser(ParseCdnUriFromHeaders.class) + String enableCDN(@PathParam("container") String container, + @HeaderParam(CloudFilesHeaders.CDN_TTL) Long ttl); + + @PUT + @Path("{container}") + @ResponseParser(ParseCdnUriFromHeaders.class) + String enableCDN(@PathParam("container") String container); + + @POST + @Path("{container}") + @ResponseParser(ParseCdnUriFromHeaders.class) + String updateCDN(@PathParam("container") String container, + @HeaderParam(CloudFilesHeaders.CDN_TTL) Long ttl); + + @POST + @Path("{container}") + @Header(key = CloudFilesHeaders.CDN_ENABLED, value = "False") + @ResponseParser(ReturnTrueOn202FalseOtherwise.class) + boolean disableCDN(@PathParam("container") String container); + +} diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNContext.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNContext.java new file mode 100644 index 0000000000..969959cf04 --- /dev/null +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNContext.java @@ -0,0 +1,39 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles; + +import org.jclouds.cloud.CloudContext; + +/** + * Represents an authenticated context to Cloud Files CDN. + * + * @see + * @see CloudFilesCDNConnection + * @see CloudContext + * @author James Murty + * + */ +public interface CloudFilesCDNContext extends CloudContext { + +} \ No newline at end of file diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNContextBuilder.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNContextBuilder.java new file mode 100644 index 0000000000..862faf9aed --- /dev/null +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNContextBuilder.java @@ -0,0 +1,84 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles; + +import java.util.List; +import java.util.Properties; + +import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; +import org.jclouds.logging.jdk.config.JDKLoggingModule; +import org.jclouds.rackspace.RackspaceContextBuilder; +import org.jclouds.rackspace.cloudfiles.config.RestCloudFilesCDNConnectionModule; + +import com.google.inject.Injector; +import com.google.inject.Module; + +/** + * Creates {@link CloudFilesCDNContext} or {@link Injector} instances based on the most commonly + * requested arguments. + *

+ * Note that Threadsafe objects will be bound as singletons to the Injector or Context provided. + *

+ *

+ * If no Modules are specified, the default {@link JDKLoggingModule logging} and + * {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed. + * + * @author James Murty + * @see CloudFilesCDNContext, CloudFilesCDNContextBuilder + */ +public class CloudFilesCDNContextBuilder extends + RackspaceContextBuilder { + + public CloudFilesCDNContextBuilder(Properties props) { + super(props); + } + + public static CloudFilesCDNContextBuilder newBuilder(String id, String secret) { + Properties properties = new Properties(); + CloudFilesCDNContextBuilder builder = new CloudFilesCDNContextBuilder(properties); + builder.authenticate(id, secret); + return builder; + } + + protected void addConnectionModule(List modules) { + super.addConnectionModule(modules); + modules.add(new RestCloudFilesCDNConnectionModule()); + } + + @Override + protected void addContextModule(List modules) { + //TODO + } + + @Override + protected void addParserModule(List modules) { + //TODO + } + + @Override + public CloudFilesCDNContext buildContext() { + return buildInjector().getInstance(CloudFilesCDNContext.class); + } + +} diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/binders/CFObjectBinder.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/binders/CFObjectBinder.java index 10cc2f9e7c..91f1ce7bdf 100644 --- a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/binders/CFObjectBinder.java +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/binders/CFObjectBinder.java @@ -72,7 +72,7 @@ public class CFObjectBinder implements EntityBinder { String hexETag = HttpUtils.toHexString(object.getMetadata().getETag()); request.getHeaders().put(HttpHeaders.ETAG, hexETag); } catch (UnsupportedEncodingException e) { - throw new RuntimeException("Failed to encode ETag for object: " + object, e); + throw new RuntimeException("jclouds requires UTF-8 encoding" + object, e); } } diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/config/RestCloudFilesCDNConnectionModule.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/config/RestCloudFilesCDNConnectionModule.java new file mode 100644 index 0000000000..28fa00e164 --- /dev/null +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/config/RestCloudFilesCDNConnectionModule.java @@ -0,0 +1,63 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles.config; + +import java.net.URI; + +import org.jclouds.cloud.ConfiguresCloudConnection; +import org.jclouds.http.RequiresHttp; +import org.jclouds.rackspace.CDN; +import org.jclouds.rackspace.cloudfiles.CloudFilesCDNConnection; +import org.jclouds.rackspace.cloudfiles.CloudFilesCDNContext; +import org.jclouds.rackspace.cloudfiles.internal.GuiceCloudFilesCDNContext; +import org.jclouds.rest.RestClientFactory; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; + +/** + * Configures the Cloud Files CDN connection, including logging and http transport. + * This class supplies the CDN-specific URI required for the CDN operations in the + * Cloud Files service. + * + * @author James Murty + */ +@ConfiguresCloudConnection +@RequiresHttp +public class RestCloudFilesCDNConnectionModule extends AbstractModule { + + @Override + protected void configure() { + bind(CloudFilesCDNContext.class).to(GuiceCloudFilesCDNContext.class); + } + + @Provides + @Singleton + protected CloudFilesCDNConnection provideCDNConnection(@CDN URI cdnUri, + RestClientFactory factory) { + return factory.create(cdnUri, CloudFilesCDNConnection.class); + } + +} \ No newline at end of file diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/domain/ContainerCDNMetadata.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/domain/ContainerCDNMetadata.java new file mode 100644 index 0000000000..3d7d34eddd --- /dev/null +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/domain/ContainerCDNMetadata.java @@ -0,0 +1,133 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles.domain; + +/** + * + * @author James Murty + * + */ +public class ContainerCDNMetadata { + public static final ContainerCDNMetadata NOT_FOUND = new ContainerCDNMetadata(); + + private String name; + private long ttl; + private boolean cdn_enabled; + private String cdn_uri; + + public ContainerCDNMetadata(String name, boolean cdnEnabled, long ttl, String cdnUri) { + this.name = name; + this.cdn_enabled = cdnEnabled; + this.ttl = ttl; + this.cdn_uri = cdnUri; + } + + public ContainerCDNMetadata() { + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("ContainerCDNMetadata [name=").append(name) + .append(", cdn_enabled=").append(cdn_enabled) + .append(", ttl=").append(ttl) + .append(", cdn_uri=").append(cdn_uri).append("]"); + return builder.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + (cdn_enabled ? 1 : 0); + result = prime * result + (int) (ttl ^ (ttl >>> 32)); + result = prime * result + ((cdn_uri == null) ? 0 : cdn_uri.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ContainerCDNMetadata other = (ContainerCDNMetadata) obj; + if (cdn_enabled != other.cdn_enabled) + return false; + if (ttl != other.ttl) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (cdn_uri == null) { + if (other.cdn_uri != null) + return false; + } else if (!cdn_uri.equals(other.cdn_uri)) + return false; + return true; + } + + public void setName(String name) { + this.name = name; + } + + /** + * Beware: The container name is not available from HEAD CDN responses and will be null. + * return + * the name of the container to which these CDN settings apply. + */ + public String getName() { + return name; + } + + public void setCdnUri(String cdnUri) { + this.cdn_uri = cdnUri; + } + + public String getCdnUri() { + return cdn_uri; + } + + public void setTtl(long ttl) { + this.ttl = ttl; + } + + public long getTtl() { + return ttl; + } + + public void setCdnEnabled(boolean cdnEnabled) { + this.cdn_enabled = cdnEnabled; + } + + public boolean isCdnEnabled() { + return cdn_enabled; + } + +} diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseCdnUriFromHeaders.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseCdnUriFromHeaders.java new file mode 100644 index 0000000000..45eaae16f2 --- /dev/null +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseCdnUriFromHeaders.java @@ -0,0 +1,51 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.jclouds.http.HttpResponse; +import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata; +import org.jclouds.rackspace.cloudfiles.reference.CloudFilesHeaders; + +import com.google.common.base.Function; + +/** + * This parses {@link AccountMetadata} from HTTP headers. + * + * @author James Murty + */ +public class ParseCdnUriFromHeaders implements + Function { + + /** + * parses the http response headers to provide the CDN URI string. + */ + public String apply(final HttpResponse from) { + String cdnUri = checkNotNull( + from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_URI), + CloudFilesHeaders.CDN_URI); + return cdnUri; + } +} \ No newline at end of file diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseContainerCDNMetadataFromHeaders.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseContainerCDNMetadataFromHeaders.java new file mode 100644 index 0000000000..1523686b7c --- /dev/null +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseContainerCDNMetadataFromHeaders.java @@ -0,0 +1,70 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.jclouds.http.HttpResponse; +import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata; +import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata; +import org.jclouds.rackspace.cloudfiles.reference.CloudFilesHeaders; + +import com.google.common.base.Function; + +/** + * This parses {@link AccountMetadata} from HTTP headers. + * + * @author James Murty + */ +public class ParseContainerCDNMetadataFromHeaders implements + Function { + + /** + * parses the http response headers to create a new {@link ContainerCDNMetadata} object. + */ + public ContainerCDNMetadata apply(final HttpResponse from) { + // TODO: The container name is not returned as a header, hopefully one day it will be + String containerName = null; + + String cdnUri = checkNotNull( + from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_URI), + CloudFilesHeaders.CDN_URI); + String cdnTTL = checkNotNull( + from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_TTL), + CloudFilesHeaders.CDN_TTL); + String cdnEnabled = checkNotNull( + from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_ENABLED), + CloudFilesHeaders.CDN_ENABLED); + if (cdnUri == null) { + // CDN is not, and has never, been enabled for this container. + return ContainerCDNMetadata.NOT_FOUND; + } else { + return new ContainerCDNMetadata( + containerName, + Boolean.parseBoolean(cdnEnabled), + Long.parseLong(cdnTTL), + cdnUri); + } + } +} \ No newline at end of file diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseContainerCDNMetadataListFromGsonResponse.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseContainerCDNMetadataListFromGsonResponse.java new file mode 100644 index 0000000000..c8a3d18c8f --- /dev/null +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ParseContainerCDNMetadataListFromGsonResponse.java @@ -0,0 +1,61 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles.functions; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Type; +import java.util.List; + +import org.jclouds.http.functions.ParseJson; +import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.google.inject.Inject; + +/** + * This parses {@link ContainerCDNMetadata} from a gson string. + * + * @author James Murty + */ +public class ParseContainerCDNMetadataListFromGsonResponse extends ParseJson> + { + + @Inject + public ParseContainerCDNMetadataListFromGsonResponse(Gson gson) { + super(gson); + } + + public List apply(InputStream stream) { + Type listType = new TypeToken>() { + }.getType(); + try { + return gson.fromJson(new InputStreamReader(stream, "UTF-8"), listType); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("jclouds requires UTF-8 encoding", e); + } + } +} \ No newline at end of file diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ReturnContainerCDNMetadataNotFoundOn404.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ReturnContainerCDNMetadataNotFoundOn404.java new file mode 100644 index 0000000000..3d3e27875e --- /dev/null +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/functions/ReturnContainerCDNMetadataNotFoundOn404.java @@ -0,0 +1,43 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles.functions; + +import org.jclouds.http.HttpResponseException; +import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata; + +import com.google.common.base.Function; + +public class ReturnContainerCDNMetadataNotFoundOn404 implements Function { + + public ContainerCDNMetadata apply(Exception from) { + if (from instanceof HttpResponseException) { + HttpResponseException responseException = (HttpResponseException) from; + if (responseException.getResponse().getStatusCode() == 404) { + return ContainerCDNMetadata.NOT_FOUND; + } + } + return null; + } + +} diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/internal/GuiceCloudFilesCDNContext.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/internal/GuiceCloudFilesCDNContext.java new file mode 100644 index 0000000000..dbdc73a15a --- /dev/null +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/internal/GuiceCloudFilesCDNContext.java @@ -0,0 +1,78 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles.internal; + +import java.io.IOException; + +import javax.annotation.Resource; + +import org.jclouds.lifecycle.Closer; +import org.jclouds.logging.Logger; +import org.jclouds.rackspace.cloudfiles.CloudFilesCDNConnection; +import org.jclouds.rackspace.cloudfiles.CloudFilesCDNContext; + +import com.google.inject.Inject; +import com.google.inject.Injector; + +/** + * Uses a Guice Injector to configure the objects served by CloudFilesCDNContext methods. + * + * @author Adrian Cole + * @see Injector + */ +public class GuiceCloudFilesCDNContext implements CloudFilesCDNContext { + + @Resource + private Logger logger = Logger.NULL; + private final Injector injector; + private final Closer closer; + + @Inject + private GuiceCloudFilesCDNContext(Injector injector, Closer closer) { + this.injector = injector; + this.closer = closer; + } + + /** + * {@inheritDoc} + */ + public CloudFilesCDNConnection getConnection() { + return injector.getInstance(CloudFilesCDNConnection.class); + } + + + /** + * {@inheritDoc} + * + * @see Closer + */ + public void close() { + try { + closer.close(); + } catch (IOException e) { + logger.error(e, "error closing content"); + } + } + +} diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/options/ListCdnContainerOptions.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/options/ListCdnContainerOptions.java new file mode 100644 index 0000000000..29267c7ea2 --- /dev/null +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/options/ListCdnContainerOptions.java @@ -0,0 +1,45 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles.options; + + +/** + * Contains options supported in the REST API for the GET container operation.

+ */ +public class ListCdnContainerOptions extends ListContainerOptions { + public static final ListCdnContainerOptions NONE = new ListCdnContainerOptions(); + + public ListCdnContainerOptions isCdnEnabled(boolean enabledOnly) { + queryParameters.put("enabled_only", (enabledOnly ? "true" : "false")); + return this; + } + + public static class Builder extends ListContainerOptions.Builder { + public static ListCdnContainerOptions isCdnEnabled(boolean enabledOnly) { + ListCdnContainerOptions options = new ListCdnContainerOptions(); + return options.isCdnEnabled(enabledOnly); + } + } + +} diff --git a/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNConnectionLiveTest.java b/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNConnectionLiveTest.java new file mode 100644 index 0000000000..92dd9dc70c --- /dev/null +++ b/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/CloudFilesCDNConnectionLiveTest.java @@ -0,0 +1,137 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.rackspace.cloudfiles; + +import static org.jclouds.rackspace.reference.RackspaceConstants.PROPERTY_RACKSPACE_KEY; +import static org.jclouds.rackspace.reference.RackspaceConstants.PROPERTY_RACKSPACE_USER; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.List; + +import org.jclouds.logging.log4j.config.Log4JLoggingModule; +import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; + +/** + * Tests behavior of {@code JaxrsAnnotationProcessor} for Cloud Files CDN service. + * + * @author James Murty + */ +@Test(groups = "live", testName = "cloudfiles.CloudFilesAuthenticationLiveTest") +public class CloudFilesCDNConnectionLiveTest { + + protected static final String sysRackspaceUser = System.getProperty(PROPERTY_RACKSPACE_USER); + protected static final String sysRackspaceKey = System.getProperty(PROPERTY_RACKSPACE_KEY); + + private String bucketPrefix = System.getProperty("user.name") + ".cfcdnint"; + CloudFilesCDNConnection cdnConnection; + CloudFilesConnection filesConnection; + + @BeforeGroups(groups = { "live" }) + public void setupConnection() { + cdnConnection = CloudFilesCDNContextBuilder.newBuilder(sysRackspaceUser, sysRackspaceKey) + .withModule(new Log4JLoggingModule()).withJsonDebug().buildContext().getConnection(); + filesConnection = CloudFilesContextBuilder.newBuilder(sysRackspaceUser, sysRackspaceKey) + .withModule(new Log4JLoggingModule()).withJsonDebug().buildContext().getConnection(); + } + + @Test + public void testCDNOperations() throws Exception { + final long minimumTTL = 60 * 60; // The minimum TTL is 1 hour + + // Create two new containers for testing + final String containerNameWithCDN = bucketPrefix + ".testCDNOperationsContainerWithCDN"; + final String containerNameWithoutCDN = bucketPrefix + ".testCDNOperationsContainerWithoutCDN"; + assertTrue(filesConnection.putContainer(containerNameWithCDN)); + assertTrue(filesConnection.putContainer(containerNameWithoutCDN)); + + ContainerCDNMetadata cdnMetadata = null; + + // Enable CDN with PUT for one container + final String cdnUri = cdnConnection.enableCDN(containerNameWithCDN); + assertTrue(cdnUri != null); + assertTrue(cdnUri.startsWith("http://")); + + // Confirm CDN is enabled via HEAD request and has default TTL + cdnMetadata = cdnConnection.getCDNMetadata(containerNameWithCDN); + assertTrue(cdnMetadata.isCdnEnabled()); + assertEquals(cdnMetadata.getCdnUri(), cdnUri); + final long initialTTL = cdnMetadata.getTtl(); + + // Check HEAD responses for non-existent container, and container with no CDN metadata + cdnMetadata = cdnConnection.getCDNMetadata(containerNameWithoutCDN); + assertEquals(cdnMetadata, ContainerCDNMetadata.NOT_FOUND); + cdnMetadata = cdnConnection.getCDNMetadata("DoesNotExist"); + assertEquals(cdnMetadata, ContainerCDNMetadata.NOT_FOUND); + + // List CDN metadata for containers, and ensure all CDN info is available for enabled container + List cdnMetadataList = cdnConnection.listCDNContainers(); + assertTrue(Iterables.any(cdnMetadataList, new Predicate() { + public boolean apply(ContainerCDNMetadata cdnMetadata) { + return ( + cdnMetadata.getName().equals(containerNameWithCDN) && + cdnMetadata.isCdnEnabled() && + cdnMetadata.getTtl() == initialTTL && + cdnMetadata.getCdnUri().equals(cdnUri)); + } + })); + + // Enable CDN with PUT for the same container, this time with a custom TTL + long ttl = 4000; + cdnConnection.enableCDN(containerNameWithCDN, ttl); + + cdnMetadata = cdnConnection.getCDNMetadata(containerNameWithCDN); + assertTrue(cdnMetadata.isCdnEnabled()); + assertEquals(cdnMetadata.getTtl(), ttl); + + // Check POST by updating TTL settings + ttl = minimumTTL; + cdnConnection.updateCDN(containerNameWithCDN, minimumTTL); + + cdnMetadata = cdnConnection.getCDNMetadata(containerNameWithCDN); + assertTrue(cdnMetadata.isCdnEnabled()); + assertEquals(cdnMetadata.getTtl(), minimumTTL); + + // Confirm that minimum allowed value for TTL is 3600, lower values are ignored. + cdnConnection.updateCDN(containerNameWithCDN, 3599L); + cdnMetadata = cdnConnection.getCDNMetadata(containerNameWithCDN); + assertEquals(cdnMetadata.getTtl(), minimumTTL); // Note that TTL is 3600 here, not 3599 + + // Disable CDN with POST + assertTrue(cdnConnection.disableCDN(containerNameWithCDN)); + + cdnMetadata = cdnConnection.getCDNMetadata(containerNameWithCDN); + assertEquals(cdnMetadata.isCdnEnabled(), false); + + // Delete test containers + assertTrue(filesConnection.deleteContainerIfEmpty(containerNameWithCDN)); + assertTrue(filesConnection.deleteContainerIfEmpty(containerNameWithoutCDN)); + } + +}