Package com.netflix.hystrix.contrib.javanica.command

Source Code of com.netflix.hystrix.contrib.javanica.command.AbstractHystrixCommand$FallbackErrorMessageBuilder

/**
* 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.google.common.base.Throwables;
import com.netflix.hystrix.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
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.Map;

/**
* Base class for hystrix commands.
*
* @param <T> the return type
*/
@ThreadSafe
public abstract class AbstractHystrixCommand<T> extends com.netflix.hystrix.HystrixCommand<T> {

    private CommandActions commandActions;
    private final Map<String, Object> commandProperties;
    private final Collection<HystrixCollapser.CollapsedRequest<Object, Object>> collapsedRequests;
    private final Class<? extends Throwable>[] ignoreExceptions;
    private final ExecutionType executionType;

    /**
     * Constructor with parameters.
     *
     * @param setterBuilder     the builder to build {@link com.netflix.hystrix.HystrixCommand.Setter}
     * @param commandActions    the command actions {@link CommandActions}
     * @param commandProperties the command properties
     * @param collapsedRequests the collapsed requests
     * @param ignoreExceptions  the exceptions which should be ignored and wrapped to throw in {@link HystrixBadRequestException}
     * @param executionType     the execution type {@link ExecutionType}
     */
    protected AbstractHystrixCommand(CommandSetterBuilder setterBuilder,
                                     CommandActions commandActions,
                                     Map<String, Object> commandProperties,
                                     Collection<HystrixCollapser.CollapsedRequest<Object, Object>> collapsedRequests,
                                     final Class<? extends Throwable>[] ignoreExceptions,
                                     ExecutionType executionType) {
        super(setterBuilder.build());
        this.commandActions = commandActions;
        this.commandProperties = commandProperties;
        this.collapsedRequests = collapsedRequests;
        this.ignoreExceptions = ignoreExceptions;
        this.executionType = executionType;
        HystrixPropertiesManager.setCommandProperties(commandProperties, getCommandKey().name());
    }

    /**
     * Gets command action.
     *
     * @return command action
     */
    CommandAction getCommandAction() {
        return commandActions.getCommandAction();
    }

    /**
     * Gets fallback action.
     *
     * @return fallback action
     */
    CommandAction getFallbackAction() {
        return commandActions.getFallbackAction();
    }

    /**
     * Gets key action.
     *
     * @return key action
     */
    CommandAction getCacheKeyAction() {
        return commandActions.getCacheKeyAction();
    }

    /**
     * Gets command properties.
     *
     * @return command properties
     */
    Map<String, Object> getCommandProperties() {
        return commandProperties;
    }

    /**
     * Gets collapsed requests.
     *
     * @return collapsed requests
     */
    Collection<HystrixCollapser.CollapsedRequest<Object, Object>> getCollapsedRequests() {
        return collapsedRequests;
    }

    /**
     * Gets exceptions types which should be ignored.
     *
     * @return exceptions types
     */
    Class<? extends Throwable>[] getIgnoreExceptions() {
        return ignoreExceptions;
    }

    public ExecutionType getExecutionType() {
        return executionType;
    }

    /**
     * {@inheritDoc}.
     */
    @Override
    protected String getCacheKey() {
        String key;
        if (commandActions.getCacheKeyAction() != null) {
            key = String.valueOf(commandActions.getCacheKeyAction().execute(executionType));
        } else {
            key = super.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.length == 0) {
            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();
        } catch (CommandActionExecutionException throwable) {
            Throwable cause = throwable.getCause();
            if (isIgnorable(cause)) {
                throw new HystrixBadRequestException(cause.getMessage(), cause);
            }
            if (cause instanceof Exception) {
                throw (Exception) cause;
            } else {
                throw Throwables.propagate(cause);
            }
        }
        return result;
    }

    /**
     * {@inheritDoc}.
     */
    @Override
    protected abstract T run() throws Exception;

    /**
     * {@inheritDoc}.
     */
    @Override
    protected T getFallback() {
        throw new RuntimeException("No fallback available.", getFailedExecutionException());
    }

    /**
     * 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();
        }
    }

}
TOP

Related Classes of com.netflix.hystrix.contrib.javanica.command.AbstractHystrixCommand$FallbackErrorMessageBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.