
org.jclouds.rest.internal.InvokeHttpMethod Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jclouds-core Show documentation
Show all versions of jclouds-core Show documentation
Core components to access jclouds services
The newest version!
/*
* 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.rest.internal;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Throwables.propagate;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.concurrent.Callable;
import javax.annotation.Resource;
import javax.inject.Inject;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.logging.Logger;
import org.jclouds.reflect.Invocation;
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.config.InvocationConfig;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.util.concurrent.TimeLimiter;
/**
* @author Adrian Cole
*/
public class InvokeHttpMethod implements Function {
@Resource
private Logger logger = Logger.NULL;
private final Function annotationProcessor;
private final HttpCommandExecutorService http;
private final TimeLimiter timeLimiter;
private final Function> transformerForRequest;
private final InvocationConfig config;
@Inject
@VisibleForTesting
InvokeHttpMethod(Function annotationProcessor,
HttpCommandExecutorService http, Function> transformerForRequest,
TimeLimiter timeLimiter, InvocationConfig config) {
this.annotationProcessor = annotationProcessor;
this.http = http;
this.timeLimiter = timeLimiter;
this.transformerForRequest = transformerForRequest;
this.config = config;
}
@Override
public Object apply(Invocation in) {
Optional timeoutNanos = config.getTimeoutNanos(in);
if (timeoutNanos.isPresent()) {
return invokeWithTimeout(in, timeoutNanos.get());
}
return invoke(in);
}
/**
* invokes the {@linkplain HttpCommand} associated with {@code invocation},
* {@link #getTransformer(String, HttpCommand) parses its response}, and
* applies a {@link #getFallback(String, Invocation, HttpCommand) fallback}
* if a {@code Throwable} is encountered.
*/
public Object invoke(Invocation invocation) {
String commandName = config.getCommandName(invocation);
HttpCommand command = toCommand(commandName, invocation);
Function transformer = getTransformer(commandName, command);
org.jclouds.Fallback> fallback = getFallback(commandName, invocation, command);
logger.debug(">> invoking %s", commandName);
try {
return transformer.apply(http.invoke(command));
} catch (Throwable t) {
try {
return fallback.createOrPropagate(t);
} catch (Exception e) {
throw propagate(e);
}
}
}
/**
* calls {@link #invoke(Invocation)}, timing out after the specified time
* limit. If the target method call finished before the limit is reached, the
* return value or exception is propagated to the caller exactly as-is. If,
* on the other hand, the time limit is reached, we attempt to abort the call
* to the target, and throw an {@link UncheckedTimeoutException} to the
* caller.
*
* @param invocation
* the Invocation to invoke via {@link #invoke(Invocation)}
* @param limitNanos
* with timeoutUnit, the maximum length of time to wait in
* nanoseconds
* @throws InterruptedException
* if our thread is interrupted during execution
* @throws UncheckedTimeoutException
* if the time limit is reached
* @see TimeLimiter#callWithTimeout(Callable, long, TimeUnit, boolean)
*/
public Object invokeWithTimeout(final Invocation invocation, final long limitNanos) {
String commandName = config.getCommandName(invocation);
HttpCommand command = toCommand(commandName, invocation);
org.jclouds.Fallback> fallback = getFallback(commandName, invocation, command);
logger.debug(">> blocking on %s for %s", invocation, limitNanos);
try {
return timeLimiter
.callWithTimeout(new InvokeAndTransform(commandName, command), limitNanos, NANOSECONDS, true);
} catch (Throwable t) {
try {
return fallback.createOrPropagate(t);
} catch (Exception e) {
throw propagate(e);
}
}
}
private org.jclouds.Fallback> getFallback(String commandName, Invocation invocation, HttpCommand command) {
HttpRequest request = command.getCurrentRequest();
org.jclouds.Fallback> fallback = config.getFallback(invocation);
if (fallback instanceof InvocationContext)
InvocationContext.class.cast(fallback).setContext(request);
logger.trace("<< exceptions from %s are parsed by %s", commandName, fallback.getClass().getSimpleName());
return fallback;
}
@VisibleForTesting
final class InvokeAndTransform implements Callable
© 2015 - 2025 Weber Informatics LLC | Privacy Policy