mirror of https://github.com/apache/jclouds.git
Issue 111: first code for atmos online storage
git-svn-id: http://jclouds.googlecode.com/svn/trunk@2003 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
7171f2c431
commit
cfab82d775
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
$HeadURL$
|
||||
$Revision$
|
||||
$Date$
|
||||
|
||||
Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
|
||||
|
||||
====================================================================
|
||||
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.html
|
||||
|
||||
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.
|
||||
====================================================================
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>jclouds-project</artifactId>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../project/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jclouds-atmosonline-project</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>jclouds atmosonline project</name>
|
||||
<modules>
|
||||
<module>saas</module>
|
||||
</modules>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.14</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-log4j</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
$HeadURL$
|
||||
$Revision$
|
||||
$Date$
|
||||
|
||||
Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
|
||||
|
||||
====================================================================
|
||||
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.html
|
||||
|
||||
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.
|
||||
====================================================================
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-emcsaas-project</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-emcsaas</artifactId>
|
||||
<name>jclouds atmosonline storage service core</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>jclouds Core components to access atmosonline saas</description>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/mezo/saas/core</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/mezo/saas/core</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk/mezo/saas/core</url>
|
||||
</scm>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
|
||||
/**
|
||||
* Related to a EMC Atmos Online Storage resource.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
|
||||
@Qualifier
|
||||
public @interface AtmosStorage {
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.atmosonline.saas.binders.BindAtmosObjectToEntityAndMetadataToHeaders;
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.atmosonline.saas.domain.DirectoryEntry;
|
||||
import org.jclouds.atmosonline.saas.filters.SignRequest;
|
||||
import org.jclouds.atmosonline.saas.functions.AtmosObjectName;
|
||||
import org.jclouds.atmosonline.saas.functions.ParseObjectFromHeadersAndHttpContent;
|
||||
import org.jclouds.atmosonline.saas.xml.ListDirectoryResponseHandler;
|
||||
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.rest.annotations.BinderParam;
|
||||
import org.jclouds.rest.annotations.Endpoint;
|
||||
import org.jclouds.rest.annotations.ExceptionParser;
|
||||
import org.jclouds.rest.annotations.ParamParser;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.annotations.SkipEncoding;
|
||||
import org.jclouds.rest.annotations.XMLResponseParser;
|
||||
|
||||
/**
|
||||
* Provides access to EMC Atmos Online Storage resources via their REST API.
|
||||
* <p/>
|
||||
*
|
||||
* @see <a href="https://community.emc.com/community/labs/atmos_online" />
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Endpoint(AtmosStorage.class)
|
||||
@RequestFilters(SignRequest.class)
|
||||
@SkipEncoding( { '/' })
|
||||
public interface AtmosStorageClient {
|
||||
|
||||
AtmosObject newObject();
|
||||
|
||||
@GET
|
||||
@Path("/rest/namespace")
|
||||
@XMLResponseParser(ListDirectoryResponseHandler.class)
|
||||
@Consumes(MediaType.TEXT_XML)
|
||||
SortedSet<DirectoryEntry> listDirectories();
|
||||
|
||||
@GET
|
||||
@Path("/rest/namespace/{directoryName}/")
|
||||
@XMLResponseParser(ListDirectoryResponseHandler.class)
|
||||
@Consumes(MediaType.TEXT_XML)
|
||||
SortedSet<DirectoryEntry> listDirectory(@PathParam("directoryName") String directoryName);
|
||||
|
||||
@POST
|
||||
@Path("/rest/namespace/{directoryName}/")
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
URI createDirectory(@PathParam("directoryName") String directoryName);
|
||||
|
||||
@POST
|
||||
@Path("/rest/namespace/{parent}/{name}")
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
Future<URI> createFile(
|
||||
@PathParam("parent") String parent,
|
||||
@PathParam("name") @ParamParser(AtmosObjectName.class) @BinderParam(BindAtmosObjectToEntityAndMetadataToHeaders.class) AtmosObject object);
|
||||
|
||||
@GET
|
||||
@ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
|
||||
@ExceptionParser(ThrowKeyNotFoundOn404.class)
|
||||
@Path("/rest/namespace/{path}")
|
||||
Future<AtmosObject> readFile(@PathParam("path") String path, GetOptions... options);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.jclouds.atmosonline.saas.config.AtmosStorageContextModule;
|
||||
import org.jclouds.atmosonline.saas.config.AtmosStorageRestClientModule;
|
||||
import org.jclouds.rest.RestContextBuilder;
|
||||
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AtmosStorageContextBuilder extends RestContextBuilder<AtmosStorageClient> {
|
||||
|
||||
public AtmosStorageContextBuilder(Properties props) {
|
||||
super(new TypeLiteral<AtmosStorageClient>() {
|
||||
}, props);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addClientModule(List<Module> modules) {
|
||||
modules.add(new AtmosStorageRestClientModule());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addContextModule(List<Module> modules) {
|
||||
modules.add(new AtmosStorageContextModule());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AtmosStorageContextBuilder withExecutorService(ExecutorService service) {
|
||||
return (AtmosStorageContextBuilder) super.withExecutorService(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AtmosStorageContextBuilder withModules(Module... modules) {
|
||||
return (AtmosStorageContextBuilder) super.withModules(modules);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.atmosonline.saas.reference.AtmosStorageConstants;
|
||||
import org.jclouds.http.HttpPropertiesBuilder;
|
||||
|
||||
/**
|
||||
* Builds properties used in AtmosStorage Connections
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AtmosStoragePropertiesBuilder extends HttpPropertiesBuilder {
|
||||
@Override
|
||||
protected Properties defaultProperties() {
|
||||
Properties properties = super.defaultProperties();
|
||||
properties.setProperty(AtmosStorageConstants.PROPERTY_EMCSAAS_ENDPOINT,
|
||||
"http://accesspoint.emccis.com");
|
||||
properties.setProperty(AtmosStorageConstants.PROPERTY_EMCSAAS_SESSIONINTERVAL, "60");
|
||||
return properties;
|
||||
}
|
||||
|
||||
public AtmosStoragePropertiesBuilder(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
public AtmosStoragePropertiesBuilder(String uid, String key) {
|
||||
super();
|
||||
withCredentials(uid, key);
|
||||
}
|
||||
|
||||
public AtmosStoragePropertiesBuilder withCredentials(String uid, String key) {
|
||||
properties.setProperty(AtmosStorageConstants.PROPERTY_EMCSAAS_UID, checkNotNull(uid, "uid"));
|
||||
properties.setProperty(AtmosStorageConstants.PROPERTY_EMCSAAS_KEY, checkNotNull(key, "key"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public AtmosStoragePropertiesBuilder withEndpoint(URI endpoint) {
|
||||
properties.setProperty(AtmosStorageConstants.PROPERTY_EMCSAAS_ENDPOINT, checkNotNull(
|
||||
endpoint, "endpoint").toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public AtmosStoragePropertiesBuilder withTimeStampExpiration(long seconds) {
|
||||
properties.setProperty(AtmosStorageConstants.PROPERTY_EMCSAAS_SESSIONINTERVAL, seconds + "");
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosStorageError;
|
||||
import org.jclouds.atmosonline.saas.handlers.ParseAtmosStorageErrorFromXmlContent;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
|
||||
/**
|
||||
* Encapsulates an Error from Atmos Storage Services.
|
||||
*
|
||||
* @see AtmosStorageError
|
||||
* @see ParseAtmosStorageErrorFromXmlContent
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public class AtmosStorageResponseException extends HttpResponseException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private AtmosStorageError error;
|
||||
|
||||
public AtmosStorageResponseException(HttpCommand command, HttpResponse response,
|
||||
AtmosStorageError error) {
|
||||
super(String.format("command %s failed with code %s, error: %s", command.toString(), response
|
||||
.getStatusCode(), error.toString()), command, response);
|
||||
this.setError(error);
|
||||
|
||||
}
|
||||
|
||||
public AtmosStorageResponseException(HttpCommand command, HttpResponse response,
|
||||
AtmosStorageError error, Throwable cause) {
|
||||
super(String.format("command %1$s failed with error: %2$s", command.toString(), error
|
||||
.toString()), command, response, cause);
|
||||
this.setError(error);
|
||||
|
||||
}
|
||||
|
||||
public AtmosStorageResponseException(String message, HttpCommand command, HttpResponse response,
|
||||
AtmosStorageError error) {
|
||||
super(message, command, response);
|
||||
this.setError(error);
|
||||
|
||||
}
|
||||
|
||||
public AtmosStorageResponseException(String message, HttpCommand command, HttpResponse response,
|
||||
AtmosStorageError error, Throwable cause) {
|
||||
super(message, command, response, cause);
|
||||
this.setError(error);
|
||||
|
||||
}
|
||||
|
||||
public void setError(AtmosStorageError error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public AtmosStorageError getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package org.jclouds.atmosonline.saas.binders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
public class BindAtmosObjectToEntityAndMetadataToHeaders implements Binder {
|
||||
private final BindUserMetadataToHeaders metaBinder;
|
||||
|
||||
@Inject
|
||||
protected BindAtmosObjectToEntityAndMetadataToHeaders(BindUserMetadataToHeaders metaBinder) {
|
||||
this.metaBinder = metaBinder;
|
||||
}
|
||||
|
||||
public void bindToRequest(HttpRequest request, Object entity) {
|
||||
AtmosObject object = (AtmosObject) entity;
|
||||
|
||||
request.setEntity(checkNotNull(object.getData(), "object.getContent()"));
|
||||
request.getHeaders().put(
|
||||
HttpHeaders.CONTENT_TYPE,
|
||||
checkNotNull(object.getContentMetadata().getContentType(),
|
||||
"object.metadata.contentType()"));
|
||||
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH,
|
||||
object.getContentMetadata().getContentLength() + "");
|
||||
|
||||
if (object.getContentMetadata().getContentMD5() != null) {
|
||||
request.getHeaders().put("Content-MD5",
|
||||
HttpUtils.toBase64String(object.getContentMetadata().getContentMD5()));
|
||||
}
|
||||
metaBinder.bindToRequest(request, object.getUserMetadata());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package org.jclouds.atmosonline.saas.binders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.UserMetadata;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
public class BindUserMetadataToHeaders implements Binder {
|
||||
|
||||
public void bindToRequest(HttpRequest request, Object entity) {
|
||||
UserMetadata md = (UserMetadata) checkNotNull(entity, "entity");
|
||||
if (md.getMetadata().size() > 0) {
|
||||
String header = join(md.getMetadata());
|
||||
request.getHeaders().put("x-emc-meta", header);
|
||||
}
|
||||
if (md.getListableMetadata().size() > 0) {
|
||||
String header = join(md.getListableMetadata());
|
||||
request.getHeaders().put("x-emc-listable-meta", header);
|
||||
}
|
||||
if (md.getTags().size() > 0) {
|
||||
String header = join(md.getTags());
|
||||
request.getHeaders().put("x-emc-tags", header);
|
||||
}
|
||||
if (md.getListableTags().size() > 0) {
|
||||
String header = join(md.getListableTags());
|
||||
request.getHeaders().put("x-emc-listable-tags", header);
|
||||
}
|
||||
}
|
||||
|
||||
private String join(Set<String> set) {
|
||||
StringBuffer header = new StringBuffer();
|
||||
for (String entry : set) {
|
||||
header.append(entry).append(",");
|
||||
}
|
||||
header.deleteCharAt(header.length() - 1);
|
||||
return header.toString();
|
||||
}
|
||||
|
||||
private String join(Map<String, String> map) {
|
||||
StringBuffer header = new StringBuffer();
|
||||
for (Entry<String, String> entry : map.entrySet()) {
|
||||
header.append(entry.getKey()).append("=").append(entry.getValue()).append(",");
|
||||
}
|
||||
header.deleteCharAt(header.length() - 1);
|
||||
return header.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package org.jclouds.atmosonline.saas.blobstore.functions;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.blobstore.domain.Blob.Factory;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ObjectToBlob implements Function<AtmosObject, Blob> {
|
||||
private final Blob.Factory blobFactory;
|
||||
private final ObjectToBlobMetadata object2BlobMd;
|
||||
|
||||
@Inject
|
||||
ObjectToBlob(Factory blobFactory, ObjectToBlobMetadata object2BlobMd) {
|
||||
this.blobFactory = blobFactory;
|
||||
this.object2BlobMd = object2BlobMd;
|
||||
}
|
||||
|
||||
public Blob apply(AtmosObject from) {
|
||||
Blob blob = blobFactory.create(object2BlobMd.apply(from));
|
||||
if (from.getContentMetadata().getContentLength() != null)
|
||||
blob.setContentLength(from.getContentMetadata().getContentLength());
|
||||
blob.setData(from.getData());
|
||||
blob.setAllHeaders(from.getAllHeaders());
|
||||
return blob;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package org.jclouds.atmosonline.saas.blobstore.functions;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.atmosonline.saas.functions.AtmosObjectName;
|
||||
import org.jclouds.blobstore.domain.MutableBlobMetadata;
|
||||
import org.jclouds.blobstore.domain.ResourceType;
|
||||
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ObjectToBlobMetadata implements Function<AtmosObject, MutableBlobMetadata> {
|
||||
private final AtmosObjectName objectName;
|
||||
|
||||
@Inject
|
||||
protected ObjectToBlobMetadata(AtmosObjectName objectName) {
|
||||
this.objectName = objectName;
|
||||
}
|
||||
|
||||
public MutableBlobMetadata apply(AtmosObject from) {
|
||||
MutableBlobMetadata to = new MutableBlobMetadataImpl();
|
||||
to.setId(from.getSystemMetadata().getObjectID());
|
||||
to.setLastModified(from.getSystemMetadata().getLastUserDataModification());
|
||||
to.setContentMD5(from.getContentMetadata().getContentMD5());
|
||||
if (from.getContentMetadata().getContentType() != null)
|
||||
to.setContentType(from.getContentMetadata().getContentType());
|
||||
to.setName(objectName.apply(from));
|
||||
to.setSize(from.getSystemMetadata().getSize());
|
||||
to.setType(ResourceType.BLOB);
|
||||
to.setUserMetadata(from.getUserMetadata().getMetadata());
|
||||
if (from.getContentMetadata().getContentType() != null
|
||||
&& from.getContentMetadata().getContentType().equals("application/directory")) {
|
||||
to.setType(ResourceType.RELATIVE_PATH);
|
||||
}
|
||||
return to;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package org.jclouds.atmosonline.saas.config;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.atmosonline.saas.domain.MutableContentMetadata;
|
||||
import org.jclouds.atmosonline.saas.domain.SystemMetadata;
|
||||
import org.jclouds.atmosonline.saas.domain.UserMetadata;
|
||||
import org.jclouds.atmosonline.saas.domain.internal.AtmosObjectImpl;
|
||||
import org.jclouds.blobstore.functions.CalculateSize;
|
||||
import org.jclouds.blobstore.functions.GenerateMD5;
|
||||
import org.jclouds.blobstore.functions.GenerateMD5Result;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Scopes;
|
||||
|
||||
/**
|
||||
* Configures the domain object mappings needed for all Atmos implementations
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AtmosObjectModule extends AbstractModule {
|
||||
|
||||
/**
|
||||
* explicit factories are created here as it has been shown that Assisted Inject is extremely
|
||||
* inefficient. http://code.google.com/p/google-guice/issues/detail?id=435
|
||||
*/
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(AtmosObject.Factory.class).to(AtmosObjectFactory.class).in(Scopes.SINGLETON);
|
||||
}
|
||||
|
||||
private static class AtmosObjectFactory implements AtmosObject.Factory {
|
||||
@Inject
|
||||
GenerateMD5Result generateMD5Result;
|
||||
@Inject
|
||||
GenerateMD5 generateMD5;
|
||||
@Inject
|
||||
CalculateSize calculateSize;
|
||||
@Inject
|
||||
Provider<MutableContentMetadata> metadataProvider;
|
||||
|
||||
public AtmosObject create(MutableContentMetadata contentMetadata) {
|
||||
return new AtmosObjectImpl(generateMD5Result, generateMD5, calculateSize,
|
||||
contentMetadata != null ? contentMetadata : metadataProvider.get());
|
||||
}
|
||||
|
||||
public AtmosObject create(SystemMetadata systemMetadata, UserMetadata userMetadata) {
|
||||
return new AtmosObjectImpl(generateMD5Result, generateMD5, calculateSize, metadataProvider
|
||||
.get(), systemMetadata, userMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
AtmosObject provideAtmosObject(AtmosObject.Factory factory) {
|
||||
return factory.create((MutableContentMetadata) null);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.config;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.atmosonline.saas.AtmosStorage;
|
||||
import org.jclouds.atmosonline.saas.AtmosStorageClient;
|
||||
import org.jclouds.atmosonline.saas.reference.AtmosStorageConstants;
|
||||
import org.jclouds.blobstore.config.BlobStoreObjectModule;
|
||||
import org.jclouds.http.RequiresHttp;
|
||||
import org.jclouds.lifecycle.Closer;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.rest.internal.RestContextImpl;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
@RequiresHttp
|
||||
public class AtmosStorageContextModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
// for converters to work.
|
||||
install(new BlobStoreObjectModule());
|
||||
install(new AtmosObjectModule());
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
RestContext<AtmosStorageClient> provideContext(Closer closer, AtmosStorageClient defaultApi,
|
||||
@AtmosStorage URI endPoint,
|
||||
@Named(AtmosStorageConstants.PROPERTY_EMCSAAS_UID) String account) {
|
||||
return new RestContextImpl<AtmosStorageClient>(closer, defaultApi, endPoint, account);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.config;
|
||||
|
||||
import static org.jclouds.atmosonline.saas.reference.AtmosStorageConstants.PROPERTY_EMCSAAS_ENDPOINT;
|
||||
import static org.jclouds.atmosonline.saas.reference.AtmosStorageConstants.PROPERTY_EMCSAAS_SESSIONINTERVAL;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.atmosonline.saas.AtmosStorage;
|
||||
import org.jclouds.atmosonline.saas.AtmosStorageClient;
|
||||
import org.jclouds.atmosonline.saas.handlers.AtmosStorageClientErrorRetryHandler;
|
||||
import org.jclouds.atmosonline.saas.handlers.ParseAtmosStorageErrorFromXmlContent;
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
import org.jclouds.http.RequiresHttp;
|
||||
import org.jclouds.http.annotation.ClientError;
|
||||
import org.jclouds.http.annotation.Redirection;
|
||||
import org.jclouds.http.annotation.ServerError;
|
||||
import org.jclouds.rest.ConfiguresRestClient;
|
||||
import org.jclouds.rest.RestClientFactory;
|
||||
import org.jclouds.util.DateService;
|
||||
import org.jclouds.util.TimeStamp;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
* Configures the EMC Atmos Online Storage authentication service connection, including logging and
|
||||
* http transport.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresRestClient
|
||||
@RequiresHttp
|
||||
public class AtmosStorageRestClientModule extends AbstractModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
@AtmosStorage
|
||||
protected URI provideAuthenticationURI(@Named(PROPERTY_EMCSAAS_ENDPOINT) String endpoint) {
|
||||
return URI.create(endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bindErrorHandlers();
|
||||
bindRetryHandlers();
|
||||
}
|
||||
|
||||
@Provides
|
||||
protected AtmosStorageClient provideClient(RestClientFactory factory) {
|
||||
return factory.create(AtmosStorageClient.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@TimeStamp
|
||||
protected String provideTimeStamp(@TimeStamp ConcurrentMap<String, String> cache) {
|
||||
return cache.get("doesn't matter");
|
||||
}
|
||||
|
||||
/**
|
||||
* borrowing concurrency code to ensure that caching takes place properly
|
||||
*/
|
||||
@Provides
|
||||
@TimeStamp
|
||||
ConcurrentMap<String, String> provideTimeStampCache(
|
||||
@Named(PROPERTY_EMCSAAS_SESSIONINTERVAL) long seconds, final DateService dateService) {
|
||||
return new MapMaker().expiration(seconds, TimeUnit.SECONDS).makeComputingMap(
|
||||
new Function<String, String>() {
|
||||
public String apply(String key) {
|
||||
return dateService.rfc822DateFormat();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void bindErrorHandlers() {
|
||||
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
|
||||
ParseAtmosStorageErrorFromXmlContent.class);
|
||||
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(
|
||||
ParseAtmosStorageErrorFromXmlContent.class);
|
||||
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(
|
||||
ParseAtmosStorageErrorFromXmlContent.class);
|
||||
}
|
||||
|
||||
protected void bindRetryHandlers() {
|
||||
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(
|
||||
AtmosStorageClientErrorRetryHandler.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package org.jclouds.atmosonline.saas.domain;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.inject.internal.Nullable;
|
||||
|
||||
/**
|
||||
* Amazon Atmos is designed to store objects. Objects are stored in buckets and consist of a
|
||||
* {@link ObjectMetadataAtmosObject#getData() value}, a {@link ObjectMetadata#getKey key},
|
||||
* {@link ObjectMetadata#getUserMetadata() metadata}, and an access control policy.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
* @see <a
|
||||
* href="http://docs.amazonwebservices.com/AmazonAtmos/2006-03-01/index.html?UsingObjects.html"
|
||||
* />
|
||||
*/
|
||||
public interface AtmosObject extends Comparable<AtmosObject> {
|
||||
public interface Factory {
|
||||
AtmosObject create(@Nullable MutableContentMetadata contentMetadata);
|
||||
|
||||
AtmosObject create(SystemMetadata systemMetadata, UserMetadata userMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* generate an MD5 Hash for the current data.
|
||||
* <p/>
|
||||
* <h2>Note</h2>
|
||||
* <p/>
|
||||
* If this is an InputStream, it will be converted to a byte array first.
|
||||
*
|
||||
* @throws IOException
|
||||
* if there is a problem generating the hash.
|
||||
*/
|
||||
void generateMD5() throws IOException;
|
||||
|
||||
/**
|
||||
* Sets entity for the request or the content from the response. If size isn't set, this will
|
||||
* attempt to discover it.
|
||||
*
|
||||
* @param data
|
||||
* typically InputStream for downloads, or File, byte [], String, or InputStream for
|
||||
* uploads.
|
||||
*/
|
||||
void setData(Object data);
|
||||
|
||||
/**
|
||||
* @return InputStream, if downloading, or whatever was set during {@link #setData(Object)}
|
||||
*/
|
||||
Object getData();
|
||||
|
||||
MutableContentMetadata getContentMetadata();
|
||||
|
||||
/**
|
||||
* @return System and User metadata relevant to this object.
|
||||
*/
|
||||
SystemMetadata getSystemMetadata();
|
||||
|
||||
UserMetadata getUserMetadata();
|
||||
|
||||
Multimap<String, String> getAllHeaders();
|
||||
|
||||
void setAllHeaders(Multimap<String, String> allHeaders);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.domain;
|
||||
|
||||
/**
|
||||
* When an Atmos Storage request is in error, the client receives an error response.
|
||||
*
|
||||
* Provides access to EMC Atmos Online Storage resources via their REST API.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public class AtmosStorageError {
|
||||
private final int code;
|
||||
private final String message;
|
||||
private String stringSigned;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AtmosStorageError [code=" + code + ", message=" + message + ", stringSigned="
|
||||
+ stringSigned + "]";
|
||||
}
|
||||
|
||||
public AtmosStorageError(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setStringSigned(String stringSigned) {
|
||||
this.stringSigned = stringSigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return what jclouds signed before sending the request.
|
||||
*/
|
||||
public String getStringSigned() {
|
||||
return stringSigned;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.domain;
|
||||
|
||||
/**
|
||||
* Metadata of a Atmos Online object
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class DirectoryEntry implements Comparable<DirectoryEntry> {
|
||||
private final String objectid;
|
||||
private final FileType type;
|
||||
private final String objname;
|
||||
|
||||
public DirectoryEntry(String objectid, FileType type, String objname) {
|
||||
this.objectid = objectid;
|
||||
this.objname = objname;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getObjectID() {
|
||||
return objectid;
|
||||
}
|
||||
|
||||
public String getObjectName() {
|
||||
return objname;
|
||||
}
|
||||
|
||||
public FileType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int compareTo(DirectoryEntry o) {
|
||||
if (getObjectName() == null)
|
||||
return -1;
|
||||
return (this == o) ? 0 : getObjectName().compareTo(o.getObjectName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((objectid == null) ? 0 : objectid.hashCode());
|
||||
result = prime * result + ((objname == null) ? 0 : objname.hashCode());
|
||||
result = prime * result + ((type == null) ? 0 : type.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;
|
||||
DirectoryEntry other = (DirectoryEntry) obj;
|
||||
if (objectid == null) {
|
||||
if (other.objectid != null)
|
||||
return false;
|
||||
} else if (!objectid.equals(other.objectid))
|
||||
return false;
|
||||
if (objname == null) {
|
||||
if (other.objname != null)
|
||||
return false;
|
||||
} else if (!objname.equals(other.objname))
|
||||
return false;
|
||||
if (type == null) {
|
||||
if (other.type != null)
|
||||
return false;
|
||||
} else if (!type.equals(other.type))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.domain;
|
||||
|
||||
public enum FileType {
|
||||
|
||||
DIRECTORY, REGULAR;
|
||||
|
||||
public String value() {
|
||||
return name().toLowerCase();
|
||||
}
|
||||
|
||||
public static FileType fromValue(String v) {
|
||||
return valueOf(v.toUpperCase());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.domain;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
/**
|
||||
* metadata of the object
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class MutableContentMetadata {
|
||||
|
||||
private String name;
|
||||
private Long contentLength;
|
||||
private String contentType = MediaType.APPLICATION_OCTET_STREAM;
|
||||
private byte[] contentMD5;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total size of the downloaded object, or the chunk that's available.
|
||||
* <p/>
|
||||
* Chunking is only used when org.jclouds.http.GetOptions is called with options like tail,
|
||||
* range, or startAt.
|
||||
*
|
||||
* @return the length in bytes that can be be obtained from {@link #getData()}
|
||||
* @see org.jclouds.http.HttpHeaders#CONTENT_LENGTH
|
||||
* @see GetObjectOptions
|
||||
*/
|
||||
public Long getContentLength() {
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getContentLength
|
||||
*/
|
||||
public void setContentLength(long contentLength) {
|
||||
this.contentLength = contentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* A standard MIME type describing the format of the contents. If none is provided, the default
|
||||
* is binary/octet-stream.
|
||||
*
|
||||
* @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17"/>
|
||||
*/
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getContentType
|
||||
*/
|
||||
public void setContentType(String contentType) {
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The 128-bit MD5 digest of the message (without the headers) according to RFC 1864. This header
|
||||
* can be used as a message integrity check to verify that the data is the same data that was
|
||||
* originally sent. Although it is optional, we recommend using the Content-MD5 mechanism as an
|
||||
* end-to-end integrity check.
|
||||
*
|
||||
*/
|
||||
public byte[] getContentMD5() {
|
||||
return contentMD5;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getContentMD5
|
||||
*/
|
||||
public void setContentMD5(byte[] contentMD5) {
|
||||
this.contentMD5 = contentMD5;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.domain;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Metadata of a Atmos Online object
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class SystemMetadata extends DirectoryEntry {
|
||||
|
||||
private final DateTime atime;
|
||||
private final DateTime ctime;
|
||||
private final String gid;
|
||||
private final DateTime itime;
|
||||
private final DateTime mtime;
|
||||
private final int nlink;
|
||||
private final String policyname;
|
||||
private final long size;
|
||||
private final String uid;
|
||||
|
||||
public SystemMetadata(DateTime atime, DateTime ctime, String gid, DateTime itime,
|
||||
DateTime mtime, int nlink, String objectid, String objname, String policyname,
|
||||
long size, FileType type, String uid) {
|
||||
super(objectid, type, objname);
|
||||
this.atime = atime;
|
||||
this.ctime = ctime;
|
||||
this.gid = gid;
|
||||
this.itime = itime;
|
||||
this.mtime = mtime;
|
||||
this.nlink = nlink;
|
||||
this.policyname = policyname;
|
||||
this.size = size;
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
public String getGroupID() {
|
||||
return gid;
|
||||
}
|
||||
|
||||
public int getHardLinkCount() {
|
||||
return nlink;
|
||||
}
|
||||
|
||||
public DateTime getInceptionTime() {
|
||||
return itime;
|
||||
}
|
||||
|
||||
public DateTime getLastAccessTime() {
|
||||
return atime;
|
||||
}
|
||||
|
||||
public DateTime getLastMetadataModification() {
|
||||
return mtime;
|
||||
}
|
||||
|
||||
public DateTime getLastUserDataModification() {
|
||||
return ctime;
|
||||
}
|
||||
|
||||
public String getPolicyName() {
|
||||
return policyname;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getUserID() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((atime == null) ? 0 : atime.hashCode());
|
||||
result = prime * result + ((ctime == null) ? 0 : ctime.hashCode());
|
||||
result = prime * result + ((gid == null) ? 0 : gid.hashCode());
|
||||
result = prime * result + ((itime == null) ? 0 : itime.hashCode());
|
||||
result = prime * result + ((mtime == null) ? 0 : mtime.hashCode());
|
||||
result = prime * result + nlink;
|
||||
result = prime * result + ((policyname == null) ? 0 : policyname.hashCode());
|
||||
result = prime * result + (int) (size ^ (size >>> 32));
|
||||
result = prime * result + ((uid == null) ? 0 : uid.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
SystemMetadata other = (SystemMetadata) obj;
|
||||
if (atime == null) {
|
||||
if (other.atime != null)
|
||||
return false;
|
||||
} else if (!atime.equals(other.atime))
|
||||
return false;
|
||||
if (ctime == null) {
|
||||
if (other.ctime != null)
|
||||
return false;
|
||||
} else if (!ctime.equals(other.ctime))
|
||||
return false;
|
||||
if (gid == null) {
|
||||
if (other.gid != null)
|
||||
return false;
|
||||
} else if (!gid.equals(other.gid))
|
||||
return false;
|
||||
if (itime == null) {
|
||||
if (other.itime != null)
|
||||
return false;
|
||||
} else if (!itime.equals(other.itime))
|
||||
return false;
|
||||
if (mtime == null) {
|
||||
if (other.mtime != null)
|
||||
return false;
|
||||
} else if (!mtime.equals(other.mtime))
|
||||
return false;
|
||||
if (nlink != other.nlink)
|
||||
return false;
|
||||
if (policyname == null) {
|
||||
if (other.policyname != null)
|
||||
return false;
|
||||
} else if (!policyname.equals(other.policyname))
|
||||
return false;
|
||||
if (size != other.size)
|
||||
return false;
|
||||
if (uid == null) {
|
||||
if (other.uid != null)
|
||||
return false;
|
||||
} else if (!uid.equals(other.uid))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.domain;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public class UploadInfo {
|
||||
private final String token;
|
||||
private final URI host;
|
||||
|
||||
public UploadInfo(String token, URI host) {
|
||||
this.token = token;
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public URI getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.domain;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* User metadata
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class UserMetadata {
|
||||
private final SortedMap<String, String> metadata = Maps.newTreeMap();
|
||||
private final SortedMap<String, String> listableMetadata = Maps.newTreeMap();
|
||||
private final SortedSet<String> tags = Sets.newTreeSet();
|
||||
private final SortedSet<String> listableTags = Sets.newTreeSet();
|
||||
|
||||
public Map<String, String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public Map<String, String> getListableMetadata() {
|
||||
return listableMetadata;
|
||||
}
|
||||
|
||||
public Set<String> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public Set<String> getListableTags() {
|
||||
return listableTags;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
package org.jclouds.atmosonline.saas.domain.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.atmosonline.saas.domain.MutableContentMetadata;
|
||||
import org.jclouds.atmosonline.saas.domain.SystemMetadata;
|
||||
import org.jclouds.atmosonline.saas.domain.UserMetadata;
|
||||
import org.jclouds.blobstore.domain.MD5InputStreamResult;
|
||||
import org.jclouds.blobstore.functions.CalculateSize;
|
||||
import org.jclouds.blobstore.functions.GenerateMD5;
|
||||
import org.jclouds.blobstore.functions.GenerateMD5Result;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* Default Implementation of {@link AtmosObject}.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AtmosObjectImpl implements AtmosObject, Comparable<AtmosObject> {
|
||||
private final UserMetadata userMetadata;
|
||||
private final GenerateMD5Result generateMD5Result;
|
||||
private final GenerateMD5 generateMD5;
|
||||
private final CalculateSize calculateSize;
|
||||
private final MutableContentMetadata contentMetadata;
|
||||
private final SystemMetadata systemMetadata;
|
||||
private Object data;
|
||||
|
||||
private Multimap<String, String> allHeaders = HashMultimap.create();
|
||||
|
||||
public AtmosObjectImpl(GenerateMD5Result generateMD5Result, GenerateMD5 generateMD5,
|
||||
CalculateSize calculateSize, MutableContentMetadata contentMetadata) {
|
||||
this(generateMD5Result, generateMD5, calculateSize, contentMetadata, null, new UserMetadata());
|
||||
}
|
||||
|
||||
public AtmosObjectImpl(GenerateMD5Result generateMD5Result, GenerateMD5 generateMD5,
|
||||
CalculateSize calculateSize, MutableContentMetadata contentMetadata,
|
||||
SystemMetadata systemMetadata, UserMetadata userMetadata) {
|
||||
this.generateMD5Result = generateMD5Result;
|
||||
this.generateMD5 = generateMD5;
|
||||
this.calculateSize = calculateSize;
|
||||
this.contentMetadata = contentMetadata;
|
||||
this.systemMetadata = systemMetadata;
|
||||
this.userMetadata = userMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void generateMD5() {
|
||||
checkState(data != null, "data");
|
||||
if (data instanceof InputStream) {
|
||||
MD5InputStreamResult result = generateMD5Result.apply((InputStream) data);
|
||||
getContentMetadata().setContentMD5(result.md5);
|
||||
getContentMetadata().setContentLength(result.length);
|
||||
setData(result.data);
|
||||
} else {
|
||||
getContentMetadata().setContentMD5(generateMD5.apply(data));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void setData(Object data) {
|
||||
this.data = checkNotNull(data, "data");
|
||||
if (getContentMetadata().getContentLength() == null) {
|
||||
Long size = calculateSize.apply(data);
|
||||
if (size != null)
|
||||
getContentMetadata().setContentLength(size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public MutableContentMetadata getContentMetadata() {
|
||||
return contentMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Multimap<String, String> getAllHeaders() {
|
||||
return allHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void setAllHeaders(Multimap<String, String> allHeaders) {
|
||||
this.allHeaders = checkNotNull(allHeaders, "allHeaders");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public int compareTo(AtmosObject o) {
|
||||
String name = getContentMetadata().getName() != null ? getContentMetadata().getName()
|
||||
: getSystemMetadata().getObjectName();
|
||||
if (name == null)
|
||||
return -1;
|
||||
String otherName = o.getContentMetadata().getName() != null ? o.getContentMetadata()
|
||||
.getName() : o.getSystemMetadata().getObjectName();
|
||||
return (this == o) ? 0 : name.compareTo(otherName);
|
||||
}
|
||||
|
||||
public SystemMetadata getSystemMetadata() {
|
||||
return systemMetadata;
|
||||
}
|
||||
|
||||
public UserMetadata getUserMetadata() {
|
||||
return userMetadata;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.filters;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.atmosonline.saas.reference.AtmosStorageConstants;
|
||||
import org.jclouds.atmosonline.saas.reference.AtmosStorageHeaders;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpRequestFilter;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.util.TimeStamp;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Signs the EMC Atmos Online Storage request.
|
||||
*
|
||||
* @see <a href="https://community.emc.com/community/labs/atmos_online" />
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class SignRequest implements HttpRequestFilter {
|
||||
|
||||
private final String uid;
|
||||
private final byte[] key;
|
||||
private final Provider<String> timeStampProvider;
|
||||
|
||||
@Inject
|
||||
public SignRequest(@Named(AtmosStorageConstants.PROPERTY_EMCSAAS_UID) String uid,
|
||||
@Named(AtmosStorageConstants.PROPERTY_EMCSAAS_KEY) String encodedKey,
|
||||
@TimeStamp Provider<String> timeStampProvider) {
|
||||
this.uid = uid;
|
||||
this.key = HttpUtils.fromBase64String(encodedKey);
|
||||
this.timeStampProvider = timeStampProvider;
|
||||
}
|
||||
|
||||
public void filter(HttpRequest request) throws HttpException {
|
||||
String toSign = replaceUIDHeader(request).replaceDateHeader(request).createStringToSign(
|
||||
request);
|
||||
calculateAndReplaceAuthHeader(request, toSign);
|
||||
}
|
||||
|
||||
public String createStringToSign(HttpRequest request) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
// re-sign the request
|
||||
appendMethod(request, buffer);
|
||||
appendHttpHeaders(request, buffer);
|
||||
appendCanonicalizedResource(request, buffer);
|
||||
appendCanonicalizedHeaders(request, buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private void calculateAndReplaceAuthHeader(HttpRequest request, String toSign)
|
||||
throws HttpException {
|
||||
String signature = signString(toSign);
|
||||
request.getHeaders().replaceValues(AtmosStorageHeaders.SIGNATURE,
|
||||
Collections.singletonList(signature));
|
||||
}
|
||||
|
||||
public String signString(String toSign) {
|
||||
String signature;
|
||||
try {
|
||||
signature = HttpUtils.hmacSha1Base64(toSign, key);
|
||||
} catch (Exception e) {
|
||||
throw new HttpException("error signing request", e);
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
private void appendMethod(HttpRequest request, StringBuilder toSign) {
|
||||
toSign.append(request.getMethod()).append("\n");
|
||||
}
|
||||
|
||||
SignRequest replaceUIDHeader(HttpRequest request) {
|
||||
request.getHeaders().replaceValues(AtmosStorageHeaders.UID, Collections.singletonList(uid));
|
||||
return this;
|
||||
}
|
||||
|
||||
SignRequest replaceDateHeader(HttpRequest request) {
|
||||
request.getHeaders().replaceValues(HttpHeaders.DATE,
|
||||
Collections.singletonList(timeStampProvider.get()));
|
||||
return this;
|
||||
}
|
||||
|
||||
private void appendCanonicalizedHeaders(HttpRequest request, StringBuilder toSign) {
|
||||
// TreeSet == SortÊtheÊheadersÊalphabetically.
|
||||
Set<String> headers = new TreeSet<String>(request.getHeaders().keySet());
|
||||
for (String header : headers) {
|
||||
if (header.startsWith("x-emc-")) {
|
||||
// ConvertÊallÊheaderÊnamesÊtoÊlowercase.
|
||||
toSign.append(header.toLowerCase()).append(":");
|
||||
// ForÊheadersÊwithÊvaluesÊthatÊspanÊmultipleÊlines,ÊconvertÊthemÊintoÊoneÊlineÊbyÊreplacingÊanyÊ
|
||||
// newlineÊcharactersÊandÊextraÊembeddedÊwhiteÊspacesÊinÊtheÊvalue.
|
||||
for (String value : request.getHeaders().get(header))
|
||||
toSign.append(value.replaceAll("\r?\n", "").replaceAll(" ", " ")).append(" ");
|
||||
toSign.deleteCharAt(toSign.lastIndexOf(" "));
|
||||
// ConcatenateÊallÊheadersÊtogether,ÊusingÊnewlinesÊ(\n)ÊseparatingÊeachÊheaderÊfromÊtheÊnextÊone.Ê
|
||||
toSign.append("\n");
|
||||
}
|
||||
}
|
||||
// ThereÊshouldÊbeÊnoÊterminatingÊnewlineÊcharacterÊatÊtheÊendÊofÊtheÊlastÊheader.
|
||||
if (toSign.charAt(toSign.length() - 1) == '\n')
|
||||
toSign.deleteCharAt(toSign.length() - 1);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void appendHttpHeaders(HttpRequest request, StringBuilder toSign) {
|
||||
// OnlyÊtheÊvalueÊisÊused,ÊnotÊtheÊheaderÊ
|
||||
// name.ÊIfÊaÊrequestÊdoesÊnotÊincludeÊtheÊheader,ÊthisÊisÊanÊemptyÊstring.
|
||||
for (String header : new String[] { HttpHeaders.CONTENT_TYPE, "Range" })
|
||||
toSign.append(valueOrEmpty(request.getHeaders().get(header)).toLowerCase()).append("\n");
|
||||
// StandardÊHTTPÊheader,ÊinÊUTCÊformat.ÊOnlyÊtheÊdateÊvalueÊisÊused, notÊtheÊheaderÊname.
|
||||
toSign.append(request.getHeaders().get(HttpHeaders.DATE).iterator().next()).append("\n");
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void appendCanonicalizedResource(HttpRequest request, StringBuilder toSign) {
|
||||
// PathÊportionÊofÊtheÊHTTPÊrequestÊURI,ÊinÊlowercase.
|
||||
toSign.append(request.getEndpoint().getRawPath().toLowerCase()).append("\n");
|
||||
}
|
||||
|
||||
private String valueOrEmpty(Collection<String> collection) {
|
||||
return (collection != null && collection.size() >= 1) ? collection.iterator().next() : "";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.jclouds.atmosonline.saas.functions;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AtmosObjectName implements Function<Object, String> {
|
||||
|
||||
public String apply(Object in) {
|
||||
AtmosObject from = (AtmosObject) in;
|
||||
return from.getContentMetadata().getName() != null ? from.getContentMetadata().getName()
|
||||
: from.getSystemMetadata().getObjectName();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package org.jclouds.atmosonline.saas.functions;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* Parses response headers and creates a new AtmosObject from them and the HTTP content.
|
||||
*
|
||||
* @see ParseMetadataFromHeaders
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ParseObjectFromHeadersAndHttpContent implements Function<HttpResponse, AtmosObject> {
|
||||
|
||||
private final ParseSystemMetadataFromHeaders systemMetadataParser;
|
||||
private final ParseUserMetadataFromHeaders userMetadataParser;
|
||||
private final AtmosObject.Factory objectProvider;
|
||||
|
||||
@Inject
|
||||
public ParseObjectFromHeadersAndHttpContent(ParseSystemMetadataFromHeaders metadataParser,
|
||||
ParseUserMetadataFromHeaders userMetadataParser, AtmosObject.Factory objectProvider) {
|
||||
this.systemMetadataParser = metadataParser;
|
||||
this.userMetadataParser = userMetadataParser;
|
||||
this.objectProvider = objectProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* First, calls {@link ParseSystemAndUserMetadataFromHeaders}.
|
||||
*
|
||||
* Then, sets the object size based on the Content-Length header and adds the content to the
|
||||
* {@link AtmosObject} result.
|
||||
*
|
||||
* @throws org.jclouds.http.HttpException
|
||||
*/
|
||||
public AtmosObject apply(HttpResponse from) {
|
||||
AtmosObject object = objectProvider.create(systemMetadataParser.apply(from),
|
||||
userMetadataParser.apply(from));
|
||||
addAllHeadersTo(from, object);
|
||||
object.setData(from.getContent());
|
||||
String contentLength = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH);
|
||||
if (contentLength != null) {
|
||||
object.getContentMetadata().setContentLength(Long.parseLong(contentLength));
|
||||
}
|
||||
String contentType = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE);
|
||||
if (contentType != null) {
|
||||
object.getContentMetadata().setContentType(contentType);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void addAllHeadersTo(HttpResponse from, AtmosObject object) {
|
||||
object.getAllHeaders().putAll(from.getHeaders());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.FileType;
|
||||
import org.jclouds.atmosonline.saas.domain.SystemMetadata;
|
||||
import org.jclouds.atmosonline.saas.reference.AtmosStorageHeaders;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.util.DateService;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ParseSystemMetadataFromHeaders implements Function<HttpResponse, SystemMetadata> {
|
||||
private final DateService dateService;
|
||||
|
||||
@Inject
|
||||
public ParseSystemMetadataFromHeaders(DateService dateService) {
|
||||
this.dateService = dateService;
|
||||
}
|
||||
|
||||
public SystemMetadata apply(HttpResponse from) {
|
||||
String meta = checkNotNull(from.getFirstHeaderOrNull(AtmosStorageHeaders.META),
|
||||
AtmosStorageHeaders.META);
|
||||
Map<String, String> metaMap = Maps.newHashMap();
|
||||
String[] metas = meta.split(", ");
|
||||
for (String entry : metas) {
|
||||
String[] entrySplit = entry.split("=");
|
||||
metaMap.put(entrySplit[0], entrySplit[1]);
|
||||
}
|
||||
assert metaMap.size() >= 12 : String.format("Should be 12 entries in %s", metaMap);
|
||||
|
||||
return new SystemMetadata(dateService.iso8601SecondsDateParse(checkNotNull(metaMap
|
||||
.get("atime"), "atime")), dateService.iso8601SecondsDateParse(checkNotNull(metaMap
|
||||
.get("ctime"), "ctime")), checkNotNull(metaMap.get("gid"), "gid"), dateService
|
||||
.iso8601SecondsDateParse(checkNotNull(metaMap.get("itime"), "itime")), dateService
|
||||
.iso8601SecondsDateParse(checkNotNull(metaMap.get("mtime"), "mtime")), Integer
|
||||
.parseInt(checkNotNull(metaMap.get("nlink"), "nlink")), checkNotNull(metaMap
|
||||
.get("objectid"), "objectid"), checkNotNull(metaMap.get("objname"), "objname"),
|
||||
checkNotNull(metaMap.get("policyname"), "policyname"), Long.parseLong(checkNotNull(
|
||||
metaMap.get("size"), "size")), FileType.fromValue(checkNotNull(metaMap
|
||||
.get("type"), "type")), checkNotNull(metaMap.get("uid"), "uid"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.UserMetadata;
|
||||
import org.jclouds.atmosonline.saas.reference.AtmosStorageHeaders;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.internal.ImmutableSet;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ParseUserMetadataFromHeaders implements Function<HttpResponse, UserMetadata> {
|
||||
private final Set<String> sysKeys = ImmutableSet.of("atime", "ctime", "gid", "itime", "mtime",
|
||||
"nlink", "policyname", "size", "uid");
|
||||
|
||||
public UserMetadata apply(HttpResponse from) {
|
||||
UserMetadata md = new UserMetadata();
|
||||
Map<String, String> metaMap = getMetaMap(checkNotNull(from
|
||||
.getFirstHeaderOrNull(AtmosStorageHeaders.META), AtmosStorageHeaders.META));
|
||||
|
||||
Set<String> keys = Sets.difference(metaMap.keySet(), sysKeys);
|
||||
for (String key : keys) {
|
||||
md.getMetadata().put(key, metaMap.get(key));
|
||||
}
|
||||
if (from.getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_META) != null)
|
||||
md.getListableMetadata().putAll(
|
||||
getMetaMap(from.getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_META)));
|
||||
|
||||
if (from.getFirstHeaderOrNull(AtmosStorageHeaders.TAGS) != null)
|
||||
md.getTags().addAll(getTags(from.getFirstHeaderOrNull(AtmosStorageHeaders.TAGS)));
|
||||
if (from.getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_TAGS) != null)
|
||||
md.getTags().addAll(getTags(from.getFirstHeaderOrNull(AtmosStorageHeaders.LISTABLE_TAGS)));
|
||||
return md;
|
||||
}
|
||||
|
||||
private Set<String> getTags(String meta) {
|
||||
Set<String> tags = Sets.newTreeSet();
|
||||
String[] metas = meta.split(", ");
|
||||
for (String entry : metas) {
|
||||
tags.add(entry);
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
private Map<String, String> getMetaMap(String meta) {
|
||||
Map<String, String> metaMap = Maps.newHashMap();
|
||||
String[] metas = meta.split(", ");
|
||||
for (String entry : metas) {
|
||||
String[] entrySplit = entry.split("=");
|
||||
metaMap.put(entrySplit[0], entrySplit[1]);
|
||||
}
|
||||
return metaMap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.handlers;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpConstants;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
/**
|
||||
* Handles Retryable responses with error codes in the 4xx range
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AtmosStorageClientErrorRetryHandler implements HttpRetryHandler {
|
||||
|
||||
@Inject(optional = true)
|
||||
@Named(HttpConstants.PROPERTY_HTTP_MAX_RETRIES)
|
||||
private int retryCountLimit = 5;
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
|
||||
Utils.closeClientButKeepContentStream(response);
|
||||
command.incrementFailureCount();
|
||||
if (!command.isReplayable()) {
|
||||
logger.warn("Cannot retry after server error, command is not replayable: %1$s", command);
|
||||
return false;
|
||||
} else if (command.getFailureCount() > retryCountLimit) {
|
||||
logger.warn(
|
||||
"Cannot retry after server error, command has exceeded retry limit %1$d: %2$s",
|
||||
retryCountLimit, command);
|
||||
return false;
|
||||
} else if (response.getStatusCode() == 409) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.handlers;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.atmosonline.saas.AtmosStorageResponseException;
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosStorageError;
|
||||
import org.jclouds.atmosonline.saas.util.AtmosStorageUtils;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
/**
|
||||
* This will parse and set an appropriate exception on the command object.
|
||||
*
|
||||
* @see AtmosStorageError
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public class ParseAtmosStorageErrorFromXmlContent implements HttpErrorHandler {
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final AtmosStorageUtils utils;
|
||||
|
||||
@Inject
|
||||
public ParseAtmosStorageErrorFromXmlContent(AtmosStorageUtils utils) {
|
||||
this.utils = utils;
|
||||
}
|
||||
|
||||
public void handleError(HttpCommand command, HttpResponse response) {
|
||||
String content;
|
||||
try {
|
||||
content = response.getContent() != null ? Utils.toStringAndClose(response.getContent())
|
||||
: null;
|
||||
if (content != null) {
|
||||
try {
|
||||
if (content.indexOf('<') >= 0) {
|
||||
AtmosStorageError error = utils.parseAtmosStorageErrorFromContent(command,
|
||||
response, content);
|
||||
command.setException(new AtmosStorageResponseException(command, response, error));
|
||||
} else {
|
||||
command.setException(new HttpResponseException(command, response, content));
|
||||
}
|
||||
} catch (Exception he) {
|
||||
command.setException(new HttpResponseException(command, response, content));
|
||||
Utils.rethrowIfRuntime(he);
|
||||
}
|
||||
} else {
|
||||
command.setException(new HttpResponseException(command, response));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
command.setException(new HttpResponseException(command, response));
|
||||
Utils.rethrowIfRuntime(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.reference;
|
||||
|
||||
/**
|
||||
* Configuration properties and constants used in AtmosStorage connections.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface AtmosStorageConstants {
|
||||
public static final String PROPERTY_EMCSAAS_ENDPOINT = "jclouds.emcsaas.endpoint";
|
||||
public static final String PROPERTY_EMCSAAS_UID = "jclouds.emcsaas.uid";
|
||||
public static final String PROPERTY_EMCSAAS_KEY = "jclouds.emcsaas.key";
|
||||
/**
|
||||
* how long do we wait before obtaining a new timestamp for requests. Clocks must be within 5m of Atmos.
|
||||
*/
|
||||
public static final String PROPERTY_EMCSAAS_SESSIONINTERVAL = "jclouds.emcsaas.sessioninterval";
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.reference;
|
||||
|
||||
/**
|
||||
* Query parameters common to AtmosStorage apis.
|
||||
*
|
||||
* @see <a href="https://community.emc.com/community/labs/atmos_online" />
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public interface AtmosStorageHeaders {
|
||||
|
||||
public static final String SIGNATURE = "x-emc-signature";
|
||||
public static final String LISTABLE_META = "x-emc-listable-meta";
|
||||
public static final String META = "x-emc-meta";
|
||||
public static final String LISTABLE_TAGS = "x-emc-listable-tags";
|
||||
public static final String TAGS = "x-emc-tags";
|
||||
public static final String USER_ACL = "x-emc-useracl";
|
||||
public static final String DATE = "x-emc-date";
|
||||
public static final String GROUP_ACL = "x-emc-groupacl";
|
||||
public static final String UID = "x-emc-uid";
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosStorageError;
|
||||
import org.jclouds.atmosonline.saas.filters.SignRequest;
|
||||
import org.jclouds.atmosonline.saas.xml.ErrorHandler;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
|
||||
/**
|
||||
* Encryption, Hashing, and IO Utilities needed to sign and verify Atmos Storage requests and
|
||||
* responses.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AtmosStorageUtils {
|
||||
|
||||
@Inject
|
||||
SignRequest signer;
|
||||
|
||||
@Inject
|
||||
ParseSax.Factory factory;
|
||||
|
||||
@Inject
|
||||
Provider<ErrorHandler> errorHandlerProvider;
|
||||
|
||||
public AtmosStorageError parseAtmosStorageErrorFromContent(HttpCommand command,
|
||||
HttpResponse response, InputStream content) throws HttpException {
|
||||
AtmosStorageError error = (AtmosStorageError) factory.create(errorHandlerProvider.get())
|
||||
.parse(content);
|
||||
if (error.getCode() == 1032) {
|
||||
error.setStringSigned(signer.createStringToSign(command.getRequest()));
|
||||
}
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
public AtmosStorageError parseAtmosStorageErrorFromContent(HttpCommand command,
|
||||
HttpResponse response, String content) throws HttpException {
|
||||
return parseAtmosStorageErrorFromContent(command, response, new ByteArrayInputStream(content
|
||||
.getBytes()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.xml;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosStorageError;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
|
||||
/**
|
||||
* Parses the error from the Atmos Online Storage REST API.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ErrorHandler extends ParseSax.HandlerWithResult<AtmosStorageError> {
|
||||
|
||||
private StringBuilder currentText = new StringBuilder();
|
||||
private int code;
|
||||
private String message;
|
||||
|
||||
public AtmosStorageError getResult() {
|
||||
return new AtmosStorageError(code, message);
|
||||
}
|
||||
|
||||
public void endElement(String uri, String name, String qName) {
|
||||
|
||||
if (qName.equals("Code")) {
|
||||
this.code = Integer.parseInt(currentText.toString().trim());
|
||||
} else if (qName.equals("Message")) {
|
||||
this.message = currentText.toString().trim();
|
||||
}
|
||||
currentText = new StringBuilder();
|
||||
}
|
||||
|
||||
public void characters(char ch[], int start, int length) {
|
||||
currentText.append(ch, start, length);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.xml;
|
||||
|
||||
import java.util.SortedSet;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.DirectoryEntry;
|
||||
import org.jclouds.atmosonline.saas.domain.FileType;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Parses an object list
|
||||
* <p/>
|
||||
*
|
||||
* @see <a href="https://community.emc.com/community/labs/atmos_online" />
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ListDirectoryResponseHandler extends
|
||||
ParseSax.HandlerWithResult<SortedSet<DirectoryEntry>> {
|
||||
|
||||
private SortedSet<DirectoryEntry> entries = Sets.newTreeSet();
|
||||
private String currentObjectId;
|
||||
private FileType currentType;
|
||||
private String currentName;
|
||||
|
||||
private StringBuilder currentText = new StringBuilder();
|
||||
|
||||
public SortedSet<DirectoryEntry> getResult() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
public void endElement(String uri, String name, String qName) {
|
||||
if (qName.equals("ObjectID")) {
|
||||
currentObjectId = currentText.toString().trim();
|
||||
} else if (qName.equals("FileType")) {
|
||||
currentType = FileType.fromValue(currentText.toString().trim());
|
||||
} else if (qName.equals("Filename")) {
|
||||
currentName = currentText.toString().trim();
|
||||
if (currentName.equals(""))
|
||||
currentName = null;
|
||||
} else if (qName.equals("DirectoryEntry")) {
|
||||
entries.add(new DirectoryEntry(currentObjectId, currentType, currentName));
|
||||
}
|
||||
currentText = new StringBuilder();
|
||||
}
|
||||
|
||||
public void characters(char ch[], int start, int length) {
|
||||
currentText.append(ch, start, length);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.net.URI;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosObject;
|
||||
import org.jclouds.atmosonline.saas.domain.DirectoryEntry;
|
||||
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
||||
import org.jclouds.util.Utils;
|
||||
import org.testng.annotations.BeforeGroups;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code AtmosStorageClient}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "live", sequential = true, testName = "emcsaas.AtmosStorageClientLiveTest")
|
||||
public class AtmosStorageClientLiveTest {
|
||||
|
||||
protected AtmosStorageClient connection;
|
||||
private String containerPrefix = BaseBlobStoreIntegrationTest.CONTAINER_PREFIX;
|
||||
|
||||
URI container1;
|
||||
URI container2;
|
||||
|
||||
@BeforeGroups(groups = { "live" })
|
||||
public void setupClient() {
|
||||
String uid = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
|
||||
String key = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
|
||||
|
||||
connection = new AtmosStorageContextBuilder(new AtmosStoragePropertiesBuilder(uid, key)
|
||||
.build()).withModules(new Log4JLoggingModule()).buildContext().getApi();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListDirectorys() throws Exception {
|
||||
SortedSet<DirectoryEntry> response = connection.listDirectories();
|
||||
assert null != response;
|
||||
}
|
||||
|
||||
String privateDirectory;
|
||||
String publicDirectory;
|
||||
String account;
|
||||
|
||||
@Test(timeOut = 5 * 60 * 1000)
|
||||
public void testCreateDirectory() throws Exception {
|
||||
boolean created = false;
|
||||
while (!created) {
|
||||
privateDirectory = containerPrefix + new SecureRandom().nextInt();
|
||||
try {
|
||||
created = connection.createDirectory(privateDirectory) != null;
|
||||
} catch (UndeclaredThrowableException e) {
|
||||
HttpResponseException htpe = (HttpResponseException) e.getCause().getCause();
|
||||
if (htpe.getResponse().getStatusCode() == 409)
|
||||
continue;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
SortedSet<DirectoryEntry> response = connection.listDirectories();
|
||||
assert response.size() > 0;
|
||||
for (DirectoryEntry id : response) {
|
||||
SortedSet<DirectoryEntry> r2 = connection.listDirectory(id.getObjectName());
|
||||
assert r2 != null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = { "testCreateDirectory" })
|
||||
public void testFileOperations() throws Exception {
|
||||
String data = "Here is my data";
|
||||
|
||||
// Test PUT with string data, ETag hash, and a piece of metadata
|
||||
AtmosObject object = connection.newObject();
|
||||
object.getContentMetadata().setName("object");
|
||||
object.setData(data);
|
||||
object.getContentMetadata().setContentLength(data.length());
|
||||
object.generateMD5();
|
||||
object.getContentMetadata().setContentType("text/plain");
|
||||
object.getUserMetadata().getMetadata().put("Metadata", "metadata-value");
|
||||
URI uri = connection.createFile(privateDirectory, object).get(30, TimeUnit.SECONDS);
|
||||
|
||||
AtmosObject getBlob = connection.readFile(privateDirectory + "/object").get(120,
|
||||
TimeUnit.SECONDS);
|
||||
assertEquals(IOUtils.toString((InputStream) getBlob.getData()), data);
|
||||
// TODO assertEquals(getBlob.getName(), object.getName());
|
||||
assertEquals(getBlob.getContentMetadata().getContentLength(), new Long(data.length()));
|
||||
assert getBlob.getContentMetadata().getContentType().startsWith("text/plain");
|
||||
assertEquals(getBlob.getUserMetadata().getMetadata().get("Metadata"), "metadata-value");
|
||||
try {
|
||||
Utils.toStringAndClose(uri.toURL().openStream());
|
||||
assert false : "shouldn't have worked, since it is private";
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.atmosonline.saas.config.AtmosStorageRestClientModule;
|
||||
import org.jclouds.atmosonline.saas.filters.SignRequest;
|
||||
import org.jclouds.atmosonline.saas.reference.AtmosStorageConstants;
|
||||
import org.jclouds.atmosonline.saas.xml.ListDirectoryResponseHandler;
|
||||
import org.jclouds.concurrent.WithinThreadExecutorService;
|
||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.http.functions.ParseURIFromListOrLocationHeaderIf20x;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.logging.Logger.LoggerFactory;
|
||||
import org.jclouds.rest.config.RestModule;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.util.Jsr330;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code AtmosStorageClient}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "azureblob.AtmosStorageClientTest")
|
||||
public class AtmosStorageClientTest {
|
||||
|
||||
public void testListDirectories() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AtmosStorageClient.class.getMethod("listDirectories");
|
||||
|
||||
GeneratedHttpRequest<AtmosStorageClient> httpMethod = processor.createRequest(method,
|
||||
new Object[] {});
|
||||
assertEquals(httpMethod.getRequestLine(),
|
||||
"GET http://accesspoint.emccis.com/rest/namespace HTTP/1.1");
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getFirstHeaderOrNull(HttpHeaders.ACCEPT), "text/xml");
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ParseSax.class);
|
||||
assertEquals(RestAnnotationProcessor.getSaxResponseParserClassOrNull(method), ListDirectoryResponseHandler.class);
|
||||
assertEquals(httpMethod.getFilters().size(), 1);
|
||||
assertEquals(httpMethod.getFilters().get(0).getClass(), SignRequest.class);
|
||||
}
|
||||
|
||||
public void testCreateDirectory() throws SecurityException, NoSuchMethodException {
|
||||
Method method = AtmosStorageClient.class.getMethod("createDirectory", String.class);
|
||||
|
||||
GeneratedHttpRequest<AtmosStorageClient> httpMethod = processor.createRequest(method,
|
||||
"dir");
|
||||
assertEquals(httpMethod.getRequestLine(),
|
||||
"POST http://accesspoint.emccis.com/rest/namespace/dir/ HTTP/1.1");
|
||||
assertEquals(httpMethod.getHeaders().size(), 1);
|
||||
assertEquals(httpMethod.getFirstHeaderOrNull(HttpHeaders.ACCEPT), MediaType.WILDCARD);
|
||||
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
|
||||
assertEquals(processor.createResponseParser(method, httpMethod).getClass(),
|
||||
ParseURIFromListOrLocationHeaderIf20x.class);
|
||||
assertEquals(RestAnnotationProcessor.getSaxResponseParserClassOrNull(method), null);
|
||||
assertEquals(httpMethod.getFilters().size(), 1);
|
||||
assertEquals(httpMethod.getFilters().get(0).getClass(), SignRequest.class);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
void setupFactory() {
|
||||
Injector injector = Guice.createInjector(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AtmosStorageConstants.PROPERTY_EMCSAAS_ENDPOINT)).to(
|
||||
"http://accesspoint.emccis.com");
|
||||
bindConstant().annotatedWith(Jsr330.named(AtmosStorageConstants.PROPERTY_EMCSAAS_UID))
|
||||
.to("uid");
|
||||
bindConstant().annotatedWith(Jsr330.named(AtmosStorageConstants.PROPERTY_EMCSAAS_KEY))
|
||||
.to(HttpUtils.toBase64String("key".getBytes()));
|
||||
bind(Logger.LoggerFactory.class).toInstance(new LoggerFactory() {
|
||||
public Logger getLogger(String category) {
|
||||
return Logger.NULL;
|
||||
}
|
||||
});
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AtmosStorageConstants.PROPERTY_EMCSAAS_SESSIONINTERVAL)).to(1l);
|
||||
}
|
||||
}, new AtmosStorageRestClientModule(), new RestModule(), new ExecutorServiceModule(
|
||||
new WithinThreadExecutorService()), new JavaUrlHttpCommandExecutorServiceModule());
|
||||
processor = injector.getInstance(Key
|
||||
.get(new TypeLiteral<RestAnnotationProcessor<AtmosStorageClient>>() {
|
||||
}));
|
||||
}
|
||||
|
||||
RestAnnotationProcessor<AtmosStorageClient> processor;
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.binders;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.UserMetadata;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code BindUserMetadataToHeaders}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "atmossaas.BindUserMetadataToHeadersTest")
|
||||
public class BindUserMetadataToHeadersTest {
|
||||
|
||||
public void testMeta() {
|
||||
Injector injector = Guice.createInjector();
|
||||
BindUserMetadataToHeaders binder = injector
|
||||
.getInstance(BindUserMetadataToHeaders.class);
|
||||
|
||||
UserMetadata metadata = new UserMetadata();
|
||||
metadata.getMetadata().put("apple","bear");
|
||||
metadata.getMetadata().put("sushi","king");
|
||||
HttpRequest request = new HttpRequest("GET",URI.create("http://localhost"));
|
||||
binder.bindToRequest(request, metadata);
|
||||
assertEquals(request.getFirstHeaderOrNull("x-emc-meta"), "apple=bear,sushi=king");
|
||||
}
|
||||
|
||||
public void testListableMeta() {
|
||||
Injector injector = Guice.createInjector();
|
||||
BindUserMetadataToHeaders binder = injector
|
||||
.getInstance(BindUserMetadataToHeaders.class);
|
||||
|
||||
UserMetadata metadata = new UserMetadata();
|
||||
metadata.getListableMetadata().put("apple","bear");
|
||||
metadata.getListableMetadata().put("sushi","king");
|
||||
HttpRequest request = new HttpRequest("GET",URI.create("http://localhost"));
|
||||
binder.bindToRequest(request, metadata);
|
||||
assertEquals(request.getFirstHeaderOrNull("x-emc-listable-meta"), "apple=bear,sushi=king");
|
||||
}
|
||||
|
||||
|
||||
public void testTags() {
|
||||
Injector injector = Guice.createInjector();
|
||||
BindUserMetadataToHeaders binder = injector
|
||||
.getInstance(BindUserMetadataToHeaders.class);
|
||||
|
||||
UserMetadata tagsdata = new UserMetadata();
|
||||
tagsdata.getTags().add("apple");
|
||||
tagsdata.getTags().add("sushi");
|
||||
HttpRequest request = new HttpRequest("GET",URI.create("http://localhost"));
|
||||
binder.bindToRequest(request, tagsdata);
|
||||
assertEquals(request.getFirstHeaderOrNull("x-emc-tags"), "apple,sushi");
|
||||
}
|
||||
|
||||
public void testListableTags() {
|
||||
Injector injector = Guice.createInjector();
|
||||
BindUserMetadataToHeaders binder = injector
|
||||
.getInstance(BindUserMetadataToHeaders.class);
|
||||
|
||||
UserMetadata tagsdata = new UserMetadata();
|
||||
tagsdata.getListableTags().add("apple");
|
||||
tagsdata.getListableTags().add("sushi");
|
||||
HttpRequest request = new HttpRequest("GET",URI.create("http://localhost"));
|
||||
binder.bindToRequest(request, tagsdata);
|
||||
assertEquals(request.getFirstHeaderOrNull("x-emc-listable-tags"), "apple,sushi");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.config;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
import org.jclouds.atmosonline.saas.handlers.AtmosStorageClientErrorRetryHandler;
|
||||
import org.jclouds.atmosonline.saas.handlers.ParseAtmosStorageErrorFromXmlContent;
|
||||
import org.jclouds.atmosonline.saas.reference.AtmosStorageConstants;
|
||||
import org.jclouds.http.functions.config.ParserModule;
|
||||
import org.jclouds.http.handlers.DelegatingErrorHandler;
|
||||
import org.jclouds.http.handlers.DelegatingRetryHandler;
|
||||
import org.jclouds.http.handlers.RedirectionRetryHandler;
|
||||
import org.jclouds.util.DateService;
|
||||
import org.jclouds.util.Jsr330;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "emcsaas.AtmosStorageRestClientModuleTest")
|
||||
public class AtmosStorageRestClientModuleTest {
|
||||
|
||||
Injector createInjector() {
|
||||
return Guice.createInjector(new AtmosStorageRestClientModule(), new ParserModule(),
|
||||
new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AtmosStorageConstants.PROPERTY_EMCSAAS_ENDPOINT)).to(
|
||||
"http://localhost");
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AtmosStorageConstants.PROPERTY_EMCSAAS_UID)).to("uid");
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AtmosStorageConstants.PROPERTY_EMCSAAS_KEY)).to(
|
||||
new String(Base64.encode("key".getBytes())));
|
||||
bindConstant().annotatedWith(
|
||||
Jsr330.named(AtmosStorageConstants.PROPERTY_EMCSAAS_SESSIONINTERVAL))
|
||||
.to("2");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdatesOnlyOncePerSecond() throws NoSuchMethodException, InterruptedException {
|
||||
AtmosStorageRestClientModule module = new AtmosStorageRestClientModule();
|
||||
|
||||
ConcurrentMap<String, String> map = module.provideTimeStampCache(1, new DateService());
|
||||
String timeStamp = map.get("foo");
|
||||
for (int i = 0; i < 10; i++)
|
||||
map.get("foo");
|
||||
assertEquals(timeStamp, map.get("foo"));
|
||||
Thread.sleep(1001);
|
||||
assertFalse(timeStamp.equals(map.get("foo")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testServerErrorHandler() {
|
||||
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
|
||||
assertEquals(handler.getServerErrorHandler().getClass(),
|
||||
ParseAtmosStorageErrorFromXmlContent.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClientErrorHandler() {
|
||||
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
|
||||
assertEquals(handler.getClientErrorHandler().getClass(),
|
||||
ParseAtmosStorageErrorFromXmlContent.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClientRetryHandler() {
|
||||
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
|
||||
assertEquals(handler.getClientErrorRetryHandler().getClass(),
|
||||
AtmosStorageClientErrorRetryHandler.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRedirectionRetryHandler() {
|
||||
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
|
||||
assertEquals(handler.getRedirectionRetryHandler().getClass(), RedirectionRetryHandler.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.filters;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.atmosonline.saas.reference.AtmosStorageConstants;
|
||||
import org.jclouds.atmosonline.saas.reference.AtmosStorageHeaders;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.util.Jsr330;
|
||||
import org.jclouds.util.TimeStamp;
|
||||
import org.jclouds.util.Utils;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
@Test(groups = "unit", testName = "emcsaas.SignRequestTest")
|
||||
public class SignRequestTest {
|
||||
|
||||
private static final String KEY = "LJLuryj6zs8ste6Y3jTGQp71xq0=";
|
||||
|
||||
private Injector injector;
|
||||
private SignRequest filter;
|
||||
|
||||
@Test
|
||||
void testCreateStringToSign() throws IOException {
|
||||
String expects = Utils.toStringAndClose(getClass().getResourceAsStream("/hashstring.txt"));
|
||||
HttpRequest request = newRequest();
|
||||
String toSign = filter.replaceDateHeader(request).createStringToSign(request);
|
||||
assertEquals(toSign, expects);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUid() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
|
||||
HttpRequest request = newRequest();
|
||||
filter.replaceUIDHeader(request);
|
||||
assertEquals(request.getFirstHeaderOrNull(AtmosStorageHeaders.UID), "user");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSignString() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
|
||||
String expects = "WHJo1MFevMnK4jCthJ974L3YHoo=";
|
||||
|
||||
HttpRequest request = newRequest();
|
||||
String toSign = filter.replaceDateHeader(request).createStringToSign(request);
|
||||
String signature = filter.signString(toSign);
|
||||
assertEquals(signature, expects);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
protected void createFilter() {
|
||||
injector = Guice.createInjector(new AbstractModule() {
|
||||
|
||||
protected void configure() {
|
||||
bindConstant().annotatedWith(Jsr330.named(AtmosStorageConstants.PROPERTY_EMCSAAS_UID))
|
||||
.to("user");
|
||||
bindConstant().annotatedWith(Jsr330.named(AtmosStorageConstants.PROPERTY_EMCSAAS_KEY))
|
||||
.to(KEY);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
@TimeStamp
|
||||
String getDate() {
|
||||
return "Thu, 05 Jun 2008 16:38:19 GMT";
|
||||
}
|
||||
});
|
||||
filter = injector.getInstance(SignRequest.class);
|
||||
|
||||
}
|
||||
|
||||
public HttpRequest newRequest() {
|
||||
HttpRequest request = new HttpRequest("POST", URI.create("http://localhost/rest/objects"));
|
||||
request.getHeaders().put(AtmosStorageHeaders.LISTABLE_META, "part4/part7/part8=quick");
|
||||
request.getHeaders().put(AtmosStorageHeaders.META, "part1=buy");
|
||||
request.getHeaders().put(HttpHeaders.ACCEPT, "*/*");
|
||||
request.getHeaders().put(AtmosStorageHeaders.USER_ACL, "john=FULL_CONTROL,mary=WRITE");
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM);
|
||||
request.getHeaders().put(AtmosStorageHeaders.DATE, "Thu, 05 Jun 2008 16:38:19 GMT");
|
||||
request.getHeaders().put(AtmosStorageHeaders.GROUP_ACL, "other=NONE");
|
||||
request.getHeaders().put(HttpHeaders.HOST, "10.5.115.118");
|
||||
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, "4286");
|
||||
request.getHeaders().put(AtmosStorageHeaders.UID, "6039ac182f194e15b9261d73ce044939/user1");
|
||||
return request;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.functions;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.FileType;
|
||||
import org.jclouds.atmosonline.saas.domain.SystemMetadata;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.util.DateService;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code ParseSystemMetadataFromHeaders}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "atmossaas.ParseSystemMetadataFromHeadersTest")
|
||||
public class ParseSystemMetadataFromHeadersTest {
|
||||
|
||||
public void test() {
|
||||
Injector injector = Guice.createInjector();
|
||||
ParseSystemMetadataFromHeaders parser = injector
|
||||
.getInstance(ParseSystemMetadataFromHeaders.class);
|
||||
DateService dateService = injector.getInstance(DateService.class);
|
||||
|
||||
HttpResponse response = new HttpResponse();
|
||||
response
|
||||
.getHeaders()
|
||||
.put(
|
||||
"x-emc-meta",
|
||||
"atime=2009-10-12T16:09:42Z, mtime=2009-10-19T04:37:00Z,"
|
||||
+ " ctime=2009-10-19T04:37:00Z, itime=2009-10-12T16:09:42Z, type=directory, uid=root, "
|
||||
+ "gid=rootr, objectid=4980cdb2b010109b04a44f7bb83f5f04ad354c638ae5, "
|
||||
+ "objname=e913e09366364e9ba384b8fead643d43, size=4096, nlink=1, policyname=default");
|
||||
SystemMetadata expected = new SystemMetadata(
|
||||
|
||||
dateService.iso8601SecondsDateParse("2009-10-12T16:09:42Z"), dateService
|
||||
.iso8601SecondsDateParse("2009-10-19T04:37:00Z"), "rootr", dateService
|
||||
.iso8601SecondsDateParse("2009-10-12T16:09:42Z"), dateService
|
||||
.iso8601SecondsDateParse("2009-10-19T04:37:00Z"), 1,
|
||||
"4980cdb2b010109b04a44f7bb83f5f04ad354c638ae5", "e913e09366364e9ba384b8fead643d43",
|
||||
"default", 4096l, FileType.DIRECTORY, "root"
|
||||
|
||||
);
|
||||
SystemMetadata data = parser.apply(response);
|
||||
|
||||
assertEquals(data, expected);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.xml;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.AtmosStorageError;
|
||||
import org.jclouds.http.functions.BaseHandlerTest;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code ErrorHandler}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "atmossaas.ErrorHandlerTest")
|
||||
public class ErrorHandlerTest extends BaseHandlerTest {
|
||||
|
||||
ParseSax<AtmosStorageError> createParser() {
|
||||
ParseSax<AtmosStorageError> parser = (ParseSax<AtmosStorageError>) factory.create(injector
|
||||
.getInstance(ErrorHandler.class));
|
||||
return parser;
|
||||
}
|
||||
|
||||
public void testApplyInputStream() {
|
||||
InputStream is = getClass().getResourceAsStream("/error.xml");
|
||||
ParseSax<AtmosStorageError> parser = createParser();
|
||||
AtmosStorageError result = parser.parse(is);
|
||||
assertEquals(result.getCode(), 1003);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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.atmosonline.saas.xml;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import org.jclouds.atmosonline.saas.domain.DirectoryEntry;
|
||||
import org.jclouds.atmosonline.saas.domain.FileType;
|
||||
import org.jclouds.http.functions.BaseHandlerTest;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code ListDirectoryResponseHandler}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "atmossaas.ListDirectoryResponseHandlerTest")
|
||||
public class ListDirectoryResponseHandlerTest extends BaseHandlerTest {
|
||||
|
||||
ParseSax<SortedSet<DirectoryEntry>> createParser() {
|
||||
ParseSax<SortedSet<DirectoryEntry>> parser = (ParseSax<SortedSet<DirectoryEntry>>) factory
|
||||
.create(injector.getInstance(ListDirectoryResponseHandler.class));
|
||||
return parser;
|
||||
}
|
||||
|
||||
public void testApplyInputStreamBase() {
|
||||
InputStream is = getClass().getResourceAsStream("/list_basic.xml");
|
||||
ParseSax<SortedSet<DirectoryEntry>> parser = createParser();
|
||||
SortedSet<DirectoryEntry> expected = Sets.newTreeSet();
|
||||
expected.add(new DirectoryEntry("4980cdb2a411106a04a4538c92a1b204ad92077de6e3",
|
||||
FileType.DIRECTORY, "adriancole-blobstore-2096685753"));
|
||||
expected.add(new DirectoryEntry("4980cdb2a410105404980d99e53a0504ad93939e7dc3",
|
||||
FileType.DIRECTORY, "adriancole-blobstore247496608"));
|
||||
SortedSet<DirectoryEntry> result = parser.parse(is);
|
||||
assertEquals(result, expected);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<Error>
|
||||
<Code>1003</Code>
|
||||
<Message>The requested object was not found.</Message>
|
||||
</Error>
|
|
@ -0,0 +1,11 @@
|
|||
POST
|
||||
application/octet-stream
|
||||
|
||||
Thu, 05 Jun 2008 16:38:19 GMT
|
||||
/rest/objects
|
||||
x-emc-date:Thu, 05 Jun 2008 16:38:19 GMT
|
||||
x-emc-groupacl:other=NONE
|
||||
x-emc-listable-meta:part4/part7/part8=quick
|
||||
x-emc-meta:part1=buy
|
||||
x-emc-uid:6039ac182f194e15b9261d73ce044939/user1
|
||||
x-emc-useracl:john=FULL_CONTROL,mary=WRITE
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!--
|
||||
|
||||
|
||||
Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
|
||||
====================================================================
|
||||
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.
|
||||
====================================================================
|
||||
|
||||
-->
|
||||
<ListDirectoryResponse xmlns='http://www.emc.com/cos/'>
|
||||
<DirectoryList>
|
||||
<DirectoryEntry>
|
||||
<ObjectID>4980cdb2a411106a04a4538c92a1b204ad92077de6e3</ObjectID>
|
||||
<FileType>directory</FileType>
|
||||
<Filename>adriancole-blobstore-2096685753</Filename>
|
||||
</DirectoryEntry>
|
||||
<DirectoryEntry>
|
||||
<ObjectID>4980cdb2a410105404980d99e53a0504ad93939e7dc3</ObjectID>
|
||||
<FileType>directory</FileType>
|
||||
<Filename>adriancole-blobstore247496608</Filename>
|
||||
</DirectoryEntry>
|
||||
</DirectoryList>
|
||||
</ListDirectoryResponse>
|
|
@ -0,0 +1,95 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!--
|
||||
|
||||
|
||||
Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
|
||||
====================================================================
|
||||
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.
|
||||
====================================================================
|
||||
|
||||
-->
|
||||
<ListObjectsResponse xmlns='http://www.emc.com/cos/'>
|
||||
<Object>
|
||||
<ObjectID>499ad542a2a8bc200499ad5a7099940499b44f51e97d
|
||||
</ObjectID>
|
||||
<SystemMetadataList>
|
||||
<Metadata>
|
||||
<Name>atime</Name>
|
||||
<Value>2009-02-17T23:15:01Z</Value>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>mtime</Name>
|
||||
<Value>2009-02-17T23:15:01Z</Value>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>ctime</Name>
|
||||
<Value>2009-02-17T23:15:01Z</Value>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>itime</Name>
|
||||
<Value>2009-02-17T23:15:01Z</Value>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>type</Name>
|
||||
<Value>regular</Value>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>uid</Name>
|
||||
<Value>user1</Value>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>gid</Name>
|
||||
<Value>apache</Value>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>objectid</Name>
|
||||
<Value>499ad542a2a8bc200499ad5a7099940499b44f51e97d
|
||||
</Value>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>objname</Name>
|
||||
<Value></Value>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>size</Name>
|
||||
<Value>7589</Value>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>nlink</Name>
|
||||
<Value>0</Value>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>policyname</Name>
|
||||
<Value>default</Value>
|
||||
</Metadata>
|
||||
</SystemMetadataList>
|
||||
<UserMetadataList>
|
||||
<Metadata>
|
||||
<Name>part1</Name>
|
||||
<Value>order</Value>
|
||||
<Listable>false</Listable>
|
||||
</Metadata>
|
||||
<Metadata>
|
||||
<Name>part4/part7/part8</Name>
|
||||
<Value>quick</Value>
|
||||
<Listable>true</Listable>
|
||||
</Metadata>
|
||||
</UserMetadataList>
|
||||
</Object>
|
||||
</ListObjectsResponse>
|
|
@ -0,0 +1,115 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
|
||||
Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
|
||||
====================================================================
|
||||
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.
|
||||
====================================================================
|
||||
|
||||
-->
|
||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
||||
|
||||
<!--
|
||||
For more configuration infromation and examples see the Apache Log4j
|
||||
website: http://logging.apache.org/log4j/
|
||||
-->
|
||||
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
|
||||
debug="false">
|
||||
|
||||
<!-- A time/date based rolling appender -->
|
||||
<appender name="WIREFILE" class="org.apache.log4j.DailyRollingFileAppender">
|
||||
<param name="File" value="target/test-data/jclouds-wire.log" />
|
||||
<param name="Append" value="true" />
|
||||
|
||||
<!-- Rollover at midnight each day -->
|
||||
<param name="DatePattern" value="'.'yyyy-MM-dd" />
|
||||
|
||||
<param name="Threshold" value="TRACE" />
|
||||
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<!-- The default pattern: Date Priority [Category] Message\n -->
|
||||
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
|
||||
|
||||
<!--
|
||||
The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
|
||||
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
|
||||
%m%n"/>
|
||||
-->
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<!-- A time/date based rolling appender -->
|
||||
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
|
||||
<param name="File" value="target/test-data/jclouds.log" />
|
||||
<param name="Append" value="true" />
|
||||
|
||||
<!-- Rollover at midnight each day -->
|
||||
<param name="DatePattern" value="'.'yyyy-MM-dd" />
|
||||
|
||||
<param name="Threshold" value="TRACE" />
|
||||
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<!-- The default pattern: Date Priority [Category] Message\n -->
|
||||
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
|
||||
|
||||
<!--
|
||||
The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
|
||||
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
|
||||
%m%n"/>
|
||||
-->
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
|
||||
<appender-ref ref="FILE" />
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNCWIRE" class="org.apache.log4j.AsyncAppender">
|
||||
<appender-ref ref="WIREFILE" />
|
||||
</appender>
|
||||
|
||||
<!-- ================ -->
|
||||
<!-- Limit categories -->
|
||||
<!-- ================ -->
|
||||
|
||||
<category name="org.jclouds">
|
||||
<priority value="DEBUG" />
|
||||
<appender-ref ref="ASYNC" />
|
||||
</category>
|
||||
|
||||
<category name="jclouds.http.headers">
|
||||
<priority value="DEBUG" />
|
||||
<appender-ref ref="ASYNCWIRE" />
|
||||
</category>
|
||||
|
||||
<category name="jclouds.http.wire">
|
||||
<priority value="DEBUG" />
|
||||
<appender-ref ref="ASYNCWIRE" />
|
||||
</category>
|
||||
|
||||
<!-- ======================= -->
|
||||
<!-- Setup the Root category -->
|
||||
<!-- ======================= -->
|
||||
|
||||
<root>
|
||||
<priority value="WARN" />
|
||||
</root>
|
||||
|
||||
</log4j:configuration>
|
|
@ -0,0 +1,60 @@
|
|||
<!--
|
||||
$HeadURL$
|
||||
$Revision$
|
||||
$Date$
|
||||
|
||||
Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
|
||||
|
||||
====================================================================
|
||||
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.html
|
||||
|
||||
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.
|
||||
====================================================================
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>jclouds-atmosonline-project</artifactId>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jclouds-emcsaas-project</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>jclouds atmosonline storage service project</name>
|
||||
<modules>
|
||||
<module>core</module>
|
||||
</modules>
|
||||
<properties>
|
||||
<jclouds.test.initializer>org.jclouds.atmosonline.saas.integration.AtmosStorageTestInitializer</jclouds.test.initializer>
|
||||
<jclouds.test.user>${jclouds.emcsaas.uid}</jclouds.test.user>
|
||||
<jclouds.test.key>${jclouds.emcsaas.key}</jclouds.test.key>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-blobstore-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-blobstore-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
Loading…
Reference in New Issue