Issue 8: Removed direct dependencies on java.util.logging, LoggingModules are now used to select logging

git-svn-id: http://jclouds.googlecode.com/svn/trunk@251 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-05-04 20:19:42 +00:00
parent 3b70fd807d
commit c5486f6c5e
53 changed files with 1872 additions and 742 deletions

View File

@ -23,14 +23,17 @@
*/ */
package org.jclouds.command.pool; 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.io.IOException;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import javax.annotation.Resource;
import org.jclouds.command.FutureCommand;
import org.jclouds.logging.Logger;
import com.google.inject.assistedinject.Assisted;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
* *
@ -43,62 +46,65 @@ public abstract class FutureCommandConnectionHandle<C> {
protected C conn; protected C conn;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected FutureCommand operation; protected FutureCommand operation;
protected final Logger logger; @Resource
protected Logger logger = Logger.NULL;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public FutureCommandConnectionHandle(java.util.logging.Logger logger, Semaphore maxConnections, @Assisted FutureCommand operation, @Assisted C conn, BlockingQueue<C> available) throws InterruptedException { public FutureCommandConnectionHandle(Semaphore maxConnections,
this.maxConnections = maxConnections; @Assisted FutureCommand operation, @Assisted C conn,
this.operation = operation; BlockingQueue<C> available) throws InterruptedException {
this.conn = conn; this.maxConnections = maxConnections;
this.available = available; this.operation = operation;
this.logger = new Logger(logger); this.conn = conn;
this.completed = new Semaphore(1); this.available = available;
completed.acquire(); this.completed = new Semaphore(1);
completed.acquire();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public FutureCommand getOperation() { public FutureCommand getOperation() {
return operation; return operation;
} }
public abstract void startConnection(); public abstract void startConnection();
public boolean isCompleted() { public boolean isCompleted() {
return (completed.availablePermits() == 1); return (completed.availablePermits() == 1);
} }
public void release() throws InterruptedException { public void release() throws InterruptedException {
if (isCompleted()) { if (isCompleted()) {
return; return;
} }
logger.trace("%1s - %2d - releasing to pool", conn, conn.hashCode()); logger.trace("%1s - %2d - releasing to pool", conn, conn.hashCode());
available.put(conn); available.put(conn);
conn = null; conn = null;
operation = null; operation = null;
completed.release(); completed.release();
} }
public void cancel() throws IOException { public void cancel() throws IOException {
if (isCompleted()) { if (isCompleted()) {
return; return;
} }
if (conn != null) { if (conn != null) {
logger.trace("%1s - %2d - cancelled; shutting down connection", conn, conn.hashCode()); logger.trace("%1s - %2d - cancelled; shutting down connection",
try { conn, conn.hashCode());
shutdownConnection(); try {
} finally { shutdownConnection();
conn = null; } finally {
operation = null; conn = null;
maxConnections.release(); operation = null;
} maxConnections.release();
} }
completed.release(); }
completed.release();
} }
public abstract void shutdownConnection() throws IOException; public abstract void shutdownConnection() throws IOException;
public void waitFor() throws InterruptedException { public void waitFor() throws InterruptedException {
completed.acquire(); completed.acquire();
completed.release(); completed.release();
} }
} }

View File

@ -23,14 +23,18 @@
*/ */
package org.jclouds.command.pool; package org.jclouds.command.pool;
import com.google.inject.Provides; import java.util.concurrent.BlockingQueue;
import com.google.inject.name.Named; import java.util.concurrent.ExecutorService;
import org.jclouds.Logger; import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import org.jclouds.command.FutureCommand; import org.jclouds.command.FutureCommand;
import org.jclouds.lifecycle.BaseLifeCycle; import org.jclouds.lifecycle.BaseLifeCycle;
import java.util.concurrent.*; import com.google.inject.Provides;
import java.util.concurrent.atomic.AtomicInteger; import com.google.inject.name.Named;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
@ -47,14 +51,13 @@ public abstract class FutureCommandConnectionPool<C> extends BaseLifeCycle {
protected volatile boolean hitBottom = false; protected volatile boolean hitBottom = false;
public FutureCommandConnectionPool( public FutureCommandConnectionPool(
Logger logger,
ExecutorService executor, ExecutorService executor,
FutureCommandConnectionRetry<C> futureCommandConnectionRetry, FutureCommandConnectionRetry<C> futureCommandConnectionRetry,
Semaphore allConnections, Semaphore allConnections,
FutureCommandConnectionHandleFactory<C> futureCommandConnectionHandleFactory, FutureCommandConnectionHandleFactory<C> futureCommandConnectionHandleFactory,
@Named("maxConnectionReuse") int maxConnectionReuse, @Named("maxConnectionReuse") int maxConnectionReuse,
BlockingQueue<C> available, BaseLifeCycle... dependencies) { BlockingQueue<C> available, BaseLifeCycle... dependencies) {
super(logger, executor, dependencies); super(executor, dependencies);
this.futureCommandConnectionRetry = futureCommandConnectionRetry; this.futureCommandConnectionRetry = futureCommandConnectionRetry;
this.allConnections = allConnections; this.allConnections = allConnections;
this.futureCommandConnectionHandleFactory = futureCommandConnectionHandleFactory; this.futureCommandConnectionHandleFactory = futureCommandConnectionHandleFactory;

View File

@ -28,7 +28,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.jclouds.Logger;
import org.jclouds.Utils; import org.jclouds.Utils;
import org.jclouds.command.FutureCommand; import org.jclouds.command.FutureCommand;
import org.jclouds.command.FutureCommandClient; import org.jclouds.command.FutureCommandClient;
@ -47,11 +46,10 @@ public class FutureCommandConnectionPoolClient<C> extends BaseLifeCycle
private final BlockingQueue<FutureCommand> commandQueue; private final BlockingQueue<FutureCommand> commandQueue;
@Inject @Inject
public FutureCommandConnectionPoolClient(java.util.logging.Logger logger, public FutureCommandConnectionPoolClient(ExecutorService executor,
ExecutorService executor,
FutureCommandConnectionPool<C> futureCommandConnectionPool, FutureCommandConnectionPool<C> futureCommandConnectionPool,
BlockingQueue<FutureCommand> commandQueue) { BlockingQueue<FutureCommand> commandQueue) {
super(new Logger(logger), executor, futureCommandConnectionPool); super(executor, futureCommandConnectionPool);
this.futureCommandConnectionPool = futureCommandConnectionPool; this.futureCommandConnectionPool = futureCommandConnectionPool;
this.commandQueue = commandQueue; this.commandQueue = commandQueue;
} }

View File

@ -27,8 +27,10 @@ import java.io.IOException;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.jclouds.Logger; import javax.annotation.Resource;
import org.jclouds.command.FutureCommand; import org.jclouds.command.FutureCommand;
import org.jclouds.logging.Logger;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
@ -38,36 +40,40 @@ import org.jclouds.command.FutureCommand;
public abstract class FutureCommandConnectionRetry<C> { public abstract class FutureCommandConnectionRetry<C> {
protected final BlockingQueue<FutureCommand> commandQueue; protected final BlockingQueue<FutureCommand> commandQueue;
protected final AtomicInteger errors; protected final AtomicInteger errors;
protected final Logger logger; @Resource
protected Logger logger = Logger.NULL;
public FutureCommandConnectionRetry(Logger logger, BlockingQueue<FutureCommand> commandQueue, AtomicInteger errors) { public FutureCommandConnectionRetry(
this.logger = logger; BlockingQueue<FutureCommand> commandQueue, AtomicInteger errors) {
this.commandQueue = commandQueue; this.commandQueue = commandQueue;
this.errors = errors; this.errors = errors;
} }
public abstract void associateHandleWithConnection(FutureCommandConnectionHandle<C> handle, C connection); public abstract void associateHandleWithConnection(
FutureCommandConnectionHandle<C> handle, C connection);
public abstract FutureCommandConnectionHandle<C> getHandleFromConnection(C connection); public abstract FutureCommandConnectionHandle<C> getHandleFromConnection(
C connection);
public boolean shutdownConnectionAndRetryOperation(C connection) { public boolean shutdownConnectionAndRetryOperation(C connection) {
FutureCommandConnectionHandle<C> handle = getHandleFromConnection(connection); FutureCommandConnectionHandle<C> handle = getHandleFromConnection(connection);
if (handle != null) { if (handle != null) {
try { try {
logger.info("%1s - shutting down connection", connection); logger.info("%1s - shutting down connection", connection);
handle.shutdownConnection(); handle.shutdownConnection();
incrementErrorCountAndRetry(handle.getOperation()); incrementErrorCountAndRetry(handle.getOperation());
return true; return true;
} catch (IOException e) { } catch (IOException e) {
logger.error(e, "%1s - error shutting down connection", connection); logger.error(e, "%1s - error shutting down connection",
} connection);
} }
return false; }
return false;
} }
public void incrementErrorCountAndRetry(FutureCommand command) { public void incrementErrorCountAndRetry(FutureCommand command) {
errors.getAndIncrement(); errors.getAndIncrement();
logger.info("resubmitting command %1s", command); logger.info("resubmitting command %1s", command);
commandQueue.add(command); commandQueue.add(command);
} }
} }

View File

@ -25,8 +25,10 @@ package org.jclouds.http;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Resource;
import org.jclouds.command.FutureCommand; import org.jclouds.command.FutureCommand;
import org.jclouds.Logger; import org.jclouds.logging.Logger;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
@ -58,12 +60,10 @@ public class HttpFutureCommand<T> extends
*/ */
public abstract static class ResponseCallable<T> implements public abstract static class ResponseCallable<T> implements
FutureCommand.ResponseCallable<HttpResponse, T> { FutureCommand.ResponseCallable<HttpResponse, T> {
protected final Logger logger; @Resource
private HttpResponse response; protected Logger logger = Logger.NULL;
public ResponseCallable(Logger logger) { private HttpResponse response;
this.logger = logger;
}
public HttpResponse getResponse() { public HttpResponse getResponse() {
return response; return response;

View File

@ -36,10 +36,12 @@ import java.net.URL;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.annotation.Resource;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.jclouds.Logger;
import org.jclouds.Utils; import org.jclouds.Utils;
import org.jclouds.command.FutureCommand; import org.jclouds.command.FutureCommand;
import org.jclouds.logging.Logger;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -51,7 +53,8 @@ import com.google.inject.Inject;
public class JavaUrlHttpFutureCommandClient implements HttpFutureCommandClient { public class JavaUrlHttpFutureCommandClient implements HttpFutureCommandClient {
private URL target; private URL target;
private List<HttpRequestFilter> requestFilters = Collections.emptyList(); private List<HttpRequestFilter> requestFilters = Collections.emptyList();
private Logger logger; @Resource
private Logger logger = Logger.NULL;
public List<HttpRequestFilter> getRequestFilters() { public List<HttpRequestFilter> getRequestFilters() {
return requestFilters; return requestFilters;
@ -63,11 +66,9 @@ public class JavaUrlHttpFutureCommandClient implements HttpFutureCommandClient {
} }
@Inject @Inject
public JavaUrlHttpFutureCommandClient(java.util.logging.Logger logger, public JavaUrlHttpFutureCommandClient(URL target)
URL target) throws MalformedURLException { throws MalformedURLException {
this.logger = new Logger(logger);
this.target = target; this.target = target;
this.logger.info("configured to connect to target: %1s", target);
} }
public <O extends FutureCommand> void submit(O operation) { public <O extends FutureCommand> void submit(O operation) {

View File

@ -23,45 +23,49 @@
*/ */
package org.jclouds.http.commands.callables; package org.jclouds.http.commands.callables;
import com.google.inject.Inject; import java.io.IOException;
import org.jclouds.Logger; import java.io.InputStream;
import org.jclouds.Utils; import org.jclouds.Utils;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommand;
import java.io.IOException; import com.google.inject.Inject;
import java.io.InputStream;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ReturnStringIf200 extends HttpFutureCommand.ResponseCallable<String> { public class ReturnStringIf200 extends
HttpFutureCommand.ResponseCallable<String> {
@Inject @Inject
public ReturnStringIf200(java.util.logging.Logger logger) { public ReturnStringIf200() {
super(new Logger(logger)); super();
} }
public String call() throws HttpException { public String call() throws HttpException {
int code = getResponse().getStatusCode(); int code = getResponse().getStatusCode();
if (code >= 400 && code < 500) { if (code >= 400 && code < 500) {
throw new HttpException(String.format("Content not found - %1s", getResponse())); throw new HttpException(String.format("Content not found - %1s",
} else if (code == 200) { getResponse()));
InputStream entity = getResponse().getContent(); } else if (code == 200) {
if (entity == null) InputStream entity = getResponse().getContent();
throw new HttpException("no content"); if (entity == null)
String toReturn = null; throw new HttpException("no content");
try { String toReturn = null;
toReturn = Utils.toStringAndClose(entity); try {
} catch (IOException e) { toReturn = Utils.toStringAndClose(entity);
throw new HttpException(String.format("Couldn't receive response %1s, entity: %2s ", getResponse(), toReturn), e); } catch (IOException e) {
} throw new HttpException(String.format(
return toReturn; "Couldn't receive response %1s, entity: %2s ",
} else { getResponse(), toReturn), e);
throw new HttpException(String.format("Unhandled status code - %1s", getResponse())); }
} return toReturn;
} else {
throw new HttpException(String.format(
"Unhandled status code - %1s", getResponse()));
}
} }
} }

View File

@ -23,30 +23,31 @@
*/ */
package org.jclouds.http.commands.callables; package org.jclouds.http.commands.callables;
import com.google.inject.Inject;
import org.jclouds.Logger;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommand;
import com.google.inject.Inject;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ReturnTrueIf200 extends HttpFutureCommand.ResponseCallable<Boolean> { public class ReturnTrueIf200 extends
HttpFutureCommand.ResponseCallable<Boolean> {
@Inject @Inject
public ReturnTrueIf200(java.util.logging.Logger logger) { public ReturnTrueIf200() {
super(new Logger(logger)); super();
} }
public Boolean call() throws HttpException { public Boolean call() throws HttpException {
if (getResponse().getStatusCode() == 200) { if (getResponse().getStatusCode() == 200) {
return true; return true;
} else if (getResponse().getStatusCode() == 404) { } else if (getResponse().getStatusCode() == 404) {
return false; return false;
} else { } else {
throw new HttpException("Error checking bucket " + getResponse()); throw new HttpException("Error checking bucket " + getResponse());
} }
} }
} }

View File

@ -23,12 +23,11 @@
*/ */
package org.jclouds.http.commands.callables.xml; package org.jclouds.http.commands.callables.xml;
import com.google.inject.Inject; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.name.Named; import java.io.InputStream;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.jclouds.Logger;
import org.jclouds.Utils; import org.jclouds.Utils;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommand;
@ -36,9 +35,10 @@ import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import org.xml.sax.XMLReader; import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.InputStream; import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.name.Named;
/** /**
* This object will parse the body of an HttpResponse and return the result of * This object will parse the body of an HttpResponse and return the result of
@ -55,9 +55,8 @@ public class ParseSax<T> extends HttpFutureCommand.ResponseCallable<T> {
private boolean suckFirst = false; private boolean suckFirst = false;
@Inject @Inject
public ParseSax(java.util.logging.Logger logger, XMLReader parser, public ParseSax(XMLReader parser, @Assisted HandlerWithResult<T> handler) {
@Assisted HandlerWithResult<T> handler) { super();
super(new Logger(checkNotNull(logger, "logger")));
this.parser = checkNotNull(parser, "parser"); this.parser = checkNotNull(parser, "parser");
this.handler = checkNotNull(handler, "handler"); this.handler = checkNotNull(handler, "handler");
} }

View File

@ -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.http.config;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.jclouds.http.HttpFutureCommandClient;
/**
* designates the the module configures a {@link HttpFutureCommandClient}
*
* @author Adrian Cole
*
*/
@Retention(RUNTIME)
@Target(TYPE)
public @interface HttpFutureCommandClientModule {
}

View File

@ -40,6 +40,7 @@ import com.google.inject.name.Named;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@HttpFutureCommandClientModule
public class JavaUrlHttpFutureCommandClientModule extends AbstractModule { public class JavaUrlHttpFutureCommandClientModule extends AbstractModule {
@Override @Override

View File

@ -23,12 +23,14 @@
*/ */
package org.jclouds.lifecycle; package org.jclouds.lifecycle;
import org.jclouds.Logger; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import java.util.concurrent.ExecutorService; import javax.annotation.Resource;
import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.logging.Logger;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
@ -36,38 +38,39 @@ import java.util.concurrent.atomic.AtomicReference;
* @author Adrian Cole * @author Adrian Cole
*/ */
public abstract class BaseLifeCycle implements Runnable, LifeCycle { public abstract class BaseLifeCycle implements Runnable, LifeCycle {
protected final Logger logger; @Resource
protected Logger logger = Logger.NULL;
protected final ExecutorService executor; protected final ExecutorService executor;
protected final BaseLifeCycle[] dependencies; protected final BaseLifeCycle[] dependencies;
protected final Object statusLock; protected final Object statusLock;
protected volatile Status status; protected volatile Status status;
protected AtomicReference<Exception> exception = new AtomicReference<Exception>(); protected AtomicReference<Exception> exception = new AtomicReference<Exception>();
public BaseLifeCycle(Logger logger, ExecutorService executor, BaseLifeCycle... dependencies) { public BaseLifeCycle(ExecutorService executor,
this.logger = logger; BaseLifeCycle... dependencies) {
this.executor = executor; this.executor = executor;
this.dependencies = dependencies; this.dependencies = dependencies;
this.statusLock = new Object(); this.statusLock = new Object();
this.status = Status.INACTIVE; this.status = Status.INACTIVE;
} }
public Status getStatus() { public Status getStatus() {
return status; return status;
} }
public void run() { public void run() {
try { try {
while (shouldDoWork()) { while (shouldDoWork()) {
doWork(); doWork();
} }
} catch (Exception e) { } catch (Exception e) {
logger.error(e, "Exception doing work"); logger.error(e, "Exception doing work");
exception.set(e); exception.set(e);
} }
this.status = Status.SHUTTING_DOWN; this.status = Status.SHUTTING_DOWN;
doShutdown(); doShutdown();
this.status = Status.SHUT_DOWN; this.status = Status.SHUT_DOWN;
logger.info("%1s", this); logger.info("%1s", this);
} }
protected abstract void doWork() throws Exception; protected abstract void doWork() throws Exception;
@ -75,94 +78,97 @@ public abstract class BaseLifeCycle implements Runnable, LifeCycle {
protected abstract void doShutdown(); protected abstract void doShutdown();
protected boolean shouldDoWork() { protected boolean shouldDoWork() {
try { try {
exceptionIfDepedenciesNotActive(); exceptionIfDepedenciesNotActive();
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
return false; return false;
} }
return status.equals(Status.ACTIVE) && exception.get() == null; return status.equals(Status.ACTIVE) && exception.get() == null;
} }
@PostConstruct @PostConstruct
public void start() { public void start() {
logger.info("starting %1s", this); logger.info("starting %1s", this);
synchronized (this.statusLock) { synchronized (this.statusLock) {
if (this.status.compareTo(Status.SHUTDOWN_REQUEST) >= 0) { if (this.status.compareTo(Status.SHUTDOWN_REQUEST) >= 0) {
doShutdown(); doShutdown();
this.status = Status.SHUT_DOWN; this.status = Status.SHUT_DOWN;
this.statusLock.notifyAll(); this.statusLock.notifyAll();
return; return;
} }
if (this.status.compareTo(Status.ACTIVE) == 0) { if (this.status.compareTo(Status.ACTIVE) == 0) {
this.statusLock.notifyAll(); this.statusLock.notifyAll();
return; return;
} }
if (this.status.compareTo(Status.INACTIVE) != 0) { if (this.status.compareTo(Status.INACTIVE) != 0) {
throw new IllegalStateException("Illegal state: " + this.status); throw new IllegalStateException("Illegal state: " + this.status);
} }
exceptionIfDepedenciesNotActive(); exceptionIfDepedenciesNotActive();
this.status = Status.ACTIVE; this.status = Status.ACTIVE;
} }
executor.execute(this); executor.execute(this);
} }
protected void exceptionIfDepedenciesNotActive() { protected void exceptionIfDepedenciesNotActive() {
for (BaseLifeCycle dependency : dependencies) { for (BaseLifeCycle dependency : dependencies) {
if (dependency.status.compareTo(Status.ACTIVE) != 0) { if (dependency.status.compareTo(Status.ACTIVE) != 0) {
throw new IllegalStateException(String.format("Illegal state: %1s for component: %2s", dependency.status, dependency)); throw new IllegalStateException(String.format(
} "Illegal state: %1s for component: %2s",
} dependency.status, dependency));
}
}
} }
public Exception getException() { public Exception getException() {
return this.exception.get(); return this.exception.get();
} }
protected void awaitShutdown(long timeout) throws InterruptedException { protected void awaitShutdown(long timeout) throws InterruptedException {
awaitStatus(Status.SHUT_DOWN, timeout); awaitStatus(Status.SHUT_DOWN, timeout);
} }
protected void awaitStatus(Status intended, long timeout) throws InterruptedException { protected void awaitStatus(Status intended, long timeout)
synchronized (this.statusLock) { throws InterruptedException {
long deadline = System.currentTimeMillis() + timeout; synchronized (this.statusLock) {
long remaining = timeout; long deadline = System.currentTimeMillis() + timeout;
while (this.status != intended) { long remaining = timeout;
this.statusLock.wait(remaining); while (this.status != intended) {
if (timeout > 0) { this.statusLock.wait(remaining);
remaining = deadline - System.currentTimeMillis(); if (timeout > 0) {
if (remaining <= 0) { remaining = deadline - System.currentTimeMillis();
break; if (remaining <= 0) {
} break;
} }
} }
} }
}
} }
@PreDestroy @PreDestroy
public void shutdown() { public void shutdown() {
shutdown(2000); shutdown(2000);
} }
public void shutdown(long waitMs) { public void shutdown(long waitMs) {
synchronized (this.statusLock) { synchronized (this.statusLock) {
if (this.status.compareTo(Status.ACTIVE) > 0) { if (this.status.compareTo(Status.ACTIVE) > 0) {
return; return;
} }
this.status = Status.SHUTDOWN_REQUEST; this.status = Status.SHUTDOWN_REQUEST;
try { try {
awaitShutdown(waitMs); awaitShutdown(waitMs);
} catch (InterruptedException ignore) { } catch (InterruptedException ignore) {
} }
} }
} }
protected void exceptionIfNotActive() { protected void exceptionIfNotActive() {
if (!status.equals(Status.ACTIVE)) if (!status.equals(Status.ACTIVE))
throw new IllegalStateException(String.format("not active: %1s", this)); throw new IllegalStateException(String.format("not active: %1s",
this));
} }
} }

View File

@ -0,0 +1,83 @@
/**
*
* 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.logging;
/**
* Base implementation that constructs formatted log strings.
*
* @author Adrian Cole
*
*/
public abstract class BaseLogger implements Logger {
protected abstract void logError(String message, Throwable e);
protected abstract void logError(String message);
protected abstract void logWarn(String message, Throwable e);
protected abstract void logWarn(String message);
protected abstract void logInfo(String message);
protected abstract void logDebug(String message);
protected abstract void logTrace(String message);
public void trace(String message, Object... args) {
if (isTraceEnabled())
logTrace(String.format(message, args));
}
public void debug(String message, Object... args) {
if (isDebugEnabled())
logDebug(String.format(message, args));
}
public void info(String message, Object... args) {
if (isInfoEnabled())
logInfo(String.format(message, args));
}
public void warn(String message, Object... args) {
if (isWarnEnabled())
logWarn(String.format(message, args));
}
public void warn(Throwable e, String message, Object... args) {
if (isWarnEnabled())
logWarn(String.format(message, args), e);
}
public void error(String message, Object... args) {
if (isErrorEnabled())
logError(String.format(message, args));
}
public void error(Throwable e, String message, Object... args) {
if (isErrorEnabled())
logError(String.format(message, args), e);
}
}

View File

@ -0,0 +1,89 @@
/**
*
* 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.logging;
/**
* JCloud log abstraction layer.
* <p/>
* Implementations of logging are optional and injected if they are configured.
* <p/>
* <code> @Resource Logger logger = Logger.NULL;</code> The above will get you a
* null-safe instance of <tt>Logger</tt>. If configured, this logger will be
* swapped with a real Logger implementation with category set to the current
* class name. This is done post-object construction, so do not attempt to use
* these loggers in your constructor.
* <p/>
* If you wish to initialize loggers like these yourself, do not use the @Resource
* annotation.
* <p/>
* This implementation first checks to see if the level is enabled before
* issuing the log command. In other words, don't do the following
* <code>if (logger.isTraceEnabled()) logger.trace("message");.
* <p/>
*
* @author Adrian Cole
*/
public interface Logger {
/**
* Assign to member to avoid NPE when no logging module is configured.
*/
public static final Logger NULL = new NullLogger();
String getCategory();
void trace(String message, Object... args);
boolean isTraceEnabled();
void debug(String message, Object... args);
boolean isDebugEnabled();
void info(String message, Object... args);
boolean isInfoEnabled();
void warn(String message, Object... args);
void warn(Throwable throwable, String message, Object... args);
boolean isWarnEnabled();
void error(String message, Object... args);
void error(Throwable throwable, String message, Object... args);
boolean isErrorEnabled();
/**
* Produces instances of {@link Logger} relevant to the specified category
*
* @author Adrian Cole
*
*/
public static interface LoggerFactory {
public Logger getLogger(String category);
}
}

View File

@ -21,57 +21,73 @@
* under the License. * under the License.
* ==================================================================== * ====================================================================
*/ */
package org.jclouds; package org.jclouds.logging;
import java.util.logging.Level; /**
* <tt>Logger</tt> that doesn't do anything.
public class Logger { * <p />
private final java.util.logging.Logger logger; * Useful to get baseline performance unaffected by logging.
*
public Logger(java.util.logging.Logger logger) { * @author Adrian Cole
this.logger = logger; *
} */
public class NullLogger implements 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) { public void debug(String message, Object... args) {
if (isDebugEnabled())
logger.fine(String.format(message, args));
}
public 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) { 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) { public void error(Throwable throwable, String message, Object... args) {
if (logger.isLoggable(Level.SEVERE))
logger.log(Level.SEVERE, String.format(message, args), throwable); }
public String getCategory() {
return null;
}
public void info(String message, Object... args) {
}
public boolean isDebugEnabled() {
return false;
}
public boolean isErrorEnabled() {
return false;
}
public boolean isInfoEnabled() {
return false;
}
public boolean isTraceEnabled() {
return false;
}
public boolean isWarnEnabled() {
return false;
}
public void trace(String message, Object... args) {
}
public void warn(String message, Object... args) {
}
public void warn(Throwable throwable, String message, Object... args) {
} }
} }

View File

@ -0,0 +1,147 @@
/**
*
* 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.logging.config;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Resource;
import org.jclouds.logging.Logger;
import org.jclouds.logging.Logger.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Module;
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;
/**
* TypeListener that will bind {@link Logger} to members annotated with
* {@link Resource}
*
* This class is a TypeListener so that it can create a logger whose category is
* the same as the name of the injected instance's class.
*
* Note that this occurs post-object construction through
* {@link Module#bindListener}.
*
* Here's an example usage:
* <pre>
* class A {
* @Resource private Logger logger = Logger.NULL;
* }
*
* Injector i = Guice.createInjector(new AbstractModule() {
* @Override protected void configure() {
* bindListener(any(), new
* BindLoggersAnnotatedWithResource( new
* JDKLogger.JDKLoggerFactory()));
* }
* });
*
* A = i.getInstance(A.class);
* // A will now have a logger associated with it
* </pre>
*
* @author Adrian Cole
*
*/
public class BindLoggersAnnotatedWithResource implements TypeListener {
static class AssignLoggerToField<I> implements InjectionListener<I> {
private final Logger logger;
private final Field field;
AssignLoggerToField(Logger logger, Field field) {
this.logger = logger;
this.field = field;
}
public void afterInjection(I injectee) {
try {
field.setAccessible(true);
field.set(injectee, logger);
} catch (IllegalAccessException e) {
throw new ProvisionException(e.getMessage(), e);
}
}
}
static class LoggerFieldsAnnotatedWithResource implements
Function<Field, Field> {
public Field apply(Field from) {
Annotation inject = from.getAnnotation(Resource.class);
if (inject != null && from.getType().isAssignableFrom(Logger.class)) {
return from;
}
return null;
}
}
private final LoggerFactory loggerFactory;
@Inject
public BindLoggersAnnotatedWithResource(LoggerFactory loggerFactory) {
this.loggerFactory = loggerFactory;
}
public <I> void hear(TypeLiteral<I> injectableType,
TypeEncounter<I> encounter) {
Class<? super I> type = injectableType.getRawType();
Set<Field> loggerFields = getLoggerFieldsAnnotatedWithResource(type);
if (loggerFields.size() == 0)
return;
Logger logger = loggerFactory.getLogger(type.getName());
for (Field field : loggerFields) {
encounter.register(new AssignLoggerToField<I>(logger, field));
}
}
@VisibleForTesting
Set<Field> getLoggerFieldsAnnotatedWithResource(Class<?> declaredType) {
Set<Field> fields = new HashSet<Field>();
Class<?> type = declaredType;
while (type != null) {
fields.addAll(Arrays.asList(type.getDeclaredFields()));
type = type.getSuperclass();
}
Set<Field> loggerFields = Sets.newHashSet(Iterables.transform(fields,
new LoggerFieldsAnnotatedWithResource()));
loggerFields.remove(null);
return loggerFields;
}
}

View File

@ -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.logging.config;
import static com.google.inject.matcher.Matchers.any;
import org.jclouds.logging.Logger;
import com.google.inject.AbstractModule;
/**
* Creates a post-injection listener that binds Loggers named the same as the
* enclosing class.
*
* @author Adrian Cole
*
*/
public abstract class LoggingModule extends AbstractModule {
@Override
protected void configure() {
bindListener(any(), new BindLoggersAnnotatedWithResource(
createLoggerFactory()));
}
public abstract Logger.LoggerFactory createLoggerFactory();
}

View File

@ -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.logging.config;
import org.jclouds.logging.Logger;
import org.jclouds.logging.NullLogger;
/**
* Configures logging of type {@link NullLogger}
*
* @author Adrian Cole
*
*/
public class NullLoggingModule extends LoggingModule {
public Logger.LoggerFactory createLoggerFactory() {
return new Logger.LoggerFactory() {
public Logger getLogger(String category) {
return Logger.NULL;
}
};
}
}

View File

@ -0,0 +1,108 @@
/**
*
* 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.logging.jdk;
import java.util.logging.Level;
import org.jclouds.logging.BaseLogger;
import org.jclouds.logging.Logger;
/**
* {@link java.util.logging.Logger} implementation of {@link Logger}.
*
* @author Adrian Cole
*
*/
public class JDKLogger extends BaseLogger {
private final java.util.logging.Logger logger;
public static class JDKLoggerFactory implements LoggerFactory {
public Logger getLogger(String category) {
return new JDKLogger(java.util.logging.Logger.getLogger(category));
}
}
public JDKLogger(java.util.logging.Logger logger) {
this.logger = logger;
}
@Override
protected void logTrace(String message) {
logger.finest(message);
}
public boolean isTraceEnabled() {
return logger.isLoggable(Level.FINEST);
}
@Override
protected void logDebug(String message) {
logger.fine(message);
}
public boolean isDebugEnabled() {
return logger.isLoggable(Level.FINE);
}
@Override
protected void logInfo(String message) {
logger.info(message);
}
public boolean isInfoEnabled() {
return logger.isLoggable(Level.INFO);
}
@Override
protected void logWarn(String message) {
logger.warning(message);
}
@Override
protected void logWarn(String message, Throwable e) {
logger.log(Level.WARNING, message, e);
}
public boolean isWarnEnabled() {
return logger.isLoggable(Level.WARNING);
}
@Override
protected void logError(String message) {
logger.severe(message);
}
@Override
protected void logError(String message, Throwable e) {
logger.log(Level.SEVERE, message, e);
}
public boolean isErrorEnabled() {
return logger.isLoggable(Level.SEVERE);
}
public String getCategory() {
return logger.getName();
}
}

View File

@ -0,0 +1,40 @@
/**
*
* 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.logging.jdk.config;
import org.jclouds.logging.Logger;
import org.jclouds.logging.config.LoggingModule;
import org.jclouds.logging.jdk.JDKLogger;
/**
* Configures logging of type {@link JDKLogger}
*
* @author Adrian Cole
*
*/
public class JDKLoggingModule extends LoggingModule {
public Logger.LoggerFactory createLoggerFactory() {
return new JDKLogger.JDKLoggerFactory();
}
}

View File

@ -43,6 +43,7 @@ import org.jclouds.http.commands.Head;
import org.jclouds.http.commands.callables.xml.ParseSax; import org.jclouds.http.commands.callables.xml.ParseSax;
import org.jclouds.http.commands.config.HttpCommandsModule; import org.jclouds.http.commands.config.HttpCommandsModule;
import org.jclouds.lifecycle.Closer; import org.jclouds.lifecycle.Closer;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.mortbay.jetty.Handler; import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Request; import org.mortbay.jetty.Request;
import org.mortbay.jetty.Server; import org.mortbay.jetty.Server;
@ -117,8 +118,8 @@ public abstract class BaseHttpFutureCommandClientTest {
protected void configure() { protected void configure() {
Names.bindProperties(binder(), properties); Names.bindProperties(binder(), properties);
} }
}, new HttpCommandsModule(), createClientModule(), }, new JDKLoggingModule(), new HttpCommandsModule(),
new AbstractModule() { createClientModule(), new AbstractModule() {
@Override @Override
protected void configure() { protected void configure() {
bind(new TypeLiteral<List<HttpRequestFilter>>() { bind(new TypeLiteral<List<HttpRequestFilter>>() {

View File

@ -23,14 +23,11 @@
*/ */
package org.jclouds.http.commands; package org.jclouds.http.commands;
import static org.easymock.classextension.EasyMock.createMock;
import org.jclouds.http.commands.callables.ReturnStringIf200; import org.jclouds.http.commands.callables.ReturnStringIf200;
import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.util.logging.Logger;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
* *
@ -40,27 +37,26 @@ import java.util.logging.Logger;
public class GetStringTest { public class GetStringTest {
private static final String GOOD_PATH = "/index.html"; private static final String GOOD_PATH = "/index.html";
private GetString get = null; private GetString get = null;
private ReturnStringIf200 callable = null; private ReturnStringIf200 callable = null;
@BeforeMethod @BeforeMethod
void setUp() { void setUp() {
callable = new ReturnStringIf200(createMock(Logger.class)); callable = new ReturnStringIf200();
get = new GetString(callable, GOOD_PATH); get = new GetString(callable, GOOD_PATH);
} }
@AfterMethod @AfterMethod
void tearDown() { void tearDown() {
get = null; get = null;
callable = null; callable = null;
} }
@Test @Test
public void testConstructor() { public void testConstructor() {
assert get.getResponseFuture() != null; assert get.getResponseFuture() != null;
assert get.getRequest().getUri().equals(GOOD_PATH); assert get.getRequest().getUri().equals(GOOD_PATH);
assert get.getRequest().getMethod().equals("GET"); assert get.getRequest().getMethod().equals("GET");
} }
} }

View File

@ -23,19 +23,22 @@
*/ */
package org.jclouds.http.commands.callables; package org.jclouds.http.commands.callables;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import static org.easymock.classextension.EasyMock.*;
import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; 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 @Test
public class ReturnStringIf200Test { public class ReturnStringIf200Test {
@ -43,53 +46,55 @@ public class ReturnStringIf200Test {
@BeforeMethod @BeforeMethod
void setUp() { void setUp() {
callable = new ReturnStringIf200(createMock(Logger.class)); callable = new ReturnStringIf200();
} }
@AfterMethod @AfterMethod
void tearDown() { void tearDown() {
callable = null; callable = null;
} }
@Test @Test
public void testExceptionWhenNoContentOn200() throws ExecutionException, InterruptedException, TimeoutException, IOException { public void testExceptionWhenNoContentOn200() throws ExecutionException,
HttpResponse response = createMock(HttpResponse.class); InterruptedException, TimeoutException, IOException {
expect(response.getStatusCode()).andReturn(200); HttpResponse response = createMock(HttpResponse.class);
expect(response.getContent()).andReturn(null); expect(response.getStatusCode()).andReturn(200);
replay(response); expect(response.getContent()).andReturn(null);
callable.setResponse(response); replay(response);
try { callable.setResponse(response);
callable.call(); try {
} catch (Exception e) { callable.call();
assert e.getMessage().equals("no content"); } catch (Exception e) {
} assert e.getMessage().equals("no content");
verify(response); }
verify(response);
} }
@Test @Test
public void testExceptionWhenIOExceptionOn200() throws ExecutionException, InterruptedException, TimeoutException, IOException { public void testExceptionWhenIOExceptionOn200() throws ExecutionException,
HttpResponse response = createMock(HttpResponse.class); InterruptedException, TimeoutException, IOException {
expect(response.getStatusCode()).andReturn(200); HttpResponse response = createMock(HttpResponse.class);
RuntimeException exception = new RuntimeException("bad"); expect(response.getStatusCode()).andReturn(200);
expect(response.getContent()).andThrow(exception); RuntimeException exception = new RuntimeException("bad");
replay(response); expect(response.getContent()).andThrow(exception);
callable.setResponse(response); replay(response);
try { callable.setResponse(response);
callable.call(); try {
} catch (Exception e) { callable.call();
assert e.equals(exception); } catch (Exception e) {
} assert e.equals(exception);
verify(response); }
verify(response);
} }
@Test @Test
public void testResponseOk() throws Exception { public void testResponseOk() throws Exception {
HttpResponse response = createMock(HttpResponse.class); HttpResponse response = createMock(HttpResponse.class);
expect(response.getStatusCode()).andReturn(200); expect(response.getStatusCode()).andReturn(200);
expect(response.getContent()).andReturn(IOUtils.toInputStream("hello")); expect(response.getContent()).andReturn(IOUtils.toInputStream("hello"));
replay(response); replay(response);
callable.setResponse(response); callable.setResponse(response);
assert "hello".equals(callable.call()); assert "hello".equals(callable.call());
verify(response); verify(response);
} }
} }

View File

@ -23,17 +23,26 @@
*/ */
package org.jclouds.lifecycle.config; package org.jclouds.lifecycle.config;
import static com.google.inject.matcher.Matchers.*;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import org.jclouds.lifecycle.Closer;
import org.jclouds.logging.Logger;
import org.jclouds.logging.config.BindLoggersAnnotatedWithResource;
import org.jclouds.logging.jdk.JDKLogger;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Injector; 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! * // TODO: Adrian: Document this!
@ -45,78 +54,81 @@ public class LifeCycleModuleTest {
@Test @Test
void testBindsExecutor() { void testBindsExecutor() {
Injector i = Guice.createInjector(new LifeCycleModule()); Injector i = Guice.createInjector(new LifeCycleModule());
assert i.getInstance(ExecutorService.class) != null; assert i.getInstance(ExecutorService.class) != null;
} }
@Test @Test
void testBindsCloser() { void testBindsCloser() {
Injector i = Guice.createInjector(new LifeCycleModule()); Injector i = Guice.createInjector(new LifeCycleModule());
assert i.getInstance(Closer.class) != null; assert i.getInstance(Closer.class) != null;
} }
@Test @Test
void testCloserClosesExecutor() throws IOException { void testCloserClosesExecutor() throws IOException {
Injector i = Guice.createInjector(new LifeCycleModule()); Injector i = Guice.createInjector(new LifeCycleModule());
ExecutorService executor = i.getInstance(ExecutorService.class); ExecutorService executor = i.getInstance(ExecutorService.class);
assert !executor.isShutdown(); assert !executor.isShutdown();
Closer closer = i.getInstance(Closer.class); Closer closer = i.getInstance(Closer.class);
closer.close(); closer.close();
assert executor.isShutdown(); assert executor.isShutdown();
} }
static class PreDestroyable { static class PreDestroyable {
boolean isClosed = false; boolean isClosed = false;
@Inject @Inject
PreDestroyable(ExecutorService executor) { PreDestroyable(ExecutorService executor) {
this.executor = executor; this.executor = executor;
} }
ExecutorService executor; ExecutorService executor;
@PreDestroy @PreDestroy
public void close() { public void close() {
assert !executor.isShutdown(); assert !executor.isShutdown();
isClosed = true; isClosed = true;
} }
} }
@Test @Test
void testCloserPreDestroyOrder() throws IOException { void testCloserPreDestroyOrder() throws IOException {
Injector i = Guice.createInjector(new LifeCycleModule(), new AbstractModule() { Injector i = Guice.createInjector(new LifeCycleModule(),
protected void configure() { new AbstractModule() {
bind(PreDestroyable.class); protected void configure() {
} bind(PreDestroyable.class);
}); }
ExecutorService executor = i.getInstance(ExecutorService.class); });
assert !executor.isShutdown(); ExecutorService executor = i.getInstance(ExecutorService.class);
PreDestroyable preDestroyable = i.getInstance(PreDestroyable.class); assert !executor.isShutdown();
assert !preDestroyable.isClosed; PreDestroyable preDestroyable = i.getInstance(PreDestroyable.class);
Closer closer = i.getInstance(Closer.class); assert !preDestroyable.isClosed;
closer.close(); Closer closer = i.getInstance(Closer.class);
assert preDestroyable.isClosed; closer.close();
assert executor.isShutdown(); assert preDestroyable.isClosed;
assert executor.isShutdown();
} }
static class PostConstructable { static class PostConstructable {
boolean isStarted; boolean isStarted;
@PostConstruct @PostConstruct
void start() { void start() {
isStarted = true; isStarted = true;
} }
} }
@Test @Test
void testPostConstruct() { void testPostConstruct() {
Injector i = Guice.createInjector(new LifeCycleModule(), new AbstractModule() { Injector i = Guice.createInjector(new LifeCycleModule(),
protected void configure() { new AbstractModule() {
bind(PostConstructable.class); protected void configure() {
} bind(PostConstructable.class);
}); }
PostConstructable postConstructable = i.getInstance(PostConstructable.class); });
assert postConstructable.isStarted; PostConstructable postConstructable = i
.getInstance(PostConstructable.class);
assert postConstructable.isStarted;
} }

View File

@ -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.logging.config;
import static com.google.inject.matcher.Matchers.any;
import static org.easymock.classextension.EasyMock.createMock;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import java.lang.reflect.Field;
import java.util.Set;
import javax.annotation.Resource;
import org.jclouds.logging.Logger;
import org.jclouds.logging.config.BindLoggersAnnotatedWithResource.AssignLoggerToField;
import org.jclouds.logging.config.BindLoggersAnnotatedWithResource.LoggerFieldsAnnotatedWithResource;
import org.jclouds.logging.jdk.JDKLogger;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
public class BindLoggersAnnotatedWithResourceTest {
private BindLoggersAnnotatedWithResource blawr;
public static class A {
@Resource
private Logger logger = Logger.NULL;
}
public static class B {
@Resource
private Logger logger = Logger.NULL;
}
@BeforeMethod
void createBlawr() {
blawr = new BindLoggersAnnotatedWithResource(
new JDKLogger.JDKLoggerFactory());
}
@Test
void testHear() {
Injector i = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindListener(any(), blawr);
}
});
assertEquals(i.getInstance(A.class).logger.getCategory(), getClass()
.getName()
+ "$A");
assertEquals(i.getInstance(B.class).logger.getCategory(), getClass()
.getName()
+ "$B");
}
@Test
public void testAssignLoggerToField() throws SecurityException,
NoSuchFieldException, IllegalArgumentException,
IllegalAccessException {
Logger logger = createMock(Logger.class);
A a = new A();
Field field = A.class.getDeclaredField("logger");
AssignLoggerToField<A> assigner = new AssignLoggerToField<A>(logger,
field);
assigner.afterInjection(a);
assert field.get(a).equals(logger);
}
@Test
public void testLoggerFieldsAnnotatedWithResource()
throws SecurityException, NoSuchFieldException {
LoggerFieldsAnnotatedWithResource function = new LoggerFieldsAnnotatedWithResource();
assertEquals(function.apply(A.class.getDeclaredField("logger")),
A.class.getDeclaredField("logger"));
}
public static class C {
@Inject
private Logger logger = Logger.NULL;
}
@Test
public void testLoggerFieldsAnnotatedWithInjectReturnsNull()
throws SecurityException, NoSuchFieldException {
LoggerFieldsAnnotatedWithResource function = new LoggerFieldsAnnotatedWithResource();
assertNull(function.apply(C.class.getDeclaredField("logger")));
}
public static class D {
@Resource
private Logger logger = Logger.NULL;
@Resource
private Logger blogger;
}
@Test
public void testGetLoggerFieldsAnnotatedWithResourceNoLogger() {
Set<Field> fields = blawr.getLoggerFieldsAnnotatedWithResource(this
.getClass());
assertEquals(fields.size(), 0);
}
@Test
public void testGetLoggerFieldsAnnotatedWithResourceOneLogger() {
Set<Field> fields = blawr.getLoggerFieldsAnnotatedWithResource(A.class);
assertEquals(fields.size(), 1);
}
@Test
public void testGetLoggerFieldsAnnotatedWithResourceTwoLoggers() {
Set<Field> fields = blawr.getLoggerFieldsAnnotatedWithResource(D.class);
assertEquals(fields.size(), 2);
}
}

View File

@ -64,6 +64,7 @@
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId> <artifactId>jclouds-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>

View File

@ -29,6 +29,7 @@ import org.apache.http.nio.NHttpConnection;
import org.jclouds.command.pool.FutureCommandConnectionRetry; import org.jclouds.command.pool.FutureCommandConnectionRetry;
import org.jclouds.http.HttpConstants; import org.jclouds.http.HttpConstants;
import org.jclouds.http.HttpFutureCommandClient; import org.jclouds.http.HttpFutureCommandClient;
import org.jclouds.http.config.HttpFutureCommandClientModule;
import org.jclouds.http.httpnio.config.internal.NonSSLHttpNioConnectionPoolClientModule; import org.jclouds.http.httpnio.config.internal.NonSSLHttpNioConnectionPoolClientModule;
import org.jclouds.http.httpnio.config.internal.SSLHttpNioConnectionPoolClientModule; import org.jclouds.http.httpnio.config.internal.SSLHttpNioConnectionPoolClientModule;
import org.jclouds.http.httpnio.pool.HttpNioConnectionPoolClient; import org.jclouds.http.httpnio.pool.HttpNioConnectionPoolClient;
@ -45,6 +46,7 @@ import com.google.inject.name.Named;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@HttpFutureCommandClientModule
public class HttpNioConnectionPoolClientModule extends AbstractModule { public class HttpNioConnectionPoolClientModule extends AbstractModule {
@Named(HttpConstants.PROPERTY_HTTP_SECURE) @Named(HttpConstants.PROPERTY_HTTP_SECURE)

View File

@ -23,8 +23,11 @@
*/ */
package org.jclouds.http.httpnio.pool; package org.jclouds.http.httpnio.pool;
import com.google.inject.Inject; import java.util.Collections;
import com.google.inject.Singleton; import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import org.apache.http.nio.NHttpConnection; import org.apache.http.nio.NHttpConnection;
import org.jclouds.command.FutureCommand; import org.jclouds.command.FutureCommand;
import org.jclouds.command.pool.FutureCommandConnectionPoolClient; import org.jclouds.command.pool.FutureCommandConnectionPoolClient;
@ -33,11 +36,8 @@ import org.jclouds.http.HttpFutureCommandClient;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpRequestFilter;
import java.util.Collections; import com.google.inject.Inject;
import java.util.List; import com.google.inject.Singleton;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.logging.Logger;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
@ -45,34 +45,41 @@ import java.util.logging.Logger;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class HttpNioConnectionPoolClient extends FutureCommandConnectionPoolClient<NHttpConnection> implements HttpFutureCommandClient { public class HttpNioConnectionPoolClient extends
FutureCommandConnectionPoolClient<NHttpConnection> implements
HttpFutureCommandClient {
private List<HttpRequestFilter> requestFilters = Collections.emptyList(); private List<HttpRequestFilter> requestFilters = Collections.emptyList();
public List<HttpRequestFilter> getRequestFilters() { public List<HttpRequestFilter> getRequestFilters() {
return requestFilters; return requestFilters;
} }
@Inject(optional = true) @Inject(optional = true)
public void setRequestFilters(List<HttpRequestFilter> requestFilters) { public void setRequestFilters(List<HttpRequestFilter> requestFilters) {
this.requestFilters = requestFilters; this.requestFilters = requestFilters;
} }
@Override @Override
protected <O extends FutureCommand> void invoke(O operation) { protected <O extends FutureCommand> void invoke(O operation) {
HttpRequest request = (HttpRequest) operation.getRequest(); HttpRequest request = (HttpRequest) operation.getRequest();
try { try {
for (HttpRequestFilter filter : getRequestFilters()) { for (HttpRequestFilter filter : getRequestFilters()) {
filter.filter(request); filter.filter(request);
} }
super.invoke(operation); super.invoke(operation);
} catch (HttpException e) { } catch (HttpException e) {
operation.setException(e); operation.setException(e);
} }
} }
@Inject @Inject
public HttpNioConnectionPoolClient(Logger logger, ExecutorService executor, HttpNioFutureCommandConnectionPool httpFutureCommandConnectionHandleNHttpConnectionNioFutureCommandConnectionPool, BlockingQueue<FutureCommand> commandQueue) { public HttpNioConnectionPoolClient(
super(logger, executor, httpFutureCommandConnectionHandleNHttpConnectionNioFutureCommandConnectionPool, commandQueue); // TODO: Adrian: Customise this generated block ExecutorService executor,
HttpNioFutureCommandConnectionPool httpFutureCommandConnectionHandleNHttpConnectionNioFutureCommandConnectionPool,
BlockingQueue<FutureCommand> commandQueue) {
super(
executor,
httpFutureCommandConnectionHandleNHttpConnectionNioFutureCommandConnectionPool,
commandQueue);
} }
} }

View File

@ -23,38 +23,42 @@
*/ */
package org.jclouds.http.httpnio.pool; package org.jclouds.http.httpnio.pool;
import com.google.inject.Inject; import java.io.IOException;
import com.google.inject.assistedinject.Assisted; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Semaphore;
import org.apache.http.nio.NHttpConnection; import org.apache.http.nio.NHttpConnection;
import org.jclouds.command.FutureCommand; import org.jclouds.command.FutureCommand;
import org.jclouds.command.pool.FutureCommandConnectionHandle; import org.jclouds.command.pool.FutureCommandConnectionHandle;
import java.io.IOException; import com.google.inject.Inject;
import java.util.concurrent.BlockingQueue; import com.google.inject.assistedinject.Assisted;
import java.util.concurrent.Semaphore;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class HttpNioFutureCommandConnectionHandle extends FutureCommandConnectionHandle<NHttpConnection> { public class HttpNioFutureCommandConnectionHandle extends
FutureCommandConnectionHandle<NHttpConnection> {
@Inject @Inject
public HttpNioFutureCommandConnectionHandle(java.util.logging.Logger logger, BlockingQueue<NHttpConnection> available, Semaphore maxConnections, @Assisted NHttpConnection conn, @Assisted FutureCommand operation) throws InterruptedException { public HttpNioFutureCommandConnectionHandle(
super(logger, maxConnections, operation, conn, available); BlockingQueue<NHttpConnection> available, Semaphore maxConnections,
@Assisted NHttpConnection conn, @Assisted FutureCommand operation)
throws InterruptedException {
super(maxConnections, operation, conn, available);
} }
public void startConnection() { public void startConnection() {
conn.getContext().setAttribute("operation", operation); conn.getContext().setAttribute("operation", operation);
logger.trace("invoking %1s on connection %2s", operation, conn); logger.trace("invoking %1s on connection %2s", operation, conn);
conn.requestOutput(); conn.requestOutput();
} }
public void shutdownConnection() throws IOException { public void shutdownConnection() throws IOException {
conn.shutdown(); conn.shutdown();
} }
} }

View File

@ -39,7 +39,6 @@ import org.apache.http.nio.reactor.IOEventDispatch;
import org.apache.http.nio.reactor.IOReactorStatus; import org.apache.http.nio.reactor.IOReactorStatus;
import org.apache.http.nio.reactor.SessionRequest; import org.apache.http.nio.reactor.SessionRequest;
import org.apache.http.nio.reactor.SessionRequestCallback; import org.apache.http.nio.reactor.SessionRequestCallback;
import org.jclouds.Logger;
import org.jclouds.command.FutureCommand; import org.jclouds.command.FutureCommand;
import org.jclouds.command.pool.FutureCommandConnectionPool; import org.jclouds.command.pool.FutureCommandConnectionPool;
import org.jclouds.command.pool.FutureCommandConnectionRetry; import org.jclouds.command.pool.FutureCommandConnectionRetry;
@ -64,7 +63,6 @@ public class HttpNioFutureCommandConnectionPool extends
@Inject @Inject
public HttpNioFutureCommandConnectionPool( public HttpNioFutureCommandConnectionPool(
java.util.logging.Logger logger,
ExecutorService executor, ExecutorService executor,
Semaphore allConnections, Semaphore allConnections,
BlockingQueue<NHttpConnection> available, BlockingQueue<NHttpConnection> available,
@ -76,9 +74,8 @@ public class HttpNioFutureCommandConnectionPool extends
FutureCommandConnectionRetry<NHttpConnection> futureCommandConnectionRetry, FutureCommandConnectionRetry<NHttpConnection> futureCommandConnectionRetry,
@Named(PoolConstants.PROPERTY_POOL_MAX_CONNECTION_REUSE) int maxConnectionReuse, @Named(PoolConstants.PROPERTY_POOL_MAX_CONNECTION_REUSE) int maxConnectionReuse,
@Named(PoolConstants.PROPERTY_POOL_MAX_SESSION_FAILURES) int maxSessionFailures) { @Named(PoolConstants.PROPERTY_POOL_MAX_SESSION_FAILURES) int maxSessionFailures) {
super(new Logger(logger), executor, futureCommandConnectionRetry, super(executor, futureCommandConnectionRetry, allConnections,
allConnections, requestHandleFactory, maxConnectionReuse, requestHandleFactory, maxConnectionReuse, available);
available);
this.ioReactor = ioReactor; this.ioReactor = ioReactor;
this.dispatch = dispatch; this.dispatch = dispatch;
this.target = target; this.target = target;

View File

@ -23,38 +23,45 @@
*/ */
package org.jclouds.http.httpnio.pool; 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.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
public class HttpNioFutureCommandConnectionRetry extends FutureCommandConnectionRetry<NHttpConnection> { import org.apache.http.nio.NHttpConnection;
import org.jclouds.command.FutureCommand;
import org.jclouds.command.pool.FutureCommandConnectionHandle;
import org.jclouds.command.pool.FutureCommandConnectionRetry;
import com.google.inject.Inject;
public class HttpNioFutureCommandConnectionRetry extends
FutureCommandConnectionRetry<NHttpConnection> {
@Inject @Inject
public HttpNioFutureCommandConnectionRetry(java.util.logging.Logger logger, BlockingQueue<FutureCommand> commandQueue, AtomicInteger errors) { public HttpNioFutureCommandConnectionRetry(
super(new Logger(logger), commandQueue, errors); BlockingQueue<FutureCommand> commandQueue, AtomicInteger errors) {
super(commandQueue, errors);
} }
@Override @Override
public void associateHandleWithConnection(FutureCommandConnectionHandle<NHttpConnection> handle, NHttpConnection connection) { public void associateHandleWithConnection(
connection.getContext().setAttribute("operation-handle", handle); FutureCommandConnectionHandle<NHttpConnection> handle,
NHttpConnection connection) {
connection.getContext().setAttribute("operation-handle", handle);
} }
@Override @Override
public HttpNioFutureCommandConnectionHandle getHandleFromConnection(NHttpConnection connection) { public HttpNioFutureCommandConnectionHandle getHandleFromConnection(
return (HttpNioFutureCommandConnectionHandle) connection.getContext().getAttribute("operation-handle"); NHttpConnection connection) {
return (HttpNioFutureCommandConnectionHandle) connection.getContext()
.getAttribute("operation-handle");
} }
// @Override // @Override
// public void incrementErrorCountAndRetry(FutureCommand operation) { // public void incrementErrorCountAndRetry(FutureCommand operation) {
// ((HttpEntityEnclosingRequest) operation.getRequest()).removeHeaders(HTTP.CONTENT_LEN); // ((HttpEntityEnclosingRequest)
// ((HttpEntityEnclosingRequest) operation.getRequest()).removeHeaders(HTTP.DATE_HEADER); // operation.getRequest()).removeHeaders(HTTP.CONTENT_LEN);
// super.incrementErrorCountAndRetry(operation); // ((HttpEntityEnclosingRequest)
// } // operation.getRequest()).removeHeaders(HTTP.DATE_HEADER);
// super.incrementErrorCountAndRetry(operation);
// }
} }

View File

@ -23,7 +23,11 @@
*/ */
package org.jclouds.http.httpnio.pool; package org.jclouds.http.httpnio.pool;
import com.google.inject.Inject; import java.io.IOException;
import java.util.concurrent.ExecutorService;
import javax.annotation.Resource;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
@ -32,117 +36,130 @@ import org.apache.http.nio.entity.ConsumingNHttpEntity;
import org.apache.http.nio.protocol.NHttpRequestExecutionHandler; import org.apache.http.nio.protocol.NHttpRequestExecutionHandler;
import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
import org.jclouds.Logger;
import org.jclouds.command.FutureCommand; import org.jclouds.command.FutureCommand;
import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommand;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.httpnio.HttpNioUtils; import org.jclouds.http.httpnio.HttpNioUtils;
import org.jclouds.logging.Logger;
import java.io.IOException; import com.google.inject.Inject;
import java.util.concurrent.ExecutorService;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class HttpNioFutureCommandExecutionHandler implements NHttpRequestExecutionHandler { public class HttpNioFutureCommandExecutionHandler implements
NHttpRequestExecutionHandler {
private final ExecutorService executor; private final ExecutorService executor;
protected final Logger logger; @Resource
protected Logger logger = Logger.NULL;
private final ConsumingNHttpEntityFactory entityFactory; private final ConsumingNHttpEntityFactory entityFactory;
private final HttpNioFutureCommandConnectionRetry futureOperationRetry; private final HttpNioFutureCommandConnectionRetry futureOperationRetry;
public interface ConsumingNHttpEntityFactory { public interface ConsumingNHttpEntityFactory {
public ConsumingNHttpEntity create(HttpEntity httpEntity); public ConsumingNHttpEntity create(HttpEntity httpEntity);
} }
@Inject @Inject
public HttpNioFutureCommandExecutionHandler(java.util.logging.Logger logger, ConsumingNHttpEntityFactory entityFactory, ExecutorService executor, HttpNioFutureCommandConnectionRetry futureOperationRetry) { public HttpNioFutureCommandExecutionHandler(
this.logger = new Logger(logger); ConsumingNHttpEntityFactory entityFactory,
this.executor = executor; ExecutorService executor,
this.entityFactory = entityFactory; HttpNioFutureCommandConnectionRetry futureOperationRetry) {
this.futureOperationRetry = futureOperationRetry; this.executor = executor;
this.entityFactory = entityFactory;
this.futureOperationRetry = futureOperationRetry;
} }
public void initalizeContext(HttpContext context, Object attachment) { public void initalizeContext(HttpContext context, Object attachment) {
} }
public HttpEntityEnclosingRequest submitRequest(HttpContext context) { public HttpEntityEnclosingRequest submitRequest(HttpContext context) {
HttpFutureCommand operation = (HttpFutureCommand) context.removeAttribute("operation"); HttpFutureCommand operation = (HttpFutureCommand) context
if (operation != null) { .removeAttribute("operation");
//TODO determine why type is lost if (operation != null) {
HttpRequest object = (HttpRequest) operation.getRequest(); // TODO determine why type is lost
return HttpNioUtils.convertToApacheRequest(object); HttpRequest object = (HttpRequest) operation.getRequest();
} return HttpNioUtils.convertToApacheRequest(object);
return null; }
return null;
} }
public ConsumingNHttpEntity responseEntity(HttpResponse response, HttpContext context) throws IOException { public ConsumingNHttpEntity responseEntity(HttpResponse response,
return entityFactory.create(response.getEntity()); HttpContext context) throws IOException {
return entityFactory.create(response.getEntity());
} }
public void handleResponse(HttpResponse response, HttpContext context)
public void handleResponse(HttpResponse response, HttpContext context) throws IOException { throws IOException {
HttpNioFutureCommandConnectionHandle handle = (HttpNioFutureCommandConnectionHandle) context.removeAttribute("operation-handle"); HttpNioFutureCommandConnectionHandle handle = (HttpNioFutureCommandConnectionHandle) context
if (handle != null) { .removeAttribute("operation-handle");
try { if (handle != null) {
FutureCommand command = handle.getOperation(); try {
int code = response.getStatusLine().getStatusCode(); FutureCommand command = handle.getOperation();
//normal codes for rest commands int code = response.getStatusLine().getStatusCode();
if ((code >= 200 && code < 300) || code == 404) { // normal codes for rest commands
processResponse(response, command); if ((code >= 200 && code < 300) || code == 404) {
} else { processResponse(response, command);
if (isRetryable(response)) { } else {
futureOperationRetry.shutdownConnectionAndRetryOperation((NHttpClientConnection) context.getAttribute(ExecutionContext.HTTP_CONNECTION)); if (isRetryable(response)) {
} else { futureOperationRetry
operationFailed(command); .shutdownConnectionAndRetryOperation((NHttpClientConnection) context
} .getAttribute(ExecutionContext.HTTP_CONNECTION));
} } else {
} finally { operationFailed(command);
releaseConnectionToPool(handle); }
} }
} else { } finally {
throw new IllegalStateException(String.format("No operation-handle associated with operation %1s", context)); releaseConnectionToPool(handle);
} }
} else {
throw new IllegalStateException(String.format(
"No operation-handle associated with operation %1s",
context));
}
} }
protected boolean isRetryable(HttpResponse response) throws IOException { protected boolean isRetryable(HttpResponse response) throws IOException {
int code = response.getStatusLine().getStatusCode(); int code = response.getStatusLine().getStatusCode();
return code == 500 || code == 503; return code == 500 || code == 503;
} }
protected void releaseConnectionToPool(HttpNioFutureCommandConnectionHandle handle) { protected void releaseConnectionToPool(
try { HttpNioFutureCommandConnectionHandle handle) {
handle.release(); try {
} catch (InterruptedException e) { handle.release();
logger.error(e, "Interrupted releasing handle %1s", handle); } catch (InterruptedException e) {
} logger.error(e, "Interrupted releasing handle %1s", handle);
}
} }
protected void operationFailed(FutureCommand command) throws IOException { protected void operationFailed(FutureCommand command) throws IOException {
String message = String.format("command failed: %1s", command); String message = String.format("command failed: %1s", command);
logger.error(message); logger.error(message);
command.getResponseFuture().setException(new IOException(message)); command.getResponseFuture().setException(new IOException(message));
} }
protected void processResponse(HttpResponse apacheResponse, FutureCommand command) throws IOException { protected void processResponse(HttpResponse apacheResponse,
org.jclouds.http.HttpResponse response = HttpNioUtils.convertToJavaCloudsResponse(apacheResponse); FutureCommand command) throws IOException {
command.getResponseFuture().setResponse(response); org.jclouds.http.HttpResponse response = HttpNioUtils
logger.trace("submitting response task %1s", command.getResponseFuture()); .convertToJavaCloudsResponse(apacheResponse);
executor.submit(command.getResponseFuture()); command.getResponseFuture().setResponse(response);
logger.trace("submitting response task %1s", command
.getResponseFuture());
executor.submit(command.getResponseFuture());
} }
public void finalizeContext(HttpContext context) { public void finalizeContext(HttpContext context) {
HttpNioFutureCommandConnectionHandle handle = (HttpNioFutureCommandConnectionHandle) context.removeAttribute("operation-handle"); HttpNioFutureCommandConnectionHandle handle = (HttpNioFutureCommandConnectionHandle) context
if (handle != null) { .removeAttribute("operation-handle");
try { if (handle != null) {
handle.cancel(); try {
} catch (Exception e) { handle.cancel();
logger.error(e, "Error cancelling handle %1s", handle); } catch (Exception e) {
} logger.error(e, "Error cancelling handle %1s", handle);
} }
}
} }
} }

69
extensions/log4j/pom.xml Normal file
View File

@ -0,0 +1,69 @@
<?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>jclouds-project</artifactId>
<groupId>org.jclouds</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../../project/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jclouds-log4j</artifactId>
<name>jclouds log4j logging module</name>
<packaging>jar</packaging>
<description>Log4J logging module</description>
<scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/extensions/log4j</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/extensions/log4j</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk/extensions/log4j</url>
</scm>
<dependencies>
<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>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,112 @@
/**
*
* 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.logging.log4j;
import static org.apache.log4j.Level.ERROR;
import static org.apache.log4j.Level.WARN;
import org.jclouds.logging.BaseLogger;
import org.jclouds.logging.Logger;
/**
* {@link org.apache.log4j.Logger} implementation of {@link Logger}.
*
* @author Adrian Cole
*
*/
public class Log4JLogger extends BaseLogger {
private final org.apache.log4j.Logger logger;
private final String category;
public static class Log4JLoggerFactory implements LoggerFactory {
public Logger getLogger(String category) {
return new Log4JLogger(category, org.apache.log4j.Logger
.getLogger(category));
}
}
public Log4JLogger(String category, org.apache.log4j.Logger logger) {
this.category = category;
this.logger = logger;
}
@Override
protected void logTrace(String message) {
logger.trace(message);
}
public boolean isTraceEnabled() {
return logger.isTraceEnabled();
}
@Override
protected void logDebug(String message) {
logger.debug(message);
}
public boolean isDebugEnabled() {
return logger.isDebugEnabled();
}
@Override
protected void logInfo(String message) {
logger.info(message);
}
public boolean isInfoEnabled() {
return logger.isInfoEnabled();
}
@Override
protected void logWarn(String message) {
logger.warn(message);
}
@Override
protected void logWarn(String message, Throwable e) {
logger.warn(message, e);
}
public boolean isWarnEnabled() {
return logger.isEnabledFor(WARN);
}
@Override
protected void logError(String message) {
logger.error(message);
}
@Override
protected void logError(String message, Throwable e) {
logger.error(message, e);
}
public boolean isErrorEnabled() {
return logger.isEnabledFor(ERROR);
}
public String getCategory() {
return category;
}
}

View File

@ -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.logging.log4j.config;
import org.jclouds.logging.Logger.LoggerFactory;
import org.jclouds.logging.config.LoggingModule;
import org.jclouds.logging.log4j.Log4JLogger;
/**
* Configures logging of type {@link Log4JLogger}
*
* @author Adrian Cole
*
*/
public class Log4JLoggingModule extends LoggingModule {
@Override
public LoggerFactory createLoggerFactory() {
return new Log4JLogger.Log4JLoggerFactory();
}
}

View File

@ -0,0 +1,53 @@
/**
*
* 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.logging.log4j.config;
import static org.testng.Assert.*;
import javax.annotation.Resource;
import org.jclouds.logging.Logger;
import org.jclouds.logging.log4j.Log4JLogger;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
@Test
public class Log4JLoggingModuleTest {
static class A {
@Resource
Logger logger = Logger.NULL;
}
@Test
public void testConfigure() {
Injector i = Guice.createInjector(new Log4JLoggingModule());
A a = i.getInstance(A.class);
assertEquals(a.logger.getClass(), Log4JLogger.class);
assertEquals(a.logger.getCategory(), getClass().getName() + "$A");
}
}

View File

@ -61,6 +61,7 @@
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>jclouds-s3</artifactId> <artifactId>jclouds-s3</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>

View File

@ -23,64 +23,68 @@
*/ */
package org.jclouds.aws.s3.nio; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.nio.entity.NStringEntity;
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandConnectionRetry;
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandExecutionHandler;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class S3HttpNioFutureCommandExecutionHandler extends HttpNioFutureCommandExecutionHandler { public class S3HttpNioFutureCommandExecutionHandler extends
HttpNioFutureCommandExecutionHandler {
@Inject @Inject
public S3HttpNioFutureCommandExecutionHandler(java.util.logging.Logger logger, ConsumingNHttpEntityFactory entityFactory, ExecutorService executor, HttpNioFutureCommandConnectionRetry futureOperationRetry) { public S3HttpNioFutureCommandExecutionHandler(
super(logger, entityFactory, executor, futureOperationRetry); ConsumingNHttpEntityFactory entityFactory,
ExecutorService executor,
HttpNioFutureCommandConnectionRetry futureOperationRetry) {
super(entityFactory, executor, futureOperationRetry);
} }
@Override @Override
protected boolean isRetryable(HttpResponse response) throws IOException { protected boolean isRetryable(HttpResponse response) throws IOException {
if (super.isRetryable(response)) if (super.isRetryable(response))
return true; return true;
int code = response.getStatusLine().getStatusCode(); int code = response.getStatusLine().getStatusCode();
if (code == 409) { if (code == 409) {
return true; return true;
} else if (code == 400) { } else if (code == 400) {
if (response.getEntity() != null) { if (response.getEntity() != null) {
InputStream input = response.getEntity().getContent(); InputStream input = response.getEntity().getContent();
if (input != null) { if (input != null) {
String reason = null; String reason = null;
try { try {
reason = IOUtils.toString(input); reason = IOUtils.toString(input);
} finally { } finally {
IOUtils.closeQuietly(input); IOUtils.closeQuietly(input);
} }
if (reason != null) { if (reason != null) {
try { try {
if (reason.indexOf("RequestTime") >= 0) return true; if (reason.indexOf("RequestTime") >= 0)
} finally { return true;
IOUtils.closeQuietly(input); } finally {
response.setEntity(new NStringEntity(reason)); IOUtils.closeQuietly(input);
} response.setEntity(new NStringEntity(reason));
} }
}
} }
} }
} }
return false; return false;
} }
} }

View File

@ -23,25 +23,29 @@
*/ */
package org.jclouds.aws.s3.nio.config; 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.apache.http.nio.protocol.NHttpRequestExecutionHandler;
import org.jclouds.aws.s3.nio.S3HttpNioFutureCommandExecutionHandler; import org.jclouds.aws.s3.nio.S3HttpNioFutureCommandExecutionHandler;
import org.jclouds.http.config.HttpFutureCommandClientModule;
import org.jclouds.http.httpnio.config.HttpNioConnectionPoolClientModule; import org.jclouds.http.httpnio.config.HttpNioConnectionPoolClientModule;
import com.google.inject.AbstractModule;
import com.google.inject.util.Modules;
/** /**
* This installs a {@link HttpNioConnectionPoolClientModule}, but overrides it binding {@link S3HttpNioFutureCommandExecutionHandler}. * This installs a {@link HttpNioConnectionPoolClientModule}, but overrides it
* binding {@link S3HttpNioFutureCommandExecutionHandler}.
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@HttpFutureCommandClientModule
public class S3HttpNioConnectionPoolClientModule extends AbstractModule { public class S3HttpNioConnectionPoolClientModule extends AbstractModule {
protected void configure() { protected void configure() {
install(Modules.override(new HttpNioConnectionPoolClientModule()).with(new AbstractModule() { install(Modules.override(new HttpNioConnectionPoolClientModule()).with(
protected void configure() { new AbstractModule() {
bind(NHttpRequestExecutionHandler.class).to(S3HttpNioFutureCommandExecutionHandler.class); protected void configure() {
} bind(NHttpRequestExecutionHandler.class).to(
})); S3HttpNioFutureCommandExecutionHandler.class);
}
}));
} }
} }

View File

@ -23,21 +23,25 @@
*/ */
package org.jclouds.aws.s3.nio; package org.jclouds.aws.s3.nio;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.isA;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.StatusLine; import org.apache.http.StatusLine;
import org.apache.http.nio.entity.NStringEntity; 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.HttpNioFutureCommandConnectionRetry;
import org.jclouds.http.httpnio.pool.HttpNioFutureCommandExecutionHandler; import org.jclouds.http.httpnio.pool.HttpNioFutureCommandExecutionHandler;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
* *
@ -51,91 +55,93 @@ public class S3HttpNioFutureCommandExecutionHandlerTest {
@BeforeMethod @BeforeMethod
public void createHandler() { public void createHandler() {
handler = new S3HttpNioFutureCommandExecutionHandler(createMock( handler = new S3HttpNioFutureCommandExecutionHandler(
java.util.logging.Logger.class), createMock(HttpNioFutureCommandExecutionHandler.ConsumingNHttpEntityFactory.class), createMock(HttpNioFutureCommandExecutionHandler.ConsumingNHttpEntityFactory.class),
createMock(ExecutorService.class), createMock(ExecutorService.class),
createMock(HttpNioFutureCommandConnectionRetry.class)); createMock(HttpNioFutureCommandConnectionRetry.class));
response = createMock(HttpResponse.class); response = createMock(HttpResponse.class);
statusline = createMock(StatusLine.class); statusline = createMock(StatusLine.class);
expect(response.getStatusLine()).andReturn(statusline).atLeastOnce(); expect(response.getStatusLine()).andReturn(statusline).atLeastOnce();
} }
@Test @Test
void test500isRetryable() throws IOException { void test500isRetryable() throws IOException {
isRetryable(500); isRetryable(500);
} }
@Test @Test
void test503isRetryable() throws IOException { void test503isRetryable() throws IOException {
isRetryable(503); isRetryable(503);
} }
@Test @Test
void test409isRetryable() throws IOException { void test409isRetryable() throws IOException {
isRetryable(409); isRetryable(409);
} }
@Test @Test
void test404NotRetryable() throws IOException { void test404NotRetryable() throws IOException {
expect(statusline.getStatusCode()).andReturn(404).atLeastOnce(); expect(statusline.getStatusCode()).andReturn(404).atLeastOnce();
replay(statusline); replay(statusline);
replay(response); replay(response);
assert !handler.isRetryable(response); assert !handler.isRetryable(response);
verify(statusline); verify(statusline);
verify(response); verify(response);
} }
@Test @Test
void test400WithNoEnitityNotRetryable() throws IOException { void test400WithNoEnitityNotRetryable() throws IOException {
expect(statusline.getStatusCode()).andReturn(400).atLeastOnce(); expect(statusline.getStatusCode()).andReturn(400).atLeastOnce();
expect(response.getEntity()).andReturn(null); expect(response.getEntity()).andReturn(null);
replay(statusline); replay(statusline);
replay(response); replay(response);
assert !handler.isRetryable(response); assert !handler.isRetryable(response);
verify(statusline); verify(statusline);
verify(response); verify(response);
} }
@Test @Test
void test400WithIrrelevantEnitityNotRetryable() throws IOException { void test400WithIrrelevantEnitityNotRetryable() throws IOException {
expect(statusline.getStatusCode()).andReturn(400).atLeastOnce(); expect(statusline.getStatusCode()).andReturn(400).atLeastOnce();
HttpEntity entity = createMock(HttpEntity.class); HttpEntity entity = createMock(HttpEntity.class);
expect(response.getEntity()).andReturn(entity).atLeastOnce(); expect(response.getEntity()).andReturn(entity).atLeastOnce();
expect(entity.getContent()).andReturn(IOUtils.toInputStream("hello")); expect(entity.getContent()).andReturn(IOUtils.toInputStream("hello"));
response.setEntity(isA(NStringEntity.class)); response.setEntity(isA(NStringEntity.class));
replay(entity); replay(entity);
replay(statusline); replay(statusline);
replay(response); replay(response);
assert !handler.isRetryable(response); assert !handler.isRetryable(response);
verify(statusline); verify(statusline);
verify(response); verify(response);
verify(entity); verify(entity);
} }
@Test @Test
void test400WithRequestTimeTooSkewedTimeEnitityRetryable() throws IOException { void test400WithRequestTimeTooSkewedTimeEnitityRetryable()
expect(statusline.getStatusCode()).andReturn(400).atLeastOnce(); throws IOException {
HttpEntity entity = createMock(HttpEntity.class); expect(statusline.getStatusCode()).andReturn(400).atLeastOnce();
expect(response.getEntity()).andReturn(entity).atLeastOnce(); HttpEntity entity = createMock(HttpEntity.class);
expect(entity.getContent()).andReturn(IOUtils.toInputStream("RequestTimeTooSkewed")); expect(response.getEntity()).andReturn(entity).atLeastOnce();
response.setEntity(isA(NStringEntity.class)); expect(entity.getContent()).andReturn(
replay(entity); IOUtils.toInputStream("RequestTimeTooSkewed"));
replay(statusline); response.setEntity(isA(NStringEntity.class));
replay(response); replay(entity);
assert handler.isRetryable(response); replay(statusline);
verify(statusline); replay(response);
verify(response); assert handler.isRetryable(response);
verify(entity); verify(statusline);
verify(response);
verify(entity);
} }
private void isRetryable(int code) throws IOException { private void isRetryable(int code) throws IOException {
expect(statusline.getStatusCode()).andReturn(code).atLeastOnce(); expect(statusline.getStatusCode()).andReturn(code).atLeastOnce();
replay(statusline); replay(statusline);
replay(response); replay(response);
assert handler.isRetryable(response); assert handler.isRetryable(response);
verify(statusline); verify(statusline);
verify(response); verify(response);
} }
} }

View File

@ -35,14 +35,16 @@ import java.net.URL;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.annotation.Resource;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.jclouds.Logger;
import org.jclouds.command.FutureCommand; import org.jclouds.command.FutureCommand;
import org.jclouds.http.HttpConstants; import org.jclouds.http.HttpConstants;
import org.jclouds.http.HttpFutureCommandClient; import org.jclouds.http.HttpFutureCommandClient;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.logging.Logger;
import com.google.appengine.api.urlfetch.HTTPHeader; import com.google.appengine.api.urlfetch.HTTPHeader;
import com.google.appengine.api.urlfetch.HTTPMethod; import com.google.appengine.api.urlfetch.HTTPMethod;
@ -60,7 +62,8 @@ import com.google.inject.Inject;
public class URLFetchServiceClient implements HttpFutureCommandClient { public class URLFetchServiceClient implements HttpFutureCommandClient {
private final URL target; private final URL target;
private List<HttpRequestFilter> requestFilters = Collections.emptyList(); private List<HttpRequestFilter> requestFilters = Collections.emptyList();
private final Logger logger; @Resource
private Logger logger = Logger.NULL;
private final URLFetchService urlFetchService; private final URLFetchService urlFetchService;
public List<HttpRequestFilter> getRequestFilters() { public List<HttpRequestFilter> getRequestFilters() {
@ -73,10 +76,9 @@ public class URLFetchServiceClient implements HttpFutureCommandClient {
} }
@Inject @Inject
public URLFetchServiceClient(java.util.logging.Logger logger, URL target, public URLFetchServiceClient(URL target, URLFetchService urlFetchService)
URLFetchService urlFetchService) throws MalformedURLException { throws MalformedURLException {
this.urlFetchService = urlFetchService; this.urlFetchService = urlFetchService;
this.logger = new Logger(logger);
this.target = target; this.target = target;
this.logger.info("configured to connect to target: %1s", target); this.logger.info("configured to connect to target: %1s", target);
} }

View File

@ -29,6 +29,7 @@ import java.net.URL;
import org.jclouds.gae.URLFetchServiceClient; import org.jclouds.gae.URLFetchServiceClient;
import org.jclouds.http.HttpConstants; import org.jclouds.http.HttpConstants;
import org.jclouds.http.HttpFutureCommandClient; import org.jclouds.http.HttpFutureCommandClient;
import org.jclouds.http.config.HttpFutureCommandClientModule;
import com.google.appengine.api.urlfetch.URLFetchService; import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory; import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
@ -42,6 +43,7 @@ import com.google.inject.name.Named;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@HttpFutureCommandClientModule
public class URLFetchServiceClientModule extends AbstractModule { public class URLFetchServiceClientModule extends AbstractModule {
@Override @Override

View File

@ -23,11 +23,11 @@
*/ */
package org.jclouds.gae; package org.jclouds.gae;
import static org.testng.Assert.*;
import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.createNiceMock; import static org.easymock.classextension.EasyMock.createNiceMock;
import static org.easymock.classextension.EasyMock.replay; import static org.easymock.classextension.EasyMock.replay;
import static org.testng.Assert.assertEquals;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -64,8 +64,7 @@ public class URLFetchServiceClientTest {
@BeforeTest @BeforeTest
void setupClient() throws MalformedURLException { void setupClient() throws MalformedURLException {
url = new URL("http://localhost:80"); url = new URL("http://localhost:80");
client = new URLFetchServiceClient( client = new URLFetchServiceClient(url,
createNiceMock(java.util.logging.Logger.class), url,
createNiceMock(URLFetchService.class)); createNiceMock(URLFetchService.class));
} }

View File

@ -42,6 +42,7 @@
<module>core</module> <module>core</module>
<module>extensions/httpnio</module> <module>extensions/httpnio</module>
<module>extensions/s3nio</module> <module>extensions/s3nio</module>
<module>extensions/log4j</module>
<module>gae</module> <module>gae</module>
<module>s3</module> <module>s3</module>
</modules> </modules>

View File

@ -35,22 +35,26 @@ import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_ADDRESS;
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_PORT; import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_PORT;
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_SECURE; import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_SECURE;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.jclouds.aws.s3.config.S3ContextModule; import org.jclouds.aws.s3.config.S3ContextModule;
import org.jclouds.http.HttpFutureCommandClient; import org.jclouds.http.config.HttpFutureCommandClientModule;
import org.jclouds.http.config.JavaUrlHttpFutureCommandClientModule; import org.jclouds.http.config.JavaUrlHttpFutureCommandClientModule;
import org.jclouds.logging.config.LoggingModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.name.Names; import com.google.inject.name.Names;
/** /**
* Creates {@link S3Context} or {@link Injector} instances based on the most * Creates {@link S3Context} or {@link Injector} instances based on the most
* commonly requested arguments. * commonly requested arguments.
@ -160,28 +164,49 @@ public class S3ContextFactory {
/** /**
* Bind the given properties and install the list of modules. If no modules * Bind the given properties and install the list of modules. If no modules
* are specified, install the default * are specified, install the default {@link JDKLoggingModule}
* {@link JavaUrlHttpFutureCommandClientModule} * {@link JavaUrlHttpFutureCommandClientModule}
* *
* @param properties * @param properties
* - contains constants used by jclouds * - contains constants used by jclouds
* {@link #DEFAULT_PROPERTIES} * {@link #DEFAULT_PROPERTIES}
* @param httpModules * @param configModules
* - modules that must bind {@link HttpFutureCommandClient} if * - alternative configuration modules
* specified */
* */
public static Injector createInjector(final Properties properties, public static Injector createInjector(final Properties properties,
Module... httpModules) { Module... configModules) {
final List<? extends Module> modules = httpModules.length != 0 ? Arrays final List<Module> modules = Lists.newArrayList(configModules);
.asList(httpModules) : Collections
.singletonList(new JavaUrlHttpFutureCommandClientModule()); addLoggingModuleIfNotPresent(modules);
addHttpModuleIfNotPresent(modules);
return Guice.createInjector(new AbstractModule() { return Guice.createInjector(new AbstractModule() {
@Override @Override
protected void configure() { protected void configure() {
Names.bindProperties(binder(), checkNotNull(properties,"properties")); Names.bindProperties(binder(), checkNotNull(properties,
"properties"));
for (Module module : modules) for (Module module : modules)
install(module); install(module);
} }
}, new S3ContextModule()); }, new S3ContextModule());
} }
@VisibleForTesting
static void addHttpModuleIfNotPresent(final List<Module> modules) {
if (!Iterables.any(modules, new Predicate<Module>() {
public boolean apply(Module input) {
return input.getClass().isAnnotationPresent(
HttpFutureCommandClientModule.class);
}
}))
modules.add(new JavaUrlHttpFutureCommandClientModule());
}
@VisibleForTesting
static void addLoggingModuleIfNotPresent(final List<Module> modules) {
if (!Iterables.any(modules, Predicates.instanceOf(LoggingModule.class)))
modules.add(new JDKLoggingModule());
}
} }

View File

@ -26,7 +26,6 @@ package org.jclouds.aws.s3.commands.callables;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.jclouds.Logger;
import org.jclouds.Utils; import org.jclouds.Utils;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommand;
@ -42,8 +41,8 @@ public class CopyObjectCallable extends
HttpFutureCommand.ResponseCallable<Boolean> { HttpFutureCommand.ResponseCallable<Boolean> {
@Inject @Inject
public CopyObjectCallable(java.util.logging.Logger logger) { public CopyObjectCallable() {
super(new Logger(logger)); super();
} }
public Boolean call() throws HttpException { public Boolean call() throws HttpException {
@ -57,7 +56,7 @@ public class CopyObjectCallable extends
} }
throw new HttpException("Error copying source " + reason); throw new HttpException("Error copying source " + reason);
} else if (getResponse().getStatusCode() == 200) { } else if (getResponse().getStatusCode() == 200) {
String response = null; String response;
InputStream content = getResponse().getContent(); InputStream content = getResponse().getContent();
if (content != null) { if (content != null) {
try { try {

View File

@ -23,12 +23,11 @@
*/ */
package org.jclouds.aws.s3.commands.callables; package org.jclouds.aws.s3.commands.callables;
import com.google.inject.Inject; import java.io.IOException;
import org.jclouds.aws.s3.S3Utils; import org.jclouds.aws.s3.S3Utils;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import java.io.IOException;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
* *
@ -36,29 +35,22 @@ import java.io.IOException;
*/ */
public class DeleteBucketCallable extends DeleteCallable { public class DeleteBucketCallable extends DeleteCallable {
private final S3Utils s3Utils;
@Inject
public DeleteBucketCallable(java.util.logging.Logger logger, S3Utils s3Utils) {
super(logger);
this.s3Utils = s3Utils;
}
public Boolean call() throws HttpException { public Boolean call() throws HttpException {
if (getResponse().getStatusCode() == 404) { if (getResponse().getStatusCode() == 404) {
return true; return true;
} else if (getResponse().getStatusCode() == 409) { } else if (getResponse().getStatusCode() == 409) {
try { try {
String reason = s3Utils.toStringAndClose(getResponse().getContent()); String reason = S3Utils.toStringAndClose(getResponse()
if (reason.indexOf("BucketNotEmpty") >= 0) .getContent());
return false; if (reason.indexOf("BucketNotEmpty") >= 0)
else return false;
throw new HttpException("Error deleting bucket.\n" + reason); else
} catch (IOException e) { throw new HttpException("Error deleting bucket.\n" + reason);
throw new HttpException("Error deleting bucket", e); } catch (IOException e) {
} throw new HttpException("Error deleting bucket", e);
} else { }
return super.call(); } else {
} return super.call();
}
} }
} }

View File

@ -23,8 +23,6 @@
*/ */
package org.jclouds.aws.s3.commands.callables; package org.jclouds.aws.s3.commands.callables;
import com.google.inject.Inject;
import org.jclouds.Logger;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommand;
@ -35,16 +33,11 @@ import org.jclouds.http.HttpFutureCommand;
*/ */
public class DeleteCallable extends HttpFutureCommand.ResponseCallable<Boolean> { public class DeleteCallable extends HttpFutureCommand.ResponseCallable<Boolean> {
@Inject
public DeleteCallable(java.util.logging.Logger logger) {
super(new Logger(logger));
}
public Boolean call() throws HttpException { public Boolean call() throws HttpException {
if (getResponse().getStatusCode() == 204) { if (getResponse().getStatusCode() == 204) {
return true; return true;
} else { } else {
throw new HttpException("Error deleting bucket " + getResponse()); throw new HttpException("Error deleting bucket " + getResponse());
} }
} }
} }

View File

@ -23,8 +23,6 @@
*/ */
package org.jclouds.aws.s3.commands.callables; package org.jclouds.aws.s3.commands.callables;
import com.google.inject.Inject;
import org.jclouds.Logger;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommand;
@ -33,20 +31,16 @@ import org.jclouds.http.HttpFutureCommand;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class PutBucketCallable extends HttpFutureCommand.ResponseCallable<Boolean> { public class PutBucketCallable extends
HttpFutureCommand.ResponseCallable<Boolean> {
@Inject
public PutBucketCallable(java.util.logging.Logger logger) {
super(new Logger(logger));
}
public Boolean call() throws HttpException { public Boolean call() throws HttpException {
if (getResponse().getStatusCode() == 200) { if (getResponse().getStatusCode() == 200) {
return true; return true;
} else if (getResponse().getStatusCode() == 404) { } else if (getResponse().getStatusCode() == 404) {
return false; return false;
} else { } else {
throw new HttpException("Error checking bucket " + getResponse()); throw new HttpException("Error checking bucket " + getResponse());
} }
} }
} }

View File

@ -25,43 +25,36 @@ package org.jclouds.aws.s3.commands.callables;
import java.io.IOException; import java.io.IOException;
import org.jclouds.Logger;
import org.jclouds.aws.s3.S3Utils; import org.jclouds.aws.s3.S3Utils;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommand;
import com.google.inject.Inject;
/** /**
* // TODO: Adrian: Document this! * // TODO: Adrian: Document this!
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class PutObjectCallable extends HttpFutureCommand.ResponseCallable<String> { public class PutObjectCallable extends
HttpFutureCommand.ResponseCallable<String> {
private final S3Utils s3Utils;
@Inject
public PutObjectCallable(java.util.logging.Logger logger, S3Utils s3Utils) {
super(new Logger(logger));
this.s3Utils = s3Utils;
}
public String call() throws HttpException { public String call() throws HttpException {
if (getResponse().getStatusCode() == 200) { if (getResponse().getStatusCode() == 200) {
try { try {
getResponse().getContent().close(); getResponse().getContent().close();
} catch (IOException e) { } catch (IOException e) {
logger.error(e, "error consuming content"); logger.error(e, "error consuming content");
} }
return getResponse().getHeaders().get("ETag").iterator().next(); return getResponse().getHeaders().get("ETag").iterator().next();
} else { } else {
try { try {
String reason = s3Utils.toStringAndClose(getResponse().getContent()); String reason = S3Utils.toStringAndClose(getResponse()
throw new HttpException(getResponse().getStatusCode() + ": Problem uploading content.\n" + reason); .getContent());
} catch (IOException e) { throw new HttpException(getResponse().getStatusCode()
throw new HttpException(getResponse().getStatusCode() + ": Problem uploading content", e); + ": Problem uploading content.\n" + reason);
} } catch (IOException e) {
} throw new HttpException(getResponse().getStatusCode()
+ ": Problem uploading content", e);
}
}
} }
} }

View File

@ -25,7 +25,6 @@ package org.jclouds.aws.s3.commands.callables;
import java.io.IOException; import java.io.IOException;
import org.jclouds.Logger;
import org.jclouds.Utils; import org.jclouds.Utils;
import org.jclouds.aws.s3.DateService; import org.jclouds.aws.s3.DateService;
import org.jclouds.aws.s3.domain.S3Object; import org.jclouds.aws.s3.domain.S3Object;
@ -45,9 +44,7 @@ public class RetrieveObjectCallable extends
private String key; private String key;
@Inject @Inject
public RetrieveObjectCallable(java.util.logging.Logger logger, public RetrieveObjectCallable(DateService dateParser) {
DateService dateParser) {
super(new Logger(logger));
this.dateParser = dateParser; this.dateParser = dateParser;
} }

View File

@ -25,13 +25,15 @@ package org.jclouds.aws.s3.internal;
import java.io.IOException; import java.io.IOException;
import org.jclouds.Logger; import javax.annotation.Resource;
import org.jclouds.aws.s3.S3Connection; import org.jclouds.aws.s3.S3Connection;
import org.jclouds.aws.s3.S3Context; import org.jclouds.aws.s3.S3Context;
import org.jclouds.aws.s3.S3InputStreamMap; import org.jclouds.aws.s3.S3InputStreamMap;
import org.jclouds.aws.s3.S3ObjectMap; import org.jclouds.aws.s3.S3ObjectMap;
import org.jclouds.aws.s3.domain.S3Bucket; import org.jclouds.aws.s3.domain.S3Bucket;
import org.jclouds.lifecycle.Closer; import org.jclouds.lifecycle.Closer;
import org.jclouds.logging.Logger;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -50,17 +52,17 @@ public class GuiceS3Context implements S3Context {
S3InputStreamMap createMapView(S3Bucket bucket); S3InputStreamMap createMapView(S3Bucket bucket);
} }
private final Logger logger; @Resource
private Logger logger = Logger.NULL;
private final Injector injector; private final Injector injector;
private final S3InputStreamMapFactory s3InputStreamMapFactory; private final S3InputStreamMapFactory s3InputStreamMapFactory;
private final S3ObjectMapFactory s3ObjectMapFactory; private final S3ObjectMapFactory s3ObjectMapFactory;
private final Closer closer; private final Closer closer;
@Inject @Inject
private GuiceS3Context(java.util.logging.Logger logger, Injector injector, private GuiceS3Context(Injector injector, Closer closer,
Closer closer, S3ObjectMapFactory s3ObjectMapFactory, S3ObjectMapFactory s3ObjectMapFactory,
S3InputStreamMapFactory s3InputStreamMapFactory) { S3InputStreamMapFactory s3InputStreamMapFactory) {
this.logger = new Logger(logger);
this.injector = injector; this.injector = injector;
this.s3InputStreamMapFactory = s3InputStreamMapFactory; this.s3InputStreamMapFactory = s3InputStreamMapFactory;
this.s3ObjectMapFactory = s3ObjectMapFactory; this.s3ObjectMapFactory = s3ObjectMapFactory;

View File

@ -32,7 +32,6 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.jclouds.http.HttpFutureCommand; import org.jclouds.http.HttpFutureCommand;
@ -48,7 +47,7 @@ public class CopyObjectCallableTest {
@BeforeMethod @BeforeMethod
void setUp() { void setUp() {
callable = new CopyObjectCallable(createMock(Logger.class)); callable = new CopyObjectCallable();
} }
@AfterMethod @AfterMethod