/* * Copyright 2014-2016 CyberVision, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kaaproject.kaa.common.channels.protocols.kaatcp.messages; import org.kaaproject.kaa.common.channels.protocols.kaatcp.KaaTcpProtocolException; /** * KaaSync message Class. * The KAASYNC message is used as intermediate class for decoding messages * SyncRequest,SyncResponse,BootstraResolve,BootstrapResponse. * * @author Andrey Panasenko * * Variable header Protocol Name byte 1 Length MSB (0) byte 2 Length LSB (6) byte 3 K * byte 4 a byte 5 a byte 6 t byte 7 c byte 8 p Protocol version byte 9 Version (1) * Message ID (2 bytes) byte 10 ID MSB byte 11 ID LSB Flags byte 12 Request/Response (bit 0) * 1 - request, 0 - response * * Zipped (bit 1) 1 - zepped, 0 - unzipped * * Encrypted(bit 2) 1 - encrypted, 0 - unencrypted * * Unused(bit 3) * * bit4-bit7 - KAASYNC subcomand id * * * KAASYNC subcomand id table Mnemonic Enumeration Description UNUSED 0 reserved * value SYNC 1 Sync request/response BOOTSTRAP 2 Bootstrap * resolve/response */ public class KaaSync extends MqttFrame { public static final int KAASYNC_VERIABLE_HEADER_LENGTH_V1 = 12; public static final byte KAASYNC_REQUEST_FLAG = 0x01; public static final byte KAASYNC_ZIPPED_FLAG = 0x02; public static final byte KAASYNC_ENCRYPTED_FLAG = 0x04; public static final byte KAASYNC_VERSION = 0x01; private static final int KAASYNC_MESSAGE_TYPE_SHIFT = 4; private static final byte[] FIXED_HEADER_CONST = new byte[]{0x00, 0x06, 'K', 'a', 'a', 't', 'c', 'p', KAASYNC_VERSION}; /** * message id if used, default 0. */ private int messageId = 0; /** * Request/Response (bit 0) 1 - request, 0 - response. */ private boolean request = false; /** * Zipped (bit 1) 1 - zepped, 0 - unzipped. */ private boolean zipped = false; /** * Encrypted(bit 2) 1 - encrypted, 0 - unencrypted. */ private boolean encrypted = false; /** * KaaSync subcommand message type. */ private KaaSyncMessageType kaaSyncMessageType = KaaSyncMessageType.UNUSED; /** * Default constructor. * * @param isRequest boolean 'true' is request, else response * @param isZipped boolean if message is Zipped * @param isEcrypted boolean if message is Encrypted */ public KaaSync(boolean isRequest, boolean isZipped, boolean isEcrypted) { setMessageType(MessageType.KAASYNC); setRequest(isRequest); setZipped(isZipped); setEncrypted(isEcrypted); remainingLength = KAASYNC_VERIABLE_HEADER_LENGTH_V1; } /** * Constructor used to migrate from KaaSync to specific message class. * * @param old KaaSync object from which need to migrate to specific class. */ protected KaaSync(KaaSync old) { super((MqttFrame) old); this.messageId = old.getMessageId(); this.request = old.isRequest(); this.zipped = old.isZipped(); this.encrypted = old.isEncrypted(); this.kaaSyncMessageType = old.getKaaSyncMessageType(); } /** * Default Constructor is used for create message class from byte stream. */ public KaaSync() { super(); setMessageType(MessageType.KAASYNC); } /** * Pack KaaSync variable header. */ protected void packVeriableHeader() { buffer.put(FIXED_HEADER_CONST); byte modId1 = (byte) (messageId & 0x0000FF00); buffer.put(modId1); byte modId2 = (byte) (messageId & 0x000000FF); buffer.put(modId2); byte flags = 0x00; if (isRequest()) { flags = (byte) (flags | KAASYNC_REQUEST_FLAG); } if (isZipped()) { flags = (byte) (flags | KAASYNC_ZIPPED_FLAG); } if (isEncrypted()) { flags = (byte) (flags | KAASYNC_ENCRYPTED_FLAG); } flags = (byte) (flags | (getKaaSyncMessageType().getType() << KAASYNC_MESSAGE_TYPE_SHIFT)); buffer.put(flags); } /** * Message ID getter. * * @return int messageId */ public int getMessageId() { return messageId; } /** * Message ID setter. * * @param messageId int */ public void setMessageId(int messageId) { this.messageId = messageId; } /** * Is avro object is SyncRequest. * * @return boolean request */ public boolean isRequest() { return request; } /** * Set to 'true' if avro object is SyncRequest. * * @param request boolean isRequest */ public void setRequest(boolean request) { this.request = request; } /** * Is avro object zipped. * * @return boolean zipped */ public boolean isZipped() { return zipped; } /** * Set to 'true' if avro object is zipped. * * @param zipped boolean isZipped */ public void setZipped(boolean zipped) { this.zipped = zipped; } /** * Is avro object is encrypted. * * @return boolean encrypted */ public boolean isEncrypted() { return encrypted; } /** * Set to 'true' if avro object is encrypted. * * @param encrypted boolean isEncrypted */ public void setEncrypted(boolean encrypted) { this.encrypted = encrypted; } /** * Decode KaaSync variable header. * * @throws KaaTcpProtocolException - if protocol version missmatch */ protected void decodeVariableHeader() throws KaaTcpProtocolException { for (int i = 0; i < FIXED_HEADER_CONST.length; i++) { if (FIXED_HEADER_CONST[i] != buffer.get()) { throw new KaaTcpProtocolException("Kaatcp protocol version missmatch"); } } int msb = (buffer.get() & 0xFF) << 8; int lsb = buffer.get() & 0xFF; messageId = (msb | lsb); byte flag = buffer.get(); if (((flag & 0xFF) & KAASYNC_REQUEST_FLAG) != 0) { request = true; } else { request = false; } if (((flag & 0xFF) & KAASYNC_ZIPPED_FLAG) != 0) { zipped = true; } else { zipped = false; } if (((flag & 0xFF) & KAASYNC_ENCRYPTED_FLAG) != 0) { encrypted = true; } else { encrypted = false; } byte kaaSyncType = (byte) ((flag >> KAASYNC_MESSAGE_TYPE_SHIFT) & 0x0F); if (kaaSyncType == KaaSyncMessageType.SYNC.getType()) { kaaSyncMessageType = KaaSyncMessageType.SYNC; } else { kaaSyncMessageType = KaaSyncMessageType.UNUSED; } } /** * Kaa Sync Message Type getter. * * @return KaaSyncMessageType */ public KaaSyncMessageType getKaaSyncMessageType() { return kaaSyncMessageType; } /** * Kaa Sync Message Type setter. * * @param type KaaSyncMessageType */ protected void setKaaSyncMessageType(KaaSyncMessageType type) { this.kaaSyncMessageType = type; } /* (non-Javadoc) * @see org.kaaproject.kaa.common.channels.protocols.kaatcp.messages.MqttFrame#pack() */ @Override protected void pack() { packVeriableHeader(); } /* (non-Javadoc) * @see org.kaaproject.kaa.common.channels.protocols.kaatcp.messages.MqttFrame#decode() */ @Override protected void decode() throws KaaTcpProtocolException { decodeVariableHeader(); } /* * (non-Javadoc) * @see org.kaaproject.kaa.common.channels.protocols.kaatcp.messages.MqttFrame#upgradeFrame() */ @Override public MqttFrame upgradeFrame() throws KaaTcpProtocolException { switch (getKaaSyncMessageType()) { case SYNC: if (isRequest()) { return new SyncRequest(this); } else { return new SyncResponse(this); } case UNUSED: throw new KaaTcpProtocolException("KaaSync Message type is incorrect"); default: break; } throw new KaaTcpProtocolException("KaaSync Message type is incorrect"); } /* (non-Javadoc) * @see * org.kaaproject.kaa.common.channels.protocols.kaatcp.messages.MqttFrame#isNeedCloseConnection() */ @Override public boolean isNeedCloseConnection() { return false; } }