All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetlinks.coap.CoapPacket Maven / Gradle / Ivy
package org.jetlinks.coap;
import org.jetlinks.coap.enums.Code;
import org.jetlinks.coap.enums.MediaTypes;
import org.jetlinks.coap.enums.MessageType;
import org.jetlinks.coap.enums.Method;
import org.jetlinks.coap.exception.CoapException;
import org.jetlinks.coap.options.HeaderOptions;
import org.jetlinks.coap.utils.DataConvertingUtility;
import org.jetlinks.coap.utils.HexArray;
import java.io.*;
import java.util.Arrays;
import java.util.Objects;
/**
* @author guyi
* @author zhouhao
* @since 1.0.0
*/
public class CoapPacket implements Serializable {
public static final int PAYLOAD_MARKER = 0xFF;
public static final byte[] DEFAULT_TOKEN = new byte[]{};
private byte version = 1;
private MessageType messageType = MessageType.Confirmable;
private int messageId;
private Code code;
private Method method;
private byte[] payload = new byte[0];
private HeaderOptions options = new HeaderOptions();
private byte[] token = DEFAULT_TOKEN; //opaque
public CoapPacket() {
}
public CoapPacket(Code code, MessageType messageType) {
this.code = code;
this.messageType = messageType;
}
public CoapPacket(Method method, MessageType messageType, String uriPath) {
this.method = method;
this.messageType = messageType;
this.headers().setUriPath(uriPath);
}
public static CoapPacket read(byte[] rawData, int length) throws CoapException {
ByteArrayInputStream inputStream = new ByteArrayInputStream(rawData, 0, length);
CoapPacket cp = new CoapPacket();
cp.readFrom(inputStream);
return cp;
}
public static CoapPacket read(byte[] rawData) throws CoapException {
return read(rawData, rawData.length);
}
public static CoapPacket deserialize(InputStream inputStream) throws CoapException {
CoapPacket coapPacket = new CoapPacket();
coapPacket.readFrom(inputStream);
return coapPacket;
}
public static byte[] serialize(CoapPacket coapPacket) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
coapPacket.writeTo(outputStream);
return outputStream.toByteArray();
}
protected void readFrom(InputStream inputStream) throws CoapException {
try {
int tempByte = inputStream.read(); //first byte
version = (byte) ((tempByte & 0xC0) >> 6);
if (version != 1) {
throw new CoapException("CoAP version %s not supported", version);
}
messageType = MessageType.valueOf((tempByte >> 4) & 0x3);
byte tokenLen = (byte) (tempByte & 0x0F);
if (tokenLen > 8) {
throw new CoapException("Wrong TOKEN value, size should be within range 0-8");
}
tempByte = inputStream.read(); //second byte
if (tempByte >= 1 && tempByte <= 10) {
//method code
method = Method.valueOf(tempByte);
} else {
code = Code.valueOf(tempByte);
}
messageId = inputStream.read() << 8;
messageId = messageId | inputStream.read();
//token
token = new byte[tokenLen];
inputStream.read(token);
//read headers
options = new HeaderOptions();
boolean hasPayloadMarker = options.deserialize(inputStream, code);
//read payload
if (hasPayloadMarker) {
int plLen = inputStream.available();
this.payload = new byte[plLen];
inputStream.read(payload);
}
} catch (IOException | IllegalArgumentException ex) {
throw new CoapException(ex);
}
}
public final HeaderOptions headers() {
return options;
}
public void setHeaderOptions(HeaderOptions options) {
this.options = options;
}
public CoapPacket createResponse() {
if (this.getCode() == null) {
return createResponse(Code.C205_CONTENT);
} else {
return createResponse(null);
}
}
public CoapPacket createResponse(Code responseCode) {
if (messageType == MessageType.NonConfirmable) {
CoapPacket response = new CoapPacket();
response.setMessageType(MessageType.NonConfirmable);
response.setCode(responseCode);
response.setToken(getToken());
return response;
}
if (messageType == MessageType.Confirmable) {
CoapPacket response = new CoapPacket();
response.setMessageId(this.messageId);
response.setMessageType(MessageType.Acknowledgement);
response.setCode(responseCode);
if (responseCode != null) {
response.setToken(getToken());
//do not put token into empty-ack
}
return response;
}
if (messageType == null && method != null) {
CoapPacket response = new CoapPacket();
response.setMessageId(this.messageId);
response.setToken(getToken());
response.setCode(responseCode);
return response;
}
return null;
}
public byte getVersion() {
return version;
}
public MessageType getMessageType() {
return messageType;
}
public void setMessageType(MessageType messageType) {
this.messageType = messageType;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public synchronized void setMessageId(int messageID) {
if (messageID > 65535 || messageID < 0) {
throw new IllegalArgumentException("invalid messageid, should be within range 0-65535: " + messageID);
}
this.messageId = messageID;
}
public synchronized int getMessageId() {
return messageId;
}
public byte[] getPayload() {
return payload;
}
public String getPayloadString() {
if (payload.length > 0) {
return DataConvertingUtility.decodeToString(payload);
}
return null;
}
public void setPayload(String payload) {
setPayload(DataConvertingUtility.encodeString(payload));
}
public void setPayload(byte[] payload) {
this.payload = payload;
}
public void setToken(byte[] token) {
if (token != null && token.length > 8) {
throw new IllegalArgumentException("Wrong TOKEN value, size should be within range 0-8");
}
if (token == null || token.length == 0) {
this.token = DEFAULT_TOKEN;
} else {
this.token = token;
}
}
public byte[] getToken() {
return token;
}
public void writeTo(OutputStream outputStream) {
try {
int tempByte;
tempByte = (0x3 & version) << 6; //Version
tempByte |= (0x3 & messageType.ordinal()) << 4; //Transaction Message Type
tempByte |= token.length & 0xF; //Token length
outputStream.write(tempByte);
writeCode(outputStream, this);
outputStream.write(0xFF & (messageId >> 8));
outputStream.write(0xFF & messageId);
//token
outputStream.write(token);
// options
options.serialize(outputStream);
//payload
if (payload != null && payload.length > 0) {
outputStream.write(PAYLOAD_MARKER);
outputStream.write(payload);
}
} catch (IOException exception) {
throw new IllegalStateException(exception.getMessage(), exception);
}
}
static Code writeCode(OutputStream os, CoapPacket coapPacket) throws IOException {
Code code = coapPacket.getCode();
Method method = coapPacket.getMethod();
if (code != null && method != null) {
throw new IllegalStateException("Forbidden operation: 'code' and 'method' use at a same time");
}
if (code != null) {
os.write(code.getCoapCode());
} else if (method != null) {
os.write(method.getCode());
} else { //no code or method used
os.write(0);
}
return code;
}
public byte[] toByteArray() {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
writeTo(outputStream);
return outputStream.toByteArray();
}
public Code getCode() {
return code;
}
public void setCode(Code code) {
this.code = code;
}
public boolean getMustAcknowledge() {
return this.messageType == MessageType.Confirmable;
}
@Override
public String toString() {
return toString(false, false, true);
}
public String toString(boolean printFullPayload) {
return toString(printFullPayload, false, true);
}
public String toString(boolean printFullPayload, boolean printPayloadOnlyAsHex, boolean printAddress) {
return toString(printFullPayload, printPayloadOnlyAsHex, printAddress, false);
}
public String toString(boolean printFullPayload, boolean printPayloadOnlyAsHex, boolean printAddress, boolean doNotPrintPayload) {
StringBuilder sb = new StringBuilder();
if (messageType != null) {
sb.append(getMessageType().toString());
}
if (method != null) {
sb.append(' ').append(method.toString());
}
if (code != null) {
if (sb.length() > 0) {
sb.append(' ');
}
sb.append(code.codeToString());
}
sb.append(" MID:").append(this.messageId);
if (this.token.length > 0) {
sb.append(" Token:0x").append(HexArray.toHex(this.token));
}
options.toString(sb, code);
payloadToString(printFullPayload, printPayloadOnlyAsHex, doNotPrintPayload, sb);
return sb.toString();
}
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
private void payloadToString(boolean printFullPayload, boolean printPayloadOnlyAsHex, boolean doNotPrintPayload, StringBuilder sb) {
if (payload != null && payload.length > 0) {
if (doNotPrintPayload) {
sb.append(" pl(").append(payload.length).append(')');
} else {
payloadToString(printFullPayload, sb, printPayloadOnlyAsHex);
}
}
}
private void payloadToString(boolean printFullPayload, StringBuilder sb, boolean printPayloadOnlyAsHex) {
if (!printPayloadOnlyAsHex && isTextBasedContentFormat()) {
String decodedPayload = getPayloadString();
if (decodedPayload.length() < 46 || printFullPayload) {
sb.append(" pl:'").append(decodedPayload).append('\'');
} else {
sb.append(" pl(").append(payload.length).append("):'").append(decodedPayload.substring(0, 44)).append("..'");
}
} else {
if (!printFullPayload) {
sb.append(" pl(").append(payload.length).append("):0x").append(HexArray.toHexShort(payload, 22));
} else {
sb.append(" pl(").append(payload.length).append("):0x").append(HexArray.toHex(payload));
}
}
}
private boolean isTextBasedContentFormat() {
if (headers().getContentFormat() == null) {
return false;
}
return headers().getContentFormat() == MediaTypes.CT_TEXT_PLAIN
|| headers().getContentFormat() == MediaTypes.CT_APPLICATION_JSON
|| headers().getContentFormat() == MediaTypes.CT_APPLICATION_LINK__FORMAT
|| headers().getContentFormat() == MediaTypes.CT_APPLICATION_XML
|| headers().getContentFormat() == MediaTypes.CT_APPLICATION_LWM2M_JSON;
}
@Override
public int hashCode() {
int hash = 7;
hash = 41 * hash + this.version;
hash = 41 * hash + Objects.hashCode(this.messageType);
hash = 41 * hash + this.messageId;
hash = 41 * hash + Objects.hashCode(this.code);
hash = 41 * hash + Objects.hashCode(this.method);
hash = 41 * hash + Arrays.hashCode(this.payload);
hash = 41 * hash + Objects.hashCode(this.options);
hash = 41 * hash + Arrays.hashCode(this.token);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final CoapPacket other = (CoapPacket) obj;
if (this.version != other.version) {
return false;
}
if (this.messageType != other.messageType) {
return false;
}
if (this.messageId != other.messageId) {
return false;
}
if (this.code != other.code) {
return false;
}
if (this.method != other.method) {
return false;
}
if (!Arrays.equals(this.payload, other.payload)) {
return false;
}
if (!Objects.equals(this.options, other.options)) {
return false;
}
if (!Arrays.equals(this.token, other.token)) {
return false;
}
return true;
}
}