/** * Initiates a new AnnotatedChildEntity instance that uses the provided {@code entityModel} to delegate command * and event handling to an annotated child entity. * * @param entityModel A {@link EntityModel} describing the entity. * @param forwardCommands Flag indicating whether commands should be forwarded to the entity. * @param commandTargetResolver Resolver for command handler methods on the target. * @param eventTargetResolver Resolver for event handler methods on the target. */ @SuppressWarnings("unchecked") public AnnotatedChildEntity(EntityModel<C> entityModel, boolean forwardCommands, BiFunction<CommandMessage<?>, P, C> commandTargetResolver, BiFunction<EventMessage<?>, P, Stream<C>> eventTargetResolver) { this.entityModel = entityModel; this.eventTargetResolver = eventTargetResolver; this.commandHandlers = new ArrayList<>(); if (forwardCommands) { entityModel.commandHandlers() .stream() .filter(eh -> eh.unwrap(CommandMessageHandlingMember.class).isPresent()) .forEach( (childHandler) -> commandHandlers .add(new ChildForwardingCommandMessageHandlingMember<>( entityModel.commandHandlerInterceptors(), childHandler, commandTargetResolver))); } }
@SuppressWarnings("unchecked") private <E> boolean matchesInstance(E candidate, Object routingValue) { Object identifier = childEntity.getIdentifier(candidate); return Objects.equals(routingValue, identifier); } }
@Override protected <T> EntityModel<Object> extractChildEntityModel(EntityModel<T> declaringEntity, Map<String, Object> attributes, Field field) { return declaringEntity.modelOf(field.getType()); }
@Override public void initialize(Field field, EntityModel childEntity) { this.childEntity = childEntity; this.routingKey = findAnnotationAttributes(field, AggregateMember.class) .map(map -> (String) map.get("routingKey")) .filter(key -> !Objects.equals(key, EMPTY_STRING)) .orElse(childEntity.routingKey()); }
@SuppressWarnings("unchecked") @Override public void publish(EventMessage<?> msg, P declaringInstance) { eventTargetResolver.apply(msg, declaringInstance) .collect(Collectors.toList()) // Creates copy to prevent ConcurrentModificationException. .forEach(target -> entityModel.publish(msg, target)); }
/** * Retrieves the routing keys of every command handler on the given {@code childEntityModel} to be able to correctly * route commands to Entities. * * @param field a {@link java.lang.reflect.Field} denoting the Child Entity upon which the {@code * childEntityModel} is based. * @param childEntityModel a {@link EntityModel} to retrieve the * routing key properties from. * @return a {@link java.util.Map} of key/value types {@link java.lang.String}/ * {@link org.axonframework.common.property.Property} from Command Message name to routing key. */ @SuppressWarnings("WeakerAccess") protected Map<String, Property<Object>> extractCommandHandlerRoutingKeys(Field field, EntityModel<Object> childEntityModel) { return childEntityModel.commandHandlers() .stream() .map(commandHandler -> commandHandler.unwrap(CommandMessageHandlingMember.class) .orElse(null)) .filter(Objects::nonNull) .collect(Collectors.toMap( CommandMessageHandlingMember::commandName, commandHandler -> extractCommandHandlerRoutingKey(childEntityModel, commandHandler, field ) )); }
@SuppressWarnings("unchecked") private Property<Object> extractCommandHandlerRoutingKey(EntityModel<Object> childEntityModel, CommandMessageHandlingMember commandHandler, Field field) { String routingKey = getOrDefault(commandHandler.routingKey(), childEntityModel.routingKey()); Property<Object> property = getProperty(commandHandler.payloadType(), routingKey); if (property == null) { throw new AxonConfigurationException(format( "Command of type [%s] doesn't have a property matching the routing key [%s] necessary to route through field [%s]", commandHandler.payloadType(), routingKey, field.toGenericString()) ); } return property; }
@SuppressWarnings("unchecked") @Override public void publish(EventMessage<?> msg, P declaringInstance) { eventTargetResolver.apply(msg, declaringInstance) .collect(Collectors.toList()) // Creates copy to prevent ConcurrentModificationException. .forEach(target -> entityModel.publish(msg, target)); }
/** * Retrieves the routing keys of every command handler on the given {@code childEntityModel} to be able to correctly * route commands to Entities. * * @param field a {@link java.lang.reflect.Field} denoting the Child Entity upon which the {@code * childEntityModel} is based. * @param childEntityModel a {@link EntityModel} to retrieve the * routing key properties from. * @return a {@link java.util.Map} of key/value types {@link java.lang.String}/ * {@link org.axonframework.common.property.Property} from Command Message name to routing key. */ @SuppressWarnings("WeakerAccess") protected Map<String, Property<Object>> extractCommandHandlerRoutingKeys(Field field, EntityModel<Object> childEntityModel) { return childEntityModel.commandHandlers() .stream() .map(commandHandler -> commandHandler.unwrap(CommandMessageHandlingMember.class) .orElse(null)) .filter(Objects::nonNull) .collect(Collectors.toMap( CommandMessageHandlingMember::commandName, commandHandler -> extractCommandHandlerRoutingKey(childEntityModel, commandHandler, field ) )); }
/** * Initiates a new AnnotatedChildEntity instance that uses the provided {@code entityModel} to delegate command * and event handling to an annotated child entity. * * @param entityModel A {@link EntityModel} describing the entity. * @param forwardCommands Flag indicating whether commands should be forwarded to the entity. * @param commandTargetResolver Resolver for command handler methods on the target. * @param eventTargetResolver Resolver for event handler methods on the target. */ @SuppressWarnings("unchecked") public AnnotatedChildEntity(EntityModel<C> entityModel, boolean forwardCommands, BiFunction<CommandMessage<?>, P, C> commandTargetResolver, BiFunction<EventMessage<?>, P, Stream<C>> eventTargetResolver) { this.entityModel = entityModel; this.eventTargetResolver = eventTargetResolver; this.commandHandlers = new ArrayList<>(); if (forwardCommands) { entityModel.commandHandlers() .stream() .filter(eh -> eh.unwrap(CommandMessageHandlingMember.class).isPresent()) .forEach( (childHandler) -> commandHandlers .add(new ChildForwardingCommandMessageHandlingMember<>( entityModel.commandHandlerInterceptors(), childHandler, commandTargetResolver))); } }
@Override protected <T> EntityModel<Object> extractChildEntityModel(EntityModel<T> declaringEntity, Map<String, Object> attributes, Field field) { Class<?> entityType = (Class<?>) attributes.get("type"); if (Void.class.equals(entityType)) { entityType = resolveGenericType(field, 0).orElseThrow( () -> new AxonConfigurationException(format( "Unable to resolve entity type of field [%s]. Please provide type explicitly in @AggregateMember annotation.", field.toGenericString() ))); } return declaringEntity.modelOf(entityType); }
@Override public void initialize(Field field, EntityModel childEntity) { this.childEntity = childEntity; this.routingKey = findAnnotationAttributes(field, AggregateMember.class) .map(map -> (String) map.get("routingKey")) .filter(key -> !Objects.equals(key, EMPTY_STRING)) .orElse(childEntity.routingKey()); }
@Override protected <T> Object resolveCommandTarget(CommandMessage<?> msg, T parent, Field field, EntityModel<Object> childEntityModel) { Map<String, Property<Object>> commandHandlerRoutingKeys = extractCommandHandlerRoutingKeys(field, childEntityModel); Object routingValue = commandHandlerRoutingKeys.get(msg.getCommandName()) .getValue(msg.getPayload()); Iterable<?> iterable = ReflectionUtils.getFieldValue(field, parent); return StreamSupport.stream(iterable.spliterator(), false) .filter(i -> Objects.equals(routingValue, childEntityModel.getIdentifier(i))) .findFirst() .orElse(null); }
@Override protected <T> EntityModel<Object> extractChildEntityModel(EntityModel<T> declaringEntity, Map<String, Object> attributes, Field field) { Class<?> entityType = (Class<?>) attributes.get("type"); if (Void.class.equals(entityType)) { entityType = resolveGenericType(field, 1).orElseThrow( () -> new AxonConfigurationException(format( "Unable to resolve entity type of field [%s]. Please provide type explicitly in @AggregateMember annotation.", field.toGenericString() ))); } return declaringEntity.modelOf(entityType); }
@SuppressWarnings("unchecked") private Property<Object> extractCommandHandlerRoutingKey(EntityModel<Object> childEntityModel, CommandMessageHandlingMember commandHandler, Field field) { String routingKey = getOrDefault(commandHandler.routingKey(), childEntityModel.routingKey()); Property<Object> property = getProperty(commandHandler.payloadType(), routingKey); if (property == null) { throw new AxonConfigurationException(format( "Command of type [%s] doesn't have a property matching the routing key [%s] necessary to route through field [%s]", commandHandler.payloadType(), routingKey, field.toGenericString()) ); } return property; }
@SuppressWarnings("unchecked") private <E> boolean matchesInstance(E candidate, Object routingValue) { Object identifier = childEntity.getIdentifier(candidate); return Objects.equals(routingValue, identifier); } }
@Override protected <T> EntityModel<Object> extractChildEntityModel(EntityModel<T> declaringEntity, Map<String, Object> attributes, Field field) { return declaringEntity.modelOf(field.getType()); }
@Override protected <T> Object resolveCommandTarget(CommandMessage<?> msg, T parent, Field field, EntityModel<Object> childEntityModel) { Map<String, Property<Object>> commandHandlerRoutingKeys = extractCommandHandlerRoutingKeys(field, childEntityModel); Object routingValue = commandHandlerRoutingKeys.get(msg.getCommandName()) .getValue(msg.getPayload()); Iterable<?> iterable = ReflectionUtils.getFieldValue(field, parent); return StreamSupport.stream(iterable.spliterator(), false) .filter(i -> Objects.equals(routingValue, childEntityModel.getIdentifier(i))) .findFirst() .orElse(null); }
@Override protected <T> EntityModel<Object> extractChildEntityModel(EntityModel<T> declaringEntity, Map<String, Object> attributes, Field field) { Class<?> entityType = (Class<?>) attributes.get("type"); if (Void.class.equals(entityType)) { entityType = resolveGenericType(field, 0).orElseThrow( () -> new AxonConfigurationException(format( "Unable to resolve entity type of field [%s]. Please provide type explicitly in @AggregateMember annotation.", field.toGenericString() ))); } return declaringEntity.modelOf(entityType); }
@Override protected <T> EntityModel<Object> extractChildEntityModel(EntityModel<T> declaringEntity, Map<String, Object> attributes, Field field) { Class<?> entityType = (Class<?>) attributes.get("type"); if (Void.class.equals(entityType)) { entityType = resolveGenericType(field, 1).orElseThrow( () -> new AxonConfigurationException(format( "Unable to resolve entity type of field [%s]. Please provide type explicitly in @AggregateMember annotation.", field.toGenericString() ))); } return declaringEntity.modelOf(entityType); }