Package org.axonframework.commandhandling.annotation

Source Code of org.axonframework.commandhandling.annotation.AnnotationCommandTargetResolver

/*
* 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.commandhandling.annotation;

import org.axonframework.commandhandling.CommandMessage;
import org.axonframework.commandhandling.CommandTargetResolver;
import org.axonframework.commandhandling.VersionedAggregateIdentifier;

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

import static java.lang.String.format;
import static org.axonframework.common.ReflectionUtils.*;

/**
* CommandTargetResolver that uses annotations on the command to identify the methods that provide the
* Aggregate Identifier of the targeted Aggregate and optionally the expected version of the aggregate.
* <p/>
* This implementation expects at least one method (without parameters) or field in the command to be annotated with
* {@link TargetAggregateIdentifier}. If on a method, the result of the invocation of that method will used as
* Aggregate Identifier. If on a field, the value held in that field is used.
* <p/>
* Similarly, the expected aggregate version may be provided by annotating a method (without parameters) or field with
* {@link TargetAggregateVersion}. The return value of the method or value held in the field is used as the expected
* version. Note that the method must return a Long value, or a value that may be parsed as a Long.
*
* @author Allard Buijze
* @since 1.2
*/
public class AnnotationCommandTargetResolver implements CommandTargetResolver {

    @Override
    public VersionedAggregateIdentifier resolveTarget(CommandMessage<?> command) {
        Object aggregateIdentifier;
        Long aggregateVersion;
        try {
            aggregateIdentifier = findIdentifier(command);
            aggregateVersion = findVersion(command);
        } catch (InvocationTargetException e) {
            throw new IllegalArgumentException("An exception occurred while extracting aggregate "
                                                       + "information form a command", e);
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException("The current security context does not allow extraction of "
                                                       + "aggregate information from the given command.", e);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("The value provided for the version is not a number.", e);
        }
        if (aggregateIdentifier == null) {
            throw new IllegalArgumentException(
                    format("Invalid command. It does not identify the target aggregate. "
                                   + "Make sure at least one of the fields or methods in the [%s] class contains the "
                                   + "@TargetAggregateIdentifier annotation and that it returns a non-null value.",
                           command.getPayloadType().getSimpleName()));
        }
        return new VersionedAggregateIdentifier(aggregateIdentifier, aggregateVersion);
    }

    @SuppressWarnings("unchecked")
    private <I> I findIdentifier(CommandMessage<?> command)
            throws InvocationTargetException, IllegalAccessException {
        for (Method m : methodsOf(command.getPayloadType())) {
            if (m.isAnnotationPresent(TargetAggregateIdentifier.class)) {
                ensureAccessible(m);
                return (I) m.invoke(command.getPayload());
            }
        }
        for (Field f : fieldsOf(command.getPayloadType())) {
            if (f.isAnnotationPresent(TargetAggregateIdentifier.class)) {
                return (I) getFieldValue(f, command.getPayload());
            }
        }
        return null;
    }

    private Long findVersion(CommandMessage<?> command) throws InvocationTargetException, IllegalAccessException {
        for (Method m : methodsOf(command.getPayloadType())) {
            if (m.isAnnotationPresent(TargetAggregateVersion.class)) {
                ensureAccessible(m);
                return asLong(m.invoke(command.getPayload()));
            }
        }
        for (Field f : fieldsOf(command.getPayloadType())) {
            if (f.isAnnotationPresent(TargetAggregateVersion.class)) {
                return asLong(getFieldValue(f, command.getPayload()));
            }
        }
        return null;
    }

    private Long asLong(Object fieldValue) {
        if (fieldValue == null) {
            return null;
        } else if (Number.class.isInstance(fieldValue)) {
            return ((Number) fieldValue).longValue();
        } else {
            return Long.parseLong(fieldValue.toString());
        }
    }
}
TOP

Related Classes of org.axonframework.commandhandling.annotation.AnnotationCommandTargetResolver

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.