mirror of https://github.com/apache/jclouds.git
initial import to svn
git-svn-id: http://jclouds.googlecode.com/svn/trunk@3 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
d81912748b
commit
483043ea87
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
$HeadURL$
|
||||
$Revision$
|
||||
$Date$
|
||||
|
||||
Copyright (C) 2009 Adrian Cole <adriancole@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>project</artifactId>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../project/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<name>jclouds Components Core</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Core components to access jclouds services</description>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/core</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/core</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk/core</url>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.guice</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>2.0-r936</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.guice</groupId>
|
||||
<artifactId>guice-assistedinject</artifactId>
|
||||
<version>2.0-r936</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.collections</groupId>
|
||||
<artifactId>google-collections</artifactId>
|
||||
<version>1.0-rc1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
<artifactId>aopalliance</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>jsr250-api</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty</artifactId>
|
||||
<version>6.1.16</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>guice-snapshot</id>
|
||||
<url>http://guice-maven.googlecode.com/svn/trunk</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class Logger {
|
||||
private final java.util.logging.Logger logger;
|
||||
|
||||
public Logger(java.util.logging.Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void trace(String message, Object... args) {
|
||||
if (isTraceEnabled())
|
||||
logger.finest(String.format(message, args));
|
||||
}
|
||||
|
||||
public boolean isTraceEnabled() {
|
||||
return logger.isLoggable(Level.FINEST);
|
||||
}
|
||||
|
||||
public void debug(String message, Object... args) {
|
||||
if (isDebugEnabled())
|
||||
logger.fine(String.format(message, args));
|
||||
}
|
||||
|
||||
private boolean isDebugEnabled() {
|
||||
return logger.isLoggable(Level.FINE);
|
||||
}
|
||||
|
||||
public void info(String message, Object... args) {
|
||||
if (logger.isLoggable(Level.INFO))
|
||||
logger.info(String.format(message, args));
|
||||
}
|
||||
|
||||
public void warn(String message, Object... args) {
|
||||
if (logger.isLoggable(Level.WARNING))
|
||||
logger.log(Level.WARNING, String.format(message, args));
|
||||
}
|
||||
|
||||
public void warn(Throwable throwable, String message, Object... args) {
|
||||
if (logger.isLoggable(Level.WARNING))
|
||||
logger.log(Level.WARNING, String.format(message, args), throwable);
|
||||
}
|
||||
|
||||
public void error(String message, Object... args) {
|
||||
if (logger.isLoggable(Level.SEVERE))
|
||||
logger.log(Level.SEVERE, String.format(message, args));
|
||||
}
|
||||
|
||||
public void error(Throwable throwable, String message, Object... args) {
|
||||
if (logger.isLoggable(Level.SEVERE))
|
||||
logger.log(Level.SEVERE, String.format(message, args), throwable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class Utils {
|
||||
|
||||
|
||||
public static <E extends Exception> void rethrowIfRuntimeOrSameType(Exception e) throws E {
|
||||
if (e instanceof ExecutionException) {
|
||||
Throwable nested = e.getCause();
|
||||
if (nested instanceof Error)
|
||||
throw (Error) nested;
|
||||
e = (Exception) nested;
|
||||
}
|
||||
|
||||
if (e instanceof RuntimeException) {
|
||||
throw (RuntimeException) e;
|
||||
} else {
|
||||
try {
|
||||
throw (E) e;
|
||||
} catch (ClassCastException throwAway) {
|
||||
// using cce as there's no way to do instanceof E in current java
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String toStringAndClose(InputStream input) throws IOException {
|
||||
try {
|
||||
return IOUtils.toString(input);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(input);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.command;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class FutureCommand<Q, R, T> implements Future<T> {
|
||||
|
||||
private Q request;
|
||||
private ResponseRunnableFuture<R, T> responseRunnableFuture;
|
||||
private volatile int failureCount;
|
||||
|
||||
public int incrementFailureCount() {
|
||||
return ++failureCount;
|
||||
}
|
||||
|
||||
public int getFailureCount() {
|
||||
return failureCount;
|
||||
}
|
||||
|
||||
public FutureCommand(Q request, ResponseCallable<R, T> responseCallable) {
|
||||
this.request = request;
|
||||
this.responseRunnableFuture = new ResponseRunnableFutureTask<R, T>(responseCallable);
|
||||
}
|
||||
|
||||
public Q getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public ResponseRunnableFuture<R, T> getResponseFuture() {
|
||||
return responseRunnableFuture;
|
||||
}
|
||||
|
||||
public void setException(Exception e) {
|
||||
responseRunnableFuture.setException(e);
|
||||
}
|
||||
|
||||
public boolean cancel(boolean b) {
|
||||
return responseRunnableFuture.cancel(b);
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return responseRunnableFuture.isCancelled();
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return responseRunnableFuture.isDone();
|
||||
}
|
||||
|
||||
public T get() throws InterruptedException, ExecutionException {
|
||||
return responseRunnableFuture.get();
|
||||
}
|
||||
|
||||
public T get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return responseRunnableFuture.get(l, timeUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public static class ResponseRunnableFutureTask<R, T> extends FutureTask<T> implements ResponseRunnableFuture<R, T> {
|
||||
private final ResponseCallable<R, T> tCallable;
|
||||
|
||||
public ResponseRunnableFutureTask(ResponseCallable<R, T> tCallable) {
|
||||
super(tCallable);
|
||||
this.tCallable = tCallable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ApacheHttpResponseFuture{" +
|
||||
"tCallable=" + tCallable +
|
||||
'}';
|
||||
}
|
||||
|
||||
public R getResponse() {
|
||||
return tCallable.getResponse();
|
||||
}
|
||||
|
||||
public void setResponse(R response) {
|
||||
tCallable.setResponse(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* opening this to public so that other errors can be associated with the request, for example i/o errors.
|
||||
*
|
||||
* @param throwable
|
||||
*/
|
||||
@Override
|
||||
public void setException(Throwable throwable) {
|
||||
super.setException(throwable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface ResponseRunnableFuture<R, T> extends Response<R>, Runnable, Future<T> {
|
||||
public void setException(Throwable throwable);
|
||||
}
|
||||
|
||||
public interface ResponseCallable<R, T> extends Response<R>, Callable<T> {
|
||||
}
|
||||
|
||||
public interface Response<R> {
|
||||
public R getResponse();
|
||||
|
||||
public void setResponse(R response);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.command;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface FutureCommandClient {
|
||||
@SuppressWarnings("unchecked")
|
||||
<O extends FutureCommand> void submit(O operation);
|
||||
void close();
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.command.pool;
|
||||
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class FutureCommandConnectionHandle<C> {
|
||||
protected final BlockingQueue<C> available;
|
||||
protected final Semaphore maxConnections;
|
||||
protected final Semaphore completed;
|
||||
protected C conn;
|
||||
@SuppressWarnings("unchecked")
|
||||
protected FutureCommand operation;
|
||||
protected final Logger logger;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public FutureCommandConnectionHandle(java.util.logging.Logger logger, Semaphore maxConnections, @Assisted FutureCommand operation, @Assisted C conn, BlockingQueue<C> available) throws InterruptedException {
|
||||
this.maxConnections = maxConnections;
|
||||
this.operation = operation;
|
||||
this.conn = conn;
|
||||
this.available = available;
|
||||
this.logger = new Logger(logger);
|
||||
this.completed = new Semaphore(1);
|
||||
completed.acquire();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public FutureCommand getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public abstract void startConnection();
|
||||
|
||||
public boolean isCompleted() {
|
||||
return (completed.availablePermits() == 1);
|
||||
}
|
||||
|
||||
public void release() throws InterruptedException {
|
||||
if (isCompleted()) {
|
||||
return;
|
||||
}
|
||||
logger.trace("%1s - %2d - releasing to pool", conn, conn.hashCode());
|
||||
available.put(conn);
|
||||
conn = null;
|
||||
operation = null;
|
||||
completed.release();
|
||||
}
|
||||
|
||||
public void cancel() throws IOException {
|
||||
if (isCompleted()) {
|
||||
return;
|
||||
}
|
||||
if (conn != null) {
|
||||
logger.trace("%1s - %2d - cancelled; shutting down connection", conn, conn.hashCode());
|
||||
try {
|
||||
shutdownConnection();
|
||||
} finally {
|
||||
conn = null;
|
||||
operation = null;
|
||||
maxConnections.release();
|
||||
}
|
||||
}
|
||||
completed.release();
|
||||
}
|
||||
|
||||
public abstract void shutdownConnection() throws IOException;
|
||||
|
||||
public void waitFor() throws InterruptedException {
|
||||
completed.acquire();
|
||||
completed.release();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.command.pool;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.name.Named;
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
import org.jclouds.lifecycle.BaseLifeCycle;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class FutureCommandConnectionPool<C> extends BaseLifeCycle {
|
||||
protected final Semaphore allConnections;
|
||||
protected final BlockingQueue<C> available;
|
||||
protected final FutureCommandConnectionHandleFactory<C> futureCommandConnectionHandleFactory;
|
||||
protected final int maxConnectionReuse;
|
||||
protected final AtomicInteger currentSessionFailures = new AtomicInteger(0);
|
||||
protected final FutureCommandConnectionRetry<C> futureCommandConnectionRetry;
|
||||
protected volatile boolean hitBottom = false;
|
||||
|
||||
public FutureCommandConnectionPool(Logger logger, ExecutorService executor, FutureCommandConnectionRetry<C> futureCommandConnectionRetry, Semaphore allConnections, FutureCommandConnectionHandleFactory<C> futureCommandConnectionHandleFactory, @Named("maxConnectionReuse") int maxConnectionReuse, BlockingQueue<C> available, BaseLifeCycle... dependencies) {
|
||||
super(logger, executor, dependencies);
|
||||
this.futureCommandConnectionRetry = futureCommandConnectionRetry;
|
||||
this.allConnections = allConnections;
|
||||
this.futureCommandConnectionHandleFactory = futureCommandConnectionHandleFactory;
|
||||
this.maxConnectionReuse = maxConnectionReuse;
|
||||
this.available = available;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void setResponseException(Exception ex, C conn) {
|
||||
FutureCommand command = futureCommandConnectionRetry.getHandleFromConnection(conn).getOperation();
|
||||
command.getResponseFuture().setException(ex);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void cancel(C conn) {
|
||||
FutureCommand command = futureCommandConnectionRetry.getHandleFromConnection(conn).getOperation();
|
||||
command.cancel(true);
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
public C getConnection() throws InterruptedException, TimeoutException {
|
||||
exceptionIfNotActive();
|
||||
if (!hitBottom) {
|
||||
hitBottom = available.size() == 0 && allConnections.availablePermits() == 0;
|
||||
if (hitBottom)
|
||||
logger.warn("%1s - saturated connection pool", this);
|
||||
}
|
||||
logger.debug("%1s - attempting to acquire connection; %d currently available", this, available.size());
|
||||
C conn = available.poll(1, TimeUnit.SECONDS);
|
||||
if (conn == null)
|
||||
throw new TimeoutException("could not obtain a pooled connection within 1 seconds");
|
||||
|
||||
logger.trace("%1s - %2d - aquired", conn, conn.hashCode());
|
||||
if (connectionValid(conn)) {
|
||||
logger.debug("%1s - %2d - reusing", conn, conn.hashCode());
|
||||
return conn;
|
||||
} else {
|
||||
logger.debug("%1s - %2d - unusable", conn, conn.hashCode());
|
||||
allConnections.release();
|
||||
return getConnection();
|
||||
}
|
||||
}
|
||||
|
||||
protected void fatalException(Exception ex, C conn) {
|
||||
setResponseException(ex, conn);
|
||||
this.exception = ex;
|
||||
allConnections.release();
|
||||
shutdown();
|
||||
}
|
||||
|
||||
protected abstract boolean connectionValid(C conn);
|
||||
|
||||
public FutureCommandConnectionHandle<C> getHandle(FutureCommand<?,?,?> command) throws InterruptedException, TimeoutException {
|
||||
exceptionIfNotActive();
|
||||
C conn = getConnection();
|
||||
FutureCommandConnectionHandle<C> handle = futureCommandConnectionHandleFactory.create(command, conn);
|
||||
futureCommandConnectionRetry.associateHandleWithConnection(handle, conn);
|
||||
return handle;
|
||||
}
|
||||
|
||||
protected abstract void createNewConnection() throws InterruptedException;
|
||||
|
||||
public interface FutureCommandConnectionHandleFactory<C> {
|
||||
@SuppressWarnings("unchecked")
|
||||
FutureCommandConnectionHandle<C> create(FutureCommand command, C conn);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.command.pool;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.Utils;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
import org.jclouds.command.FutureCommandClient;
|
||||
import org.jclouds.lifecycle.BaseLifeCycle;
|
||||
import org.jclouds.lifecycle.Closer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class FutureCommandConnectionPoolClient<C> extends BaseLifeCycle implements FutureCommandClient {
|
||||
@Inject private Closer closer;
|
||||
private final FutureCommandConnectionPool<C> futureCommandConnectionPool;
|
||||
private final BlockingQueue<FutureCommand> commandQueue;
|
||||
|
||||
@Inject
|
||||
public FutureCommandConnectionPoolClient(java.util.logging.Logger logger, ExecutorService executor, FutureCommandConnectionPool<C> futureCommandConnectionPool, BlockingQueue<FutureCommand> commandQueue) {
|
||||
super(new Logger(logger), executor, futureCommandConnectionPool);
|
||||
this.futureCommandConnectionPool = futureCommandConnectionPool;
|
||||
this.commandQueue = commandQueue;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean shouldDoWork() {
|
||||
return super.shouldDoWork() && futureCommandConnectionPool.getStatus().equals(Status.ACTIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doShutdown() {
|
||||
if (exception == null && futureCommandConnectionPool.getException() != null)
|
||||
exception = futureCommandConnectionPool.getException();
|
||||
while (!commandQueue.isEmpty()) {
|
||||
FutureCommand command = commandQueue.remove();
|
||||
if (command != null) {
|
||||
if (exception != null)
|
||||
command.setException(exception);
|
||||
else
|
||||
command.cancel(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void doWork() throws InterruptedException {
|
||||
FutureCommand command = commandQueue.poll(1, TimeUnit.SECONDS);
|
||||
if (command != null) {
|
||||
try {
|
||||
invoke(command);
|
||||
} catch (Exception e) {
|
||||
Utils.<InterruptedException>rethrowIfRuntimeOrSameType(e);
|
||||
logger.error(e, "Error processing command %s", command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public <O extends FutureCommand> void submit(O operation) {
|
||||
exceptionIfNotActive();
|
||||
commandQueue.add(operation);
|
||||
}
|
||||
|
||||
protected <O extends FutureCommand> void invoke(O operation) {
|
||||
exceptionIfNotActive();
|
||||
FutureCommandConnectionHandle<C> connectionHandle = null;
|
||||
try {
|
||||
connectionHandle = futureCommandConnectionPool.getHandle(operation);
|
||||
} catch (InterruptedException e) {
|
||||
logger.warn(e, "Interrupted getting a connection for operation %1s; retrying", operation);
|
||||
commandQueue.add(operation);
|
||||
return;
|
||||
} catch (TimeoutException e) {
|
||||
logger.warn(e, "Timeout getting a connection for operation %1s; retrying", operation);
|
||||
commandQueue.add(operation);
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionHandle == null) {
|
||||
logger.error("Failed to obtain connection for operation %1s; retrying", operation);
|
||||
commandQueue.add(operation);
|
||||
return;
|
||||
}
|
||||
connectionHandle.startConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("FutureCommandConnectionPoolClient");
|
||||
sb.append("{status=").append(status);
|
||||
sb.append(", commandQueue=").append((commandQueue != null) ? commandQueue.size() : 0);
|
||||
sb.append(", futureCommandConnectionPool=").append(futureCommandConnectionPool);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void close(){
|
||||
try {
|
||||
closer.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(); // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.command.pool;
|
||||
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class FutureCommandConnectionRetry<C> {
|
||||
protected final BlockingQueue<FutureCommand> commandQueue;
|
||||
protected final AtomicInteger errors;
|
||||
protected final Logger logger;
|
||||
|
||||
public FutureCommandConnectionRetry(Logger logger, BlockingQueue<FutureCommand> commandQueue, AtomicInteger errors) {
|
||||
this.logger = logger;
|
||||
this.commandQueue = commandQueue;
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
public abstract void associateHandleWithConnection(FutureCommandConnectionHandle<C> handle, C connection);
|
||||
|
||||
public abstract FutureCommandConnectionHandle<C> getHandleFromConnection(C connection);
|
||||
|
||||
public void shutdownConnectionAndRetryOperation(C connection) {
|
||||
FutureCommandConnectionHandle<C> handle = getHandleFromConnection(connection);
|
||||
if (handle != null) {
|
||||
try {
|
||||
logger.info("%1s - shutting down connection", connection);
|
||||
handle.shutdownConnection();
|
||||
incrementErrorCountAndRetry(handle.getOperation());
|
||||
} catch (IOException e) {
|
||||
logger.error(e, "%1s - error shutting down connection", connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void incrementErrorCountAndRetry(FutureCommand command) {
|
||||
errors.getAndIncrement();
|
||||
logger.info("resubmitting command %1s", command);
|
||||
commandQueue.add(command);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.command.pool.config;
|
||||
|
||||
import com.google.inject.*;
|
||||
import com.google.inject.name.Named;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
import org.jclouds.lifecycle.config.LifeCycleModule;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class FutureCommandConnectionPoolClientModule<C> extends AbstractModule {
|
||||
protected void configure() {
|
||||
install(new LifeCycleModule());
|
||||
bind(AtomicInteger.class).toInstance(new AtomicInteger());// max errors
|
||||
bind(new TypeLiteral<BlockingQueue<FutureCommand>>() {
|
||||
}).to(new TypeLiteral<LinkedBlockingQueue<FutureCommand>>() {
|
||||
}).in(Scopes.SINGLETON);
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public abstract BlockingQueue<C> provideAvailablePool(@Named("jclouds.pool.max_connections") int max) throws Exception;
|
||||
|
||||
/**
|
||||
* controls production and destruction of real connections.
|
||||
* <p/>
|
||||
* aquire before a new connection is created
|
||||
* release after an error has occurred
|
||||
*
|
||||
* @param max
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Provides
|
||||
@Singleton
|
||||
public Semaphore provideTotalConnectionSemaphore(@Named("jclouds.pool.max_connections") int max) throws Exception {
|
||||
return new Semaphore(max, true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class HttpConstants {
|
||||
public static final String CONTENT_LENGTH = "Content-Length";
|
||||
public static final String CONTENT_TYPE = "Content-Type";
|
||||
public static final String HOST = "Host";
|
||||
public static final String DATE = "Date";
|
||||
public static final String BINARY = "application/octet-stream";
|
||||
public static final String PLAIN = "text/plain";
|
||||
public static final String TRANSFER_ENCODING = "Transfer-Encoding";
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class HttpException extends Exception {
|
||||
public HttpException(String s) {
|
||||
super(s); // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public HttpException(String s, Throwable throwable) {
|
||||
super(s, throwable); // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public HttpException(Throwable throwable) {
|
||||
super(throwable); // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http;
|
||||
|
||||
import org.jclouds.command.FutureCommand;
|
||||
import org.jclouds.Logger;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class HttpFutureCommand<T> extends FutureCommand<HttpRequest, HttpResponse, T> {
|
||||
public HttpFutureCommand(String method, String uri, ResponseCallable<T> responseCallable) {
|
||||
super(new HttpRequest(method, uri), responseCallable);
|
||||
}
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract static class ResponseCallable<T> implements FutureCommand.ResponseCallable<HttpResponse, T> {
|
||||
protected final Logger logger;
|
||||
private HttpResponse response;
|
||||
|
||||
public ResponseCallable(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public HttpResponse getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
public void setResponse(HttpResponse response) {
|
||||
this.response = response;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
import org.jclouds.command.FutureCommandClient;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface HttpFutureCommandClient extends FutureCommandClient {
|
||||
List<HttpRequestFilter> getRequestFilters();
|
||||
|
||||
@Inject
|
||||
void setRequestFilters(List<HttpRequestFilter> requestFilters);
|
||||
|
||||
<O extends FutureCommand> void submit(O operation);
|
||||
|
||||
void close();
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class HttpRequest {
|
||||
|
||||
String method;
|
||||
String uri;
|
||||
Multimap<String, String> headers = HashMultimap.create();
|
||||
Object content;
|
||||
String contentType;
|
||||
long contentLength = -1;
|
||||
|
||||
public HttpRequest(String method, String uri) {
|
||||
this.method = checkNotNull(method, "method");
|
||||
this.uri = checkNotNull(uri, "uri");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("HttpRequest");
|
||||
sb.append("{method='").append(method).append('\'');
|
||||
sb.append(", uri='").append(uri).append('\'');
|
||||
sb.append(", headers=").append(headers);
|
||||
sb.append(", content set=").append(content != null);
|
||||
sb.append(", contentType='").append(contentType).append('\'');
|
||||
sb.append(", contentLength=").append(contentLength);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public Multimap<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(Multimap<String, String> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public Object getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(Object content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public void setContentType(String contentType) {
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public long getContentLength() {
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
public void setContentLength(long contentLength) {
|
||||
this.contentLength = contentLength;
|
||||
}
|
||||
|
||||
public String getFirstHeaderOrNull(String string) {
|
||||
Collection<String> values = headers.get(string);
|
||||
return (values != null && values.size() >= 1) ? values.iterator()
|
||||
.next() : null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface HttpRequestFilter {
|
||||
void filter(HttpRequest request) throws HttpException;
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class HttpResponse {
|
||||
int statusCode;
|
||||
Multimap<String, String> headers = HashMultimap.create();
|
||||
String message;
|
||||
InputStream content;
|
||||
String contentType;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("HttpResponse");
|
||||
sb.append("{statusCode=").append(statusCode);
|
||||
sb.append(", headers=").append(headers);
|
||||
sb.append(", message='").append(message).append('\'');
|
||||
sb.append(", content set=").append(content != null);
|
||||
sb.append(", contentType='").append(contentType).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
public void setStatusCode(int statusCode) {
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public Multimap<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(Multimap<String, String> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public InputStream getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(InputStream content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public void setContentType(String contentType) {
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public String getFirstHeaderOrNull(String string) {
|
||||
Collection<String> values = headers.get(string);
|
||||
return (values != null && values.size() >= 1) ? values.iterator()
|
||||
.next() : null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.Utils;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class JavaUrlHttpFutureCommandClient implements HttpFutureCommandClient {
|
||||
private URL target;
|
||||
private List<HttpRequestFilter> requestFilters = Collections.emptyList();
|
||||
private Logger logger;
|
||||
|
||||
public List<HttpRequestFilter> getRequestFilters() {
|
||||
return requestFilters;
|
||||
}
|
||||
|
||||
@Inject(optional = true)
|
||||
public void setRequestFilters(List<HttpRequestFilter> requestFilters) {
|
||||
this.requestFilters = requestFilters;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public JavaUrlHttpFutureCommandClient(java.util.logging.Logger logger,
|
||||
URL target) throws MalformedURLException {
|
||||
this.logger = new Logger(logger);
|
||||
this.target = target;
|
||||
this.logger.info("configured to connect to target: %1s", target);
|
||||
}
|
||||
|
||||
public <O extends FutureCommand> void submit(O operation) {
|
||||
HttpRequest request = (HttpRequest) operation.getRequest();
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
for (HttpRequestFilter filter : getRequestFilters()) {
|
||||
filter.filter(request);
|
||||
}
|
||||
logger.trace("%1s - submitting request %2s", target, request);
|
||||
connection = openJavaConnection(request);
|
||||
HttpResponse response = getResponse(connection);
|
||||
logger.trace("%1s - received response %2s", target, response);
|
||||
|
||||
operation.getResponseFuture().setResponse(response);
|
||||
operation.getResponseFuture().run();
|
||||
} catch (Exception e) {
|
||||
if (connection != null) {
|
||||
InputStream errorStream = connection.getErrorStream();
|
||||
if (errorStream != null) {
|
||||
try {
|
||||
String errorMessage = Utils.toStringAndClose(connection
|
||||
.getErrorStream());
|
||||
logger.error(e,
|
||||
"error encountered during the exception: %1s",
|
||||
errorMessage);
|
||||
} catch (IOException e1) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
operation.setException(e);
|
||||
} finally {
|
||||
// DO NOT disconnect, as it will also close the unconsumed outputStream from above.
|
||||
// connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
// Nothing to stop;
|
||||
}
|
||||
|
||||
private HttpResponse getResponse(HttpURLConnection connection)
|
||||
throws IOException {
|
||||
HttpResponse response = new HttpResponse();
|
||||
response.setStatusCode(connection.getResponseCode());
|
||||
for (String header : connection.getHeaderFields().keySet()) {
|
||||
response.getHeaders().putAll(header,
|
||||
connection.getHeaderFields().get(header));
|
||||
}
|
||||
|
||||
response.setMessage(connection.getResponseMessage());
|
||||
response.setContent(connection.getInputStream());
|
||||
response.setContentType(connection
|
||||
.getHeaderField(HttpConstants.CONTENT_TYPE));
|
||||
return response;
|
||||
}
|
||||
|
||||
private HttpURLConnection openJavaConnection(HttpRequest request)
|
||||
throws IOException {
|
||||
URL url = new URL(target, request.getUri());
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setDoOutput(true);
|
||||
connection.setRequestMethod(request.getMethod());
|
||||
for (String header : request.getHeaders().keySet()) {
|
||||
for (String value : request.getHeaders().get(header))
|
||||
connection.setRequestProperty(header, value);
|
||||
}
|
||||
connection.setRequestProperty(HttpConstants.CONTENT_TYPE, request
|
||||
.getContentType());
|
||||
if (request.getContent() != null) {
|
||||
OutputStream out = connection.getOutputStream();
|
||||
try {
|
||||
if (request.getContent() instanceof String) {
|
||||
OutputStreamWriter writer = new OutputStreamWriter(out);
|
||||
writer.write((String) request.getContent());
|
||||
writer.close();
|
||||
} else if (request.getContent() instanceof InputStream) {
|
||||
IOUtils.copy((InputStream) request.getContent(), out);
|
||||
} else if (request.getContent() instanceof File) {
|
||||
IOUtils.copy(new FileInputStream((File) request
|
||||
.getContent()), out);
|
||||
} else if (request.getContent() instanceof byte[]) {
|
||||
IOUtils.write((byte[]) request.getContent(), out);
|
||||
} else {
|
||||
throw new UnsupportedOperationException(
|
||||
"Content not supported "
|
||||
+ request.getContent().getClass());
|
||||
}
|
||||
} finally {
|
||||
IOUtils.closeQuietly(out);
|
||||
}
|
||||
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands;
|
||||
|
||||
import org.jclouds.http.commands.callables.xml.ParseSax;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class CommandFactory {
|
||||
|
||||
@Inject
|
||||
private ParseSaxFactory parseSaxFactory;
|
||||
|
||||
public static interface ParseSaxFactory {
|
||||
ParseSax<?> create(ParseSax.HandlerWithResult<?> handler);
|
||||
}
|
||||
|
||||
public GetAndParseSax<?> createGetAndParseSax(String uri,
|
||||
ParseSax.HandlerWithResult<?> handler) {
|
||||
return new GetAndParseSax(uri, parseSaxFactory.create(handler));
|
||||
}
|
||||
|
||||
@Inject
|
||||
private GetStringFactory getStringFactory;
|
||||
|
||||
public static interface GetStringFactory {
|
||||
GetString create(String uri);
|
||||
}
|
||||
|
||||
public GetString createGetString(String uri) {
|
||||
return getStringFactory.create(uri);
|
||||
}
|
||||
|
||||
@Inject
|
||||
private HeadFactory headFactory;
|
||||
|
||||
public static interface HeadFactory {
|
||||
Head create(String uri);
|
||||
}
|
||||
|
||||
public Head createHead(String uri) {
|
||||
return headFactory.create(uri);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands;
|
||||
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
import org.jclouds.http.commands.callables.xml.ParseSax;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class GetAndParseSax<T> extends HttpFutureCommand<T> {
|
||||
|
||||
public GetAndParseSax(String uri, ParseSax<T> callable) {
|
||||
super("GET", uri, callable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
import org.jclouds.http.commands.callables.ReturnStringIf200;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class GetString extends HttpFutureCommand<String> {
|
||||
|
||||
@Inject
|
||||
public GetString(ReturnStringIf200 callable, @Assisted String uri) {
|
||||
super("GET", uri, callable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
import org.jclouds.http.commands.callables.ReturnTrueIf200;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class Head extends HttpFutureCommand<Boolean> {
|
||||
|
||||
@Inject
|
||||
public Head(ReturnTrueIf200 callable, @Assisted String uri) {
|
||||
super("HEAD", uri, callable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands.callables;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.Utils;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ReturnStringIf200 extends HttpFutureCommand.ResponseCallable<String> {
|
||||
|
||||
@Inject
|
||||
public ReturnStringIf200(java.util.logging.Logger logger) {
|
||||
super(new Logger(logger));
|
||||
}
|
||||
|
||||
|
||||
public String call() throws HttpException {
|
||||
int code = getResponse().getStatusCode();
|
||||
if (code >= 400 && code < 500) {
|
||||
throw new HttpException(String.format("Content not found - %1s", getResponse()));
|
||||
} else if (code == 200) {
|
||||
InputStream entity = getResponse().getContent();
|
||||
if (entity == null)
|
||||
throw new HttpException("no content");
|
||||
String toReturn = null;
|
||||
try {
|
||||
toReturn = Utils.toStringAndClose(entity);
|
||||
} catch (IOException e) {
|
||||
throw new HttpException(String.format("Couldn't receive response %1s, entity: %2s ", getResponse(), toReturn), e);
|
||||
}
|
||||
return toReturn;
|
||||
} else {
|
||||
throw new HttpException(String.format("Unhandled status code - %1s", getResponse()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands.callables;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ReturnTrueIf200 extends HttpFutureCommand.ResponseCallable<Boolean> {
|
||||
|
||||
@Inject
|
||||
public ReturnTrueIf200(java.util.logging.Logger logger) {
|
||||
super(new Logger(logger));
|
||||
}
|
||||
|
||||
public Boolean call() throws HttpException {
|
||||
if (getResponse().getStatusCode() == 200) {
|
||||
return true;
|
||||
} else if (getResponse().getStatusCode() == 404) {
|
||||
return false;
|
||||
} else {
|
||||
throw new HttpException("Error checking bucket " + getResponse());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands.callables.xml;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.Utils;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ParseSax<T> extends HttpFutureCommand.ResponseCallable<T> {
|
||||
|
||||
private XMLReader parser;
|
||||
private HandlerWithResult<T> handler;
|
||||
private boolean suckFirst = false;
|
||||
|
||||
@Inject
|
||||
public ParseSax(java.util.logging.Logger logger, XMLReader parser, @Assisted HandlerWithResult<T> handler) {
|
||||
super(new Logger(logger));
|
||||
this.parser = parser;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public T call() throws HttpException {
|
||||
InputStream input = null;
|
||||
try {
|
||||
input = getResponse().getContent();
|
||||
if (input != null) {
|
||||
return parse(input);
|
||||
} else {
|
||||
throw new HttpException("No input to parse");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Utils.<HttpException>rethrowIfRuntimeOrSameType(e);
|
||||
throw new HttpException("Error parsing input for " + getResponse(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public T parse(InputStream xml) throws HttpException {
|
||||
parseAndCloseStream(xml, handler);
|
||||
return handler.getResult();
|
||||
}
|
||||
|
||||
private void parseAndCloseStream(InputStream xml, ContentHandler handler) throws HttpException {
|
||||
parser.setContentHandler(handler);
|
||||
String response = null;
|
||||
try {
|
||||
if (suckFirst) {
|
||||
response = IOUtils.toString(xml);
|
||||
logger.trace("received content %n%s", response);
|
||||
IOUtils.closeQuietly(xml);
|
||||
xml = IOUtils.toInputStream(response);
|
||||
}
|
||||
parser.parse(new InputSource(xml));
|
||||
} catch (Exception e) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append("Error parsing input for ").append(handler);
|
||||
if (response != null) {
|
||||
message.append("\n").append(response);
|
||||
}
|
||||
logger.error(e, message.toString());
|
||||
Utils.<HttpException>rethrowIfRuntimeOrSameType(e);
|
||||
throw new HttpException(message.toString(), e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(xml);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract static class HandlerWithResult<T> extends DefaultHandler {
|
||||
public abstract T getResult();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands.callables.xml.config;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Singleton;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class SaxModule extends AbstractModule {
|
||||
|
||||
@Provides
|
||||
XMLReader provideXMLReader(SAXParserFactory factory) throws ParserConfigurationException, SAXException {
|
||||
SAXParser saxParser = factory.newSAXParser();
|
||||
XMLReader parser = saxParser.getXMLReader();
|
||||
return parser;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
SAXParserFactory provideSAXParserFactory() {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(false);
|
||||
factory.setValidating(false);
|
||||
factory.setXIncludeAware(false);
|
||||
return factory;
|
||||
}
|
||||
|
||||
protected void configure() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands.config;
|
||||
|
||||
import org.jclouds.http.commands.CommandFactory;
|
||||
import org.jclouds.http.commands.GetString;
|
||||
import org.jclouds.http.commands.Head;
|
||||
import org.jclouds.http.commands.callables.xml.ParseSax;
|
||||
import org.jclouds.http.commands.callables.xml.config.SaxModule;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.assistedinject.FactoryProvider;
|
||||
|
||||
/**
|
||||
* note that all this private factory clutter will go away when the following is
|
||||
* implemented @link http://code.google.com/p/google-guice/issues/detail?id=346
|
||||
* it will be replaced with a configuration:
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class HttpCommandsModule extends AbstractModule {
|
||||
protected void configure() {
|
||||
bind(CommandFactory.GetStringFactory.class)
|
||||
.toProvider(
|
||||
FactoryProvider.newFactory(
|
||||
CommandFactory.GetStringFactory.class,
|
||||
GetString.class));
|
||||
bind(CommandFactory.HeadFactory.class).toProvider(
|
||||
FactoryProvider.newFactory(CommandFactory.HeadFactory.class,
|
||||
Head.class));
|
||||
|
||||
install(new SaxModule());
|
||||
bind(CommandFactory.ParseSaxFactory.class).toProvider(
|
||||
FactoryProvider.newFactory(
|
||||
new TypeLiteral<CommandFactory.ParseSaxFactory>() {
|
||||
}, new TypeLiteral<ParseSax<?>>() {
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.config;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.name.Named;
|
||||
import org.jclouds.http.HttpFutureCommandClient;
|
||||
import org.jclouds.http.JavaUrlHttpFutureCommandClient;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class JavaUrlHttpFutureCommandClientModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
//note this is not threadsafe, so it cannot be singleton
|
||||
bind(HttpFutureCommandClient.class).to(JavaUrlHttpFutureCommandClient.class);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
protected URL provideAddress(@Named("jclouds.http.address") String address, @Named("jclouds.http.port") int port, @Named("jclouds.http.secure") boolean isSecure) throws MalformedURLException {
|
||||
|
||||
return new URL(isSecure ? "https" : "http", address, port, "/");
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.lifecycle;
|
||||
|
||||
import org.jclouds.Logger;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class BaseLifeCycle implements Runnable, LifeCycle {
|
||||
protected final Logger logger;
|
||||
protected final ExecutorService executor;
|
||||
protected final BaseLifeCycle[] dependencies;
|
||||
protected final Object statusLock;
|
||||
protected volatile Status status;
|
||||
protected Exception exception;
|
||||
|
||||
public BaseLifeCycle(Logger logger, ExecutorService executor, BaseLifeCycle... dependencies) {
|
||||
this.logger = logger;
|
||||
this.executor = executor;
|
||||
this.dependencies = dependencies;
|
||||
this.statusLock = new Object();
|
||||
this.status = Status.INACTIVE;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
while (shouldDoWork()) {
|
||||
doWork();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(e, "Exception doing work");
|
||||
this.exception = e;
|
||||
}
|
||||
this.status = Status.SHUTTING_DOWN;
|
||||
doShutdown();
|
||||
this.status = Status.SHUT_DOWN;
|
||||
logger.info("%1s", this);
|
||||
}
|
||||
|
||||
protected abstract void doWork() throws Exception;
|
||||
|
||||
protected abstract void doShutdown();
|
||||
|
||||
protected boolean shouldDoWork() {
|
||||
try {
|
||||
exceptionIfDepedenciesNotActive();
|
||||
} catch (IllegalStateException e) {
|
||||
return false;
|
||||
}
|
||||
return status.equals(Status.ACTIVE) && exception == null;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
logger.info("starting %1s", this);
|
||||
synchronized (this.statusLock) {
|
||||
if (this.status.compareTo(Status.SHUTDOWN_REQUEST) >= 0) {
|
||||
doShutdown();
|
||||
this.status = Status.SHUT_DOWN;
|
||||
this.statusLock.notifyAll();
|
||||
return;
|
||||
}
|
||||
if (this.status.compareTo(Status.ACTIVE) == 0) {
|
||||
this.statusLock.notifyAll();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.status.compareTo(Status.INACTIVE) != 0) {
|
||||
throw new IllegalStateException("Illegal state: " + this.status);
|
||||
}
|
||||
|
||||
exceptionIfDepedenciesNotActive();
|
||||
|
||||
this.status = Status.ACTIVE;
|
||||
}
|
||||
executor.execute(this);
|
||||
}
|
||||
|
||||
protected void exceptionIfDepedenciesNotActive() {
|
||||
for (BaseLifeCycle dependency : dependencies) {
|
||||
if (dependency.status.compareTo(Status.ACTIVE) != 0) {
|
||||
throw new IllegalStateException(String.format("Illegal state: %1s for component: %2s", dependency.status, dependency));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Exception getException() {
|
||||
return this.exception;
|
||||
}
|
||||
|
||||
protected void awaitShutdown(long timeout) throws InterruptedException {
|
||||
awaitStatus(Status.SHUT_DOWN, timeout);
|
||||
}
|
||||
|
||||
protected void awaitStatus(Status intended, long timeout) throws InterruptedException {
|
||||
synchronized (this.statusLock) {
|
||||
long deadline = System.currentTimeMillis() + timeout;
|
||||
long remaining = timeout;
|
||||
while (this.status != intended) {
|
||||
this.statusLock.wait(remaining);
|
||||
if (timeout > 0) {
|
||||
remaining = deadline - System.currentTimeMillis();
|
||||
if (remaining <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
shutdown(2000);
|
||||
}
|
||||
|
||||
public void shutdown(long waitMs) {
|
||||
synchronized (this.statusLock) {
|
||||
if (this.status.compareTo(Status.ACTIVE) > 0) {
|
||||
return;
|
||||
}
|
||||
this.status = Status.SHUTDOWN_REQUEST;
|
||||
try {
|
||||
awaitShutdown(waitMs);
|
||||
} catch (InterruptedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void exceptionIfNotActive() {
|
||||
if (!status.equals(Status.ACTIVE))
|
||||
throw new IllegalStateException(String.format("not active: %1s", this));
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.lifecycle;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class Closer implements Closeable {
|
||||
List<Closeable> methodsToClose = new ArrayList<Closeable>();
|
||||
|
||||
public void addToClose(Closeable toClose) {
|
||||
methodsToClose.add(toClose);
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
Collections.reverse(methodsToClose);
|
||||
for (Closeable toClose : methodsToClose) {
|
||||
toClose.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.lifecycle;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface LifeCycle {
|
||||
|
||||
/**
|
||||
* @return the current state of the component;
|
||||
*/
|
||||
Status getStatus();
|
||||
|
||||
/**
|
||||
* @return Exception or null, if there are no fatal Exceptions encountered in the lifecycle of this component.
|
||||
*/
|
||||
Exception getException();
|
||||
|
||||
/**
|
||||
* Asynchronously starts the component
|
||||
*/
|
||||
@PostConstruct
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Requests shutdown of the component.
|
||||
*/
|
||||
@PreDestroy
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* Requests shutdown, but will only wait @link waitms milliseconds
|
||||
*
|
||||
* @param waitMs maximum time to wait in milliseconds
|
||||
*/
|
||||
void shutdown(long waitMs);
|
||||
|
||||
/**
|
||||
* States that are possible for a component.
|
||||
*/
|
||||
public static enum Status {
|
||||
|
||||
/**
|
||||
* The component is inactive / has not been started
|
||||
*/
|
||||
INACTIVE,
|
||||
|
||||
/**
|
||||
* The component is active / processing I/O events.
|
||||
*/
|
||||
ACTIVE,
|
||||
|
||||
/**
|
||||
* Shutdown of the component has been requested.
|
||||
*/
|
||||
SHUTDOWN_REQUEST,
|
||||
|
||||
/**
|
||||
* The component is shutting down.
|
||||
*/
|
||||
SHUTTING_DOWN,
|
||||
|
||||
/**
|
||||
* The component has shut down.
|
||||
*/
|
||||
SHUT_DOWN;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.lifecycle.config;
|
||||
|
||||
import static com.google.inject.matcher.Matchers.any;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.jclouds.lifecycle.Closer;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.ProvisionException;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.spi.InjectionListener;
|
||||
import com.google.inject.spi.TypeEncounter;
|
||||
import com.google.inject.spi.TypeListener;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class LifeCycleModule extends AbstractModule {
|
||||
|
||||
protected void configure() {
|
||||
final ExecutorService executor = Executors.newCachedThreadPool();
|
||||
bind(ExecutorService.class).toInstance(executor);
|
||||
Closer closer = new Closer();
|
||||
closer.addToClose(new Closeable() {
|
||||
public void close() throws IOException {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
});
|
||||
bind(Closer.class).toInstance(closer);
|
||||
bindPostInjectionInvoke(closer);
|
||||
}
|
||||
|
||||
protected void bindPostInjectionInvoke(final Closer closer) {
|
||||
bindListener(any(), new TypeListener() {
|
||||
public <I> void hear(TypeLiteral<I> injectableType,
|
||||
TypeEncounter<I> encounter) {
|
||||
Set<Method> methods = new HashSet<Method>();
|
||||
Class<? super I> type = injectableType.getRawType();
|
||||
while (type != null) {
|
||||
methods.addAll(Arrays.asList(type.getDeclaredMethods()));
|
||||
type = type.getSuperclass();
|
||||
}
|
||||
for (final Method method : methods) {
|
||||
PostConstruct postConstruct = method
|
||||
.getAnnotation(PostConstruct.class);
|
||||
if (postConstruct != null) {
|
||||
encounter.register(new InjectionListener<I>() {
|
||||
public void afterInjection(I injectee) {
|
||||
try {
|
||||
method.invoke(injectee);
|
||||
} catch (InvocationTargetException ie) {
|
||||
Throwable e = ie.getTargetException();
|
||||
throw new ProvisionException(
|
||||
e.getMessage(), e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ProvisionException(
|
||||
e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
PreDestroy preDestroy = method
|
||||
.getAnnotation(PreDestroy.class);
|
||||
if (preDestroy != null) {
|
||||
encounter.register(new InjectionListener<I>() {
|
||||
public void afterInjection(final I injectee) {
|
||||
closer.addToClose(new Closeable() {
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
method.invoke(injectee);
|
||||
} catch (InvocationTargetException ie) {
|
||||
Throwable e = ie
|
||||
.getTargetException();
|
||||
throw new IOException(e
|
||||
.getMessage());
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IOException(e
|
||||
.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.guice;
|
||||
|
||||
import java.util.logging.*;
|
||||
|
||||
/**
|
||||
* Enable or disable Guice debug output
|
||||
* on the console.
|
||||
*/
|
||||
public class GuiceDebug {
|
||||
private static final Handler HANDLER;
|
||||
|
||||
static {
|
||||
HANDLER = new StreamHandler(System.out, new Formatter() {
|
||||
public String format(LogRecord record) {
|
||||
return String.format("[Guice %s] %s%n",
|
||||
record.getLevel().getName(),
|
||||
record.getMessage());
|
||||
}
|
||||
});
|
||||
HANDLER.setLevel(Level.ALL);
|
||||
}
|
||||
|
||||
private GuiceDebug() {
|
||||
}
|
||||
|
||||
public static Logger getLogger() {
|
||||
return Logger.getLogger("com.google.inject");
|
||||
}
|
||||
|
||||
public static void enable() {
|
||||
Logger guiceLogger = getLogger();
|
||||
guiceLogger.addHandler(GuiceDebug.HANDLER);
|
||||
guiceLogger.setLevel(Level.ALL);
|
||||
}
|
||||
|
||||
public static void disable() {
|
||||
Logger guiceLogger = getLogger();
|
||||
guiceLogger.setLevel(Level.OFF);
|
||||
guiceLogger.removeHandler(GuiceDebug.HANDLER);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.jclouds.http.commands.CommandFactory;
|
||||
import org.jclouds.http.commands.GetAndParseSax;
|
||||
import org.jclouds.http.commands.GetString;
|
||||
import org.jclouds.http.commands.Head;
|
||||
import org.jclouds.http.commands.callables.xml.ParseSax;
|
||||
import org.jclouds.http.commands.config.HttpCommandsModule;
|
||||
import org.mortbay.jetty.Handler;
|
||||
import org.mortbay.jetty.Request;
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.handler.AbstractHandler;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Optional;
|
||||
import org.testng.annotations.Parameters;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(threadPoolSize = 100)
|
||||
public abstract class BaseHttpFutureCommandClientTest {
|
||||
protected static final String XML = "<foo><bar>whoppers</bar></foo>";
|
||||
protected Server server = null;
|
||||
protected CommandFactory factory;
|
||||
protected HttpFutureCommandClient client;
|
||||
protected Injector injector;
|
||||
|
||||
@BeforeClass
|
||||
@Parameters( { "test-jetty-port" })
|
||||
public void setUpJetty(@Optional("8123") final int testPort)
|
||||
throws Exception {
|
||||
Handler handler = new AbstractHandler() {
|
||||
public void handle(String target, HttpServletRequest request,
|
||||
HttpServletResponse response, int dispatch)
|
||||
throws IOException, ServletException {
|
||||
if (request.getHeader("test") != null) {
|
||||
response.setContentType("text/plain");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.getWriter().println("test");
|
||||
} else {
|
||||
response.setContentType("text/xml");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.getWriter().println(XML);
|
||||
}
|
||||
((Request) request).setHandled(true);
|
||||
}
|
||||
};
|
||||
|
||||
server = new Server(testPort);
|
||||
server.setHandler(handler);
|
||||
server.start();
|
||||
final Properties properties = new Properties();
|
||||
properties.put("jclouds.http.address", "localhost");
|
||||
properties.put("jclouds.http.port", testPort + "");
|
||||
properties.put("jclouds.http.secure", "false");
|
||||
addConnectionProperties(properties);
|
||||
final List<HttpRequestFilter> filters = new ArrayList<HttpRequestFilter>(
|
||||
1);
|
||||
filters.add(new HttpRequestFilter() {
|
||||
public void filter(HttpRequest request) throws HttpException {
|
||||
if (request.getHeaders().containsKey("filterme")) {
|
||||
request.getHeaders().put("test", "test");
|
||||
}
|
||||
}
|
||||
});
|
||||
injector = Guice.createInjector(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
|
||||
Names.bindProperties(binder(), properties);
|
||||
}
|
||||
}, new HttpCommandsModule(), createClientModule(),
|
||||
new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(new TypeLiteral<List<HttpRequestFilter>>() {
|
||||
}).toInstance(filters);
|
||||
}
|
||||
});
|
||||
factory = injector.getInstance(CommandFactory.class);
|
||||
client = injector.getInstance(HttpFutureCommandClient.class);
|
||||
assert client != null;
|
||||
}
|
||||
|
||||
protected abstract void addConnectionProperties(Properties props);
|
||||
|
||||
protected abstract Module createClientModule();
|
||||
|
||||
@AfterClass
|
||||
public void tearDownJetty() throws Exception {
|
||||
client.close();
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test(invocationCount = 500, timeOut = 1000)
|
||||
void testRequestFilter() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException {
|
||||
GetString get = factory.createGetString("/");
|
||||
get.getRequest().getHeaders().put("filterme", "filterme");
|
||||
client.submit(get);
|
||||
assert get.get().trim().equals("test") : String.format(
|
||||
"expected: [%1s], but got [%2s]", "test", get.get());
|
||||
}
|
||||
|
||||
@Test(invocationCount = 500, timeOut = 1000)
|
||||
void testGetStringWithHeader() throws MalformedURLException,
|
||||
ExecutionException, InterruptedException {
|
||||
GetString get = factory.createGetString("/");
|
||||
get.getRequest().getHeaders().put("test", "test");
|
||||
client.submit(get);
|
||||
assert get.get().trim().equals("test") : String.format(
|
||||
"expected: [%1s], but got [%2s]", "test", get.get());
|
||||
}
|
||||
|
||||
@Test(invocationCount = 500, timeOut = 1000)
|
||||
void testGetString() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException {
|
||||
GetString get = factory.createGetString("/");
|
||||
assert get != null;
|
||||
client.submit(get);
|
||||
assert get.get().trim().equals(XML) : String.format(
|
||||
"expected: [%1s], but got [%2s]", XML, get.get());
|
||||
}
|
||||
|
||||
@Test(invocationCount = 500, timeOut = 1000)
|
||||
void testHead() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException {
|
||||
Head head = factory.createHead("/");
|
||||
assert head != null;
|
||||
client.submit(head);
|
||||
assert head.get();
|
||||
}
|
||||
|
||||
@Test(invocationCount = 500, timeOut = 1000)
|
||||
void testGetAndParseSax() throws MalformedURLException, ExecutionException,
|
||||
InterruptedException {
|
||||
GetAndParseSax getAndParseSax = factory.createGetAndParseSax("/",
|
||||
new ParseSax.HandlerWithResult<String>() {
|
||||
@Override
|
||||
public String getResult() {
|
||||
return bar;
|
||||
}
|
||||
|
||||
private String bar = null;
|
||||
private StringBuilder currentText = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String name, String qName) {
|
||||
|
||||
if (qName.equals("bar")) {
|
||||
bar = currentText.toString();
|
||||
}
|
||||
currentText = new StringBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters(char ch[], int start, int length) {
|
||||
currentText.append(ch, start, length);
|
||||
}
|
||||
});
|
||||
assert getAndParseSax != null;
|
||||
client.submit(getAndParseSax);
|
||||
assert getAndParseSax.get().equals("whoppers");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http;
|
||||
|
||||
import com.google.inject.Module;
|
||||
import org.jclouds.http.config.JavaUrlHttpFutureCommandClientModule;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test
|
||||
public class JavaUrlHttpFutureCommandFutureCommandClientTest extends BaseHttpFutureCommandClientTest {
|
||||
|
||||
protected Module createClientModule() {
|
||||
return new JavaUrlHttpFutureCommandClientModule();
|
||||
}
|
||||
|
||||
|
||||
protected void addConnectionProperties(Properties props) {
|
||||
//NONE
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands;
|
||||
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import org.jclouds.http.commands.callables.ReturnStringIf200;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test
|
||||
public class GetStringTest {
|
||||
private static final String GOOD_PATH = "/index.html";
|
||||
|
||||
|
||||
private GetString get = null;
|
||||
private ReturnStringIf200 callable = null;
|
||||
|
||||
@BeforeMethod
|
||||
void setUp() {
|
||||
callable = new ReturnStringIf200(createMock(Logger.class));
|
||||
get = new GetString(callable, GOOD_PATH);
|
||||
|
||||
}
|
||||
|
||||
@AfterMethod
|
||||
void tearDown() {
|
||||
get = null;
|
||||
callable = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructor() {
|
||||
assert get.getResponseFuture() != null;
|
||||
assert get.getRequest().getUri().equals(GOOD_PATH);
|
||||
assert get.getRequest().getMethod().equals("GET");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands.callables;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import static org.easymock.classextension.EasyMock.*;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Test
|
||||
public class ReturnStringIf200Test {
|
||||
|
||||
private HttpFutureCommand.ResponseCallable<String> callable = null;
|
||||
|
||||
@BeforeMethod
|
||||
void setUp() {
|
||||
callable = new ReturnStringIf200(createMock(Logger.class));
|
||||
}
|
||||
|
||||
@AfterMethod
|
||||
void tearDown() {
|
||||
callable = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionWhenNoContentOn200() throws ExecutionException, InterruptedException, TimeoutException, IOException {
|
||||
HttpResponse response = createMock(HttpResponse.class);
|
||||
expect(response.getStatusCode()).andReturn(200);
|
||||
expect(response.getContent()).andReturn(null);
|
||||
replay(response);
|
||||
callable.setResponse(response);
|
||||
try {
|
||||
callable.call();
|
||||
} catch (Exception e) {
|
||||
assert e.getMessage().equals("no content");
|
||||
}
|
||||
verify(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionWhenIOExceptionOn200() throws ExecutionException, InterruptedException, TimeoutException, IOException {
|
||||
HttpResponse response = createMock(HttpResponse.class);
|
||||
expect(response.getStatusCode()).andReturn(200);
|
||||
RuntimeException exception = new RuntimeException("bad");
|
||||
expect(response.getContent()).andThrow(exception);
|
||||
replay(response);
|
||||
callable.setResponse(response);
|
||||
try {
|
||||
callable.call();
|
||||
} catch (Exception e) {
|
||||
assert e.equals(exception);
|
||||
}
|
||||
verify(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseOk() throws Exception {
|
||||
HttpResponse response = createMock(HttpResponse.class);
|
||||
expect(response.getStatusCode()).andReturn(200);
|
||||
expect(response.getContent()).andReturn(IOUtils.toInputStream("hello"));
|
||||
replay(response);
|
||||
callable.setResponse(response);
|
||||
assert "hello".equals(callable.call());
|
||||
verify(response);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.commands.config;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
import org.jclouds.http.commands.CommandFactory;
|
||||
import org.jclouds.http.commands.callables.xml.ParseSax;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test
|
||||
public class HttpCommandsModuleTest {
|
||||
|
||||
public void testGetString() {
|
||||
Injector i = Guice.createInjector(new HttpCommandsModule());
|
||||
CommandFactory factory = i.getInstance(CommandFactory.class);
|
||||
HttpFutureCommand get = factory.createGetString("/index.html");
|
||||
assert get != null;
|
||||
assert get.getResponseFuture() != null;
|
||||
}
|
||||
|
||||
public void testHead() {
|
||||
Injector i = Guice.createInjector(new HttpCommandsModule());
|
||||
CommandFactory factory = i.getInstance(CommandFactory.class);
|
||||
HttpFutureCommand Head = factory.createHead("/index.html");
|
||||
assert Head != null;
|
||||
assert Head.getResponseFuture() != null;
|
||||
}
|
||||
|
||||
public void testGetAndParseXml() {
|
||||
Injector i = Guice.createInjector(new HttpCommandsModule());
|
||||
CommandFactory factory = i.getInstance(CommandFactory.class);
|
||||
HttpFutureCommand GetAndParseXml = factory.createGetAndParseSax("/index.html", new ParseSax.HandlerWithResult<String>(){
|
||||
public String getResult() {
|
||||
return "hello";
|
||||
}
|
||||
});
|
||||
assert GetAndParseXml != null;
|
||||
assert GetAndParseXml.getResponseFuture() != null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.lifecycle.config;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import org.jclouds.lifecycle.Closer;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test
|
||||
public class LifeCycleModuleTest {
|
||||
|
||||
@Test
|
||||
void testBindsExecutor() {
|
||||
Injector i = Guice.createInjector(new LifeCycleModule());
|
||||
assert i.getInstance(ExecutorService.class) != null;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindsCloser() {
|
||||
Injector i = Guice.createInjector(new LifeCycleModule());
|
||||
assert i.getInstance(Closer.class) != null;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCloserClosesExecutor() throws IOException {
|
||||
Injector i = Guice.createInjector(new LifeCycleModule());
|
||||
ExecutorService executor = i.getInstance(ExecutorService.class);
|
||||
assert !executor.isShutdown();
|
||||
Closer closer = i.getInstance(Closer.class);
|
||||
closer.close();
|
||||
assert executor.isShutdown();
|
||||
}
|
||||
|
||||
static class PreDestroyable {
|
||||
boolean isClosed = false;
|
||||
|
||||
@Inject
|
||||
PreDestroyable(ExecutorService executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
ExecutorService executor;
|
||||
|
||||
@PreDestroy
|
||||
public void close() {
|
||||
assert !executor.isShutdown();
|
||||
isClosed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCloserPreDestroyOrder() throws IOException {
|
||||
Injector i = Guice.createInjector(new LifeCycleModule(), new AbstractModule() {
|
||||
protected void configure() {
|
||||
bind(PreDestroyable.class);
|
||||
}
|
||||
});
|
||||
ExecutorService executor = i.getInstance(ExecutorService.class);
|
||||
assert !executor.isShutdown();
|
||||
PreDestroyable preDestroyable = i.getInstance(PreDestroyable.class);
|
||||
assert !preDestroyable.isClosed;
|
||||
Closer closer = i.getInstance(Closer.class);
|
||||
closer.close();
|
||||
assert preDestroyable.isClosed;
|
||||
assert executor.isShutdown();
|
||||
}
|
||||
|
||||
static class PostConstructable {
|
||||
boolean isStarted;
|
||||
|
||||
@PostConstruct
|
||||
void start() {
|
||||
isStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPostConstruct() {
|
||||
Injector i = Guice.createInjector(new LifeCycleModule(), new AbstractModule() {
|
||||
protected void configure() {
|
||||
bind(PostConstructable.class);
|
||||
}
|
||||
});
|
||||
PostConstructable postConstructable = i.getInstance(PostConstructable.class);
|
||||
assert postConstructable.isStarted;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
$HeadURL$
|
||||
$Revision$
|
||||
$Date$
|
||||
|
||||
Copyright (C) 2009 Adrian Cole <adriancole@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>project</artifactId>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../../project/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jclouds-httpnio</artifactId>
|
||||
<name>jclouds HttpNio Client</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>HttpNio Connection Pooling client</description>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/extensions/httpnio</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/extensions/httpnio</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk/extensions/httpnio</url>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
<!-- TODO find out how to get this transatively from core -->
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty</artifactId>
|
||||
<version>6.1.16</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore-nio</artifactId>
|
||||
<version>4.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.httpnio;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.HttpVersion;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
|
||||
import org.apache.http.nio.entity.NByteArrayEntity;
|
||||
import org.apache.http.nio.entity.NFileEntity;
|
||||
import org.apache.http.nio.entity.NStringEntity;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
|
||||
public class HttpNioUtils {
|
||||
public static HttpEntityEnclosingRequest convertToApacheRequest(
|
||||
HttpRequest object) {
|
||||
BasicHttpEntityEnclosingRequest apacheRequest = new BasicHttpEntityEnclosingRequest(
|
||||
object.getMethod(), object.getUri(), HttpVersion.HTTP_1_1);
|
||||
for (String header : object.getHeaders().keySet()) {
|
||||
for (String value : object.getHeaders().get(header))
|
||||
apacheRequest.addHeader(header, value);
|
||||
}
|
||||
Object content = object.getContent();
|
||||
if (content != null) {
|
||||
addEntityForContent(apacheRequest, content,
|
||||
object.getContentType(), object.getContentLength());
|
||||
}
|
||||
return apacheRequest;
|
||||
}
|
||||
|
||||
public static void addEntityForContent(
|
||||
BasicHttpEntityEnclosingRequest apacheRequest, Object content,
|
||||
String contentType, long length) {
|
||||
if (content instanceof InputStream) {
|
||||
InputStream inputStream = (InputStream) content;
|
||||
if (length <= 0)
|
||||
throw new IllegalArgumentException(
|
||||
"you must specify size when content is an InputStream");
|
||||
InputStreamEntity entity = new InputStreamEntity(inputStream,
|
||||
length);
|
||||
entity.setContentType(contentType);
|
||||
apacheRequest.setEntity(entity);
|
||||
} else if (content instanceof String) {
|
||||
NStringEntity nStringEntity = null;
|
||||
try {
|
||||
nStringEntity = new NStringEntity((String) content);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Encoding not supported", e);
|
||||
}
|
||||
nStringEntity.setContentType(contentType);
|
||||
apacheRequest.setEntity(nStringEntity);
|
||||
} else if (content instanceof File) {
|
||||
apacheRequest.setEntity(new NFileEntity((File) content,
|
||||
contentType, true));
|
||||
} else if (content instanceof byte[]) {
|
||||
NByteArrayEntity entity = new NByteArrayEntity((byte[]) content);
|
||||
entity.setContentType(contentType);
|
||||
apacheRequest.setEntity(entity);
|
||||
} else {
|
||||
throw new UnsupportedOperationException(
|
||||
"Content class not supported: "
|
||||
+ content.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static HttpResponse convertToJavaCloudsResponse(
|
||||
org.apache.http.HttpResponse apacheResponse) throws IOException {
|
||||
HttpResponse response = new HttpResponse();
|
||||
if (apacheResponse.getEntity() != null) {
|
||||
response.setContent(apacheResponse.getEntity().getContent());
|
||||
}
|
||||
for (Header header : apacheResponse.getAllHeaders()) {
|
||||
response.getHeaders().put(header.getName(), header.getValue());
|
||||
}
|
||||
response.setStatusCode(apacheResponse.getStatusLine().getStatusCode());
|
||||
return response;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.httpnio.config;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.name.Named;
|
||||
|
||||
import org.apache.http.nio.NHttpConnection;
|
||||
import org.jclouds.command.pool.FutureCommandConnectionRetry;
|
||||
import org.jclouds.http.HttpFutureCommandClient;
|
||||
import org.jclouds.http.httpnio.config.internal.NonSSLHttpNioConnectionPoolClientModule;
|
||||
import org.jclouds.http.httpnio.config.internal.SSLHttpNioConnectionPoolClientModule;
|
||||
import org.jclouds.http.httpnio.pool.HttpNioConnectionPoolClient;
|
||||
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandConnectionRetry;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class HttpNioConnectionPoolClientModule extends AbstractModule {
|
||||
|
||||
@Named("jclouds.http.secure")
|
||||
boolean isSecure;
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
requestInjection(this);
|
||||
//TODO test...
|
||||
if (isSecure)
|
||||
install(new SSLHttpNioConnectionPoolClientModule());
|
||||
else
|
||||
install(new NonSSLHttpNioConnectionPoolClientModule());
|
||||
bind(new TypeLiteral<FutureCommandConnectionRetry<NHttpConnection>>(){}).to(HttpNioFutureCommandConnectionRetry.class);
|
||||
bind(HttpFutureCommandClient.class).to(HttpNioConnectionPoolClient.class);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
protected InetSocketAddress provideAddress(@Named("jclouds.http.address") String address, @Named("jclouds.http.port") int port) {
|
||||
return new InetSocketAddress(address, port);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.httpnio.config.internal;
|
||||
|
||||
import com.google.inject.*;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.assistedinject.FactoryProvider;
|
||||
import com.google.inject.name.Named;
|
||||
import org.apache.http.ConnectionReuseStrategy;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.impl.DefaultConnectionReuseStrategy;
|
||||
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
|
||||
import org.apache.http.nio.NHttpConnection;
|
||||
import org.apache.http.nio.entity.BufferingNHttpEntity;
|
||||
import org.apache.http.nio.protocol.AsyncNHttpClientHandler;
|
||||
import org.apache.http.nio.protocol.NHttpRequestExecutionHandler;
|
||||
import org.apache.http.nio.reactor.IOEventDispatch;
|
||||
import org.apache.http.nio.reactor.IOReactorException;
|
||||
import org.apache.http.nio.util.ByteBufferAllocator;
|
||||
import org.apache.http.nio.util.HeapByteBufferAllocator;
|
||||
import org.apache.http.params.BasicHttpParams;
|
||||
import org.apache.http.params.CoreConnectionPNames;
|
||||
import org.apache.http.params.CoreProtocolPNames;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.protocol.*;
|
||||
import org.jclouds.command.pool.FutureCommandConnectionRetry;
|
||||
import org.jclouds.command.pool.config.FutureCommandConnectionPoolClientModule;
|
||||
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandConnectionHandle;
|
||||
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandConnectionPool;
|
||||
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandConnectionRetry;
|
||||
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandExecutionHandler;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class BaseHttpNioConnectionPoolClientModule extends FutureCommandConnectionPoolClientModule<NHttpConnection> {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public AsyncNHttpClientHandler provideAsyncNttpClientHandler(BasicHttpProcessor httpProcessor, NHttpRequestExecutionHandler execHandler, ConnectionReuseStrategy connStrategy, ByteBufferAllocator allocator, HttpParams params) {
|
||||
return new AsyncNHttpClientHandler(httpProcessor, execHandler, connStrategy, allocator, params);
|
||||
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public BasicHttpProcessor provideClientProcessor() {
|
||||
BasicHttpProcessor httpproc = new BasicHttpProcessor();
|
||||
httpproc.addInterceptor(new RequestContent());
|
||||
httpproc.addInterceptor(new RequestTargetHost());
|
||||
httpproc.addInterceptor(new RequestConnControl());
|
||||
httpproc.addInterceptor(new RequestUserAgent());
|
||||
httpproc.addInterceptor(new RequestExpectContinue());
|
||||
return httpproc;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public HttpParams provideHttpParams() {
|
||||
HttpParams params = new BasicHttpParams();
|
||||
params
|
||||
.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000)
|
||||
.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
|
||||
.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
|
||||
.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
|
||||
.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "jclouds/1.0");
|
||||
return params;
|
||||
}
|
||||
|
||||
protected void configure() {
|
||||
super.configure();
|
||||
bind(HttpNioFutureCommandExecutionHandler.ConsumingNHttpEntityFactory.class).toProvider(FactoryProvider.newFactory(HttpNioFutureCommandExecutionHandler.ConsumingNHttpEntityFactory.class, InjectableBufferingNHttpEntity.class)).in(Scopes.SINGLETON);
|
||||
bind(NHttpRequestExecutionHandler.class).to(HttpNioFutureCommandExecutionHandler.class).in(Scopes.SINGLETON);
|
||||
bind(ConnectionReuseStrategy.class).to(DefaultConnectionReuseStrategy.class).in(Scopes.SINGLETON);
|
||||
bind(ByteBufferAllocator.class).to(HeapByteBufferAllocator.class);
|
||||
bind(FutureCommandConnectionRetry.class).to(HttpNioFutureCommandConnectionRetry.class);
|
||||
bind(HttpNioFutureCommandConnectionPool.FutureCommandConnectionHandleFactory.class).toProvider(FactoryProvider.newFactory(new TypeLiteral<HttpNioFutureCommandConnectionPool.FutureCommandConnectionHandleFactory>() {
|
||||
}, new TypeLiteral<HttpNioFutureCommandConnectionHandle>() {
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
static class InjectableBufferingNHttpEntity extends BufferingNHttpEntity {
|
||||
@Inject
|
||||
public InjectableBufferingNHttpEntity(@Assisted HttpEntity httpEntity, ByteBufferAllocator allocator) {
|
||||
super(httpEntity, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockingQueue<NHttpConnection> provideAvailablePool(@Named("jclouds.pool.max_connections") int max) throws Exception {
|
||||
return new ArrayBlockingQueue<NHttpConnection>(max, true);
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public abstract IOEventDispatch provideClientEventDispatch(AsyncNHttpClientHandler handler, HttpParams params) throws Exception;
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public DefaultConnectingIOReactor provideDefaultConnectingIOReactor(@Named("jclouds.http.pool.io_worker_threads") int ioWorkerThreads, HttpParams params) throws IOReactorException {
|
||||
return new DefaultConnectingIOReactor(ioWorkerThreads, params);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.httpnio.config.internal;
|
||||
|
||||
import org.apache.http.impl.nio.DefaultClientIOEventDispatch;
|
||||
import org.apache.http.nio.protocol.AsyncNHttpClientHandler;
|
||||
import org.apache.http.nio.reactor.IOEventDispatch;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.jclouds.http.httpnio.config.internal.BaseHttpNioConnectionPoolClientModule;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class NonSSLHttpNioConnectionPoolClientModule extends BaseHttpNioConnectionPoolClientModule {
|
||||
public IOEventDispatch provideClientEventDispatch(AsyncNHttpClientHandler handler, HttpParams params) throws Exception {
|
||||
return new DefaultClientIOEventDispatch(
|
||||
handler,
|
||||
params);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.httpnio.config.internal;
|
||||
|
||||
import org.apache.http.impl.nio.SSLClientIOEventDispatch;
|
||||
import org.apache.http.nio.reactor.IOEventDispatch;
|
||||
import org.apache.http.nio.protocol.AsyncNHttpClientHandler;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.jclouds.http.httpnio.config.internal.BaseHttpNioConnectionPoolClientModule;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class SSLHttpNioConnectionPoolClientModule extends BaseHttpNioConnectionPoolClientModule {
|
||||
|
||||
protected void configure() {
|
||||
super.configure();
|
||||
}
|
||||
|
||||
// note until a bug is fixed, you cannot annotate overriding methods with google annotations
|
||||
// http://code.google.com/p/google-guice/issues/detail?id=347
|
||||
@Override
|
||||
public IOEventDispatch provideClientEventDispatch(AsyncNHttpClientHandler handler, HttpParams params) throws Exception {
|
||||
SSLContext context = SSLContext.getInstance("TLS");
|
||||
context.init(null, null, null);
|
||||
return new SSLClientIOEventDispatch(
|
||||
handler,
|
||||
context,
|
||||
params);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.httpnio.pool;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import org.apache.http.nio.NHttpConnection;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
import org.jclouds.command.pool.FutureCommandConnectionPoolClient;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpFutureCommandClient;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpRequestFilter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class HttpNioConnectionPoolClient extends FutureCommandConnectionPoolClient<NHttpConnection> implements HttpFutureCommandClient {
|
||||
private List<HttpRequestFilter> requestFilters = Collections.emptyList();
|
||||
|
||||
public List<HttpRequestFilter> getRequestFilters() {
|
||||
return requestFilters;
|
||||
}
|
||||
|
||||
@Inject(optional = true)
|
||||
public void setRequestFilters(List<HttpRequestFilter> requestFilters) {
|
||||
this.requestFilters = requestFilters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <O extends FutureCommand> void invoke(O operation) {
|
||||
HttpRequest request = (HttpRequest) operation.getRequest();
|
||||
try {
|
||||
for (HttpRequestFilter filter : getRequestFilters()) {
|
||||
filter.filter(request);
|
||||
}
|
||||
super.invoke(operation);
|
||||
} catch (HttpException e) {
|
||||
operation.setException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
public HttpNioConnectionPoolClient(Logger logger, ExecutorService executor, HttpNioFutureCommandConnectionPool httpFutureCommandConnectionHandleNHttpConnectionNioFutureCommandConnectionPool, BlockingQueue<FutureCommand> commandQueue) {
|
||||
super(logger, executor, httpFutureCommandConnectionHandleNHttpConnectionNioFutureCommandConnectionPool, commandQueue); // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.httpnio.pool;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import org.apache.http.nio.NHttpConnection;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
import org.jclouds.command.pool.FutureCommandConnectionHandle;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class HttpNioFutureCommandConnectionHandle extends FutureCommandConnectionHandle<NHttpConnection> {
|
||||
|
||||
@Inject
|
||||
public HttpNioFutureCommandConnectionHandle(java.util.logging.Logger logger, BlockingQueue<NHttpConnection> available, Semaphore maxConnections, @Assisted NHttpConnection conn, @Assisted FutureCommand operation) throws InterruptedException {
|
||||
super(logger, maxConnections, operation, conn, available);
|
||||
|
||||
}
|
||||
|
||||
public void startConnection() {
|
||||
conn.getContext().setAttribute("operation", operation);
|
||||
logger.trace("invoking %1s on connection %2s", operation, conn);
|
||||
conn.requestOutput();
|
||||
}
|
||||
|
||||
public void shutdownConnection() throws IOException {
|
||||
conn.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.httpnio.pool;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.name.Named;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
|
||||
import org.apache.http.nio.NHttpConnection;
|
||||
import org.apache.http.nio.protocol.AsyncNHttpClientHandler;
|
||||
import org.apache.http.nio.protocol.EventListener;
|
||||
import org.apache.http.nio.reactor.IOEventDispatch;
|
||||
import org.apache.http.nio.reactor.IOReactorStatus;
|
||||
import org.apache.http.nio.reactor.SessionRequest;
|
||||
import org.apache.http.nio.reactor.SessionRequestCallback;
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
import org.jclouds.command.pool.FutureCommandConnectionPool;
|
||||
import org.jclouds.command.pool.FutureCommandConnectionRetry;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class HttpNioFutureCommandConnectionPool extends FutureCommandConnectionPool<NHttpConnection> implements EventListener {
|
||||
|
||||
private final NHttpClientConnectionPoolSessionRequestCallback sessionCallback;
|
||||
private final DefaultConnectingIOReactor ioReactor;
|
||||
private final IOEventDispatch dispatch;
|
||||
private final InetSocketAddress target;
|
||||
private final int maxSessionFailures;
|
||||
|
||||
@Inject
|
||||
public HttpNioFutureCommandConnectionPool(java.util.logging.Logger logger, ExecutorService executor, Semaphore allConnections, BlockingQueue<NHttpConnection> available, AsyncNHttpClientHandler clientHandler, DefaultConnectingIOReactor ioReactor, IOEventDispatch dispatch, FutureCommandConnectionHandleFactory requestHandleFactory, InetSocketAddress target, FutureCommandConnectionRetry<NHttpConnection> futureCommandConnectionRetry, @Named("jclouds.http.pool.max_connection_reuse") int maxConnectionReuse, @Named("jclouds.http.pool.max_session_failures") int maxSessionFailures) {
|
||||
super(new Logger(logger), executor, futureCommandConnectionRetry, allConnections, requestHandleFactory, maxConnectionReuse, available);
|
||||
this.ioReactor = ioReactor;
|
||||
this.dispatch = dispatch;
|
||||
this.target = target;
|
||||
this.maxSessionFailures = maxSessionFailures;
|
||||
this.sessionCallback = new NHttpClientConnectionPoolSessionRequestCallback();
|
||||
clientHandler.setEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
synchronized (this.statusLock) {
|
||||
if (this.status.compareTo(Status.INACTIVE) == 0) {
|
||||
executor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
ioReactor.execute(dispatch);
|
||||
} catch (IOException e) {
|
||||
exception = e;
|
||||
logger.error(e, "Error dispatching %1s", dispatch);
|
||||
status = Status.SHUTDOWN_REQUEST;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
super.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdownReactor(long waitMs) {
|
||||
try {
|
||||
this.ioReactor.shutdown(waitMs);
|
||||
} catch (IOException e) {
|
||||
logger.error(e, "Error shutting down reactor");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean connectionValid(NHttpConnection conn) {
|
||||
return conn.isOpen() && !conn.isStale() && conn.getMetrics().getRequestCount() < maxConnectionReuse;
|
||||
}
|
||||
|
||||
protected void doWork() throws Exception {
|
||||
createNewConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doShutdown() {
|
||||
// Give the I/O reactor 10 sec to shut down
|
||||
shutdownReactor(10000);
|
||||
}
|
||||
|
||||
protected void createNewConnection() throws InterruptedException {
|
||||
boolean acquired = allConnections.tryAcquire(1, TimeUnit.SECONDS);
|
||||
if (acquired) {
|
||||
if (shouldDoWork()) {
|
||||
logger.debug("%1s - opening new connection", target);
|
||||
ioReactor.connect(target, null, null, sessionCallback);
|
||||
} else {
|
||||
allConnections.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldDoWork() {
|
||||
return super.shouldDoWork() && ioReactor.getStatus().equals(IOReactorStatus.ACTIVE);
|
||||
}
|
||||
|
||||
class NHttpClientConnectionPoolSessionRequestCallback implements SessionRequestCallback {
|
||||
|
||||
public void completed(SessionRequest request) {
|
||||
logger.trace("%1s - %2s - operation complete", request, request.getAttachment());
|
||||
}
|
||||
|
||||
public void cancelled(SessionRequest request) {
|
||||
logger.info("%1s - %2s - operation cancelled", request, request.getAttachment());
|
||||
releaseConnectionAndCancelResponse(request);
|
||||
}
|
||||
|
||||
private void releaseConnectionAndCancelResponse(SessionRequest request) {
|
||||
allConnections.release();
|
||||
FutureCommand frequest = (FutureCommand) request.getAttachment();
|
||||
if (frequest != null) {
|
||||
frequest.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseConnectionAndSetResponseException(SessionRequest request, Exception e) {
|
||||
allConnections.release();
|
||||
FutureCommand frequest = (FutureCommand) request.getAttachment();
|
||||
if (frequest != null) {
|
||||
frequest.setException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void failed(SessionRequest request) {
|
||||
int count = currentSessionFailures.getAndIncrement();
|
||||
logger.error(request.getException(), "%1s - %2s - operation failed", request, request.getAttachment());
|
||||
releaseConnectionAndSetResponseException(request, request.getException());
|
||||
if (count >= maxSessionFailures) {
|
||||
exception = request.getException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void timeout(SessionRequest request) {
|
||||
logger.warn("%1s - %2s - operation timed out", request, request.getAttachment());
|
||||
releaseConnectionAndCancelResponse(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void connectionOpen(NHttpConnection conn) {
|
||||
conn.setSocketTimeout(0);
|
||||
available.offer(conn);
|
||||
logger.trace("%1s - %2d - open", conn, conn.hashCode());
|
||||
}
|
||||
|
||||
|
||||
public void connectionTimeout(NHttpConnection conn) {
|
||||
logger.warn("%1s - %2d - timeout %2d", conn, conn.hashCode(), conn.getSocketTimeout());
|
||||
allConnections.release();
|
||||
futureCommandConnectionRetry.shutdownConnectionAndRetryOperation(conn);
|
||||
}
|
||||
|
||||
public void connectionClosed(NHttpConnection conn) {
|
||||
allConnections.release();
|
||||
logger.trace("%1s - %2d - closed", conn, conn.hashCode());
|
||||
}
|
||||
|
||||
public void fatalIOException(IOException ex, NHttpConnection conn) {
|
||||
exception = ex;
|
||||
logger.error(ex, "%1s - %2d - %3s - pool error", conn, conn.hashCode(), target);
|
||||
futureCommandConnectionRetry.shutdownConnectionAndRetryOperation(conn);
|
||||
}
|
||||
|
||||
public void fatalProtocolException(HttpException ex, NHttpConnection conn) {
|
||||
exception = ex;
|
||||
logger.error(ex, "%1s - %2d - %3s - http error", conn, conn.hashCode(), target);
|
||||
fatalException(ex, conn);
|
||||
}
|
||||
|
||||
public static interface FutureCommandConnectionHandleFactory extends FutureCommandConnectionPool.FutureCommandConnectionHandleFactory<NHttpConnection> {
|
||||
HttpNioFutureCommandConnectionHandle create(FutureCommand command, NHttpConnection conn);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.httpnio.pool;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.apache.http.nio.NHttpConnection;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.command.pool.FutureCommandConnectionRetry;
|
||||
import org.jclouds.command.pool.FutureCommandConnectionHandle;
|
||||
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandConnectionHandle;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class HttpNioFutureCommandConnectionRetry extends FutureCommandConnectionRetry<NHttpConnection> {
|
||||
|
||||
@Inject
|
||||
public HttpNioFutureCommandConnectionRetry(java.util.logging.Logger logger, BlockingQueue<FutureCommand> commandQueue, AtomicInteger errors) {
|
||||
super(new Logger(logger), commandQueue, errors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void associateHandleWithConnection(FutureCommandConnectionHandle<NHttpConnection> handle, NHttpConnection connection) {
|
||||
connection.getContext().setAttribute("operation-handle", handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpNioFutureCommandConnectionHandle getHandleFromConnection(NHttpConnection connection) {
|
||||
return (HttpNioFutureCommandConnectionHandle) connection.getContext().getAttribute("operation-handle");
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void incrementErrorCountAndRetry(FutureCommand operation) {
|
||||
// ((HttpEntityEnclosingRequest) operation.getRequest()).removeHeaders(HTTP.CONTENT_LEN);
|
||||
// ((HttpEntityEnclosingRequest) operation.getRequest()).removeHeaders(HTTP.DATE_HEADER);
|
||||
// super.incrementErrorCountAndRetry(operation);
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.httpnio.pool;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.nio.NHttpClientConnection;
|
||||
import org.apache.http.nio.entity.ConsumingNHttpEntity;
|
||||
import org.apache.http.nio.protocol.NHttpRequestExecutionHandler;
|
||||
import org.apache.http.protocol.ExecutionContext;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.command.FutureCommand;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.httpnio.HttpNioUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class HttpNioFutureCommandExecutionHandler implements NHttpRequestExecutionHandler {
|
||||
private final ExecutorService executor;
|
||||
protected final Logger logger;
|
||||
private final ConsumingNHttpEntityFactory entityFactory;
|
||||
private final HttpNioFutureCommandConnectionRetry futureOperationRetry;
|
||||
|
||||
public interface ConsumingNHttpEntityFactory {
|
||||
public ConsumingNHttpEntity create(HttpEntity httpEntity);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public HttpNioFutureCommandExecutionHandler(java.util.logging.Logger logger, ConsumingNHttpEntityFactory entityFactory, ExecutorService executor, HttpNioFutureCommandConnectionRetry futureOperationRetry) {
|
||||
this.logger = new Logger(logger);
|
||||
this.executor = executor;
|
||||
this.entityFactory = entityFactory;
|
||||
this.futureOperationRetry = futureOperationRetry;
|
||||
}
|
||||
|
||||
|
||||
public void initalizeContext(HttpContext context, Object attachment) {
|
||||
}
|
||||
|
||||
public HttpEntityEnclosingRequest submitRequest(HttpContext context) {
|
||||
HttpFutureCommand operation = (HttpFutureCommand) context.removeAttribute("operation");
|
||||
if (operation != null) {
|
||||
//TODO determine why type is lost
|
||||
HttpRequest object = (HttpRequest) operation.getRequest();
|
||||
return HttpNioUtils.convertToApacheRequest(object);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public ConsumingNHttpEntity responseEntity(HttpResponse response, HttpContext context) throws IOException {
|
||||
return entityFactory.create(response.getEntity());
|
||||
}
|
||||
|
||||
|
||||
public void handleResponse(HttpResponse response, HttpContext context) throws IOException {
|
||||
HttpNioFutureCommandConnectionHandle handle = (HttpNioFutureCommandConnectionHandle) context.removeAttribute("operation-handle");
|
||||
if (handle != null) {
|
||||
try {
|
||||
FutureCommand command = handle.getOperation();
|
||||
int code = response.getStatusLine().getStatusCode();
|
||||
//normal codes for rest commands
|
||||
if ((code >= 200 && code < 300) || code == 404) {
|
||||
processResponse(response, command);
|
||||
} else {
|
||||
if (isRetryable(response)) {
|
||||
futureOperationRetry.shutdownConnectionAndRetryOperation((NHttpClientConnection) context.getAttribute(ExecutionContext.HTTP_CONNECTION));
|
||||
} else {
|
||||
operationFailed(command);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
releaseConnectionToPool(handle);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException(String.format("No operation-handle associated with operation %1s", context));
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isRetryable(HttpResponse response) throws IOException {
|
||||
int code = response.getStatusLine().getStatusCode();
|
||||
return code == 500 || code == 503;
|
||||
}
|
||||
|
||||
protected void releaseConnectionToPool(HttpNioFutureCommandConnectionHandle handle) {
|
||||
try {
|
||||
handle.release();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e, "Interrupted releasing handle %1s", handle);
|
||||
}
|
||||
}
|
||||
|
||||
protected void operationFailed(FutureCommand command) throws IOException {
|
||||
String message = String.format("command failed: %1s", command);
|
||||
logger.error(message);
|
||||
command.getResponseFuture().setException(new IOException(message));
|
||||
}
|
||||
|
||||
protected void processResponse(HttpResponse apacheResponse, FutureCommand command) throws IOException {
|
||||
org.jclouds.http.HttpResponse response = HttpNioUtils.convertToJavaCloudsResponse(apacheResponse);
|
||||
command.getResponseFuture().setResponse(response);
|
||||
logger.trace("submitting response task %1s", command.getResponseFuture());
|
||||
executor.submit(command.getResponseFuture());
|
||||
}
|
||||
|
||||
public void finalizeContext(HttpContext context) {
|
||||
HttpNioFutureCommandConnectionHandle handle = (HttpNioFutureCommandConnectionHandle) context.removeAttribute("operation-handle");
|
||||
if (handle != null) {
|
||||
try {
|
||||
handle.cancel();
|
||||
} catch (Exception e) {
|
||||
logger.error(e, "Error cancelling handle %1s", handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.http.httpnio.pool;
|
||||
|
||||
import com.google.inject.Module;
|
||||
import org.jclouds.http.BaseHttpFutureCommandClientTest;
|
||||
import org.jclouds.http.httpnio.config.HttpNioConnectionPoolClientModule;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test
|
||||
public class HttpNioConnectionPoolFutureCommandClientTest extends BaseHttpFutureCommandClientTest {
|
||||
|
||||
protected void addConnectionProperties(Properties properties) {
|
||||
properties.setProperty("jclouds.http.pool.max_connection_reuse", "75");
|
||||
properties.setProperty("jclouds.http.pool.max_session_failures", "2");
|
||||
properties.setProperty("jclouds.http.pool.request_invoker_threads", "1");
|
||||
properties.setProperty("jclouds.http.pool.io_worker_threads", "2");
|
||||
properties.setProperty("jclouds.pool.max_connections", "12");
|
||||
}
|
||||
|
||||
protected Module createClientModule() {
|
||||
return new HttpNioConnectionPoolClientModule();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
$HeadURL$
|
||||
$Revision$
|
||||
$Date$
|
||||
|
||||
Copyright (C) 2009 Adrian Cole <adriancole@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>project</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../../project/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-s3nio</artifactId>
|
||||
<name>Connection pooling NIO connection for S3</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Connection pooling NIO connection for S3</description>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/extensions/s3nio</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/extensions/s3nio</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk/extensions/s3nio</url>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-httpnio</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3.nio;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.nio.entity.NStringEntity;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandConnectionRetry;
|
||||
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandExecutionHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class S3HttpNioFutureCommandExecutionHandler extends HttpNioFutureCommandExecutionHandler {
|
||||
|
||||
@Inject
|
||||
public S3HttpNioFutureCommandExecutionHandler(java.util.logging.Logger logger, ConsumingNHttpEntityFactory entityFactory, ExecutorService executor, HttpNioFutureCommandConnectionRetry futureOperationRetry) {
|
||||
super(logger, entityFactory, executor, futureOperationRetry);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRetryable(HttpResponse response) throws IOException {
|
||||
if (super.isRetryable(response))
|
||||
return true;
|
||||
int code = response.getStatusLine().getStatusCode();
|
||||
if (code == 409) {
|
||||
return true;
|
||||
} else if (code == 400) {
|
||||
if (response.getEntity() != null) {
|
||||
InputStream input = response.getEntity().getContent();
|
||||
if (input != null) {
|
||||
String reason = null;
|
||||
try {
|
||||
reason = IOUtils.toString(input);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(input);
|
||||
}
|
||||
if (reason != null) {
|
||||
try {
|
||||
if (reason.indexOf("RequestTime") >= 0) return true;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(input);
|
||||
response.setEntity(new NStringEntity(reason));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3.nio.config;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.util.Modules;
|
||||
import org.apache.http.nio.protocol.NHttpRequestExecutionHandler;
|
||||
import org.jclouds.aws.s3.nio.S3HttpNioFutureCommandExecutionHandler;
|
||||
import org.jclouds.http.httpnio.config.HttpNioConnectionPoolClientModule;
|
||||
|
||||
/**
|
||||
* This installs a {@link HttpNioConnectionPoolClientModule}, but overrides it binding {@link S3HttpNioFutureCommandExecutionHandler}.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class S3HttpNioConnectionPoolClientModule extends AbstractModule {
|
||||
protected void configure() {
|
||||
install(Modules.override(new HttpNioConnectionPoolClientModule()).with(new AbstractModule() {
|
||||
protected void configure() {
|
||||
bind(NHttpRequestExecutionHandler.class).to(S3HttpNioFutureCommandExecutionHandler.class);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3.nio;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.nio.entity.NStringEntity;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.*;
|
||||
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandConnectionRetry;
|
||||
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandExecutionHandler;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test
|
||||
public class S3HttpNioFutureCommandExecutionHandlerTest {
|
||||
S3HttpNioFutureCommandExecutionHandler handler = null;
|
||||
HttpResponse response = null;
|
||||
StatusLine statusline = null;
|
||||
|
||||
@BeforeMethod
|
||||
public void createHandler() {
|
||||
handler = new S3HttpNioFutureCommandExecutionHandler(createMock(
|
||||
java.util.logging.Logger.class), createMock(HttpNioFutureCommandExecutionHandler.ConsumingNHttpEntityFactory.class),
|
||||
createMock(ExecutorService.class),
|
||||
createMock(HttpNioFutureCommandConnectionRetry.class));
|
||||
response = createMock(HttpResponse.class);
|
||||
statusline = createMock(StatusLine.class);
|
||||
expect(response.getStatusLine()).andReturn(statusline).atLeastOnce();
|
||||
}
|
||||
|
||||
@Test
|
||||
void test500isRetryable() throws IOException {
|
||||
isRetryable(500);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test503isRetryable() throws IOException {
|
||||
isRetryable(503);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test409isRetryable() throws IOException {
|
||||
isRetryable(409);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test404NotRetryable() throws IOException {
|
||||
expect(statusline.getStatusCode()).andReturn(404).atLeastOnce();
|
||||
|
||||
replay(statusline);
|
||||
replay(response);
|
||||
assert !handler.isRetryable(response);
|
||||
verify(statusline);
|
||||
verify(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test400WithNoEnitityNotRetryable() throws IOException {
|
||||
expect(statusline.getStatusCode()).andReturn(400).atLeastOnce();
|
||||
expect(response.getEntity()).andReturn(null);
|
||||
replay(statusline);
|
||||
replay(response);
|
||||
assert !handler.isRetryable(response);
|
||||
verify(statusline);
|
||||
verify(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test400WithIrrelevantEnitityNotRetryable() throws IOException {
|
||||
expect(statusline.getStatusCode()).andReturn(400).atLeastOnce();
|
||||
HttpEntity entity = createMock(HttpEntity.class);
|
||||
expect(response.getEntity()).andReturn(entity).atLeastOnce();
|
||||
expect(entity.getContent()).andReturn(IOUtils.toInputStream("hello"));
|
||||
response.setEntity(isA(NStringEntity.class));
|
||||
replay(entity);
|
||||
replay(statusline);
|
||||
replay(response);
|
||||
assert !handler.isRetryable(response);
|
||||
verify(statusline);
|
||||
verify(response);
|
||||
verify(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test400WithRequestTimeTooSkewedTimeEnitityRetryable() throws IOException {
|
||||
expect(statusline.getStatusCode()).andReturn(400).atLeastOnce();
|
||||
HttpEntity entity = createMock(HttpEntity.class);
|
||||
expect(response.getEntity()).andReturn(entity).atLeastOnce();
|
||||
expect(entity.getContent()).andReturn(IOUtils.toInputStream("RequestTimeTooSkewed"));
|
||||
response.setEntity(isA(NStringEntity.class));
|
||||
replay(entity);
|
||||
replay(statusline);
|
||||
replay(response);
|
||||
assert handler.isRetryable(response);
|
||||
verify(statusline);
|
||||
verify(response);
|
||||
verify(entity);
|
||||
}
|
||||
|
||||
private void isRetryable(int code) throws IOException {
|
||||
expect(statusline.getStatusCode()).andReturn(code).atLeastOnce();
|
||||
replay(statusline);
|
||||
replay(response);
|
||||
assert handler.isRetryable(response);
|
||||
verify(statusline);
|
||||
verify(response);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3.nio.config;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.name.Names;
|
||||
import org.apache.http.nio.protocol.NHttpRequestExecutionHandler;
|
||||
import org.jclouds.aws.s3.nio.S3HttpNioFutureCommandExecutionHandler;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test
|
||||
public class S3HttpNioConnectionPoolClientModuleTest {
|
||||
|
||||
public void testConfigureBindsS3Handler() {
|
||||
final Properties properties = new Properties();
|
||||
properties.put("jclouds.http.address", "localhost");
|
||||
properties.put("jclouds.http.port", "8088");
|
||||
properties.put("jclouds.http.secure", "false");
|
||||
properties.setProperty("jclouds.http.pool.max_connection_reuse", "75");
|
||||
properties.setProperty("jclouds.http.pool.max_session_failures", "2");
|
||||
properties.setProperty("jclouds.http.pool.request_invoker_threads", "1");
|
||||
properties.setProperty("jclouds.http.pool.io_worker_threads", "2");
|
||||
properties.setProperty("jclouds.pool.max_connections", "12");
|
||||
|
||||
Injector i = Guice.createInjector(new S3HttpNioConnectionPoolClientModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
Names.bindProperties(binder(), properties);
|
||||
super.configure();
|
||||
}
|
||||
});
|
||||
NHttpRequestExecutionHandler handler = i.getInstance(NHttpRequestExecutionHandler.class);
|
||||
assert handler instanceof S3HttpNioFutureCommandExecutionHandler;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
$HeadURL$
|
||||
$Revision$
|
||||
$Date$
|
||||
|
||||
Copyright (C) 2009 Adrian Cole <adriancole@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>project</artifactId>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>project/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>default</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>JClouds</name>
|
||||
<modules>
|
||||
<module>project</module>
|
||||
<module>core</module>
|
||||
<module>extensions/httpnio</module>
|
||||
<module>extensions/s3nio</module>
|
||||
<module>s3</module>
|
||||
<module>s3/perftest</module>
|
||||
<module>samples/googleappengine</module>
|
||||
</modules>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.google.code.maven-license-plugin</groupId>
|
||||
<artifactId>maven-license-plugin</artifactId>
|
||||
<version>1.4.0</version>
|
||||
<configuration>
|
||||
<header>project/src/etc/header.txt</header>
|
||||
<aggregate>true</aggregate>
|
||||
<excludes>
|
||||
<!-- amazon files have their own license -->
|
||||
<exclude>**/src/main/java/com/amazon/**</exclude>
|
||||
<exclude>**/S3Driver.java</exclude>
|
||||
</excludes>
|
||||
<properties>
|
||||
<year>${project.inceptionYear}</year>
|
||||
<email>adriancole@jclouds.org</email>
|
||||
</properties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,199 @@
|
|||
====
|
||||
|
||||
Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
|
||||
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.
|
||||
====================================================================
|
||||
====
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
|
@ -0,0 +1,303 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
$HeadURL$
|
||||
$Revision$
|
||||
$Date$
|
||||
|
||||
Copyright (C) 2009 Adrian Cole <adriancole@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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>jclouds</name>
|
||||
<url>http://code.google.com/p/jclouds</url>
|
||||
<description>Concurrent API for Amazon Web Services</description>
|
||||
<inceptionYear>2009</inceptionYear>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License</name>
|
||||
<url>LICENSE.txt</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<organization>
|
||||
<name>jclouds</name>
|
||||
<url>http://www.jclouds.org/</url>
|
||||
</organization>
|
||||
|
||||
<issueManagement>
|
||||
<system>Google Code</system>
|
||||
<url>http://code.google.com/p/jclouds/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>Contributors</name>
|
||||
<subscribe>
|
||||
http://groups.google.com/group/jclouds-contributors
|
||||
</subscribe>
|
||||
<unsubscribe>
|
||||
http://groups.google.com/group/jclouds-contributors
|
||||
</unsubscribe>
|
||||
<post>jclouds-contributors@googlegroups.com</post>
|
||||
<archive>
|
||||
http://groups.google.com/group/jclouds-contributors
|
||||
</archive>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>SVN Commits</name>
|
||||
<subscribe>
|
||||
http://groups.google.com/group/jclouds-commits
|
||||
</subscribe>
|
||||
<unsubscribe>
|
||||
http://groups.google.com/group/jclouds-commits
|
||||
</unsubscribe>
|
||||
<post>jclouds-commits@googlegroups.com</post>
|
||||
<archive>http://groups.google.com/group/jclouds-commits</archive>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/project</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/project</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk/project</url>
|
||||
</scm>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jclouds</id>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk/repo</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>mc-release</id>
|
||||
<name>Alternate Maven repository of releases</name>
|
||||
<url>dav:https://mc-repo.googlecode.com/svn/maven2/releases</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>mc-snapshot</id>
|
||||
<name>Alternate Maven repository of snapshots</name>
|
||||
<url>dav:https://mc-repo.googlecode.com/svn/maven2/snapshots</url>
|
||||
<uniqueVersion>false</uniqueVersion>
|
||||
</snapshotRepository>
|
||||
<site>
|
||||
<id>website</id>
|
||||
<name>website</name>
|
||||
<url>file://${basedir}/target/dist/site/jclouds-testing/</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>central</id>
|
||||
<url>http://repo1.maven.org/maven2</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Adrian Cole</name>
|
||||
<id>ferncam1</id>
|
||||
<email>adriancole -at- jclouds.org</email>
|
||||
<organization>jclouds</organization>
|
||||
<roles>
|
||||
<role>Java Developer</role>
|
||||
<role>PMC</role>
|
||||
</roles>
|
||||
<url>http://www.jclouds.org</url>
|
||||
<timezone>+0</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<properties>
|
||||
<parent-basedir>${basedir}</parent-basedir>
|
||||
<maven.compile.source>1.5</maven.compile.source>
|
||||
<maven.compile.target>1.5</maven.compile.target>
|
||||
<maven.compile.optimize>true</maven.compile.optimize>
|
||||
<maven.compile.deprecation>true</maven.compile.deprecation>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<version>5.8</version>
|
||||
<scope>test</scope>
|
||||
<classifier>jdk15</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easymock</groupId>
|
||||
<artifactId>easymockclassextension</artifactId>
|
||||
<version>2.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-banned-dependencies</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<bannedDependencies>
|
||||
<excludes>
|
||||
<exclude>:maven-depedency-plugin</exclude>
|
||||
</excludes>
|
||||
</bannedDependencies>
|
||||
</rules>
|
||||
<fail>true</fail>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compile.source}</source>
|
||||
<target>${maven.compile.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Specification-Title>jclouds ${pom.name}</Specification-Title>
|
||||
<Specification-Vendor>jclouds</Specification-Vendor>
|
||||
<Implementation-Vendor>jclouds</Implementation-Vendor>
|
||||
<Implementation-Vendor-Id>org.jclouds.aws.s3</Implementation-Vendor-Id>
|
||||
<Implementation-Version>${pom.version}</Implementation-Version>
|
||||
<X-Compile-Source-JDK>${maven.compile.source}</X-Compile-Source-JDK>
|
||||
<X-Compile-Target-JDK>${maven.compile.target}</X-Compile-Target-JDK>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
</plugin>
|
||||
<!-- enforce java 1.5 and maven 2.1.0 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-java</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireJavaVersion>
|
||||
<version>[1.5,)</version>
|
||||
</requireJavaVersion>
|
||||
<requireMavenVersion>
|
||||
<version>[2.1.0,)</version>
|
||||
</requireMavenVersion>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>cpd</report>
|
||||
<report>findbugs</report>
|
||||
<report>issue-tracking</report>
|
||||
<report>mail-lists</report>
|
||||
<report>pmd</report>
|
||||
<report>rat-report</report>
|
||||
<report>source-repository</report>
|
||||
<report>surefire-report</report>
|
||||
<report>maven-emma-plugin</report>
|
||||
<report>team-list</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>emma-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>surefire-report-maven-plugin</artifactId>
|
||||
<inherited>true</inherited>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>rat-maven-plugin</artifactId>
|
||||
<inherited>true</inherited>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<configuration>
|
||||
<targetJdk>${maven.compile.source}</targetJdk>
|
||||
</configuration>
|
||||
<inherited>true</inherited>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<xmlOutput>true</xmlOutput>
|
||||
</configuration>
|
||||
<inherited>true</inherited>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
Copyright (C) ${year} Adrian Cole <adriancole@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
|
||||
|
||||
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.
|
||||
====================================================================
|
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
$HeadURL$
|
||||
$Revision$
|
||||
$Date$
|
||||
|
||||
Copyright (C) 2009 Adrian Cole <adriancole@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.
|
||||
====================================================================
|
||||
-->
|
||||
<!--
|
||||
Note that the code that these performance tests are evaluated against exist in src/main. The code in that
|
||||
location was copied straight from Amazon's website. There have been small modifications to make unit testing
|
||||
possible. That code exists with the following license:
|
||||
|
||||
This software code is made available "AS IS" without warranties of any
|
||||
kind. You may copy, display, modify and redistribute the software
|
||||
code either by itself or as incorporated into your code; provided that
|
||||
you do not remove any proprietary notices. Your use of this software
|
||||
code is at your own risk and you waive any claim against Amazon
|
||||
Digital Services, Inc. or its affiliates with respect to your use of
|
||||
this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
||||
affiliates.
|
||||
-->
|
||||
<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>project</artifactId>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../../project/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>s3core-perftest</artifactId>
|
||||
<name>Performance test verses Amazon samples implementation</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<description>Performance test verses Amazon samples implementation</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-s3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-s3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-s3nio</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jets3t</groupId>
|
||||
<artifactId>jets3t</artifactId>
|
||||
<version>0.7.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/s3core/perftest</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/s3core/perftest</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk/s3core/perftest</url>
|
||||
</scm>
|
||||
|
||||
<repositories>
|
||||
<!-- For Amazon S3 artifacts -->
|
||||
<repository>
|
||||
<name>jets3t</name>
|
||||
<id>jets3t</id>
|
||||
<url>http://jets3t.s3.amazonaws.com/maven2</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,159 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006-2007 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.amazon.s3.AWSAuthConnection;
|
||||
import com.amazon.s3.CallingFormat;
|
||||
import com.amazon.s3.QueryStringAuthGenerator;
|
||||
import com.amazon.s3.S3Object;
|
||||
|
||||
public class S3Driver {
|
||||
|
||||
static final String awsAccessKeyId = "<INSERT YOUR AWS ACCESS KEY ID HERE>";
|
||||
static final String awsSecretAccessKey = "<INSERT YOUR AWS SECRET ACCESS KEY HERE>";
|
||||
|
||||
|
||||
// convert the bucket to lowercase for vanity domains
|
||||
// the bucket name must be lowercase since DNS is case-insensitive
|
||||
static final String bucketName = awsAccessKeyId.toLowerCase() + "-test-bucket";
|
||||
static final String keyName = "test-key";
|
||||
static final String copiedKeyName = "copy-of-" + keyName;
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
if (awsAccessKeyId.startsWith("<INSERT")) {
|
||||
System.err.println("Please examine S3Driver.java and update it with your credentials");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
AWSAuthConnection conn =
|
||||
new AWSAuthConnection(awsAccessKeyId, awsSecretAccessKey);
|
||||
QueryStringAuthGenerator generator =
|
||||
new QueryStringAuthGenerator(awsAccessKeyId, awsSecretAccessKey);
|
||||
|
||||
// Check if the bucket exists. The high availability engineering of
|
||||
// Amazon S3 is focused on get, put, list, and delete operations.
|
||||
// Because bucket operations work against a centralized, global
|
||||
// resource space, it is not appropriate to make bucket create or
|
||||
// delete calls on the high availability code path of your application.
|
||||
// It is better to create or delete buckets in a separate initialization
|
||||
// or setup routine that you run less often.
|
||||
if (!conn.checkBucketExists(bucketName))
|
||||
{
|
||||
System.out.println("----- creating bucket -----");
|
||||
System.out.println(conn.createBucket(bucketName, AWSAuthConnection.LOCATION_DEFAULT, null).connection.getResponseMessage());
|
||||
// sample creating an EU located bucket.
|
||||
// (note path-style urls will not work with location-constrained buckets)
|
||||
//System.out.println(conn.createBucket(bucketName, AWSAuthConnection.LOCATION_EU, null).connection.getResponseMessage());
|
||||
}
|
||||
|
||||
System.out.println("----- listing bucket -----");
|
||||
System.out.println(conn.listBucket(bucketName, null, null, null, null).entries);
|
||||
|
||||
System.out.println("----- bucket location -----");
|
||||
System.out.println(conn.getBucketLocation(bucketName).getLocation());
|
||||
|
||||
System.out.println("----- putting object -----");
|
||||
S3Object object = new S3Object("this is a test".getBytes(), null);
|
||||
Map headers = new TreeMap();
|
||||
headers.put("Content-Type", Arrays.asList(new String[] { "text/plain" }));
|
||||
System.out.println(
|
||||
conn.put(bucketName, keyName, object, headers).connection.getResponseMessage()
|
||||
);
|
||||
|
||||
System.out.println("----- copying object -----");
|
||||
// Straight Copy; destination key will be private.
|
||||
conn.copy( bucketName, keyName, bucketName, copiedKeyName, null );
|
||||
{
|
||||
// Update the metadata; destination key will be private.
|
||||
Map updateMetadata = new TreeMap();
|
||||
updateMetadata.put("metadata-key", Arrays.asList("this will be the metadata in the copied key"));
|
||||
conn.copy( bucketName, copiedKeyName, bucketName, copiedKeyName, updateMetadata, null );
|
||||
}
|
||||
|
||||
System.out.println("----- listing bucket -----");
|
||||
System.out.println(conn.listBucket(bucketName, null, null, null, null).entries);
|
||||
|
||||
System.out.println("----- getting object -----");
|
||||
System.out.println(
|
||||
new String(conn.get(bucketName, keyName, null).object.data)
|
||||
);
|
||||
|
||||
System.out.println("----- query string auth example -----");
|
||||
generator.setExpiresIn(60 * 1000);
|
||||
|
||||
System.out.println("Try this url in your web browser (it will only work for 60 seconds)\n");
|
||||
System.out.println(generator.get(bucketName, keyName, null));
|
||||
System.out.print("\npress enter> ");
|
||||
System.in.read();
|
||||
|
||||
System.out.println("\nNow try just the url without the query string arguments. It should fail.\n");
|
||||
System.out.println(generator.makeBareURL(bucketName, keyName));
|
||||
System.out.print("\npress enter> ");
|
||||
System.in.read();
|
||||
|
||||
System.out.println("----- putting object with metadata and public read acl -----");
|
||||
|
||||
Map metadata = new TreeMap();
|
||||
metadata.put("blah", Arrays.asList(new String[] { "foo" }));
|
||||
object = new S3Object("this is a publicly readable test".getBytes(), metadata);
|
||||
|
||||
headers = new TreeMap();
|
||||
headers.put("x-amz-acl", Arrays.asList(new String[] { "public-read" }));
|
||||
headers.put("Content-Type", Arrays.asList(new String[] { "text/plain" }));
|
||||
|
||||
System.out.println(
|
||||
conn.put(bucketName, keyName + "-public", object, headers).connection.getResponseMessage()
|
||||
);
|
||||
|
||||
System.out.println("----- anonymous read test -----");
|
||||
System.out.println("\nYou should be able to try this in your browser\n");
|
||||
System.out.println(generator.makeBareURL(bucketName, keyName + "-public"));
|
||||
System.out.print("\npress enter> ");
|
||||
System.in.read();
|
||||
|
||||
System.out.println("----- path style url example -----");
|
||||
System.out.println("\nNon-location-constrained buckets can also be specified as part of the url path. (This was the original url style supported by S3.)");
|
||||
System.out.println("\nTry this url out in your browser (it will only be valid for 60 seconds)\n");
|
||||
generator.setCallingFormat(CallingFormat.getPathCallingFormat());
|
||||
// could also have been done like this:
|
||||
// generator = new QueryStringAuthGenerator(awsAccessKeyId, awsSecretAccessKey, true, Utils.DEFAULT_HOST, CallingFormat.getPathCallingFormat());
|
||||
generator.setExpiresIn(60 * 1000);
|
||||
System.out.println(generator.get(bucketName, keyName, null));
|
||||
System.out.print("\npress enter> ");
|
||||
System.in.read();
|
||||
|
||||
System.out.println("----- getting object's acl -----");
|
||||
System.out.println(new String(conn.getACL(bucketName, keyName, null).object.data));
|
||||
|
||||
System.out.println("----- deleting objects -----");
|
||||
System.out.println(
|
||||
conn.delete(bucketName, copiedKeyName, null).connection.getResponseMessage()
|
||||
);
|
||||
System.out.println(
|
||||
conn.delete(bucketName, keyName, null).connection.getResponseMessage()
|
||||
);
|
||||
System.out.println(
|
||||
conn.delete(bucketName, keyName + "-public", null).connection.getResponseMessage()
|
||||
);
|
||||
|
||||
System.out.println("----- listing bucket -----");
|
||||
System.out.println(conn.listBucket(bucketName, null, null, null, null).entries);
|
||||
|
||||
System.out.println("----- listing all my buckets -----");
|
||||
System.out.println(conn.listAllMyBuckets(null).entries);
|
||||
|
||||
System.out.println("----- deleting bucket -----");
|
||||
System.out.println(
|
||||
conn.deleteBucket(bucketName, null).connection.getResponseMessage()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,633 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.
|
||||
* ====================================================================
|
||||
*/
|
||||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006-2007 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* An interface into the S3 system. It is initially configured with
|
||||
* authentication and connection parameters and exposes methods to access and
|
||||
* manipulate S3 data.
|
||||
*/
|
||||
public class AWSAuthConnection {
|
||||
public static final String LOCATION_DEFAULT = null;
|
||||
public static final String LOCATION_EU = "EU";
|
||||
|
||||
private String awsAccessKeyId;
|
||||
private String awsSecretAccessKey;
|
||||
private boolean isSecure;
|
||||
private String server;
|
||||
private int port;
|
||||
private CallingFormat callingFormat;
|
||||
|
||||
public AWSAuthConnection(String awsAccessKeyId, String awsSecretAccessKey) {
|
||||
this(awsAccessKeyId, awsSecretAccessKey, true);
|
||||
}
|
||||
|
||||
public AWSAuthConnection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure) {
|
||||
this(awsAccessKeyId, awsSecretAccessKey, isSecure, Utils.DEFAULT_HOST);
|
||||
}
|
||||
|
||||
public AWSAuthConnection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure,
|
||||
String server)
|
||||
{
|
||||
this(awsAccessKeyId, awsSecretAccessKey, isSecure, server,
|
||||
isSecure ? Utils.SECURE_PORT : Utils.INSECURE_PORT);
|
||||
}
|
||||
|
||||
public AWSAuthConnection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure,
|
||||
String server, int port) {
|
||||
this(awsAccessKeyId, awsSecretAccessKey, isSecure, server, port, CallingFormat.getSubdomainCallingFormat());
|
||||
|
||||
}
|
||||
|
||||
public AWSAuthConnection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure,
|
||||
String server, CallingFormat format) {
|
||||
this(awsAccessKeyId, awsSecretAccessKey, isSecure, server,
|
||||
isSecure ? Utils.SECURE_PORT : Utils.INSECURE_PORT,
|
||||
format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new interface to interact with S3 with the given credential and connection
|
||||
* parameters
|
||||
*
|
||||
* @param awsAccessKeyId Your user key into AWS
|
||||
* @param awsSecretAccessKey The secret string used to generate signatures for authentication.
|
||||
* @param isSecure use SSL encryption
|
||||
* @param server Which host to connect to. Usually, this will be s3.amazonaws.com
|
||||
* @param port Which port to use.
|
||||
* @param callingFormat Type of request Regular/Vanity or Pure Vanity domain
|
||||
*/
|
||||
public AWSAuthConnection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure,
|
||||
String server, int port, CallingFormat format)
|
||||
{
|
||||
this.awsAccessKeyId = awsAccessKeyId;
|
||||
this.awsSecretAccessKey = awsSecretAccessKey;
|
||||
this.isSecure = isSecure;
|
||||
this.server = server;
|
||||
this.port = port;
|
||||
this.callingFormat = format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new bucket.
|
||||
* @param bucket The name of the bucket to create.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
* @param metadata A Map of String to List of Strings representing the s3
|
||||
* metadata for this bucket (can be null).
|
||||
* @deprecated use version that specifies location
|
||||
*/
|
||||
public Response createBucket(String bucket, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
return createBucket(bucket, null, headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new bucket.
|
||||
* @param bucket The name of the bucket to create.
|
||||
* @param location Desired location ("EU") (or null for default).
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
* @param metadata A Map of String to List of Strings representing the s3
|
||||
* metadata for this bucket (can be null).
|
||||
* @throws IllegalArgumentException on invalid location
|
||||
*/
|
||||
public Response createBucket(String bucket, String location, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
String body;
|
||||
if (location == null) {
|
||||
body = null;
|
||||
} else if (LOCATION_EU.equals(location)) {
|
||||
if (!callingFormat.supportsLocatedBuckets())
|
||||
throw new IllegalArgumentException("Creating location-constrained bucket with unsupported calling-format");
|
||||
body = "<CreateBucketConstraint><LocationConstraint>" + location + "</LocationConstraint></CreateBucketConstraint>";
|
||||
} else
|
||||
throw new IllegalArgumentException("Invalid Location: "+location);
|
||||
|
||||
// validate bucket name
|
||||
if (!Utils.validateBucketName(bucket, callingFormat, location != null))
|
||||
throw new IllegalArgumentException("Invalid S3Bucket Name: "+bucket);
|
||||
|
||||
HttpURLConnection request = makeRequest("PUT", bucket, "", null, headers);
|
||||
if (body != null)
|
||||
{
|
||||
request.setDoOutput(true);
|
||||
request.getOutputStream().write(body.getBytes("UTF-8"));
|
||||
}
|
||||
return new Response(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the specified bucket exists (via a HEAD request)
|
||||
* @param bucket The name of the bucket to check
|
||||
* @return true if HEAD access returned success
|
||||
*/
|
||||
public boolean checkBucketExists(String bucket) throws MalformedURLException, IOException
|
||||
{
|
||||
HttpURLConnection response = makeRequest("HEAD", bucket, "", null, null);
|
||||
int httpCode = response.getResponseCode();
|
||||
return httpCode >= 200 && httpCode < 300;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the contents of a bucket.
|
||||
* @param bucket The name of the bucket to create.
|
||||
* @param prefix All returned keys will start with this string (can be null).
|
||||
* @param marker All returned keys will be lexographically greater than
|
||||
* this string (can be null).
|
||||
* @param maxKeys The maximum number of keys to return (can be null).
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public ListBucketResponse listBucket(String bucket, String prefix, String marker,
|
||||
Integer maxKeys, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
return listBucket(bucket, prefix, marker, maxKeys, null, headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the contents of a bucket.
|
||||
* @param bucket The name of the bucket to list.
|
||||
* @param prefix All returned keys will start with this string (can be null).
|
||||
* @param marker All returned keys will be lexographically greater than
|
||||
* this string (can be null).
|
||||
* @param maxKeys The maximum number of keys to return (can be null).
|
||||
* @param delimiter Keys that contain a string between the prefix and the first
|
||||
* occurrence of the delimiter will be rolled up into a single element.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public ListBucketResponse listBucket(String bucket, String prefix, String marker,
|
||||
Integer maxKeys, String delimiter, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
|
||||
Map pathArgs = Utils.paramsForListOptions(prefix, marker, maxKeys, delimiter);
|
||||
return new ListBucketResponse(makeRequest("GET", bucket, "", pathArgs, headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a bucket.
|
||||
* @param bucket The name of the bucket to delete.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public Response deleteBucket(String bucket, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
return new Response(makeRequest("DELETE", bucket, "", null, headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an object to S3.
|
||||
* @param bucket The name of the bucket to which the object will be added.
|
||||
* @param key The name of the key to use.
|
||||
* @param object An S3Object containing the data to write.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public Response put(String bucket, String key, S3Object object, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
HttpURLConnection request =
|
||||
makeRequest("PUT", bucket, Utils.urlencode(key), null, headers, object);
|
||||
|
||||
request.setDoOutput(true);
|
||||
request.getOutputStream().write(object.data == null ? new byte[] {} : object.data);
|
||||
|
||||
return new Response(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of an existing S3 Object. In this signature, we will copy the
|
||||
* existing metadata. The default access control policy is private; if you want
|
||||
* to override it, please use x-amz-acl in the headers.
|
||||
* @param sourceBucket The name of the bucket where the source object lives.
|
||||
* @param sourceKey The name of the key to copy.
|
||||
* @param destinationBucket The name of the bucket to which the object will be added.
|
||||
* @param destinationKey The name of the key to use.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null). You may wish to set the x-amz-acl header appropriately.
|
||||
*/
|
||||
public Response copy( String sourceBucket, String sourceKey, String destinationBucket, String destinationKey, Map headers )
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
S3Object object = new S3Object(new byte[] {}, new HashMap());
|
||||
headers = headers == null ? new HashMap() : new HashMap(headers);
|
||||
headers.put("x-amz-copy-source", Arrays.asList( new String[] { sourceBucket + "/" + sourceKey } ) );
|
||||
headers.put("x-amz-metadata-directive", Arrays.asList( new String[] { "COPY" } ) );
|
||||
return verifyCopy( put( destinationBucket, destinationKey, object, headers ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of an existing S3 Object. In this signature, we will replace the
|
||||
* existing metadata. The default access control policy is private; if you want
|
||||
* to override it, please use x-amz-acl in the headers.
|
||||
* @param sourceBucket The name of the bucket where the source object lives.
|
||||
* @param sourceKey The name of the key to copy.
|
||||
* @param destinationBucket The name of the bucket to which the object will be added.
|
||||
* @param destinationKey The name of the key to use.
|
||||
* @param metadata A Map of String to List of Strings representing the S3 metadata
|
||||
* for the new object.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null). You may wish to set the x-amz-acl header appropriately.
|
||||
*/
|
||||
public Response copy( String sourceBucket, String sourceKey, String destinationBucket, String destinationKey, Map metadata, Map headers )
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
S3Object object = new S3Object(new byte[] {}, metadata);
|
||||
headers = headers == null ? new HashMap() : new HashMap(headers);
|
||||
headers.put("x-amz-copy-source", Arrays.asList( new String[] { sourceBucket + "/" + sourceKey } ) );
|
||||
headers.put("x-amz-metadata-directive", Arrays.asList( new String[] { "REPLACE" } ) );
|
||||
return verifyCopy( put( destinationBucket, destinationKey, object, headers ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy sometimes returns a successful response and starts to send whitespace
|
||||
* characters to us. This method processes those whitespace characters and
|
||||
* will throw an exception if the response is either unknown or an error.
|
||||
* @param response Response object from the PUT request.
|
||||
* @return The response with the input stream drained.
|
||||
* @throws IOException If anything goes wrong.
|
||||
*/
|
||||
private Response verifyCopy( Response response ) throws IOException {
|
||||
if (response.connection.getResponseCode() < 400) {
|
||||
byte[] body = GetResponse.slurpInputStream(response.connection.getInputStream());
|
||||
String message = new String( body );
|
||||
if ( message.indexOf( "<Error" ) != -1 ) {
|
||||
throw new IOException( message.substring( message.indexOf( "<Error" ) ) );
|
||||
} else if ( message.indexOf( "</CopyObjectResult>" ) != -1 ) {
|
||||
// It worked!
|
||||
} else {
|
||||
throw new IOException( "Unexpected response: " + message );
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an object from S3.
|
||||
* @param bucket The name of the bucket where the object lives.
|
||||
* @param key The name of the key to use.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public GetResponse get(String bucket, String key, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
return new GetResponse(makeRequest("GET", bucket, Utils.urlencode(key), null, headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an object from S3.
|
||||
* @param bucket The name of the bucket where the object lives.
|
||||
* @param key The name of the key to use.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public Response delete(String bucket, String key, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
return new Response(makeRequest("DELETE", bucket, Utils.urlencode(key), null, headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the requestPayment xml document for a given bucket
|
||||
* @param bucket The name of the bucket
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public GetResponse getBucketRequestPayment(String bucket, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
Map pathArgs = new HashMap();
|
||||
pathArgs.put("requestPayment", null);
|
||||
return new GetResponse(makeRequest("GET", bucket, "", pathArgs, headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new requestPayment xml document for a given bucket
|
||||
* @param loggingXMLDoc The xml representation of the requestPayment configuration as a String
|
||||
* @param bucket The name of the bucket
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public Response putBucketRequestPayment(String bucket, String requestPaymentXMLDoc, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
Map pathArgs = new HashMap();
|
||||
pathArgs.put("requestPayment", null);
|
||||
S3Object object = new S3Object(requestPaymentXMLDoc.getBytes(), null);
|
||||
HttpURLConnection request = makeRequest("PUT", bucket, "", pathArgs, headers, object);
|
||||
|
||||
request.setDoOutput(true);
|
||||
request.getOutputStream().write(object.data == null ? new byte[] {} : object.data);
|
||||
|
||||
return new Response(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the logging xml document for a given bucket
|
||||
* @param bucket The name of the bucket
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public GetResponse getBucketLogging(String bucket, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
Map pathArgs = new HashMap();
|
||||
pathArgs.put("logging", null);
|
||||
return new GetResponse(makeRequest("GET", bucket, "", pathArgs, headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new logging xml document for a given bucket
|
||||
* @param loggingXMLDoc The xml representation of the logging configuration as a String
|
||||
* @param bucket The name of the bucket
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public Response putBucketLogging(String bucket, String loggingXMLDoc, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
Map pathArgs = new HashMap();
|
||||
pathArgs.put("logging", null);
|
||||
S3Object object = new S3Object(loggingXMLDoc.getBytes(), null);
|
||||
HttpURLConnection request = makeRequest("PUT", bucket, "", pathArgs, headers, object);
|
||||
|
||||
request.setDoOutput(true);
|
||||
request.getOutputStream().write(object.data == null ? new byte[] {} : object.data);
|
||||
|
||||
return new Response(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ACL for a given bucket
|
||||
* @param bucket The name of the bucket where the object lives.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public GetResponse getBucketACL(String bucket, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
return getACL(bucket, "", headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ACL for a given object (or bucket, if key is null).
|
||||
* @param bucket The name of the bucket where the object lives.
|
||||
* @param key The name of the key to use.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public GetResponse getACL(String bucket, String key, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
if (key == null) key = "";
|
||||
|
||||
Map pathArgs = new HashMap();
|
||||
pathArgs.put("acl", null);
|
||||
|
||||
return new GetResponse(
|
||||
makeRequest("GET", bucket, Utils.urlencode(key), pathArgs, headers)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new ACL for a given bucket
|
||||
* @param aclXMLDoc The xml representation of the ACL as a String
|
||||
* @param bucket The name of the bucket where the object lives.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public Response putBucketACL(String bucket, String aclXMLDoc, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
return putACL(bucket, "", aclXMLDoc, headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new ACL for a given object
|
||||
* @param aclXMLDoc The xml representation of the ACL as a String
|
||||
* @param bucket The name of the bucket where the object lives.
|
||||
* @param key The name of the key to use.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public Response putACL(String bucket, String key, String aclXMLDoc, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
S3Object object = new S3Object(aclXMLDoc.getBytes(), null);
|
||||
|
||||
Map pathArgs = new HashMap();
|
||||
pathArgs.put("acl", null);
|
||||
|
||||
HttpURLConnection request =
|
||||
makeRequest("PUT", bucket, Utils.urlencode(key), pathArgs, headers, object);
|
||||
|
||||
request.setDoOutput(true);
|
||||
request.getOutputStream().write(object.data == null ? new byte[] {} : object.data);
|
||||
|
||||
return new Response(request);
|
||||
}
|
||||
|
||||
public LocationResponse getBucketLocation(String bucket)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
Map pathArgs = new HashMap();
|
||||
pathArgs.put("location", null);
|
||||
return new LocationResponse(makeRequest("GET", bucket, "", pathArgs, null));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List all the buckets created by this account.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
public ListAllMyBucketsResponse listAllMyBuckets(Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
return new ListAllMyBucketsResponse(makeRequest("GET", "", "", null, headers));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Make a new HttpURLConnection without passing an S3Object parameter.
|
||||
* Use this method for key operations that do require arguments
|
||||
* @param method The method to invoke
|
||||
* @param bucketName the bucket this request is for
|
||||
* @param key the key this request is for
|
||||
* @param pathArgs the
|
||||
* @param headers
|
||||
* @return
|
||||
* @throws MalformedURLException
|
||||
* @throws IOException
|
||||
*/
|
||||
private HttpURLConnection makeRequest(String method, String bucketName, String key, Map pathArgs, Map headers)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
return makeRequest(method, bucketName, key, pathArgs, headers, null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Make a new HttpURLConnection.
|
||||
* @param method The HTTP method to use (GET, PUT, DELETE)
|
||||
* @param bucketName The bucket name this request affects
|
||||
* @param key The key this request is for
|
||||
* @param pathArgs parameters if any to be sent along this request
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
* @param object The S3Object that is to be written (can be null).
|
||||
*/
|
||||
private HttpURLConnection makeRequest(String method, String bucket, String key, Map pathArgs, Map headers,
|
||||
S3Object object)
|
||||
throws MalformedURLException, IOException
|
||||
{
|
||||
CallingFormat callingFormat = Utils.getCallingFormatForBucket( this.callingFormat, bucket );
|
||||
if ( isSecure && callingFormat != CallingFormat.getPathCallingFormat() && bucket.indexOf( "." ) != -1 ) {
|
||||
System.err.println( "You are making an SSL connection, however, the bucket contains periods and the wildcard certificate will not match by default. Please consider using HTTP." );
|
||||
}
|
||||
|
||||
// build the domain based on the calling format
|
||||
URL url = callingFormat.getURL(isSecure, server, this.port, bucket, key, pathArgs);
|
||||
|
||||
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
|
||||
connection.setRequestMethod(method);
|
||||
|
||||
// subdomain-style urls may encounter http redirects.
|
||||
// Ensure that redirects are supported.
|
||||
if (!connection.getInstanceFollowRedirects()
|
||||
&& callingFormat.supportsLocatedBuckets())
|
||||
throw new RuntimeException("HTTP redirect support required.");
|
||||
|
||||
addHeaders(connection, headers);
|
||||
if (object != null) addMetadataHeaders(connection, object.metadata);
|
||||
addAuthHeader(connection, method, bucket, key, pathArgs);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given headers to the HttpURLConnection.
|
||||
* @param connection The HttpURLConnection to which the headers will be added.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
*/
|
||||
private void addHeaders(HttpURLConnection connection, Map headers) {
|
||||
addHeaders(connection, headers, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given metadata fields to the HttpURLConnection.
|
||||
* @param connection The HttpURLConnection to which the headers will be added.
|
||||
* @param metadata A Map of String to List of Strings representing the s3
|
||||
* metadata for this resource.
|
||||
*/
|
||||
private void addMetadataHeaders(HttpURLConnection connection, Map metadata) {
|
||||
addHeaders(connection, metadata, Utils.METADATA_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given headers to the HttpURLConnection with a prefix before the keys.
|
||||
* @param connection The HttpURLConnection to which the headers will be added.
|
||||
* @param headers A Map of String to List of Strings representing the http
|
||||
* headers to pass (can be null).
|
||||
* @param prefix The string to prepend to each key before adding it to the connection.
|
||||
*/
|
||||
private void addHeaders(HttpURLConnection connection, Map headers, String prefix) {
|
||||
if (headers != null) {
|
||||
for (Iterator i = headers.keySet().iterator(); i.hasNext(); ) {
|
||||
String key = (String)i.next();
|
||||
for (Iterator j = ((List)headers.get(key)).iterator(); j.hasNext(); ) {
|
||||
String value = (String)j.next();
|
||||
connection.addRequestProperty(prefix + key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the appropriate Authorization header to the HttpURLConnection.
|
||||
* @param connection The HttpURLConnection to which the header will be added.
|
||||
* @param method The HTTP method to use (GET, PUT, DELETE)
|
||||
* @param bucket the bucket name this request is for
|
||||
* @param key the key this request is for
|
||||
* @param pathArgs path arguments which are part of this request
|
||||
*/
|
||||
private void addAuthHeader(HttpURLConnection connection, String method, String bucket, String key, Map pathArgs) {
|
||||
if (connection.getRequestProperty("Date") == null) {
|
||||
connection.setRequestProperty("Date", httpDate());
|
||||
}
|
||||
if (connection.getRequestProperty("Content-Type") == null) {
|
||||
connection.setRequestProperty("Content-Type", "");
|
||||
}
|
||||
|
||||
String canonicalString =
|
||||
Utils.makeCanonicalString(method, bucket, key, pathArgs, connection.getRequestProperties());
|
||||
String encodedCanonical = Utils.encode(this.awsSecretAccessKey, canonicalString, false);
|
||||
connection.setRequestProperty("Authorization",
|
||||
"AWS " + this.awsAccessKeyId + ":" + encodedCanonical);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate an rfc822 date for use in the Date HTTP header.
|
||||
*/
|
||||
public static String httpDate() {
|
||||
final String DateFormat = "EEE, dd MMM yyyy HH:mm:ss ";
|
||||
SimpleDateFormat format = new SimpleDateFormat( DateFormat, Locale.US );
|
||||
format.setTimeZone( TimeZone.getTimeZone( "GMT" ) );
|
||||
return format.format( new Date() ) + "GMT";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* A class representing a single bucket. Returned as a component of ListAllMyBucketsResponse.
|
||||
*/
|
||||
public class Bucket {
|
||||
/**
|
||||
* The name of the bucket.
|
||||
*/
|
||||
public String name;
|
||||
|
||||
/**
|
||||
* The bucket's creation date.
|
||||
*/
|
||||
public Date creationDate;
|
||||
|
||||
public Bucket() {
|
||||
this.name = null;
|
||||
this.creationDate = null;
|
||||
}
|
||||
|
||||
public Bucket(String name, Date creationDate) {
|
||||
this.name = name;
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006-2007 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class CallingFormat {
|
||||
|
||||
protected static CallingFormat pathCallingFormat = new PathCallingFormat();
|
||||
protected static CallingFormat subdomainCallingFormat = new SubdomainCallingFormat();
|
||||
protected static CallingFormat vanityCallingFormat = new VanityCallingFormat();
|
||||
|
||||
public abstract boolean supportsLocatedBuckets();
|
||||
public abstract String getEndpoint(String server, int port, String bucket);
|
||||
public abstract String getPathBase(String bucket, String key);
|
||||
public abstract URL getURL (boolean isSecure, String server, int port, String bucket, String key, Map pathArgs)
|
||||
throws MalformedURLException;
|
||||
|
||||
public static CallingFormat getPathCallingFormat() {
|
||||
return pathCallingFormat;
|
||||
}
|
||||
|
||||
public static CallingFormat getSubdomainCallingFormat() {
|
||||
return subdomainCallingFormat;
|
||||
}
|
||||
|
||||
public static CallingFormat getVanityCallingFormat() {
|
||||
return vanityCallingFormat;
|
||||
}
|
||||
|
||||
static private class PathCallingFormat extends CallingFormat {
|
||||
public boolean supportsLocatedBuckets() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getPathBase(String bucket, String key) {
|
||||
return isBucketSpecified(bucket) ? "/" + bucket + "/" + key : "/";
|
||||
}
|
||||
|
||||
public String getEndpoint(String server, int port, String bucket) {
|
||||
return server + ":" + port;
|
||||
}
|
||||
|
||||
public URL getURL(boolean isSecure, String server, int port, String bucket, String key, Map pathArgs)
|
||||
throws MalformedURLException {
|
||||
String pathBase = isBucketSpecified(bucket) ? "/" + bucket + "/" + key : "/";
|
||||
String pathArguments = Utils.convertPathArgsHashToString(pathArgs);
|
||||
return new URL(isSecure ? "https": "http", server, port, pathBase + pathArguments);
|
||||
}
|
||||
|
||||
private boolean isBucketSpecified(String bucket) {
|
||||
if(bucket == null) return false;
|
||||
if(bucket.length() == 0) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static private class SubdomainCallingFormat extends CallingFormat {
|
||||
public boolean supportsLocatedBuckets() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getServer(String server, String bucket) {
|
||||
return bucket + "." + server;
|
||||
}
|
||||
public String getEndpoint(String server, int port, String bucket) {
|
||||
return getServer(server, bucket) + ":" + port ;
|
||||
}
|
||||
public String getPathBase(String bucket, String key) {
|
||||
return "/" + key;
|
||||
}
|
||||
|
||||
public URL getURL(boolean isSecure, String server, int port, String bucket, String key, Map pathArgs)
|
||||
throws MalformedURLException {
|
||||
if (bucket == null || bucket.length() == 0)
|
||||
{
|
||||
//The bucket is null, this is listAllBuckets request
|
||||
String pathArguments = Utils.convertPathArgsHashToString(pathArgs);
|
||||
return new URL(isSecure ? "https": "http", server, port, "/" + pathArguments);
|
||||
} else {
|
||||
String serverToUse = getServer(server, bucket);
|
||||
String pathBase = getPathBase(bucket, key);
|
||||
String pathArguments = Utils.convertPathArgsHashToString(pathArgs);
|
||||
return new URL(isSecure ? "https": "http", serverToUse, port, pathBase + pathArguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static private class VanityCallingFormat extends SubdomainCallingFormat {
|
||||
public String getServer(String server, String bucket) {
|
||||
return bucket;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
public class CommonPrefixEntry {
|
||||
/**
|
||||
* The prefix common to the delimited keys it represents
|
||||
*/
|
||||
public String prefix;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* A Response object returned from AWSAuthConnection.get(). Exposes the attribute object, which
|
||||
* represents the retrieved object.
|
||||
*/
|
||||
public class GetResponse extends Response {
|
||||
public S3Object object;
|
||||
|
||||
/**
|
||||
* Pulls a representation of an S3Object out of the HttpURLConnection response.
|
||||
*/
|
||||
public GetResponse(HttpURLConnection connection) throws IOException {
|
||||
super(connection);
|
||||
if (connection.getResponseCode() < 400) {
|
||||
Map metadata = extractMetadata(connection);
|
||||
byte[] body = slurpInputStream(connection.getInputStream());
|
||||
this.object = new S3Object(body, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Examines the response's header fields and returns a Map from String to List of Strings
|
||||
* representing the object's metadata.
|
||||
*/
|
||||
private Map extractMetadata(HttpURLConnection connection) {
|
||||
TreeMap metadata = new TreeMap();
|
||||
Map headers = connection.getHeaderFields();
|
||||
for (Iterator i = headers.keySet().iterator(); i.hasNext(); ) {
|
||||
String key = (String)i.next();
|
||||
if (key == null) continue;
|
||||
if (key.startsWith(Utils.METADATA_PREFIX)) {
|
||||
metadata.put(key.substring(Utils.METADATA_PREFIX.length()), headers.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the input stream and dump it all into a big byte array
|
||||
*/
|
||||
static byte[] slurpInputStream(InputStream stream) throws IOException {
|
||||
final int chunkSize = 2048;
|
||||
byte[] buf = new byte[chunkSize];
|
||||
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(chunkSize);
|
||||
int count;
|
||||
|
||||
while ((count=stream.read(buf)) != -1) byteStream.write(buf, 0, count);
|
||||
|
||||
return byteStream.toByteArray();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.SimpleTimeZone;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
* Returned by AWSAuthConnection.listAllMyBuckets().
|
||||
*/
|
||||
public class ListAllMyBucketsResponse extends Response {
|
||||
/**
|
||||
* A list of Bucket objects, one for each of this account's buckets. Will be null if
|
||||
* the request fails.
|
||||
*/
|
||||
public List entries;
|
||||
|
||||
public ListAllMyBucketsResponse(HttpURLConnection connection) throws IOException {
|
||||
super(connection);
|
||||
if (connection.getResponseCode() < 400) {
|
||||
try {
|
||||
XMLReader xr = Utils.createXMLReader();;
|
||||
ListAllMyBucketsHandler handler = new ListAllMyBucketsHandler();
|
||||
xr.setContentHandler(handler);
|
||||
xr.setErrorHandler(handler);
|
||||
|
||||
xr.parse(new InputSource(connection.getInputStream()));
|
||||
this.entries = handler.getEntries();
|
||||
} catch (SAXException e) {
|
||||
throw new RuntimeException("Unexpected error parsing ListAllMyBuckets xml", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class ListAllMyBucketsHandler extends DefaultHandler {
|
||||
|
||||
private List entries = null;
|
||||
private Bucket currBucket = null;
|
||||
private StringBuffer currText = null;
|
||||
private SimpleDateFormat iso8601Parser = null;
|
||||
|
||||
public ListAllMyBucketsHandler() {
|
||||
super();
|
||||
entries = new ArrayList();
|
||||
this.iso8601Parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
||||
this.iso8601Parser.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||
this.currText = new StringBuffer();
|
||||
}
|
||||
|
||||
public void startDocument() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
public void endDocument() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
public void startElement(String uri, String name, String qName, Attributes attrs) {
|
||||
if (name.equals("Bucket")) {
|
||||
this.currBucket = new Bucket();
|
||||
}
|
||||
}
|
||||
|
||||
public void endElement(String uri, String name, String qName) {
|
||||
if (name.equals("Bucket")) {
|
||||
this.entries.add(this.currBucket);
|
||||
} else if (name.equals("Name")) {
|
||||
this.currBucket.name = this.currText.toString();
|
||||
} else if (name.equals("CreationDate")) {
|
||||
try {
|
||||
this.currBucket.creationDate = this.iso8601Parser.parse(this.currText.toString());
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException("Unexpected date format in list bucket output", e);
|
||||
}
|
||||
}
|
||||
this.currText = new StringBuffer();
|
||||
}
|
||||
|
||||
public void characters(char ch[], int start, int length) {
|
||||
this.currText.append(ch, start, length);
|
||||
}
|
||||
|
||||
public List getEntries() {
|
||||
return this.entries;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.SimpleTimeZone;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
|
||||
/**
|
||||
* Returned by AWSAuthConnection.listBucket()
|
||||
*/
|
||||
public class ListBucketResponse extends Response {
|
||||
|
||||
/**
|
||||
* The name of the bucket being listed. Null if request fails.
|
||||
*/
|
||||
public String name = null;
|
||||
|
||||
/**
|
||||
* The prefix echoed back from the request. Null if request fails.
|
||||
*/
|
||||
public String prefix = null;
|
||||
|
||||
/**
|
||||
* The marker echoed back from the request. Null if request fails.
|
||||
*/
|
||||
public String marker = null;
|
||||
|
||||
/**
|
||||
* The delimiter echoed back from the request. Null if not specified in
|
||||
* the request, or if it fails.
|
||||
*/
|
||||
public String delimiter = null;
|
||||
|
||||
/**
|
||||
* The maxKeys echoed back from the request if specified. 0 if request fails.
|
||||
*/
|
||||
public int maxKeys = 0;
|
||||
|
||||
/**
|
||||
* Indicates if there are more results to the list. True if the current
|
||||
* list results have been truncated. false if request fails.
|
||||
*/
|
||||
public boolean isTruncated = false;
|
||||
|
||||
/**
|
||||
* Indicates what to use as a marker for subsequent list requests in the event
|
||||
* that the results are truncated. Present only when a delimiter is specified.
|
||||
* Null if request fails.
|
||||
*/
|
||||
public String nextMarker = null;
|
||||
|
||||
/**
|
||||
* A List of ListEntry objects representing the objects in the given bucket.
|
||||
* Null if the request fails.
|
||||
*/
|
||||
public List entries = null;
|
||||
|
||||
/**
|
||||
* A List of CommonPrefixEntry objects representing the common prefixes of the
|
||||
* keys that matched up to the delimiter. Null if the request fails.
|
||||
*/
|
||||
public List commonPrefixEntries = null;
|
||||
|
||||
public ListBucketResponse(HttpURLConnection connection) throws IOException {
|
||||
super(connection);
|
||||
if (connection.getResponseCode() < 400) {
|
||||
try {
|
||||
XMLReader xr = Utils.createXMLReader();
|
||||
ListBucketHandler handler = new ListBucketHandler();
|
||||
xr.setContentHandler(handler);
|
||||
xr.setErrorHandler(handler);
|
||||
|
||||
xr.parse(new InputSource(connection.getInputStream()));
|
||||
|
||||
this.name = handler.getName();
|
||||
this.prefix = handler.getPrefix();
|
||||
this.marker = handler.getMarker();
|
||||
this.delimiter = handler.getDelimiter();
|
||||
this.maxKeys = handler.getMaxKeys();
|
||||
this.isTruncated = handler.getIsTruncated();
|
||||
this.nextMarker = handler.getNextMarker();
|
||||
this.entries = handler.getKeyEntries();
|
||||
this.commonPrefixEntries = handler.getCommonPrefixEntries();
|
||||
|
||||
} catch (SAXException e) {
|
||||
throw new RuntimeException("Unexpected error parsing ListBucket xml", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ListBucketHandler extends DefaultHandler {
|
||||
|
||||
private String name = null;
|
||||
private String prefix = null;
|
||||
private String marker = null;
|
||||
private String delimiter = null;
|
||||
private int maxKeys = 0;
|
||||
private boolean isTruncated = false;
|
||||
private String nextMarker = null;
|
||||
private boolean isEchoedPrefix = false;
|
||||
private List keyEntries = null;
|
||||
private ListEntry keyEntry = null;
|
||||
private List commonPrefixEntries = null;
|
||||
private CommonPrefixEntry commonPrefixEntry = null;
|
||||
private StringBuffer currText = null;
|
||||
private SimpleDateFormat iso8601Parser = null;
|
||||
|
||||
public ListBucketHandler() {
|
||||
super();
|
||||
keyEntries = new ArrayList();
|
||||
commonPrefixEntries = new ArrayList();
|
||||
this.iso8601Parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
||||
this.iso8601Parser.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||
this.currText = new StringBuffer();
|
||||
}
|
||||
|
||||
public void startDocument() {
|
||||
this.isEchoedPrefix = true;
|
||||
}
|
||||
|
||||
public void endDocument() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
public void startElement(String uri, String name, String qName, Attributes attrs) {
|
||||
if (name.equals("Contents")) {
|
||||
this.keyEntry = new ListEntry();
|
||||
} else if (name.equals("Owner")) {
|
||||
this.keyEntry.owner = new Owner();
|
||||
} else if (name.equals("CommonPrefixes")){
|
||||
this.commonPrefixEntry = new CommonPrefixEntry();
|
||||
}
|
||||
}
|
||||
|
||||
public void endElement(String uri, String name, String qName) {
|
||||
if (name.equals("Name")) {
|
||||
this.name = this.currText.toString();
|
||||
}
|
||||
// this prefix is the one we echo back from the request
|
||||
else if (name.equals("Prefix") && this.isEchoedPrefix) {
|
||||
this.prefix = this.currText.toString();
|
||||
this.isEchoedPrefix = false;
|
||||
} else if (name.equals("Marker")) {
|
||||
this.marker = this.currText.toString();
|
||||
} else if (name.equals("MaxKeys")) {
|
||||
this.maxKeys = Integer.parseInt(this.currText.toString());
|
||||
} else if (name.equals("Delimiter")) {
|
||||
this.delimiter = this.currText.toString();
|
||||
} else if (name.equals("IsTruncated")) {
|
||||
this.isTruncated = Boolean.valueOf(this.currText.toString());
|
||||
} else if (name.equals("NextMarker")) {
|
||||
this.nextMarker = this.currText.toString();
|
||||
} else if (name.equals("Contents")) {
|
||||
this.keyEntries.add(this.keyEntry);
|
||||
} else if (name.equals("Key")) {
|
||||
this.keyEntry.key = this.currText.toString();
|
||||
} else if (name.equals("LastModified")) {
|
||||
try {
|
||||
this.keyEntry.lastModified = this.iso8601Parser.parse(this.currText.toString());
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException("Unexpected date format in list bucket output", e);
|
||||
}
|
||||
} else if (name.equals("ETag")) {
|
||||
this.keyEntry.eTag = this.currText.toString();
|
||||
} else if (name.equals("Size")) {
|
||||
this.keyEntry.size = Long.parseLong(this.currText.toString());
|
||||
} else if (name.equals("StorageClass")) {
|
||||
this.keyEntry.storageClass = this.currText.toString();
|
||||
} else if (name.equals("ID")) {
|
||||
this.keyEntry.owner.id = this.currText.toString();
|
||||
} else if (name.equals("DisplayName")) {
|
||||
this.keyEntry.owner.displayName = this.currText.toString();
|
||||
} else if (name.equals("CommonPrefixes")) {
|
||||
this.commonPrefixEntries.add(this.commonPrefixEntry);
|
||||
}
|
||||
// this is the common prefix for keys that match up to the delimiter
|
||||
else if (name.equals("Prefix")) {
|
||||
this.commonPrefixEntry.prefix = this.currText.toString();
|
||||
}
|
||||
if(this.currText.length() != 0)
|
||||
this.currText = new StringBuffer();
|
||||
}
|
||||
|
||||
public void characters(char ch[], int start, int length) {
|
||||
this.currText.append(ch, start, length);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return this.prefix;
|
||||
}
|
||||
|
||||
public String getMarker() {
|
||||
return this.marker;
|
||||
}
|
||||
|
||||
public String getDelimiter() {
|
||||
return this.delimiter;
|
||||
}
|
||||
|
||||
public int getMaxKeys(){
|
||||
return this.maxKeys;
|
||||
}
|
||||
|
||||
public boolean getIsTruncated() {
|
||||
return this.isTruncated;
|
||||
}
|
||||
|
||||
public String getNextMarker() {
|
||||
return this.nextMarker;
|
||||
}
|
||||
|
||||
public List getKeyEntries() {
|
||||
return this.keyEntries;
|
||||
}
|
||||
|
||||
public List getCommonPrefixEntries() {
|
||||
return this.commonPrefixEntries;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* A structure representing a single object stored in S3. Returned as a part of ListBucketResponse.
|
||||
*/
|
||||
public class ListEntry {
|
||||
/**
|
||||
* The name of the object
|
||||
*/
|
||||
public String key;
|
||||
|
||||
/**
|
||||
* The date at which the object was last modified.
|
||||
*/
|
||||
public Date lastModified;
|
||||
|
||||
/**
|
||||
* The object's ETag, which can be used for conditional GETs.
|
||||
*/
|
||||
public String eTag;
|
||||
|
||||
/**
|
||||
* The size of the object in bytes.
|
||||
*/
|
||||
public long size;
|
||||
|
||||
/**
|
||||
* The object's storage class
|
||||
*/
|
||||
public String storageClass;
|
||||
|
||||
/**
|
||||
* The object's owner
|
||||
*/
|
||||
public Owner owner;
|
||||
|
||||
public String toString() {
|
||||
return key;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006-2007 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* A Response object returned from AWSAuthConnection.getBucketLocation().
|
||||
* Parses the response XML and exposes the location constraint
|
||||
* via the geteLocation() method.
|
||||
*/
|
||||
public class LocationResponse extends Response {
|
||||
String location;
|
||||
|
||||
/**
|
||||
* Parse the response to a ?location query.
|
||||
*/
|
||||
public LocationResponse(HttpURLConnection connection) throws IOException {
|
||||
super(connection);
|
||||
if (connection.getResponseCode() < 400) {
|
||||
try {
|
||||
XMLReader xr = Utils.createXMLReader();;
|
||||
LocationResponseHandler handler = new LocationResponseHandler();
|
||||
xr.setContentHandler(handler);
|
||||
xr.setErrorHandler(handler);
|
||||
|
||||
xr.parse(new InputSource(connection.getInputStream()));
|
||||
this.location = handler.location;
|
||||
} catch (SAXException e) {
|
||||
throw new RuntimeException("Unexpected error parsing ListAllMyBuckets xml", e);
|
||||
}
|
||||
} else {
|
||||
this.location = "<error>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the location-constraint for a bucket.
|
||||
* A value of null indicates an error;
|
||||
* the empty string indicates no constraint;
|
||||
* and any other value is an actual location constraint value.
|
||||
*/
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to parse LocationConstraint response XML
|
||||
*/
|
||||
static class LocationResponseHandler extends DefaultHandler {
|
||||
String location = null;
|
||||
private StringBuffer currText = null;
|
||||
|
||||
public void startDocument() {
|
||||
}
|
||||
|
||||
public void startElement(String uri, String name, String qName, Attributes attrs) {
|
||||
if (name.equals("LocationConstraint")) {
|
||||
this.currText = new StringBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
public void endElement(String uri, String name, String qName) {
|
||||
if (name.equals("LocationConstraint")) {
|
||||
location = this.currText.toString();
|
||||
this.currText = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void characters(char ch[], int start, int length) {
|
||||
if (currText != null)
|
||||
this.currText.append(ch, start, length);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
/**
|
||||
* A structure representing the owner of an object, used as a part of ListEntry.
|
||||
*/
|
||||
public class Owner {
|
||||
public String id;
|
||||
public String displayName;
|
||||
}
|
|
@ -0,0 +1,264 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006-2007 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* This class mimics the behavior of AWSAuthConnection, except instead of actually performing
|
||||
* the operation, QueryStringAuthGenerator will return URLs with query string parameters that
|
||||
* can be used to do the same thing. These parameters include an expiration date, so that
|
||||
* if you hand them off to someone else, they will only work for a limited amount of time.
|
||||
*/
|
||||
public class QueryStringAuthGenerator {
|
||||
|
||||
private String awsAccessKeyId;
|
||||
private String awsSecretAccessKey;
|
||||
private boolean isSecure;
|
||||
private String server;
|
||||
private int port;
|
||||
private CallingFormat callingFormat;
|
||||
|
||||
private Long expiresIn = null;
|
||||
private Long expires = null;
|
||||
|
||||
// by default, expire in 1 minute.
|
||||
private static final Long DEFAULT_EXPIRES_IN = new Long(60 * 1000);
|
||||
|
||||
public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey) {
|
||||
this(awsAccessKeyId, awsSecretAccessKey, true);
|
||||
}
|
||||
|
||||
public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey,
|
||||
boolean isSecure)
|
||||
{
|
||||
this(awsAccessKeyId, awsSecretAccessKey, isSecure, Utils.DEFAULT_HOST);
|
||||
}
|
||||
|
||||
public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey,
|
||||
boolean isSecure, String server)
|
||||
{
|
||||
this(awsAccessKeyId, awsSecretAccessKey, isSecure, server,
|
||||
isSecure ? Utils.SECURE_PORT : Utils.INSECURE_PORT);
|
||||
}
|
||||
|
||||
public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey,
|
||||
boolean isSecure, String server, int port)
|
||||
{
|
||||
this(awsAccessKeyId, awsSecretAccessKey, isSecure, server,
|
||||
port, CallingFormat.getSubdomainCallingFormat());
|
||||
}
|
||||
|
||||
public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey,
|
||||
boolean isSecure, String server, CallingFormat callingFormat)
|
||||
{
|
||||
this(awsAccessKeyId, awsSecretAccessKey, isSecure, server,
|
||||
isSecure ? Utils.SECURE_PORT : Utils.INSECURE_PORT,
|
||||
callingFormat);
|
||||
}
|
||||
|
||||
public QueryStringAuthGenerator(String awsAccessKeyId, String awsSecretAccessKey,
|
||||
boolean isSecure, String server, int port, CallingFormat callingFormat)
|
||||
{
|
||||
this.awsAccessKeyId = awsAccessKeyId;
|
||||
this.awsSecretAccessKey = awsSecretAccessKey;
|
||||
this.isSecure = isSecure;
|
||||
this.server = server;
|
||||
this.port = port;
|
||||
this.callingFormat = callingFormat;
|
||||
|
||||
this.expiresIn = DEFAULT_EXPIRES_IN;
|
||||
this.expires = null;
|
||||
}
|
||||
|
||||
|
||||
public void setCallingFormat(CallingFormat format) {
|
||||
this.callingFormat = format;
|
||||
}
|
||||
|
||||
public void setExpires(long millisSinceEpoch) {
|
||||
expires = new Long(millisSinceEpoch);
|
||||
expiresIn = null;
|
||||
}
|
||||
|
||||
public void setExpiresIn(long millis) {
|
||||
expiresIn = new Long(millis);
|
||||
expires = null;
|
||||
}
|
||||
|
||||
public String createBucket(String bucket, Map headers)
|
||||
{
|
||||
// validate bucket name
|
||||
if (!Utils.validateBucketName(bucket, callingFormat, false))
|
||||
throw new IllegalArgumentException("Invalid S3Bucket Name: "+bucket);
|
||||
|
||||
Map pathArgs = new HashMap();
|
||||
return generateURL("PUT", bucket, "", pathArgs, headers);
|
||||
}
|
||||
|
||||
public String listBucket(String bucket, String prefix, String marker,
|
||||
Integer maxKeys, Map headers){
|
||||
return listBucket(bucket, prefix, marker, maxKeys, null, headers);
|
||||
}
|
||||
|
||||
public String listBucket(String bucket, String prefix, String marker,
|
||||
Integer maxKeys, String delimiter, Map headers)
|
||||
{
|
||||
Map pathArgs = Utils.paramsForListOptions(prefix, marker, maxKeys, delimiter);
|
||||
return generateURL("GET", bucket, "", pathArgs, headers);
|
||||
}
|
||||
|
||||
public String deleteBucket(String bucket, Map headers)
|
||||
{
|
||||
Map pathArgs = new HashMap();
|
||||
return generateURL("DELETE", bucket, "", pathArgs, headers);
|
||||
}
|
||||
|
||||
public String put(String bucket, String key, S3Object object, Map headers) {
|
||||
Map metadata = null;
|
||||
Map pathArgs = new HashMap();
|
||||
if (object != null) {
|
||||
metadata = object.metadata;
|
||||
}
|
||||
|
||||
|
||||
return generateURL("PUT", bucket, Utils.urlencode(key), pathArgs, mergeMeta(headers, metadata));
|
||||
}
|
||||
|
||||
public String get(String bucket, String key, Map headers)
|
||||
{
|
||||
Map pathArgs = new HashMap();
|
||||
return generateURL("GET", bucket, Utils.urlencode(key), pathArgs, headers);
|
||||
}
|
||||
|
||||
public String delete(String bucket, String key, Map headers)
|
||||
{
|
||||
Map pathArgs = new HashMap();
|
||||
return generateURL("DELETE", bucket, Utils.urlencode(key), pathArgs, headers);
|
||||
}
|
||||
|
||||
public String getBucketLogging(String bucket, Map headers) {
|
||||
Map pathArgs = new HashMap();
|
||||
pathArgs.put("logging", null);
|
||||
return generateURL("GET", bucket, "", pathArgs, headers);
|
||||
}
|
||||
|
||||
public String putBucketLogging(String bucket, String loggingXMLDoc, Map headers) {
|
||||
Map pathArgs = new HashMap();
|
||||
pathArgs.put("logging", null);
|
||||
return generateURL("PUT", bucket, "", pathArgs, headers);
|
||||
}
|
||||
|
||||
public String getBucketACL(String bucket, Map headers) {
|
||||
return getACL(bucket, "", headers);
|
||||
}
|
||||
|
||||
public String getACL(String bucket, String key, Map headers)
|
||||
{
|
||||
Map pathArgs = new HashMap();
|
||||
pathArgs.put("acl", null);
|
||||
return generateURL("GET", bucket, Utils.urlencode(key), pathArgs, headers);
|
||||
}
|
||||
|
||||
public String putBucketACL(String bucket, String aclXMLDoc, Map headers) {
|
||||
return putACL(bucket, "", aclXMLDoc, headers);
|
||||
}
|
||||
|
||||
public String putACL(String bucket, String key, String aclXMLDoc, Map headers)
|
||||
{
|
||||
Map pathArgs = new HashMap();
|
||||
pathArgs.put("acl", null);
|
||||
return generateURL("PUT", bucket, Utils.urlencode(key), pathArgs, headers);
|
||||
}
|
||||
|
||||
public String listAllMyBuckets(Map headers)
|
||||
{
|
||||
Map pathArgs = new HashMap();
|
||||
return generateURL("GET", "", "", pathArgs, headers);
|
||||
}
|
||||
|
||||
public String makeBareURL(String bucket, String key) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
if (this.isSecure) {
|
||||
buffer.append("https://");
|
||||
} else {
|
||||
buffer.append("http://");
|
||||
}
|
||||
buffer.append(this.server).append(":").append(this.port).append("/").append(bucket);
|
||||
buffer.append("/").append(Utils.urlencode(key));
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private String generateURL(String method, String bucketName, String key, Map pathArgs, Map headers)
|
||||
{
|
||||
long expires = 0L;
|
||||
if (this.expiresIn != null) {
|
||||
expires = System.currentTimeMillis() + this.expiresIn.longValue();
|
||||
} else if (this.expires != null) {
|
||||
expires = this.expires.longValue();
|
||||
} else {
|
||||
throw new RuntimeException("Illegal expires state");
|
||||
}
|
||||
|
||||
// convert to seconds
|
||||
expires /= 1000;
|
||||
|
||||
String canonicalString = Utils.makeCanonicalString(method, bucketName, key, pathArgs, headers, ""+expires);
|
||||
String encodedCanonical = Utils.encode(this.awsSecretAccessKey, canonicalString, true);
|
||||
|
||||
pathArgs.put("Signature", encodedCanonical);
|
||||
pathArgs.put("Expires", Long.toString(expires));
|
||||
pathArgs.put("AWSAccessKeyId", this.awsAccessKeyId);
|
||||
|
||||
CallingFormat callingFormat = Utils.getCallingFormatForBucket( this.callingFormat, bucketName );
|
||||
if ( isSecure && callingFormat != CallingFormat.getPathCallingFormat() && bucketName.indexOf( "." ) != -1 ) {
|
||||
System.err.println( "You are making an SSL connection, however, the bucket contains periods and the wildcard certificate will not match by default. Please consider using HTTP." );
|
||||
}
|
||||
|
||||
String returnString;
|
||||
try {
|
||||
URL url = callingFormat.getURL(isSecure, server, port, bucketName, key, pathArgs);
|
||||
returnString = url.toString();
|
||||
} catch (MalformedURLException e) {
|
||||
returnString = "Exception generating url " + e;
|
||||
}
|
||||
|
||||
return returnString;
|
||||
}
|
||||
|
||||
private Map mergeMeta(Map headers, Map metadata) {
|
||||
Map merged = new TreeMap();
|
||||
if (headers != null) {
|
||||
for (Iterator i = headers.keySet().iterator(); i.hasNext(); ) {
|
||||
String key = (String)i.next();
|
||||
merged.put(key, headers.get(key));
|
||||
}
|
||||
}
|
||||
if (metadata != null) {
|
||||
for (Iterator i = metadata.keySet().iterator(); i.hasNext(); ) {
|
||||
String key = (String)i.next();
|
||||
String metadataKey = Utils.METADATA_PREFIX + key;
|
||||
if (merged.containsKey(metadataKey)) {
|
||||
((List)merged.get(metadataKey)).addAll((List)metadata.get(key));
|
||||
} else {
|
||||
merged.put(metadataKey, metadata.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* The parent class of all other Responses. This class keeps track of the
|
||||
* HttpURLConnection response.
|
||||
*/
|
||||
public class Response {
|
||||
public HttpURLConnection connection;
|
||||
|
||||
public Response(HttpURLConnection connection) throws IOException {
|
||||
this.connection = connection;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A representation of a single object stored in S3.
|
||||
*/
|
||||
public class S3Object {
|
||||
|
||||
public byte[] data;
|
||||
|
||||
/**
|
||||
* A Map from String to List of Strings representing the object's metadata
|
||||
*/
|
||||
public Map metadata;
|
||||
|
||||
public S3Object(byte[] data, Map metadata) {
|
||||
this.data = data;
|
||||
this.metadata = metadata;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,324 @@
|
|||
// This software code is made available "AS IS" without warranties of any
|
||||
// kind. You may copy, display, modify and redistribute the software
|
||||
// code either by itself or as incorporated into your code; provided that
|
||||
// you do not remove any proprietary notices. Your use of this software
|
||||
// code is at your own risk and you waive any claim against Amazon
|
||||
// Digital Services, Inc. or its affiliates with respect to your use of
|
||||
// this software code. (c) 2006-2007 Amazon Digital Services, Inc. or its
|
||||
// affiliates.
|
||||
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.amazon.thirdparty.Base64;
|
||||
|
||||
public class Utils {
|
||||
static final String METADATA_PREFIX = "x-amz-meta-";
|
||||
static final String AMAZON_HEADER_PREFIX = "x-amz-";
|
||||
static final String ALTERNATIVE_DATE_HEADER = "x-amz-date";
|
||||
public static final String DEFAULT_HOST = "s3.amazonaws.com";
|
||||
|
||||
public static final int SECURE_PORT = 443;
|
||||
public static final int INSECURE_PORT = 80;
|
||||
|
||||
|
||||
/**
|
||||
* HMAC/SHA1 Algorithm per RFC 2104.
|
||||
*/
|
||||
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
|
||||
|
||||
static String makeCanonicalString(String method, String bucket, String key, Map pathArgs, Map headers) {
|
||||
return makeCanonicalString(method, bucket, key, pathArgs, headers, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the canonical string. When expires is non-null, it will be
|
||||
* used instead of the Date header.
|
||||
*/
|
||||
static String makeCanonicalString(String method, String bucketName, String key, Map pathArgs,
|
||||
Map headers, String expires)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append(method + "\n");
|
||||
|
||||
// Add all interesting headers to a list, then sort them. "Interesting"
|
||||
// is defined as Content-MD5, Content-Type, Date, and x-amz-
|
||||
SortedMap interestingHeaders = new TreeMap();
|
||||
if (headers != null) {
|
||||
for (Iterator i = headers.keySet().iterator(); i.hasNext(); ) {
|
||||
String hashKey = (String)i.next();
|
||||
if (hashKey == null) continue;
|
||||
String lk = hashKey.toLowerCase();
|
||||
|
||||
// Ignore any headers that are not particularly interesting.
|
||||
if (lk.equals("content-type") || lk.equals("content-md5") || lk.equals("date") ||
|
||||
lk.startsWith(AMAZON_HEADER_PREFIX))
|
||||
{
|
||||
List s = (List)headers.get(hashKey);
|
||||
interestingHeaders.put(lk, concatenateList(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interestingHeaders.containsKey(ALTERNATIVE_DATE_HEADER)) {
|
||||
interestingHeaders.put("date", "");
|
||||
}
|
||||
|
||||
// if the expires is non-null, use that for the date field. this
|
||||
// trumps the x-amz-date behavior.
|
||||
if (expires != null) {
|
||||
interestingHeaders.put("date", expires);
|
||||
}
|
||||
|
||||
// these headers require that we still put a new line in after them,
|
||||
// even if they don't exist.
|
||||
if (! interestingHeaders.containsKey("content-type")) {
|
||||
interestingHeaders.put("content-type", "");
|
||||
}
|
||||
if (! interestingHeaders.containsKey("content-md5")) {
|
||||
interestingHeaders.put("content-md5", "");
|
||||
}
|
||||
|
||||
// Finally, add all the interesting headers (i.e.: all that startwith x-amz- ;-))
|
||||
for (Iterator i = interestingHeaders.keySet().iterator(); i.hasNext(); ) {
|
||||
String headerKey = (String)i.next();
|
||||
if (headerKey.startsWith(AMAZON_HEADER_PREFIX)) {
|
||||
buf.append(headerKey).append(':').append(interestingHeaders.get(headerKey));
|
||||
} else {
|
||||
buf.append(interestingHeaders.get(headerKey));
|
||||
}
|
||||
buf.append("\n");
|
||||
}
|
||||
|
||||
// build the path using the bucket and key
|
||||
if (bucketName != null && !bucketName.equals("")) {
|
||||
buf.append("/" + bucketName );
|
||||
}
|
||||
|
||||
// append the key (it might be an empty string)
|
||||
// append a slash regardless
|
||||
buf.append("/");
|
||||
if(key != null) {
|
||||
buf.append(key);
|
||||
}
|
||||
|
||||
// if there is an acl, logging or torrent parameter
|
||||
// add them to the string
|
||||
if (pathArgs != null ) {
|
||||
if (pathArgs.containsKey("acl")) {
|
||||
buf.append("?acl");
|
||||
} else if (pathArgs.containsKey("torrent")) {
|
||||
buf.append("?torrent");
|
||||
} else if (pathArgs.containsKey("logging")) {
|
||||
buf.append("?logging");
|
||||
} else if (pathArgs.containsKey("location")) {
|
||||
buf.append("?location");
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the HMAC/SHA1 on a string.
|
||||
* @param data Data to sign
|
||||
* @param passcode Passcode to sign it with
|
||||
* @return Signature
|
||||
* @throws NoSuchAlgorithmException If the algorithm does not exist. Unlikely
|
||||
* @throws InvalidKeyException If the key is invalid.
|
||||
*/
|
||||
static String encode(String awsSecretAccessKey, String canonicalString,
|
||||
boolean urlencode)
|
||||
{
|
||||
// The following HMAC/SHA1 code for the signature is taken from the
|
||||
// AWS Platform's implementation of RFC2104 (amazon.webservices.common.Signature)
|
||||
//
|
||||
// Acquire an HMAC/SHA1 from the raw key bytes.
|
||||
SecretKeySpec signingKey =
|
||||
new SecretKeySpec(awsSecretAccessKey.getBytes(), HMAC_SHA1_ALGORITHM);
|
||||
|
||||
// Acquire the MAC instance and initialize with the signing key.
|
||||
Mac mac = null;
|
||||
try {
|
||||
mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// should not happen
|
||||
throw new RuntimeException("Could not find sha1 algorithm", e);
|
||||
}
|
||||
try {
|
||||
mac.init(signingKey);
|
||||
} catch (InvalidKeyException e) {
|
||||
// also should not happen
|
||||
throw new RuntimeException("Could not initialize the MAC algorithm", e);
|
||||
}
|
||||
|
||||
// Compute the HMAC on the digest, and set it.
|
||||
String b64 = Base64.encodeBytes(mac.doFinal(canonicalString.getBytes()));
|
||||
|
||||
if (urlencode) {
|
||||
return urlencode(b64);
|
||||
} else {
|
||||
return b64;
|
||||
}
|
||||
}
|
||||
|
||||
static Map paramsForListOptions(String prefix, String marker, Integer maxKeys) {
|
||||
return paramsForListOptions(prefix, marker, maxKeys, null);
|
||||
}
|
||||
|
||||
static Map paramsForListOptions(String prefix, String marker, Integer maxKeys, String delimiter) {
|
||||
|
||||
Map argParams = new HashMap();
|
||||
// these three params must be url encoded
|
||||
if (prefix != null)
|
||||
argParams.put("prefix", urlencode(prefix));
|
||||
if (marker != null)
|
||||
argParams.put("marker", urlencode(marker));
|
||||
if (delimiter != null)
|
||||
argParams.put("delimiter", urlencode(delimiter));
|
||||
|
||||
if (maxKeys != null)
|
||||
argParams.put("max-keys", Integer.toString(maxKeys.intValue()));
|
||||
|
||||
return argParams;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the Path Arguments from a map to String which can be used in url construction
|
||||
* @param pathArgs a map of arguments
|
||||
* @return a string representation of pathArgs
|
||||
*/
|
||||
public static String convertPathArgsHashToString(Map pathArgs) {
|
||||
StringBuffer pathArgsString = new StringBuffer();
|
||||
String argumentValue;
|
||||
boolean firstRun = true;
|
||||
if (pathArgs != null) {
|
||||
for (Iterator argumentIterator = pathArgs.keySet().iterator(); argumentIterator.hasNext(); ) {
|
||||
String argument = (String)argumentIterator.next();
|
||||
if (firstRun) {
|
||||
firstRun = false;
|
||||
pathArgsString.append("?");
|
||||
} else {
|
||||
pathArgsString.append("&");
|
||||
}
|
||||
|
||||
argumentValue = (String)pathArgs.get(argument);
|
||||
pathArgsString.append(argument);
|
||||
if (argumentValue != null) {
|
||||
pathArgsString.append("=");
|
||||
pathArgsString.append(argumentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pathArgsString.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static String urlencode(String unencoded) {
|
||||
try {
|
||||
return URLEncoder.encode(unencoded, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// should never happen
|
||||
throw new RuntimeException("Could not url encode to UTF-8", e);
|
||||
}
|
||||
}
|
||||
|
||||
static XMLReader createXMLReader() {
|
||||
try {
|
||||
return XMLReaderFactory.createXMLReader();
|
||||
} catch (SAXException e) {
|
||||
// oops, lets try doing this (needed in 1.4)
|
||||
System.setProperty("org.xml.sax.driver", "org.apache.crimson.parser.XMLReaderImpl");
|
||||
}
|
||||
try {
|
||||
// try once more
|
||||
return XMLReaderFactory.createXMLReader();
|
||||
} catch (SAXException e) {
|
||||
throw new RuntimeException("Couldn't initialize a sax driver for the XMLReader");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates a bunch of header values, seperating them with a comma.
|
||||
* @param values List of header values.
|
||||
* @return String of all headers, with commas.
|
||||
*/
|
||||
private static String concatenateList(List values) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0, size = values.size(); i < size; ++ i) {
|
||||
buf.append(((String)values.get(i)).replaceAll("\n", "").trim());
|
||||
if (i != (size - 1)) {
|
||||
buf.append(",");
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate bucket-name
|
||||
*/
|
||||
static boolean validateBucketName(String bucketName, CallingFormat callingFormat, boolean located) {
|
||||
if (callingFormat == CallingFormat.getPathCallingFormat())
|
||||
{
|
||||
final int MIN_BUCKET_LENGTH = 3;
|
||||
final int MAX_BUCKET_LENGTH = 255;
|
||||
final String BUCKET_NAME_REGEX = "^[0-9A-Za-z\\.\\-_]*$";
|
||||
|
||||
return null != bucketName &&
|
||||
bucketName.length() >= MIN_BUCKET_LENGTH &&
|
||||
bucketName.length() <= MAX_BUCKET_LENGTH &&
|
||||
bucketName.matches(BUCKET_NAME_REGEX);
|
||||
} else {
|
||||
return isValidSubdomainBucketName( bucketName );
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isValidSubdomainBucketName( String bucketName ) {
|
||||
final int MIN_BUCKET_LENGTH = 3;
|
||||
final int MAX_BUCKET_LENGTH = 63;
|
||||
// don't allow names that look like 127.0.0.1
|
||||
final String IPv4_REGEX = "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$";
|
||||
// dns sub-name restrictions
|
||||
final String BUCKET_NAME_REGEX = "^[a-z0-9]([a-z0-9\\-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9\\-]*[a-z0-9])?)*$";
|
||||
|
||||
// If there wasn't a location-constraint, then the current actual
|
||||
// restriction is just that no 'part' of the name (i.e. sequence
|
||||
// of characters between any 2 '.'s has to be 63) but the recommendation
|
||||
// is to keep the entire bucket name under 63.
|
||||
return null != bucketName &&
|
||||
bucketName.length() >= MIN_BUCKET_LENGTH &&
|
||||
bucketName.length() <= MAX_BUCKET_LENGTH &&
|
||||
!bucketName.matches(IPv4_REGEX) &&
|
||||
bucketName.matches(BUCKET_NAME_REGEX);
|
||||
}
|
||||
|
||||
static CallingFormat getCallingFormatForBucket( CallingFormat desiredFormat, String bucketName ) {
|
||||
CallingFormat callingFormat = desiredFormat;
|
||||
if ( callingFormat == CallingFormat.getSubdomainCallingFormat() && ! Utils.isValidSubdomainBucketName( bucketName ) ) {
|
||||
callingFormat = CallingFormat.getPathCallingFormat();
|
||||
}
|
||||
return callingFormat;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,84 @@
|
|||
This is one of a collection of interface libraries that can be used to interact
|
||||
with the Amazon S3 system in a number of different languages. They each expose
|
||||
two main interface classes, AWSAuthConnection and QueryStringAuthGenerator.
|
||||
The first actually performs all the operations using the appropriate libraries
|
||||
for the language, including header signing. The second,
|
||||
QueryStringAuthGenerator, has the same interface, but instead of performing
|
||||
the operation, this class will return urls with the right query string
|
||||
authentication parameters set.
|
||||
|
||||
|
||||
Basic Operations:
|
||||
|
||||
object requests:
|
||||
|
||||
GetResponse get(bucketName, keyName) - retrieves an object
|
||||
GetResponse getACL(bucketName, keyName) - returns the xml acl doc
|
||||
Response put(bucketName, keyName, object) - writes an object
|
||||
Response putACL(bucketName, keyName, aclXMLDoc) - sets the xml acl doc
|
||||
Response delete(bucketName, keyName) - deletes an object
|
||||
|
||||
bucket requests:
|
||||
|
||||
Response createBucket(bucketName, location) - creates a bucket
|
||||
ListResponse listBucket(bucketName) - lists a bucket's contents
|
||||
LocationResponse getBucketLocation(bucketName) - return the location-constraint of this bucket
|
||||
GetResponse getBucketACL(bucketName) - returns the xml representation of this bucket's access control list
|
||||
Response putBucketAcl(bucketName, aclXMLDoc) - sets xml representation of the bucket acl
|
||||
Response deleteBucket(bucketName) - delete an empty bucket
|
||||
GetResponse getBucketLogging(bucketName) - returns the xml representation of this bucket's access logging configuration
|
||||
Response putBucketLogging(bucketName, loggingXMLDoc) - sets the xml representation of the bucket logging configuration
|
||||
|
||||
ListAllMyBucketsResponse listAllMyBuckets() - returns a list of all buckets owned by this AWS Access Key Id
|
||||
|
||||
|
||||
|
||||
Dependencies:
|
||||
|
||||
None, beyond the standard libraries.
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
Please note that this uses the public domain iHarder.net Base64 library. For updates to that library,
|
||||
see http://iharder.sourceforge.net/current/java/base64/ .
|
||||
|
||||
If your bucket name contains periods, you will need to use a non-HTTPS connection as the SSL certificate
|
||||
presented by s3.amazonaws.com will not match if you do.
|
||||
|
||||
Limitations:
|
||||
|
||||
One of the main limitations of these sample AWSAuthConnection implementations
|
||||
is that the interfaces are not streaming. This means that you have to pass the
|
||||
data in as a string or as a byte array and the operation returns a string or a
|
||||
byte array back. This is conceptually simpler, and fine for smaller objects,
|
||||
but large objects, say a couple megabytes or greater, will show poor
|
||||
performance, since everything is being passed around in memory. More
|
||||
sophisticated libraries would pass streams in and out, and would only read the
|
||||
data on-demand, rather than storing it all in memory (S3 itself would have no
|
||||
problem with such streaming applications). Another upshot of this is that the
|
||||
interfaces are all blocking---that is, you cannot look at the data until all of
|
||||
it has downloaded. Again, this is fine for smaller objects, but unacceptable
|
||||
for larger ones.
|
||||
|
||||
These libraries have nearly non-existent error handling. All errors from lower
|
||||
libraries are simply passed up. The response code in the connection object needs
|
||||
to be checked after each request to verify whether the request succeeded.
|
||||
|
||||
Only the java library has proper handling for repeated headers. The others
|
||||
assume that each header will have only one value.
|
||||
|
||||
It is our intention that these libraries act as a starting point for future
|
||||
development. They are meant to show off the various operations and provide an
|
||||
example of how to negotiate the authentication process.
|
||||
|
||||
|
||||
|
||||
This software code is made available "AS IS" without warranties of any
|
||||
kind. You may copy, display, modify and redistribute the software
|
||||
code either by itself or as incorporated into your code; provided that
|
||||
you do not remove any proprietary notices. Your use of this software
|
||||
code is at your own risk and you waive any claim against Amazon
|
||||
Digital Services, Inc. or its affiliates with respect to your use of
|
||||
this software code. (c) 2006 Amazon Digital Services, Inc. or its
|
||||
affiliates.
|
|
@ -0,0 +1,119 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Optional;
|
||||
import org.testng.annotations.Parameters;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(sequential = true, timeOut = 2 * 60 * 1000, testName = "s3.AmazonPerformance", groups = "performance")
|
||||
public class AmazonPerformance extends BasePerformance {
|
||||
private AWSAuthConnection amzClient;
|
||||
|
||||
@Override
|
||||
@BeforeTest
|
||||
@Parameters( { "jclouds.aws.accesskeyid", "jclouds.aws.secretaccesskey" })
|
||||
protected void setUpClient(@Optional String AWSAccessKeyId, @Optional String AWSSecretAccessKey) throws Exception {
|
||||
super.setUpClient(AWSAccessKeyId, AWSSecretAccessKey);
|
||||
amzClient = new AWSAuthConnection(AWSAccessKeyId, AWSSecretAccessKey,
|
||||
false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void testPutFileSerial() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void testPutFileParallel() throws InterruptedException,
|
||||
ExecutionException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void testPutInputStreamSerial() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void testPutInputStreamParallel() throws InterruptedException,
|
||||
ExecutionException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void testPutStringSerial() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void testPutStringParallel() throws InterruptedException,
|
||||
ExecutionException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean putByteArray(String bucket, String key, byte[] data,
|
||||
String contentType) throws Exception {
|
||||
com.amazon.s3.S3Object object = new com.amazon.s3.S3Object(data, null);
|
||||
Map headers = new TreeMap();
|
||||
headers
|
||||
.put("Content-Type", Arrays
|
||||
.asList(new String[] { contentType }));
|
||||
return amzClient.put(bucket, key, object, headers).connection
|
||||
.getResponseMessage() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean putFile(String bucket, String key, File data,
|
||||
String contentType) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean putInputStream(String bucket, String key,
|
||||
InputStream data, String contentType) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean putString(String bucket, String key, String data,
|
||||
String contentType) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public abstract class BaseJCloudsPerformance extends BasePerformance {
|
||||
// boolean get
|
||||
// (
|
||||
// int id) throws Exception {
|
||||
// S3Bucket s3Bucket = new S3Bucket();
|
||||
// s3Bucket.setName(bucketPrefix + "-jclouds-puts");
|
||||
// org.jclouds.aws.s3.domain.S3Object object = new
|
||||
// org.jclouds.aws.s3.domain.S3Object();
|
||||
// object.setKey(id + "");
|
||||
// //object.setContentType("text/plain");
|
||||
// object.setContentType("application/octetstream");
|
||||
// //object.setContent("this is a test");
|
||||
// object.setContent(test);
|
||||
// return clientProvider.getObject(s3Bucket, object.getKey()).get() !=
|
||||
// org.jclouds.aws.s3.domain.S3Object.NOT_FOUND;
|
||||
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected boolean putByteArray(String bucket, String key, byte[] data,
|
||||
String contentType) throws Exception {
|
||||
S3Bucket s3Bucket = new S3Bucket();
|
||||
s3Bucket.setName(bucket);
|
||||
org.jclouds.aws.s3.domain.S3Object object = new org.jclouds.aws.s3.domain.S3Object();
|
||||
object.setKey(key);
|
||||
object.setContentType(contentType);
|
||||
object.setContent(data);
|
||||
return client.addObject(s3Bucket, object).get() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean putFile(String bucket, String key, File data,
|
||||
String contentType) throws Exception {
|
||||
S3Bucket s3Bucket = new S3Bucket();
|
||||
s3Bucket.setName(bucket);
|
||||
org.jclouds.aws.s3.domain.S3Object object = new org.jclouds.aws.s3.domain.S3Object();
|
||||
object.setKey(key);
|
||||
object.setContentType(contentType);
|
||||
object.setContent(data);
|
||||
return client.addObject(s3Bucket, object).get() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean putInputStream(String bucket, String key,
|
||||
InputStream data, String contentType) throws Exception {
|
||||
S3Bucket s3Bucket = new S3Bucket();
|
||||
s3Bucket.setName(bucket);
|
||||
org.jclouds.aws.s3.domain.S3Object object = new org.jclouds.aws.s3.domain.S3Object();
|
||||
object.setKey(key);
|
||||
object.setContentType(contentType);
|
||||
object.setContent(data);
|
||||
object.setSize(data.available());
|
||||
return client.addObject(s3Bucket, object).get() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean putString(String bucket, String key, String data,
|
||||
String contentType) throws Exception {
|
||||
S3Bucket s3Bucket = new S3Bucket();
|
||||
s3Bucket.setName(bucket);
|
||||
org.jclouds.aws.s3.domain.S3Object object = new org.jclouds.aws.s3.domain.S3Object();
|
||||
object.setKey(key);
|
||||
object.setContentType(contentType);
|
||||
object.setContent(data);
|
||||
return client.addObject(s3Bucket, object).get() != null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,258 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletionService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.jclouds.aws.s3.S3IntegrationTest;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
import org.testng.annotations.AfterTest;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Optional;
|
||||
import org.testng.annotations.Parameters;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.inject.Provider;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(sequential = true, timeOut = 2 * 60 * 1000, groups = "performance")
|
||||
public abstract class BasePerformance extends S3IntegrationTest {
|
||||
protected static int LOOP_COUNT = 100;
|
||||
|
||||
protected ExecutorService exec;
|
||||
protected final String BUCKET_BYTES = bucketPrefix + "-bytes";
|
||||
protected final String BUCKET_INPUTSTREAM = bucketPrefix + "-inputstream";
|
||||
protected final String BUCKET_STRING = bucketPrefix + "-string";
|
||||
protected final String BUCKET_FILE = bucketPrefix + "-file";
|
||||
protected final String[] BUCKETS = { BUCKET_BYTES, BUCKET_INPUTSTREAM,
|
||||
BUCKET_STRING, BUCKET_FILE };
|
||||
protected PutBytesCallable putBytesCallable;
|
||||
protected PutFileCallable putFileCallable;
|
||||
protected PutInputStreamCallable putInputStreamCallable;
|
||||
protected PutStringCallable putStringCallable;
|
||||
|
||||
protected CompletionService<Boolean> completer;
|
||||
|
||||
@BeforeTest
|
||||
protected void setUpCallables() {
|
||||
putBytesCallable = new PutBytesCallable();
|
||||
putFileCallable = new PutFileCallable();
|
||||
putInputStreamCallable = new PutInputStreamCallable();
|
||||
putStringCallable = new PutStringCallable();
|
||||
exec = Executors.newCachedThreadPool();
|
||||
completer = new ExecutorCompletionService<Boolean>(exec);
|
||||
}
|
||||
|
||||
@Override
|
||||
@BeforeTest
|
||||
@Parameters( { "jclouds.aws.accesskeyid", "jclouds.aws.secretaccesskey" })
|
||||
protected void setUpClient(@Optional String AWSAccessKeyId,
|
||||
@Optional String AWSSecretAccessKey) throws Exception {
|
||||
super.setUpClient(AWSAccessKeyId, AWSSecretAccessKey);
|
||||
S3Bucket s3Bucket = new S3Bucket();
|
||||
for (String bucket : BUCKETS) {
|
||||
s3Bucket.setName(bucket);
|
||||
client.createBucketIfNotExists(s3Bucket).get();
|
||||
}
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
protected void tearDownExecutor() throws Exception {
|
||||
exec.shutdownNow();
|
||||
exec = null;
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
protected void testPutBytesSerial() throws Exception {
|
||||
doSerial(putBytesCallable, LOOP_COUNT / 10);
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
protected void testPutBytesParallel() throws InterruptedException,
|
||||
ExecutionException {
|
||||
doParallel(putBytesCallable, LOOP_COUNT);
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
protected void testPutFileSerial() throws Exception {
|
||||
doSerial(putFileCallable, LOOP_COUNT / 10);
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
protected void testPutFileParallel() throws InterruptedException,
|
||||
ExecutionException {
|
||||
doParallel(putFileCallable, LOOP_COUNT);
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
protected void testPutInputStreamSerial() throws Exception {
|
||||
doSerial(putInputStreamCallable, LOOP_COUNT / 10);
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
protected void testPutInputStreamParallel() throws InterruptedException,
|
||||
ExecutionException {
|
||||
doParallel(putInputStreamCallable, LOOP_COUNT);
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
protected void testPutStringSerial() throws Exception {
|
||||
doSerial(putStringCallable, LOOP_COUNT / 10);
|
||||
}
|
||||
|
||||
@Test(enabled = true)
|
||||
protected void testPutStringParallel() throws InterruptedException,
|
||||
ExecutionException {
|
||||
doParallel(putStringCallable, LOOP_COUNT);
|
||||
}
|
||||
|
||||
private void doSerial(Provider<Callable<Boolean>> provider, int loopCount)
|
||||
throws Exception, ExecutionException {
|
||||
for (int i = 0; i < loopCount; i++)
|
||||
assert provider.get().call();
|
||||
}
|
||||
|
||||
private void doParallel(Provider<Callable<Boolean>> provider, int loopCount)
|
||||
throws InterruptedException, ExecutionException {
|
||||
for (int i = 0; i < loopCount; i++)
|
||||
completer.submit(provider.get());
|
||||
for (int i = 0; i < loopCount; i++)
|
||||
assert completer.take().get();
|
||||
}
|
||||
|
||||
class PutBytesCallable implements Provider<Callable<Boolean>> {
|
||||
final AtomicInteger key = new AtomicInteger(0);
|
||||
protected byte[] test = new byte[1024 * 2];
|
||||
|
||||
public Callable<Boolean> get() {
|
||||
return new Callable<Boolean>() {
|
||||
public Boolean call() throws Exception {
|
||||
return putByteArray(BUCKET_BYTES, key.getAndIncrement()
|
||||
+ "", test, "application/octetstring");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class PutFileCallable implements Provider<Callable<Boolean>> {
|
||||
final AtomicInteger key = new AtomicInteger(0);
|
||||
protected File file = new File(
|
||||
"/Users/adriancole/Desktop/charles_ca_certificate.zip");
|
||||
|
||||
public Callable<Boolean> get() {
|
||||
return new Callable<Boolean>() {
|
||||
public Boolean call() throws Exception {
|
||||
return putFile(BUCKET_FILE, key.getAndIncrement() + "",
|
||||
file, "application/zip");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class PutInputStreamCallable extends PutBytesCallable {
|
||||
final AtomicInteger key = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
public Callable<Boolean> get() {
|
||||
return new Callable<Boolean>() {
|
||||
public Boolean call() throws Exception {
|
||||
return putInputStream(BUCKET_INPUTSTREAM, key
|
||||
.getAndIncrement()
|
||||
+ "", new ByteArrayInputStream(test),
|
||||
"application/octetstring");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class PutStringCallable implements Provider<Callable<Boolean>> {
|
||||
final AtomicInteger key = new AtomicInteger(0);
|
||||
protected String testString = "hello world!";
|
||||
|
||||
public Callable<Boolean> get() {
|
||||
return new Callable<Boolean>() {
|
||||
public Boolean call() throws Exception {
|
||||
return putString(BUCKET_STRING, key.getAndIncrement() + "",
|
||||
testString, "text/plain");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract boolean putByteArray(String bucket, String key,
|
||||
byte[] data, String contentType) throws Exception;
|
||||
|
||||
protected abstract boolean putFile(String bucket, String key, File data,
|
||||
String contentType) throws Exception;
|
||||
|
||||
protected abstract boolean putInputStream(String bucket, String key,
|
||||
InputStream data, String contentType) throws Exception;
|
||||
|
||||
protected abstract boolean putString(String bucket, String key,
|
||||
String data, String contentType) throws Exception;
|
||||
|
||||
// private class BucketDeleter implements Callable<Boolean> {
|
||||
// private BucketDeleter(S3Bucket bucket) {
|
||||
// this.bucket = bucket;
|
||||
// }
|
||||
//
|
||||
// private S3Bucket bucket;
|
||||
//
|
||||
// @Override
|
||||
// public String toString() {
|
||||
// return "BucketDeleter{" + "bucket=" + bucket + '}';
|
||||
// }
|
||||
//
|
||||
// public Boolean call() throws Exception {
|
||||
// bucket = clientProvider.get().getBucket(bucket).get();
|
||||
// List<Future<Boolean>> deletes = new ArrayList<Future<Boolean>>();
|
||||
// for (org.jclouds.aws.s3.domain.S3Object object : bucket
|
||||
// .getContents()) {
|
||||
// deletes.add(clientProvider.get().deleteObject(bucket,
|
||||
// object.getKey()));
|
||||
// }
|
||||
// for (Future<Boolean> isdeleted : deletes)
|
||||
// assert isdeleted.get() : String.format("failed to delete %1s",
|
||||
// isdeleted);
|
||||
// return clientProvider.get().deleteBucket(bucket).get();
|
||||
// }
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package com.amazon.s3;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import org.jclouds.aws.PerformanceTest;
|
||||
import org.jclouds.aws.s3.DateService;
|
||||
import org.joda.time.DateTime;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletionService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
|
||||
@Test(sequential = true, timeOut = 2 * 60 * 1000, testName = "s3.DateTest", groups = "performance")
|
||||
public class DateTest extends PerformanceTest {
|
||||
Injector i = Guice.createInjector();
|
||||
|
||||
DateService utils = i.getInstance(DateService.class);
|
||||
SimpleDateFormat dateParser;
|
||||
|
||||
|
||||
public DateTest() {
|
||||
this.dateParser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
||||
this.dateParser.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||
}
|
||||
|
||||
Date amazonDateFromString(String toParse) throws ParseException {
|
||||
return this.dateParser.parse(toParse);
|
||||
}
|
||||
|
||||
private static String toParse = "2009-03-12T02:00:07.000Z";
|
||||
|
||||
@Test
|
||||
public void testParseDateSameAsAmazon() throws ParseException, ExecutionException, InterruptedException {
|
||||
Date java = dateParser.parse(toParse);
|
||||
DateTime joda = utils.dateTimeFromXMLFormat(toParse);
|
||||
assert java.equals(joda.toDate());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTimeStampDateSameAsAmazon() throws ExecutionException, InterruptedException {
|
||||
String java = AWSAuthConnection.httpDate();
|
||||
String joda = utils.timestampAsHeaderString();
|
||||
assert java.equals(joda);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTimeStampSerialResponseTime() throws ExecutionException, InterruptedException {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
utils.timestampAsHeaderString();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonTimeStampSerialResponseTime() {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
AWSAuthConnection.httpDate();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTimeStampParallelResponseTime() throws InterruptedException, ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(exec);
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() throws ExecutionException, InterruptedException {
|
||||
utils.timestampAsHeaderString();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++) assert completer.take().get();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonTimeStampParallelResponseTime() throws InterruptedException, ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(exec);
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() {
|
||||
AWSAuthConnection.httpDate();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++) assert completer.take().get();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testParseDateSerialResponseTime() throws ExecutionException, InterruptedException {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
utils.dateTimeFromXMLFormat(toParse);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonParseDateSerialResponseTime() {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
AWSAuthConnection.httpDate();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParseDateParallelResponseTime() throws InterruptedException, ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(exec);
|
||||
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() throws ExecutionException, InterruptedException {
|
||||
utils.dateTimeFromXMLFormat(toParse);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++) assert completer.take().get();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonParseDateParallelResponseTime() throws InterruptedException, ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(exec);
|
||||
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() {
|
||||
AWSAuthConnection.httpDate();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++) assert completer.take().get();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package com.amazon.s3;
|
||||
|
||||
|
||||
import com.google.inject.Module;
|
||||
import org.jclouds.aws.s3.nio.config.S3HttpNioConnectionPoolClientModule;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
@Test(sequential = true, timeOut = 2 * 60 * 1000, testName = "s3.JCloudsNioPerformance", groups = "performance")
|
||||
public class JCloudsNioPerformance extends BaseJCloudsPerformance {
|
||||
|
||||
@Override
|
||||
protected Properties buildS3Properties(String AWSAccessKeyId,
|
||||
String AWSSecretAccessKey) {
|
||||
Properties properties = super.buildS3Properties(AWSAccessKeyId, AWSSecretAccessKey);
|
||||
properties.setProperty("jclouds.http.pool.max_connection_reuse", "75");
|
||||
properties.setProperty("jclouds.http.pool.max_session_failures", "2");
|
||||
properties.setProperty("jclouds.http.pool.request_invoker_threads", "1");
|
||||
properties.setProperty("jclouds.http.pool.io_worker_threads", "2");
|
||||
properties.setProperty("jclouds.pool.max_connections", "12");
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Module createHttpModule() {
|
||||
return new S3HttpNioConnectionPoolClientModule();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package com.amazon.s3;
|
||||
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@Test(sequential = true, timeOut = 2 * 60 * 1000, testName = "s3.JCloudsPerformance", groups = "performance")
|
||||
public class JCloudsPerformance extends BaseJCloudsPerformance {
|
||||
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package com.amazon.s3;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.jets3t.service.S3Service;
|
||||
import org.jets3t.service.impl.rest.httpclient.RestS3Service;
|
||||
import org.jets3t.service.security.AWSCredentials;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(sequential = true, timeOut = 2 * 60 * 1000, testName = "s3.Jets3tPerformance", groups = "performance")
|
||||
public class Jets3tPerformance extends BasePerformance {
|
||||
private S3Service jetClient;
|
||||
|
||||
@Override
|
||||
protected void setUpClient(String AWSAccessKeyId, String AWSSecretAccessKey)
|
||||
throws Exception {
|
||||
super.setUpClient(AWSAccessKeyId, AWSSecretAccessKey);
|
||||
jetClient = new RestS3Service(new AWSCredentials(AWSAccessKeyId,
|
||||
AWSSecretAccessKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void testPutStringSerial() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void testPutStringParallel() throws InterruptedException,
|
||||
ExecutionException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void testPutBytesSerial() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void testPutBytesParallel() throws InterruptedException,
|
||||
ExecutionException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean putByteArray(String bucket, String key, byte[] data,
|
||||
String contentType) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean putFile(String bucket, String key, File data,
|
||||
String contentType) throws Exception {
|
||||
org.jets3t.service.model.S3Object object = new org.jets3t.service.model.S3Object(
|
||||
key);
|
||||
object.setContentType(contentType);
|
||||
object.setDataInputFile(data);
|
||||
object.setContentLength(data.length());
|
||||
return jetClient.putObject(bucket, object) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean putInputStream(String bucket, String key,
|
||||
InputStream data, String contentType) throws Exception {
|
||||
org.jets3t.service.model.S3Object object = new org.jets3t.service.model.S3Object(
|
||||
key);
|
||||
object.setContentType(contentType);
|
||||
object.setDataInputStream(data);
|
||||
object.setContentLength(data.available());
|
||||
return jetClient.putObject(bucket, object) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean putString(String bucket, String key, String data,
|
||||
String contentType) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package com.amazon.s3;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletionService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(sequential = true, timeOut = 2 * 60 * 1000, testName = "s3.S3ParserTest", groups = "performance")
|
||||
public class S3ParserTest extends org.jclouds.aws.s3.commands.S3ParserTest {
|
||||
|
||||
class MockHttpURLConnection extends HttpURLConnection {
|
||||
private String content;
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return IOUtils.toInputStream(content);
|
||||
}
|
||||
|
||||
protected MockHttpURLConnection(String content) {
|
||||
super(null);
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
}
|
||||
|
||||
public boolean usingProxy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResponseCode() throws IOException {
|
||||
return 200;
|
||||
}
|
||||
|
||||
public void connect() throws IOException {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonParseListAllMyBucketsSerialResponseTime() throws IOException {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
runAmazonParseListAllMyBuckets();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonParseListAllMyBucketsParallelResponseTime()
|
||||
throws InterruptedException, ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(
|
||||
exec);
|
||||
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() throws IOException {
|
||||
runAmazonParseListAllMyBuckets();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
assert completer.take().get();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAmazonCanParseListAllMyBuckets() throws IOException {
|
||||
ListAllMyBucketsResponse response = runAmazonParseListAllMyBuckets();
|
||||
List<Bucket> buckets = response.entries;
|
||||
Bucket bucket1 = (Bucket) buckets.get(0);
|
||||
assert bucket1.name.equals("adrianjbosstest");
|
||||
Date expectedDate1 = new DateTime("2009-03-12T02:00:07.000Z").toDate();
|
||||
Date date1 = bucket1.creationDate;
|
||||
assert date1.toString().equals(expectedDate1.toString());
|
||||
Bucket bucket2 = (Bucket) buckets.get(1);
|
||||
assert bucket2.name.equals("adrianjbosstest2");
|
||||
Date expectedDate2 = new DateTime("2009-03-12T02:00:09.000Z").toDate();
|
||||
Date date2 = bucket2.creationDate;
|
||||
assert date2.toString().equals(expectedDate2.toString());
|
||||
assert buckets.size() == 2;
|
||||
}
|
||||
|
||||
private ListAllMyBucketsResponse runAmazonParseListAllMyBuckets()
|
||||
throws IOException {
|
||||
ListAllMyBucketsResponse response = new ListAllMyBucketsResponse(
|
||||
new MockHttpURLConnection(listAllMyBucketsResult));
|
||||
return response;
|
||||
}
|
||||
|
||||
public void testAmazonCanParseListBucketResult() throws IOException {
|
||||
ListBucketResponse response = runAmazonParseListBucketResult();
|
||||
ListEntry content = (ListEntry) response.entries.get(0);
|
||||
assert content.key.equals("3366");
|
||||
assert content.lastModified.equals(new DateTime(
|
||||
"2009-03-12T02:00:13.000Z").toDate());
|
||||
assert content.eTag.equals("\"9d7bb64e8e18ee34eec06dd2cf37b766\"");
|
||||
assert content.size == 136;
|
||||
assert content.owner.id
|
||||
.equals("e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0");
|
||||
assert content.owner.displayName.equals("ferncam");
|
||||
assert content.storageClass.equals("STANDARD");
|
||||
}
|
||||
|
||||
private ListBucketResponse runAmazonParseListBucketResult()
|
||||
throws IOException {
|
||||
ListBucketResponse response = new ListBucketResponse(
|
||||
new MockHttpURLConnection(listBucketResult));
|
||||
return response;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonParseListBucketResultSerialResponseTime() throws IOException {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
runAmazonParseListBucketResult();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonParseListBucketResultParallelResponseTime()
|
||||
throws InterruptedException, ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(
|
||||
exec);
|
||||
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() throws IOException {
|
||||
runAmazonParseListBucketResult();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
assert completer.take().get();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package com.amazon.s3;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletionService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
|
||||
@Test(sequential = true, timeOut = 2 * 60 * 1000, testName = "s3.S3UtilsTest", groups = "performance")
|
||||
public class S3UtilsTest extends org.jclouds.aws.s3.S3UtilsTest {
|
||||
|
||||
@Test(dataProvider = "hmacsha1")
|
||||
void testAmazonSampleDigestSerialResponseTime(byte[] key, String message, String base64Digest) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException {
|
||||
for (int i = 0; i < 10000; i++)
|
||||
testAmazonSampleDigest(key, message, base64Digest);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "hmacsha1")
|
||||
public void testAmazonSampleDigest(byte[] key, String message, String base64Digest) {
|
||||
String encoded = Utils.encode(new String(key), message, false);
|
||||
assert encoded.equals(base64Digest);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "hmacsha1")
|
||||
void testAmazonSampleDigestParallelResponseTime(final byte[] key, final String message, final String base64Digest) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, InterruptedException, ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(exec);
|
||||
for (int i = 0; i < 10000; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() {
|
||||
try {
|
||||
testAmazonSampleDigest(key, message, base64Digest);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < 10000; i++) assert completer.take().get();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
$HeadURL$
|
||||
$Revision$
|
||||
$Date$
|
||||
|
||||
Copyright (C) 2009 Adrian Cole <adriancole@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>project</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../project/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-s3</artifactId>
|
||||
<name>Amazon S3 Components Core</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Core components to access Amazon S3</description>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/s3</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/s3</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk/s3</url>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<jclouds.aws.accesskeyid></jclouds.aws.accesskeyid>
|
||||
<jclouds.aws.secretaccesskey></jclouds.aws.secretaccesskey>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>1.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15</artifactId>
|
||||
<version>140</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>jclouds.aws.accesskeyid</name>
|
||||
<value>${jclouds.aws.accesskeyid}</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>jclouds.aws.secretaccesskey</name>
|
||||
<value>${jclouds.aws.secretaccesskey}</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
public class DateService {
|
||||
private DateTimeFormatter headerDateFormat = DateTimeFormat.forPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'");
|
||||
private DateTimeFormatter dataDateFormat = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
||||
|
||||
|
||||
public DateTime dateTimeFromXMLFormat(String toParse) {
|
||||
//return dataDateFormat.parseDateTime(toParse);
|
||||
return new DateTime(toParse);
|
||||
}
|
||||
|
||||
public DateTime dateTimeFromHeaderFormat(String toParse) {
|
||||
return headerDateFormat.parseDateTime(toParse);
|
||||
}
|
||||
|
||||
public String timestampAsHeaderString() {
|
||||
return headerDateFormat.print(new DateTime(DateTimeZone.UTC));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.jclouds.aws.s3.commands.CopyObject;
|
||||
import org.jclouds.aws.s3.commands.DeleteBucket;
|
||||
import org.jclouds.aws.s3.commands.DeleteObject;
|
||||
import org.jclouds.aws.s3.commands.HeadBucket;
|
||||
import org.jclouds.aws.s3.commands.ListAllMyBuckets;
|
||||
import org.jclouds.aws.s3.commands.ListBucket;
|
||||
import org.jclouds.aws.s3.commands.PutBucket;
|
||||
import org.jclouds.aws.s3.commands.PutObject;
|
||||
import org.jclouds.aws.s3.commands.RetrieveObject;
|
||||
import org.jclouds.aws.s3.commands.S3CommandFactory;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.http.HttpFutureCommandClient;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* Non-blocking interface to Amazon S3.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class LiveS3Connection implements S3Connection {
|
||||
|
||||
/**
|
||||
* not all clients are threadsafe, but this connection needs to be.
|
||||
*/
|
||||
private final HttpFutureCommandClient client;
|
||||
private final S3CommandFactory factory;
|
||||
|
||||
@Inject
|
||||
public LiveS3Connection(HttpFutureCommandClient client,
|
||||
S3CommandFactory factory) {
|
||||
this.client = client;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public Future<S3Object> getObject(S3Bucket s3Bucket, String key) {
|
||||
RetrieveObject getRequestObject = factory.createRetrieveObject(
|
||||
s3Bucket, key, true);
|
||||
client.submit(getRequestObject);
|
||||
return getRequestObject;
|
||||
}
|
||||
|
||||
public Future<S3Object> headObject(S3Bucket s3Bucket, String key) {
|
||||
RetrieveObject getRequestObject = factory.createRetrieveObject(
|
||||
s3Bucket, key, false);
|
||||
client.submit(getRequestObject);
|
||||
return getRequestObject;
|
||||
}
|
||||
|
||||
public Future<Boolean> deleteObject(S3Bucket s3Bucket, String key) {
|
||||
DeleteObject deleteObject = factory.createDeleteObject(s3Bucket, key);
|
||||
client.submit(deleteObject);
|
||||
return deleteObject;
|
||||
}
|
||||
|
||||
public Future<String> addObject(S3Bucket s3Bucket, S3Object object) {
|
||||
PutObject putObject = factory.createPutObject(s3Bucket, object);
|
||||
client.submit(putObject);
|
||||
return putObject;
|
||||
}
|
||||
|
||||
public Future<Boolean> createBucketIfNotExists(S3Bucket s3Bucket) {
|
||||
PutBucket putBucket = factory.createPutBucket(s3Bucket);
|
||||
client.submit(putBucket);
|
||||
return putBucket;
|
||||
}
|
||||
|
||||
public Future<Boolean> deleteBucket(S3Bucket s3Bucket) {
|
||||
DeleteBucket deleteBucket = factory.createDeleteBucket(s3Bucket);
|
||||
client.submit(deleteBucket);
|
||||
return deleteBucket;
|
||||
}
|
||||
|
||||
public Future<Boolean> copyObject(S3Bucket sourceBucket,
|
||||
S3Object sourceObject, S3Bucket destinationBucket,
|
||||
S3Object destinationObject) {
|
||||
CopyObject copy = factory.createCopyObject(sourceBucket, sourceObject,
|
||||
destinationBucket, destinationObject);
|
||||
client.submit(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
public Future<Boolean> bucketExists(S3Bucket s3Bucket) {
|
||||
HeadBucket headRequestObject = factory.createHeadBucket(s3Bucket);
|
||||
client.submit(headRequestObject);
|
||||
return headRequestObject;
|
||||
}
|
||||
|
||||
public Future<S3Bucket> getBucket(S3Bucket s3Bucket) {
|
||||
ListBucket listRequest = factory.createListBucket(s3Bucket);
|
||||
client.submit(listRequest);
|
||||
return listRequest;
|
||||
}
|
||||
|
||||
public Future<List<S3Bucket>> getBuckets() {
|
||||
ListAllMyBuckets listRequest = factory.createListAllMyBuckets();
|
||||
client.submit(listRequest);
|
||||
return listRequest;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
client.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3;
|
||||
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Closeable;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface S3Connection extends Closeable {
|
||||
Future<S3Object> getObject(S3Bucket s3Bucket, String key);
|
||||
|
||||
Future<S3Object> headObject(S3Bucket s3Bucket, String key);
|
||||
|
||||
Future<Boolean> deleteObject(S3Bucket s3Bucket, String key);
|
||||
|
||||
Future<String> addObject(S3Bucket s3Bucket, S3Object object);
|
||||
|
||||
Future<Boolean> createBucketIfNotExists(S3Bucket s3Bucket);
|
||||
|
||||
Future<Boolean> deleteBucket(S3Bucket s3Bucket);
|
||||
|
||||
Future<Boolean> copyObject(S3Bucket sourceBucket, S3Object sourceObject, S3Bucket destinationBucket, S3Object destinationObject);
|
||||
|
||||
Future<Boolean> bucketExists(S3Bucket s3Bucket);
|
||||
|
||||
Future<S3Bucket> getBucket(S3Bucket s3Bucket);
|
||||
|
||||
Future<List<S3Bucket>> getBuckets();
|
||||
|
||||
public void close() throws IOException;
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.name.Names;
|
||||
import org.jclouds.http.config.JavaUrlHttpFutureCommandClientModule;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document return getConnection!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class S3ConnectionFactory {
|
||||
public static final Properties DEFAULT_PROPERTIES;
|
||||
|
||||
static {
|
||||
DEFAULT_PROPERTIES = new Properties();
|
||||
DEFAULT_PROPERTIES.setProperty("jclouds.http.address", "s3.amazonaws.com");
|
||||
DEFAULT_PROPERTIES.setProperty("jclouds.http.port", "443");
|
||||
DEFAULT_PROPERTIES.setProperty("jclouds.http.secure", "true");
|
||||
DEFAULT_PROPERTIES.setProperty("jclouds.http.pool.max_connection_reuse", "75");
|
||||
DEFAULT_PROPERTIES.setProperty("jclouds.http.pool.max_session_failures", "2");
|
||||
DEFAULT_PROPERTIES.setProperty("jclouds.http.pool.request_invoker_threads", "1");
|
||||
DEFAULT_PROPERTIES.setProperty("jclouds.http.pool.io_worker_threads", "2");
|
||||
DEFAULT_PROPERTIES.setProperty("jclouds.pool.max_connections", "12");
|
||||
}
|
||||
|
||||
public static S3Connection getConnection(String awsAccessKeyId, String awsSecretAccessKey) {
|
||||
Properties properties = new Properties(DEFAULT_PROPERTIES);
|
||||
properties.setProperty("jclouds.aws.accesskeyid", awsAccessKeyId);
|
||||
properties.setProperty("jclouds.aws.secretaccesskey", awsSecretAccessKey);
|
||||
return getConnection(properties, new JavaUrlHttpFutureCommandClientModule());
|
||||
}
|
||||
|
||||
public static S3Connection getConnection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure) {
|
||||
Properties properties = new Properties(DEFAULT_PROPERTIES);
|
||||
properties.setProperty("jclouds.aws.accesskeyid", awsAccessKeyId);
|
||||
properties.setProperty("jclouds.aws.secretaccesskey", awsSecretAccessKey);
|
||||
properties.setProperty("jclouds.http.secure", Boolean.toString(isSecure));
|
||||
if (!isSecure)
|
||||
properties.setProperty("jclouds.http.port", "80");
|
||||
|
||||
return getConnection(properties, new JavaUrlHttpFutureCommandClientModule());
|
||||
}
|
||||
|
||||
public static S3Connection getConnection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure,
|
||||
String server) {
|
||||
Properties properties = new Properties(DEFAULT_PROPERTIES);
|
||||
properties.setProperty("jclouds.aws.accesskeyid", awsAccessKeyId);
|
||||
properties.setProperty("jclouds.aws.secretaccesskey", awsSecretAccessKey);
|
||||
properties.setProperty("jclouds.http.secure", Boolean.toString(isSecure));
|
||||
properties.setProperty("jclouds.http.address", server);
|
||||
if (!isSecure)
|
||||
properties.setProperty("jclouds.http.port", "80");
|
||||
return getConnection(properties, new JavaUrlHttpFutureCommandClientModule());
|
||||
}
|
||||
|
||||
public static S3Connection getConnection(String awsAccessKeyId, String awsSecretAccessKey, boolean isSecure,
|
||||
String server, int port) {
|
||||
Properties properties = new Properties(DEFAULT_PROPERTIES);
|
||||
properties.setProperty("jclouds.aws.accesskeyid", awsAccessKeyId);
|
||||
properties.setProperty("jclouds.aws.secretaccesskey", awsSecretAccessKey);
|
||||
properties.setProperty("jclouds.http.secure", Boolean.toString(isSecure));
|
||||
properties.setProperty("jclouds.http.address", server);
|
||||
properties.setProperty("jclouds.http.port", port + "");
|
||||
return getConnection(properties, new JavaUrlHttpFutureCommandClientModule());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new interface to interact with S3 with the given credential and connection
|
||||
* parameters
|
||||
*/
|
||||
public static synchronized S3Connection getConnection(final Properties properties, Module httpModule) {
|
||||
return getInjector(properties, httpModule).getInstance(S3Connection.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new interface to interact with S3 with the given credential and connection
|
||||
* parameters
|
||||
*/
|
||||
public static synchronized Injector getInjector(final Properties properties, Module httpModule) {
|
||||
return Guice.createInjector(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
Names.bindProperties(binder(), properties);
|
||||
}
|
||||
}, httpModule, new S3ConnectionModule());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.Scopes;
|
||||
import org.jclouds.aws.s3.commands.config.S3CommandsModule;
|
||||
import org.jclouds.aws.s3.filters.RemoveTransferEncodingHeader;
|
||||
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
|
||||
import org.jclouds.http.HttpRequestFilter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class S3ConnectionModule extends AbstractModule {
|
||||
|
||||
protected void configure() {
|
||||
install(new S3CommandsModule());
|
||||
bind(S3Connection.class).to(LiveS3Connection.class).in(Scopes.SINGLETON);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
List<HttpRequestFilter> provideRequestFilters(RemoveTransferEncodingHeader removTransferEncodingHeader, RequestAuthorizeSignature requestAuthorizeSignature) {
|
||||
List<HttpRequestFilter> filters = new ArrayList<HttpRequestFilter>();
|
||||
filters.add(removTransferEncodingHeader);
|
||||
filters.add(requestAuthorizeSignature);
|
||||
return filters;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3;
|
||||
|
||||
import org.jclouds.http.HttpConstants;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class S3Constants extends HttpConstants {
|
||||
public static final String AUTH = "Authorization";
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.jclouds.Logger;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* // TODO: Adrian: Document this!
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class S3ObjectMap implements ConcurrentMap<String, Object> {
|
||||
private Logger logger;
|
||||
private S3Connection connection;
|
||||
private S3Bucket bucket;
|
||||
private S3Utils utils;
|
||||
|
||||
@Inject
|
||||
public S3ObjectMap(java.util.logging.Logger logger, S3Connection connection, S3Bucket bucket, S3Utils utils) {
|
||||
this.logger = new Logger(logger);
|
||||
this.connection = connection;
|
||||
this.bucket = bucket;
|
||||
this.utils = utils;
|
||||
}
|
||||
|
||||
|
||||
public Object putIfAbsent(String s, Object o) {
|
||||
return null; // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public boolean remove(Object o, Object o1) {
|
||||
return false; // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public boolean replace(String s, Object o, Object o1) {
|
||||
return false; // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public Object replace(String s, Object o) {
|
||||
return null; // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public int size() {
|
||||
try {
|
||||
bucket = connection.getBucket(bucket).get();
|
||||
return bucket.getContents().size();
|
||||
} catch (Exception e) {
|
||||
S3Utils.<S3RuntimeException>rethrowIfRuntimeOrSameType(e);
|
||||
throw new S3RuntimeException("Error clearing bucket" + bucket, e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return false; // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public boolean containsKey(Object o) {
|
||||
return false; // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public boolean containsValue(Object o) {
|
||||
return false; // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public Object get(Object o) {
|
||||
try {
|
||||
return connection.getObject(bucket, o.toString()).get();
|
||||
} catch (Exception e) {
|
||||
S3Utils.<S3RuntimeException>rethrowIfRuntimeOrSameType(e);
|
||||
throw new S3RuntimeException(String.format("Error geting object %1s:%2s", bucket, o), e);
|
||||
}
|
||||
}
|
||||
|
||||
public Object put(String s, Object o) {
|
||||
S3Object object = new S3Object();
|
||||
try {
|
||||
object.setKey(s);
|
||||
object.setContent(o);
|
||||
return connection.addObject(bucket, object).get();
|
||||
} catch (Exception e) {
|
||||
S3Utils.<S3RuntimeException>rethrowIfRuntimeOrSameType(e);
|
||||
throw new S3RuntimeException(String.format("Error adding object %1s:%2s", bucket, object), e);
|
||||
}
|
||||
}
|
||||
|
||||
public Object remove(Object o) {
|
||||
return null; // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public void putAll(Map<? extends String, ? extends Object> map) {
|
||||
// TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
private class S3RuntimeException extends RuntimeException {
|
||||
public S3RuntimeException(String s) {
|
||||
super(s); // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public S3RuntimeException(String s, Throwable throwable) {
|
||||
super(s, throwable); // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
try {
|
||||
bucket = connection.getBucket(bucket).get();
|
||||
List<Future<Boolean>> deletes = new ArrayList<Future<Boolean>>();
|
||||
for (S3Object object : bucket.getContents()) {
|
||||
deletes.add(connection.deleteObject(bucket, object.getKey()));
|
||||
}
|
||||
for (Future<Boolean> isdeleted : deletes)
|
||||
if (!isdeleted.get()) {
|
||||
throw new S3RuntimeException("failed to delete entry");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
S3Utils.<S3RuntimeException>rethrowIfRuntimeOrSameType(e);
|
||||
throw new S3RuntimeException("Error clearing bucket" + bucket, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> keySet() {
|
||||
return null; // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public Collection<Object> values() {
|
||||
return null; // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
|
||||
public Set<Entry<String, Object>> entrySet() {
|
||||
return null; // TODO: Adrian: Customise this generated block
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3;
|
||||
|
||||
import org.bouncycastle.crypto.digests.SHA1Digest;
|
||||
import org.bouncycastle.crypto.macs.HMac;
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
import org.jclouds.Utils;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
|
||||
public class S3Utils extends Utils {
|
||||
|
||||
|
||||
public static String digest(String toEncode, byte[] key) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException {
|
||||
HMac hmac = new HMac(new SHA1Digest());
|
||||
byte[] resBuf = new byte[hmac.getMacSize()];
|
||||
byte[] plainBytes = toEncode.getBytes();
|
||||
byte[] keyBytes = key;
|
||||
hmac.init(new KeyParameter(keyBytes));
|
||||
hmac.update(plainBytes, 0, plainBytes.length);
|
||||
hmac.doFinal(resBuf, 0);
|
||||
return new String(Base64.encode(resBuf));
|
||||
}
|
||||
|
||||
|
||||
public static String getContentAsStringAndClose(S3Object object) throws IOException {
|
||||
Object o = object.getContent();
|
||||
|
||||
if (o instanceof InputStream) {
|
||||
String returnVal = toStringAndClose((InputStream) o);
|
||||
if (object.getContentType().indexOf("xml") >= 0) {
|
||||
|
||||
}
|
||||
return returnVal;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Object type not supported: " + o.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3.commands;
|
||||
|
||||
import org.jclouds.aws.s3.commands.callables.CopyObjectCallable;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.name.Named;
|
||||
|
||||
public class CopyObject extends HttpFutureCommand<Boolean> {
|
||||
|
||||
@Inject
|
||||
public CopyObject(@Named("jclouds.http.address") String amazonHost, CopyObjectCallable callable, @Assisted("sourceBucket") S3Bucket sourceBucket, @Assisted("sourceObject") S3Object sourceObject, @Assisted("destinationBucket") S3Bucket destinationBucket, @Assisted("destinationObject") S3Object destinationObject) {
|
||||
super("PUT", "/" + destinationObject.getKey(), callable);
|
||||
getRequest().getHeaders().put("Host",
|
||||
destinationBucket.getName() + "." + amazonHost);
|
||||
getRequest().getHeaders().put("x-amz-copy-source", String.format("/%1s/%2s", sourceBucket.getName(), sourceObject.getKey()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3.commands;
|
||||
|
||||
import org.jclouds.aws.s3.commands.callables.DeleteBucketCallable;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.name.Named;
|
||||
|
||||
public class DeleteBucket extends HttpFutureCommand<Boolean> {
|
||||
|
||||
@Inject
|
||||
public DeleteBucket(@Named("jclouds.http.address") String amazonHost,
|
||||
DeleteBucketCallable callable, @Assisted S3Bucket s3Bucket) {
|
||||
super("DELETE", "/", callable);
|
||||
getRequest().getHeaders().put("Host",
|
||||
s3Bucket.getName() + "." + amazonHost);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3.commands;
|
||||
|
||||
import org.jclouds.aws.s3.commands.callables.DeleteCallable;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.name.Named;
|
||||
|
||||
public class DeleteObject extends HttpFutureCommand<Boolean> {
|
||||
|
||||
@Inject
|
||||
public DeleteObject(@Named("jclouds.http.address") String amazonHost,
|
||||
DeleteCallable callable, @Assisted S3Bucket s3Bucket,
|
||||
@Assisted String key) {
|
||||
super("DELETE", "/" + key, callable);
|
||||
getRequest().getHeaders().put("Host",
|
||||
s3Bucket.getName() + "." + amazonHost);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adriancole@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
|
||||
*
|
||||
* 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.aws.s3.commands;
|
||||
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
import org.jclouds.http.HttpFutureCommand;
|
||||
import org.jclouds.http.commands.callables.ReturnTrueIf200;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.name.Named;
|
||||
|
||||
public class HeadBucket extends HttpFutureCommand<Boolean> {
|
||||
|
||||
@Inject
|
||||
public HeadBucket(@Named("jclouds.http.address") String amazonHost,
|
||||
ReturnTrueIf200 callable, @Assisted S3Bucket s3Bucket) {
|
||||
super("HEAD", "/", callable);
|
||||
getRequest().getHeaders().put("Host",
|
||||
s3Bucket.getName() + "." + amazonHost);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue