Package org.axonframework.saga.annotation

Source Code of org.axonframework.saga.annotation.SagaMethodMessageHandler

/*
* Copyright (c) 2010-2014. Axon Framework
*
* 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 org.axonframework.saga.annotation;

import org.axonframework.common.AxonConfigurationException;
import org.axonframework.common.annotation.MessageHandlerInvocationException;
import org.axonframework.common.annotation.MethodMessageHandler;
import org.axonframework.common.property.Property;
import org.axonframework.common.property.PropertyAccessStrategy;
import org.axonframework.domain.EventMessage;
import org.axonframework.saga.AssociationValue;
import org.axonframework.saga.SagaCreationPolicy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static java.lang.String.format;

/**
* A data holder containing information of {@link SagaEventHandler} annotated methods.
*
* @author Allard Buijze
* @since 2.0
*/
public class SagaMethodMessageHandler implements Comparable<SagaMethodMessageHandler> {

    private static final SagaMethodMessageHandler NO_HANDLER_CONFIGURATION =
            new SagaMethodMessageHandler(SagaCreationPolicy.NONE, null, null, null);

    /**
     * Returns a SagaMethodMessageHandler indicating that a inspected method is *not* a SagaEventHandler.
     *
     * @return a SagaMethodMessageHandler indicating that a inspected method is *not* a SagaEventHandler
     */
    public static SagaMethodMessageHandler noHandler() {
        return NO_HANDLER_CONFIGURATION;
    }

    private final SagaCreationPolicy creationPolicy;
    private final MethodMessageHandler handlerMethod;
    private final String associationKey;
    private final Property associationProperty;

    /**
     * Create a SagaMethodMessageHandler for the given <code>methodHandler</code>. The SagaMethodMessageHandler add
     * information specific to the behavior of Sagas, such as the association value and creation policy.
     *
     * @param methodHandler The handler for incoming events
     * @return a SagaMethodMessageHandler for the handler
     */
    @SuppressWarnings("unchecked")
    public static SagaMethodMessageHandler getInstance(MethodMessageHandler methodHandler) {
        Method handlerMethod = methodHandler.getMethod();
        SagaEventHandler handlerAnnotation = handlerMethod.getAnnotation(SagaEventHandler.class);
        String associationPropertyName = handlerAnnotation.associationProperty();
        Property associationProperty = PropertyAccessStrategy.getProperty(methodHandler.getPayloadType(),
                                                                          associationPropertyName);
        if (associationProperty == null) {
            throw new AxonConfigurationException(format("SagaEventHandler %s.%s defines a property %s that is not "
                                                                + "defined on the Event it declares to handle (%s)",
                                                        methodHandler.getMethod().getDeclaringClass().getName(),
                                                        methodHandler.getMethodName(), associationPropertyName,
                                                        methodHandler.getPayloadType().getName()
            ));
        }
        String associationKey = handlerAnnotation.keyName().isEmpty()
                ? associationPropertyName
                : handlerAnnotation.keyName();
        StartSaga startAnnotation = handlerMethod.getAnnotation(StartSaga.class);
        SagaCreationPolicy sagaCreationPolicy;
        if (startAnnotation == null) {
            sagaCreationPolicy = SagaCreationPolicy.NONE;
        } else if (startAnnotation.forceNew()) {
            sagaCreationPolicy = SagaCreationPolicy.ALWAYS;
        } else {
            sagaCreationPolicy = SagaCreationPolicy.IF_NONE_FOUND;
        }

        return new SagaMethodMessageHandler(sagaCreationPolicy, methodHandler, associationKey, associationProperty);
    }

    /**
     * Creates a SagaMethodMessageHandler.
     *
     * @param creationPolicy      The creation policy for the handlerMethod
     * @param handler             The handler for the event
     * @param associationKey      The association key configured for this handler
     * @param associationProperty The association property configured for this handler
     */
    protected SagaMethodMessageHandler(SagaCreationPolicy creationPolicy, MethodMessageHandler handler,
                                       String associationKey, Property associationProperty) {
        this.creationPolicy = creationPolicy;
        this.handlerMethod = handler;
        this.associationKey = associationKey;
        this.associationProperty = associationProperty;
    }

    /**
     * Indicates whether the inspected method is an Event Handler.
     *
     * @return true if the saga has a handler
     */
    public boolean isHandlerAvailable() {
        return handlerMethod != null;
    }

    /**
     * The AssociationValue to find the saga instance with, or <code>null</code> if no AssociationValue can be found on
     * the given <code>eventMessage</code>.
     *
     * @param eventMessage The event message containing the value of the association
     * @return the AssociationValue to find the saga instance with, or <code>null</code> if none found
     */
    @SuppressWarnings("unchecked")
    public AssociationValue getAssociationValue(EventMessage eventMessage) {
        if (associationProperty == null) {
            return null;
        }

        Object associationValue = associationProperty.getValue(eventMessage.getPayload());
        return associationValue == null ? null : new AssociationValue(associationKey, associationValue.toString());
    }

    /**
     * Returns the creation policy of the inspected method.
     *
     * @return the creation policy of the inspected method
     */
    public SagaCreationPolicy getCreationPolicy() {
        return creationPolicy;
    }

    /**
     * Indicates whether this Handler is suitable for the given <code>message</code>.
     *
     * @param message The message to inspect
     * @return <code>true</code> if this handler can handle the message, otherwise <code>false</code>.
     */
    public boolean matches(EventMessage message) {
        return handlerMethod != null && handlerMethod.matches(message);
    }

    /**
     * Indicates whether this handler is one that ends the Saga lifecycle
     *
     * @return <code>true</code> if the Saga lifecycle ends unconditionally after this call, otherwise
     * <code>false</code>
     */
    public boolean isEndingHandler() {
        return handlerMethod != null && handlerMethod.getMethod().isAnnotationPresent(EndSaga.class);
    }

    @Override
    public int compareTo(SagaMethodMessageHandler o) {
        if (this.handlerMethod == null && o.handlerMethod == null) {
            return 0;
        } else if (this.handlerMethod == null) {
            return -1;
        } else if (o.handlerMethod == null) {
            return 1;
        }
        final int handlerEquality = handlerMethod.compareTo(o.handlerMethod);
        if (handlerEquality == 0) {
            return o.handlerMethod.getMethod().getParameterTypes().length
                    - this.handlerMethod.getMethod().getParameterTypes().length;
        }
        return handlerEquality;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        SagaMethodMessageHandler that = (SagaMethodMessageHandler) o;

        return this.compareTo(that) != 0;
    }

    @Override
    public int hashCode() {
        return handlerMethod != null ? handlerMethod.hashCode() : 0;
    }

    /**
     * Invoke a handler on given <code>target</code> for given <code>message</code>.
     *
     * @param target  The instance to invoke a method on
     * @param message The message to use to resolve the parameters of the handler to invoke
     */
    public void invoke(Object target, EventMessage message) {
        if (!isHandlerAvailable()) {
            return;
        }
        try {
            handlerMethod.invoke(target, message);
        } catch (IllegalAccessException e) {
            throw new MessageHandlerInvocationException("Access to the message handler method was denied.", e);
        } catch (InvocationTargetException e) {
            if (e.getCause() instanceof RuntimeException) {
                throw (RuntimeException) e.getCause();
            }
            throw new MessageHandlerInvocationException("An exception occurred while invoking the handler method.", e);
        }
    }

    /**
     * Returns the name of the handler.
     *
     * @return the name of the handler
     */
    public String getName() {
        return handlerMethod.getMethodName();
    }
}
TOP

Related Classes of org.axonframework.saga.annotation.SagaMethodMessageHandler

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.