com.microsoft.azure.gateway.messaging.Message Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gateway-java-binding Show documentation
Show all versions of gateway-java-binding Show documentation
Azure IoT Gateway SDK Java Module Binding
The 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.gateway.messaging;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public final class Message {
private Map properties;
private byte[] content;
/**
* Constructor for a {@link Message} with {@code content} {@link byte[]} and {@link Map} {@code properties}.
*
* Both {@code content} and {@code properties} may be null.
*
* @param content The message content as a string. Null creates an empty content {@link byte[]}
* @param properties The string to string map of peroperties for this message. Null creates an empty {@link Map}
*/
public Message(byte[] content, Map properties){
/*Codes_SRS_JAVA_MESSAGE_14_003: [ The constructor shall save the message content and properties map. ]*/
this.content = content != null ? content : new byte[0];
this.properties = properties != null ? properties : new HashMap();
}
/**
* Construcor for a {@link Message} created from a fully and properly serialized message {@link byte[]}.
*
* @see Message Documentation
*
* @param serializedMessage The fully serialized message.
*
* @throws IllegalArgumentException If the {@link byte[]} cannot be de-serialized.
*/
public Message(byte[] serializedMessage){
try {
/*Codes_SRS_JAVA_MESSAGE_14_001: [ The constructor shall create a Message object by deserializing the byte array. ]*/
/*Codes_SRS_JAVA_MESSAGE_14_002: [ If the byte array is malformed, the function shall throw an IllegalArgumentException. ]*/
fromByteArray(serializedMessage);
} catch (IOException e) {
throw new IllegalArgumentException("Invalid byte array input.");
}
}
/**
* Serializes the {@link Message} to a {@link byte[]}.
*
* @see Message Documentation
*
* @return The serialized {@link byte[]}.
* @throws IOException If this {@link Message} cannot be serialized.
*/
public byte[] toByteArray() throws IOException {
/*Codes_SRS_JAVA_MESSAGE_14_004: [ The function shall serialize the Message content and properties according to the specification in message.h ]*/
/*Codes_SRS_JAVA_MESSAGE_14_005: [ The function shall return throw an IOException if the Message could not be serialized. ]*/
ByteArrayOutputStream _bos = new ByteArrayOutputStream();
DataOutputStream _dos = new DataOutputStream(_bos);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
//Write Properties Count
_dos.writeInt(this.properties.size());
//Write Properties
Object[] keys = this.properties.keySet().toArray();
for(int index = 0; index < keys.length; index++){
byte[] key = ((String)keys[index]).getBytes("UTF-8");
_dos.write(key);
_dos.writeByte('\0');
byte[] value = this.properties.get(keys[index]).getBytes("UTF-8");
_dos.write(value);
_dos.writeByte('\0');
}
//Write message content size
_dos.writeInt(this.content.length);
//Write message content
_dos.write(this.content);
byte[] _result = _bos.toByteArray();
//Write Header
dos.writeByte(0xA1);
dos.writeByte(0x60);
//Write ArraySize
dos.writeInt(_result.length + 6);
dos.write(_result);
byte[] result = bos.toByteArray();
return result;
}
public Map getProperties(){
return properties;
}
public byte[] getContent(){
return content;
}
public String toString(){
return "Content: " + new String(this.content) + "\nProperties: " + this.properties.toString();
}
/**
* Deserializes a byte array and sets the {@link Message#content} and {@link Message#properties}.
*
* @param serializedMessage The message to be deserialized.
* @throws IOException if the byte array in malformed.
*/
private void fromByteArray(byte[] serializedMessage) throws IOException {
try {
ByteArrayInputStream bis = new ByteArrayInputStream(serializedMessage);
DataInputStream dis = new DataInputStream(bis);
//Get Header
byte header1 = dis.readByte();
byte header2 = dis.readByte();
if (header1 == (byte) 0xA1 && header2 == (byte) 0x60) {
int arraySize = dis.readInt();
if (arraySize >= 14) {
Map _properties = new HashMap();
int propCount = dis.readInt();
if (propCount > 0) {
for (int count = 0; count < propCount; count++) {
byte[] key = readNullTerminatedString(bis);
byte[] value = readNullTerminatedString(bis);
_properties.put(new String(key), new String(value));
}
}
int contentLength = dis.readInt();
byte[] content = new byte[contentLength];
dis.readFully(content);
//At this point it should be safe to set both properties and content
this.properties = _properties;
this.content = content;
} else {
throw new IOException("Invalid byte array size.");
}
} else {
throw new IOException("Invalid byte array header.");
}
} catch(Exception e){
throw new IOException("Unexpected exception occurred: " + e.getMessage());
}
}
/**
* Returns the first null-terminated ('\0') sub-array.
*
* @param bis The {@link ByteArrayInputStream} object from which to read the string.
* @return The null-terminated string in a byte array.
* @throws IOException if the null-terminated string could not be read.
*/
private byte[] readNullTerminatedString(ByteArrayInputStream bis) throws IOException {
ArrayList byteArray = new ArrayList();
byte b = (byte) bis.read();
while(b != '\0' && b != -1){
byteArray.add(b);
b = (byte)bis.read();
}
byte[] result;
if(b != -1) {
result = new byte[byteArray.size()];
for (int index = 0; index < result.length; index++) {
result[index] = byteArray.get(index);
}
} else {
throw new IOException("Could not read null-terminated string.");
}
return result;
}
}