All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.azure.eventhubs.EventData Maven / Gradle / Ivy

There is a newer version: 3.3.0
Show newest version
/*
 * Copyright (c) Microsoft. All rights reserved.
 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
 */
package com.microsoft.azure.eventhubs;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.time.Instant;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.qpid.proton.Proton;
import org.apache.qpid.proton.amqp.Binary;
import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
import org.apache.qpid.proton.amqp.messaging.Data;
import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
import org.apache.qpid.proton.message.Message;

import com.microsoft.azure.servicebus.amqp.AmqpConstants;

/**
 * The data structure encapsulating the Event being sent-to and received-from EventHubs.
 * Each EventHubs partition can be visualized as a Stream of {@link EventData}.
 */
public class EventData implements Serializable
{
	private static final long serialVersionUID = -5631628195600014255L;

	transient private Binary bodyData;
	
	private Map properties;
	private SystemProperties systemProperties;

	private EventData()
	{
	}

	/**
	 * Internal Constructor - intended to be used only by the {@link PartitionReceiver} to Create #EventData out of #Message
	 */
	@SuppressWarnings("unchecked")
	EventData(Message amqpMessage)
	{
		if (amqpMessage == null)
		{
			throw new IllegalArgumentException("amqpMessage cannot be null");
		}

		final Map messageAnnotations = amqpMessage.getMessageAnnotations().getValue();
		final HashMap receiveProperties = new HashMap();
		
		for(Map.Entry annotation: messageAnnotations.entrySet())
		{
			receiveProperties.put(annotation.getKey().toString(), annotation.getValue() != null ? annotation.getValue() : null);
		}
		
		if (amqpMessage.getProperties() != null)
		{
			if (amqpMessage.getMessageId() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_MESSAGE_ID, amqpMessage.getMessageId());
			if (amqpMessage.getUserId() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_USER_ID, amqpMessage.getUserId());
			if (amqpMessage.getAddress() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_TO, amqpMessage.getAddress());
			if (amqpMessage.getSubject() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_SUBJECT, amqpMessage.getSubject());
			if (amqpMessage.getReplyTo() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_REPLY_TO, amqpMessage.getReplyTo());
			if (amqpMessage.getCorrelationId() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_CORRELATION_ID, amqpMessage.getCorrelationId());
			if (amqpMessage.getContentType() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_CONTENT_TYPE, amqpMessage.getContentType());
			if (amqpMessage.getContentEncoding() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_CONTENT_ENCODING, amqpMessage.getContentEncoding());
			if (amqpMessage.getProperties().getAbsoluteExpiryTime() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_ABSOLUTE_EXPRITY_time, amqpMessage.getExpiryTime());
			if (amqpMessage.getProperties().getCreationTime() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_CREATION_TIME, amqpMessage.getCreationTime());
			if (amqpMessage.getGroupId() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_GROUP_ID, amqpMessage.getGroupId());
			if (amqpMessage.getProperties().getGroupSequence() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_GROUP_SEQUENCE, amqpMessage.getGroupSequence());
			if (amqpMessage.getReplyToGroupId() != null) receiveProperties.put(AmqpConstants.AMQP_PROPERTY_REPLY_TO_GROUP_ID, amqpMessage.getReplyToGroupId());
		}
		
		this.systemProperties = new SystemProperties(receiveProperties);	
		this.properties = amqpMessage.getApplicationProperties() == null ? null 
				: ((Map)(amqpMessage.getApplicationProperties().getValue()));

		this.bodyData = amqpMessage.getBody() == null ? null : ((Data) amqpMessage.getBody()).getValue();

		amqpMessage.clear();
	}

	/**
	 * Construct EventData to Send to EventHubs.
	 * Typical pattern to create a Sending EventData is:
	 * 
	 * i.	Serialize the sending ApplicationEvent to be sent to EventHubs into bytes.
	 * ii.	If complex serialization logic is involved (for example: multiple types of data) - add a Hint using the {@link #getProperties()} for the Consumer.
	 * 
*

Sample Code: *

	 * EventData eventData = new EventData(telemetryEventBytes);
	 * eventData.getProperties().put("eventType", "com.microsoft.azure.monitoring.EtlEvent");
	 * partitionSender.Send(eventData);
	 * 
* @param data the actual payload of data in bytes to be Sent to EventHubs. * @see EventHubClient#createFromConnectionString(String) */ public EventData(byte[] data) { this(); if (data == null) { throw new IllegalArgumentException("data cannot be null"); } this.bodyData = new Binary(data); } /** * Construct EventData to Send to EventHubs. * Typical pattern to create a Sending EventData is: *
	 * i.	Serialize the sending ApplicationEvent to be sent to EventHubs into bytes.
	 * ii.	If complex serialization logic is involved (for example: multiple types of data) - add a Hint using the {@link #getProperties()} for the Consumer.
	 *  
*

Illustration: *

 {@code
	 *  EventData eventData = new EventData(telemetryEventBytes, offset, length);
	 *  eventData.getProperties().put("eventType", "com.microsoft.azure.monitoring.EtlEvent");
	 *  partitionSender.Send(eventData);
	 *  }
* @param data the byte[] where the payload of the Event to be sent to EventHubs is present * @param offset Offset in the byte[] to read from ; inclusive index * @param length length of the byte[] to be read, starting from offset * @see EventHubClient#createFromConnectionString(String) */ public EventData(byte[] data, final int offset, final int length) { this(); if (data == null) { throw new IllegalArgumentException("data cannot be null"); } this.bodyData = new Binary(data, offset, length); } /** * Construct EventData to Send to EventHubs. * Typical pattern to create a Sending EventData is: *
	 * i.	Serialize the sending ApplicationEvent to be sent to EventHubs into bytes.
	 * ii.	If complex serialization logic is involved (for example: multiple types of data) - add a Hint using the {@link #getProperties()} for the Consumer.
	 *  
*

Illustration: *

 {@code
	 *  EventData eventData = new EventData(telemetryEventByteBuffer);
	 *  eventData.getProperties().put("eventType", "com.microsoft.azure.monitoring.EtlEvent");
	 *	partitionSender.Send(eventData);
	 *  }
* @param buffer ByteBuffer which references the payload of the Event to be sent to EventHubs * @see EventHubClient#createFromConnectionString(String) */ public EventData(ByteBuffer buffer) { this(); if (buffer == null) { throw new IllegalArgumentException("data cannot be null"); } this.bodyData = Binary.create(buffer); } /** * Get Actual Payload/Data wrapped by EventData. * This is the underlying array and should be used in conjunction with {@link #getBodyOffset()} and {@link #getBodyLength()}. * @return returns the byte[] of the actual data */ public byte[] getBody() { return this.bodyData == null ? null : this.bodyData.getArray(); } /** * Get the offset of the current Payload/Data in the byte array returned by {@link #getBody()}. * @return returns the byte[] of the actual data * @see #getBodyLength() * @see #getBody() */ public int getBodyOffset() { return this.bodyData == null ? 0 : this.bodyData.getArrayOffset(); } /** * Get the length of the Actual Payload/Data in the byte array returned by {@link #getBody()}. * @return returns the byte[] of the actual data * @see #getBody() * @see #getBodyOffset() */ public int getBodyLength() { return this.bodyData == null ? 0 : this.bodyData.getLength(); } /** * Application property bag * @return returns Application properties */ public Map getProperties() { if (this.properties == null) { this.properties = new HashMap(); } return this.properties; } /** * Set Application Properties * @param applicationProperties the Application Properties bag * @deprecated use {@link #getProperties()} and add properties to the bag. */ @Deprecated public void setProperties(final Map applicationProperties) { this.properties = applicationProperties; } /** * SystemProperties that are populated by EventHubService. *

As these are populated by Service, they are only present on a Received EventData. *

Usage:

* * final String offset = eventData.getSystemProperties().getOffset(); * * @return an encapsulation of all SystemProperties appended by EventHubs service into EventData. * null if the {@link #EventData()} is not received and is created by the public constructors. * @see SystemProperties#getOffset * @see SystemProperties#getSequenceNumber * @see SystemProperties#getPartitionKey * @see SystemProperties#getEnqueuedTime */ public SystemProperties getSystemProperties() { return this.systemProperties; } // This is intended to be used while sending EventData - so EventData.SystemProperties will not be copied over to the AmqpMessage Message toAmqpMessage() { final Message amqpMessage = Proton.message(); if (this.properties != null && !this.properties.isEmpty()) { final ApplicationProperties applicationProperties = new ApplicationProperties(this.properties); amqpMessage.setApplicationProperties(applicationProperties); } if (this.systemProperties != null && !this.systemProperties.isEmpty()) { for(Map.Entry systemProperty: this.systemProperties.entrySet()) { final String propertyName = systemProperty.getKey(); if (!EventDataUtil.RESERVED_SYSTEM_PROPERTIES.contains(propertyName)) { if (AmqpConstants.RESERVED_PROPERTY_NAMES.contains(propertyName)) switch (propertyName) { case AmqpConstants.AMQP_PROPERTY_MESSAGE_ID: amqpMessage.setMessageId(systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_USER_ID: amqpMessage.setUserId((byte[]) systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_TO: amqpMessage.setAddress((String) systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_SUBJECT: amqpMessage.setSubject((String) systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_REPLY_TO: amqpMessage.setReplyTo((String) systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_CORRELATION_ID: amqpMessage.setCorrelationId(systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_CONTENT_TYPE: amqpMessage.setContentType((String) systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_CONTENT_ENCODING: amqpMessage.setContentEncoding((String) systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_ABSOLUTE_EXPRITY_time: amqpMessage.setExpiryTime((long) systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_CREATION_TIME: amqpMessage.setCreationTime((long) systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_GROUP_ID: amqpMessage.setGroupId((String) systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_GROUP_SEQUENCE: amqpMessage.setGroupSequence((long) systemProperty.getValue()); break; case AmqpConstants.AMQP_PROPERTY_REPLY_TO_GROUP_ID: amqpMessage.setReplyToGroupId((String) systemProperty.getValue()); break; default: throw new RuntimeException("unreachable"); } else { final MessageAnnotations messageAnnotations = (amqpMessage.getMessageAnnotations() == null) ? new MessageAnnotations(new HashMap()) : amqpMessage.getMessageAnnotations(); messageAnnotations.getValue().put(Symbol.getSymbol(systemProperty.getKey()), systemProperty.getValue()); amqpMessage.setMessageAnnotations(messageAnnotations); } } } } if (this.bodyData != null) { amqpMessage.setBody(new Data(this.bodyData)); } return amqpMessage; } Message toAmqpMessage(final String partitionKey) { final Message amqpMessage = this.toAmqpMessage(); final MessageAnnotations messageAnnotations = (amqpMessage.getMessageAnnotations() == null) ? new MessageAnnotations(new HashMap()) : amqpMessage.getMessageAnnotations(); messageAnnotations.getValue().put(AmqpConstants.PARTITION_KEY, partitionKey); amqpMessage.setMessageAnnotations(messageAnnotations); return amqpMessage; } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(this.bodyData.getLength()); out.write(this.bodyData.getArray(), this.bodyData.getArrayOffset(), this.bodyData.getLength()); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); final int length = in.readInt(); final byte[] data = new byte[length]; in.read(data, 0, length); this.bodyData = new Binary(data, 0, length); } public static class SystemProperties extends HashMap { private static final long serialVersionUID = -2827050124966993723L; public SystemProperties(final HashMap map) { super(Collections.unmodifiableMap(map)); } public String getOffset() { return this.getSystemProperty(AmqpConstants.OFFSET_ANNOTATION_NAME); } public String getPartitionKey() { return this.getSystemProperty(AmqpConstants.PARTITION_KEY_ANNOTATION_NAME); } public Instant getEnqueuedTime() { final Date enqueuedTimeValue = this.getSystemProperty(AmqpConstants.ENQUEUED_TIME_UTC_ANNOTATION_NAME); return enqueuedTimeValue != null ? enqueuedTimeValue.toInstant() : null; } public long getSequenceNumber() { return this.getSystemProperty(AmqpConstants.SEQUENCE_NUMBER_ANNOTATION_NAME); } public String getPublisher() { return this.getSystemProperty(AmqpConstants.PUBLISHER_ANNOTATION_NAME); } @SuppressWarnings("unchecked") private T getSystemProperty(final String key) { if (this.containsKey(key)) { return (T) (this.get(key)); } return null; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy