@Override public <T> Message<T> convertToOutboundMessage(EventMessage<T> event) { Map<String, Object> headers = new HashMap<>(); event.getMetaData().forEach(headers::put); headers.put(MESSAGE_ID, event.getIdentifier()); if (event instanceof DomainEventMessage) { headers.put(AGGREGATE_ID, ((DomainEventMessage) event).getAggregateIdentifier()); headers.put(AGGREGATE_SEQ, ((DomainEventMessage) event).getSequenceNumber()); headers.put(AGGREGATE_TYPE, ((DomainEventMessage) event).getType()); } return new GenericMessage<>(event.getPayload(), new SettableTimestampMessageHeaders(headers, event.getTimestamp().toEpochMilli())); }
private void doPublish(EventMessage<?> message, T target) { getHandler(message).ifPresent(h -> { try { h.handle(message, target); } catch (Exception e) { throw new MessageHandlerInvocationException( format("Error handling event of type [%s] in aggregate", message.getPayloadType()), e); } }); children.forEach(i -> i.publish(message, target)); }
/** * Construct a new event entry from a published event message to enable storing the event or sending it to a remote * location. * <p> * The given {@code serializer} will be used to serialize the payload and metadata in the given {@code eventMessage}. * The type of the serialized data will be the same as the given {@code contentType}. * * @param eventMessage The event message to convert to a serialized event entry * @param serializer The serializer to convert the event * @param contentType The data type of the payload and metadata after serialization */ public AbstractEventEntry(EventMessage<?> eventMessage, Serializer serializer, Class<T> contentType) { SerializedObject<T> payload = eventMessage.serializePayload(serializer, contentType); SerializedObject<T> metaData = eventMessage.serializeMetaData(serializer, contentType); this.eventIdentifier = eventMessage.getIdentifier(); this.payloadType = payload.getType().getName(); this.payloadRevision = payload.getType().getRevision(); this.payload = payload.getData(); this.metaData = metaData.getData(); this.timeStamp = formatInstant(eventMessage.getTimestamp()); }
@Override public void onError(Exception exception, EventMessage<?> event, EventMessageHandler eventHandler) { logger.error("EventListener [{}] failed to handle event [{}] ({}). " + "Continuing processing with next listener", eventHandler.getTargetType().getSimpleName(), event.getIdentifier(), event.getPayloadType().getName(), exception); } }
private EventMessage<Object> timeCorrectedEventMessage(Object event) { EventMessage<?> msg = GenericEventMessage.asEventMessage(event); return new GenericEventMessage<>(msg.getIdentifier(), msg.getPayload(), msg.getMetaData(), currentTime()); }
@Override public ResultValidator<T> expectEvents(EventMessage... expectedEvents) { this.expectEvents(Stream.of(expectedEvents).map(Message::getPayload).toArray()); Iterator<EventMessage<?>> iterator = publishedEvents.iterator(); for (EventMessage expectedEvent : expectedEvents) { EventMessage actualEvent = iterator.next(); if (!verifyMetaDataEquality(expectedEvent.getPayloadType(), expectedEvent.getMetaData(), actualEvent.getMetaData())) { reporter.reportWrongEvent(publishedEvents, Arrays.asList(expectedEvents), actualException); } } return this; }
/** * Creates a new message for the scheduled event. This ensures that a new identifier and timestamp will always * be generated, so that the timestamp will reflect the actual moment the trigger occurred. * * @param event The actual event (either a payload or an entire message) to create the message from * @return the message to publish */ private EventMessage<?> createMessage(Object event) { EventMessage<?> eventMessage; if (event instanceof EventMessage) { eventMessage = new GenericEventMessage<>(((EventMessage) event).getPayload(), ((EventMessage) event).getMetaData()); } else { eventMessage = new GenericEventMessage<>(event, MetaData.emptyInstance()); } return eventMessage; } }
public Event map(EventMessage<?> eventMessage, Serializer serializer) { Event.Builder builder = Event.newBuilder(); if (eventMessage instanceof GenericDomainEventMessage) { builder.setAggregateIdentifier(((GenericDomainEventMessage) eventMessage).getAggregateIdentifier()) .setAggregateSequenceNumber(((GenericDomainEventMessage) eventMessage).getSequenceNumber()) .setAggregateType(((GenericDomainEventMessage) eventMessage).getType()); } SerializedObject<byte[]> serializedPayload = eventMessage.serializePayload(serializer, byte[].class); builder.setMessageIdentifier(eventMessage.getIdentifier()).setPayload( io.axoniq.axonserver.grpc.SerializedObject.newBuilder() .setType(serializedPayload.getType().getName()) .setRevision(getOrDefault( serializedPayload.getType().getRevision(), "" )) .setData(ByteString.copyFrom(serializedPayload.getData())) ).setTimestamp(eventMessage.getTimestamp().toEpochMilli()); eventMessage.getMetaData().forEach((k, v) -> builder.putMetaData(k, converter.convertToMetaDataValue(v))); return builder.build(); }
@SuppressWarnings("rawtypes") public static KafkaMessage createKafkaMessage(final Serializer serializer, final EventMessage<?> eventMessage) { final SerializedObject<byte[]> serializedObject = serializePayload(eventMessage, serializer, byte[].class); final Map<String, Object> headers = new HashMap<>(); eventMessage.getMetaData().forEach((k, v) -> headers.put("axon-metadata-" + k, v)); headers.put("axon-message-id", eventMessage.getIdentifier()); headers.put("axon-message-type", serializedObject.getType().getName()); headers.put("axon-message-revision", serializedObject.getType().getRevision()); headers.put("axon-message-timestamp", eventMessage.getTimestamp().toString()); if (eventMessage instanceof DomainEventMessage) { headers.put("axon-message-aggregate-id", ((DomainEventMessage) eventMessage).getAggregateIdentifier()); headers.put("axon-message-aggregate-seq", ((DomainEventMessage) eventMessage).getSequenceNumber()); headers.put("axon-message-aggregate-type", ((DomainEventMessage) eventMessage).getType()); } final KafkaPayload payload = new KafkaPayload(headers, serializedObject.getData()); final SerializedObject<byte[]> serializedKafkaPayload = serializer.serialize(payload, byte[].class); return new KafkaMessage(eventMessage.getTimestamp().toString(), serializedKafkaPayload.getData()); }
/** * Generate defaults headers to recognise an event message. * * @param message event message. * @param serializedObject payload. * @return headers */ public static Map<String, Object> defaultHeaders(EventMessage<?> message, SerializedObject<?> serializedObject) { Assert.notNull(message, () -> "Event message cannot be null"); Assert.notNull(serializedObject, () -> "Serialized Object cannot be null"); Assert.notNull(serializedObject.getType(), () -> "SerializedObject Type cannot be null"); HashMap<String, Object> headers = new HashMap<>(); headers.put(MESSAGE_ID, message.getIdentifier()); headers.put(MESSAGE_TYPE, serializedObject.getType().getName()); headers.put(MESSAGE_REVISION, serializedObject.getType().getRevision()); headers.put(MESSAGE_TIMESTAMP, message.getTimestamp()); if (message instanceof DomainEventMessage) { headers.put(AGGREGATE_ID, ((DomainEventMessage<?>) message).getAggregateIdentifier()); headers.put(AGGREGATE_SEQ, ((DomainEventMessage<?>) message).getSequenceNumber()); headers.put(AGGREGATE_TYPE, ((DomainEventMessage<?>) message).getType()); } return Collections.unmodifiableMap(headers); }
/** * Convert a plain {@link EventMessage} to a {@link DomainEventMessage}. If the message already is a {@link * DomainEventMessage} it will be returned as is. Otherwise a new {@link GenericDomainEventMessage} is made with * {@code null} type, aggegrateIdentifier equal to messageIdentifier and sequence number of 0L. * * @param eventMessage the input event message * @param <T> The type of payload in the message * @return the message converted to a domain event message */ public static <T> DomainEventMessage<T> asDomainEventMessage(EventMessage<T> eventMessage) { if (eventMessage instanceof DomainEventMessage<?>) { return (DomainEventMessage<T>) eventMessage; } return new GenericDomainEventMessage<>(null, eventMessage.getIdentifier(), 0L, eventMessage, eventMessage::getTimestamp); }
private String payloadContentType(Object event) { String simpleName; if (EventMessage.class.isInstance(event)) { simpleName = ((EventMessage) event).getPayload().getClass().getName(); } else { simpleName = event.getClass().getName(); } return simpleName; }
@Override public Instant resolveParameterValue(Message message) { if (message instanceof EventMessage) { return ((EventMessage) message).getTimestamp(); } return null; }
/** * Finds the association property value by looking up the association property name in the event message's * {@link org.axonframework.messaging.MetaData}. */ @Override public <T> Object resolve(String associationPropertyName, EventMessage<?> message, MessageHandlingMember<T> handler) { return message.getMetaData().get(associationPropertyName); } }
@Override public AMQPMessage createAMQPMessage(EventMessage<?> eventMessage) { SerializedObject<byte[]> serializedObject = eventMessage.serializePayload(serializer, byte[].class); String routingKey = routingKeyResolver.resolveRoutingKey(eventMessage); AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder(); Map<String, Object> headers = new HashMap<>(); eventMessage.getMetaData().forEach((k, v) -> headers.put(Headers.MESSAGE_METADATA + "-" + k, v)); Headers.defaultHeaders(eventMessage, serializedObject).forEach((k, v) -> { if (k.equals(MESSAGE_TIMESTAMP)) { headers.put(k, formatInstant(eventMessage.getTimestamp())); } else { headers.put(k, v); } }); properties.headers(headers); if (durable) { properties.deliveryMode(2); } return new AMQPMessage(serializedObject.getData(), routingKey, properties.build(), false, false); }
@Override public AMQPMessage createAMQPMessage(EventMessage<?> eventMessage) { SerializedObject<byte[]> serializedObject = serializePayload(eventMessage, serializer, byte[].class); String routingKey = routingKeyResolver.resolveRoutingKey(eventMessage); AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties.Builder(); Map<String, Object> headers = new HashMap<>(); eventMessage.getMetaData().forEach((k, v) -> headers.put(Headers.MESSAGE_METADATA + "-" + k, v)); Headers.defaultHeaders(eventMessage, serializedObject).forEach((k, v) -> { if (k.equals(MESSAGE_TIMESTAMP)) { headers.put(k, formatInstant(eventMessage.getTimestamp())); } else { headers.put(k, v); } }); properties.headers(headers); if (durable) { properties.deliveryMode(2); } return new AMQPMessage(serializedObject.getData(), routingKey, properties.build(), false, false); }
@Override protected void publishOnEventBus(EventMessage<?> msg) { if (!initializing) { // force conversion of LazyIdentifierDomainEventMessage to Generic to release reference to Aggregate. super.publishOnEventBus(msg.andMetaData(Collections.emptyMap())); } }
@Override public ProducerRecord<String, byte[]> createKafkaMessage(EventMessage<?> eventMessage, String topic) { SerializedObject<byte[]> serializedObject = eventMessage.serializePayload(serializer, byte[].class); byte[] payload = serializedObject.getData(); return new ProducerRecord<>(topic, null, null, key(eventMessage), payload, toHeaders(eventMessage, serializedObject, headerValueMapper)); }
/** * Creates a new message for the scheduled event. This ensures that a new identifier and timestamp will always * be generated, so that the timestamp will reflect the actual moment the trigger occurred. * * @return the message to publish */ private EventMessage<?> createMessage() { EventMessage<?> eventMessage; if (event instanceof EventMessage) { eventMessage = new GenericEventMessage<>(((EventMessage) event).getPayload(), ((EventMessage) event).getMetaData()); } else { eventMessage = new GenericEventMessage<>(event, MetaData.emptyInstance()); } return eventMessage; } }
public Event map(EventMessage<?> eventMessage, Serializer serializer) { Event.Builder builder = Event.newBuilder(); if (eventMessage instanceof GenericDomainEventMessage) { builder.setAggregateIdentifier(((GenericDomainEventMessage) eventMessage).getAggregateIdentifier()) .setAggregateSequenceNumber(((GenericDomainEventMessage) eventMessage).getSequenceNumber()) .setAggregateType(((GenericDomainEventMessage) eventMessage).getType()); } SerializedObject<byte[]> serializedPayload = eventMessage.serializePayload(serializer, byte[].class); builder.setMessageIdentifier(eventMessage.getIdentifier()).setPayload( io.axoniq.axonserver.grpc.SerializedObject.newBuilder() .setType(serializedPayload.getType().getName()) .setRevision(getOrDefault( serializedPayload.getType().getRevision(), "" )) .setData(ByteString.copyFrom(serializedPayload.getData())) ).setTimestamp(eventMessage.getTimestamp().toEpochMilli()); eventMessage.getMetaData().forEach((k, v) -> builder.putMetaData(k, converter.convertToMetaDataValue(v))); return builder.build(); }