com.netflix.hystrix.contrib.javanica.command.AbstractHystrixCommand Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hystrix-javanica Show documentation
Show all versions of hystrix-javanica Show documentation
hystrix-javanica developed by Netflix
The newest version!
/**
* Copyright 2012 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.netflix.hystrix.contrib.javanica.command;
import com.netflix.hystrix.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.cache.CacheInvocationContext;
import com.netflix.hystrix.contrib.javanica.cache.HystrixCacheKeyGenerator;
import com.netflix.hystrix.contrib.javanica.cache.HystrixGeneratedCacheKey;
import com.netflix.hystrix.contrib.javanica.cache.HystrixRequestCacheManager;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;
import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
import com.netflix.hystrix.contrib.javanica.exception.CommandActionExecutionException;
import com.netflix.hystrix.exception.HystrixBadRequestException;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import javax.annotation.concurrent.ThreadSafe;
import java.util.Collection;
import java.util.List;
/**
* Base class for hystrix commands.
*
* @param the return type
*/
@ThreadSafe
public abstract class AbstractHystrixCommand extends com.netflix.hystrix.HystrixCommand {
private final CommandActions commandActions;
private final CacheInvocationContext cacheResultInvocationContext;
private final CacheInvocationContext cacheRemoveInvocationContext;
private final Collection> collapsedRequests;
private final List> ignoreExceptions;
private final ExecutionType executionType;
private final HystrixCacheKeyGenerator defaultCacheKeyGenerator = HystrixCacheKeyGenerator.getInstance();
protected AbstractHystrixCommand(HystrixCommandBuilder builder) {
super(builder.getSetterBuilder().build());
this.commandActions = builder.getCommandActions();
this.collapsedRequests = builder.getCollapsedRequests();
this.cacheResultInvocationContext = builder.getCacheResultInvocationContext();
this.cacheRemoveInvocationContext = builder.getCacheRemoveInvocationContext();
this.ignoreExceptions = builder.getIgnoreExceptions();
this.executionType = builder.getExecutionType();
}
/**
* Gets command action.
*
* @return command action
*/
protected CommandAction getCommandAction() {
return commandActions.getCommandAction();
}
/**
* Gets fallback action.
*
* @return fallback action
*/
protected CommandAction getFallbackAction() {
return commandActions.getFallbackAction();
}
/**
* Gets collapsed requests.
*
* @return collapsed requests
*/
protected Collection> getCollapsedRequests() {
return collapsedRequests;
}
/**
* Gets exceptions types which should be ignored.
*
* @return exceptions types
*/
protected List> getIgnoreExceptions() {
return ignoreExceptions;
}
protected ExecutionType getExecutionType() {
return executionType;
}
/**
* {@inheritDoc}.
*/
@Override
protected String getCacheKey() {
String key = null;
if (cacheResultInvocationContext != null) {
HystrixGeneratedCacheKey hystrixGeneratedCacheKey =
defaultCacheKeyGenerator.generateCacheKey(cacheResultInvocationContext);
key = hystrixGeneratedCacheKey.getCacheKey();
}
return key;
}
/**
* Check whether triggered exception is ignorable.
*
* @param throwable the exception occurred during a command execution
* @return true if exception is ignorable, otherwise - false
*/
boolean isIgnorable(Throwable throwable) {
if (ignoreExceptions == null || ignoreExceptions.isEmpty()) {
return false;
}
for (Class extends Throwable> ignoreException : ignoreExceptions) {
if (ignoreException.isAssignableFrom(throwable.getClass())) {
return true;
}
}
return false;
}
/**
* Executes an action. If an action has failed and an exception is ignorable then propagate it as HystrixBadRequestException
* otherwise propagate original exception to trigger fallback method.
* Note: If an exception occurred in a command directly extends {@link java.lang.Throwable} then this exception cannot be re-thrown
* as original exception because HystrixCommand.run() allows throw subclasses of {@link java.lang.Exception}.
* Thus we need to wrap cause in RuntimeException, anyway in this case the fallback logic will be triggered.
*
* @param action the action
* @return result of command action execution
*/
Object process(Action action) throws Exception {
Object result;
try {
result = action.execute();
flushCache();
} catch (CommandActionExecutionException throwable) {
Throwable cause = throwable.getCause();
if (isIgnorable(cause)) {
throw new HystrixBadRequestException(cause.getMessage(), cause);
}
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Exception) {
throw (Exception) cause;
} else {
// instance of Throwable
throw new CommandActionExecutionException(cause);
}
}
return result;
}
/**
* {@inheritDoc}.
*/
@Override
protected abstract T run() throws Exception;
/**
* {@inheritDoc}.
*/
@Override
protected T getFallback() {
throw new RuntimeException("No fallback available.", getExecutionException());
}
/**
* Clears cache for the specified hystrix command.
*/
protected void flushCache() {
if (cacheRemoveInvocationContext != null) {
HystrixRequestCacheManager.getInstance().clearCache(cacheRemoveInvocationContext);
}
}
/**
* Common action.
*/
abstract class Action {
/**
* Each implementation of this method should wrap any exceptions in CommandActionExecutionException.
*
* @return execution result
* @throws CommandActionExecutionException
*/
abstract Object execute() throws CommandActionExecutionException;
}
/**
* Builder to create error message for failed fallback operation.
*/
static class FallbackErrorMessageBuilder {
private StringBuilder builder = new StringBuilder("failed to processed fallback");
static FallbackErrorMessageBuilder create() {
return new FallbackErrorMessageBuilder();
}
public FallbackErrorMessageBuilder append(CommandAction action, Throwable throwable) {
return commandAction(action).exception(throwable);
}
private FallbackErrorMessageBuilder commandAction(CommandAction action) {
if (action instanceof CommandExecutionAction || action instanceof LazyCommandExecutionAction) {
builder.append(": '").append(action.getActionName()).append("'. ")
.append(action.getActionName()).append(" fallback is a hystrix command. ");
} else if (action instanceof MethodExecutionAction) {
builder.append(" is the method: '").append(action.getActionName()).append("'. ");
}
return this;
}
private FallbackErrorMessageBuilder exception(Throwable throwable) {
if (throwable instanceof HystrixBadRequestException) {
builder.append("exception: '").append(throwable.getCause().getClass())
.append("' occurred in fallback was ignored and wrapped to HystrixBadRequestException.\n");
} else if (throwable instanceof HystrixRuntimeException) {
builder.append("exception: '").append(throwable.getCause().getClass())
.append("' occurred in fallback wasn't ignored.\n");
}
return this;
}
public String build() {
return builder.toString();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy