/**
* Copyright 2013-2015 Seagate Technology LLC.
*
* This Source Code Form is subject to the terms of the Mozilla
* Public License, v. 2.0. If a copy of the MPL was not
* distributed with this file, You can obtain one at
* https://mozilla.org/MP:/2.0/.
*
* This program is distributed in the hope that it will be useful,
* but is provided AS-IS, WITHOUT ANY WARRANTY; including without
* the implied warranty of MERCHANTABILITY, NON-INFRINGEMENT or
* FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public
* License for more details.
*
* See www.openkinetic.org for more project information
*/
package com.seagate.kinetic.common.protocol.codec;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.CorruptedFrameException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.seagate.kinetic.common.lib.KineticMessage;
import com.seagate.kinetic.common.lib.ProtocolMessageUtil;
import com.seagate.kinetic.proto.Kinetic.Command;
import com.seagate.kinetic.proto.Kinetic.Message;
/**
*
* Kinetic protocol buffer message decoder (version2 protocol).
* <p>
* The client library, simulator, or a Kinetic drive uses the following protocol
* to decode a message.
*
* <ul>
* <li>1. read magic byte 'F'
* <li>2. read protobuf message length.
* <li>3. read value length (0 if no value)
* <li>4. read protobuf message byte[]
* <li>5. read value byte[] if any
* </ul>
* <p>
* To log/print the decoded message, set the "kinetic.io.in" Java System
* property to true.
* <p>
* For example, set the following Java VM argument when running a Kinetic
* application or Simulator.
* <p>
* -D"kinetic.io.in"=true
*
* @author chiaming
*/
public class KineticDecoder extends ByteToMessageDecoder {
private final Logger logger = Logger.getLogger(KineticDecoder.class
.getName());
private static boolean printMessage = Boolean.getBoolean("kinetic.io.in");
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in,
List<Object> out) {
in.markReaderIndex();
// Wait until the length prefix is available
// (magic ('F') + proto-msg-size + value-size)
if (in.readableBytes() < 9) {
in.resetReaderIndex();
return;
}
// 1. Read magic number.
int magicNumber = in.readUnsignedByte();
if (magicNumber != 'F') {
in.resetReaderIndex();
throw new CorruptedFrameException("Invalid magic number: "
+ magicNumber);
}
// 2. protobuf message size
int protoMessageLength = in.readInt();
// 3. attched value size
int attachedValueLength = in.readInt();
// wait until whole message is available
if (in.readableBytes() < (protoMessageLength + attachedValueLength)) {
in.resetReaderIndex();
return;
}
// 4. read protobuf message
byte[] decoded = new byte[protoMessageLength];
in.readBytes(decoded);
// kinetic message
KineticMessage km = new KineticMessage();
// construct protobuf message
Message.Builder mbuilder = Message.newBuilder();
try {
mbuilder.mergeFrom(decoded);
} catch (Exception e) {
in.resetReaderIndex();
logger.log(Level.WARNING, e.getMessage(), e);
throw new RuntimeException(e);
}
// 5. read attched value if any
if (attachedValueLength > 0) {
// construct byte[]
byte[] attachedValue = new byte[attachedValueLength];
// read from buffer
in.readBytes(attachedValue);
// set to message
// mbuilder.setValue(ByteString.copyFrom(attachedValue));
km.setValue(attachedValue);
}
Message message = mbuilder.build();
km.setMessage(message);
// get command bytes
ByteString commandBytes = message.getCommandBytes();
// build command
Command.Builder commandBuilder = Command.newBuilder();
try {
commandBuilder.mergeFrom(commandBytes);
km.setCommand(commandBuilder.build());
} catch (InvalidProtocolBufferException e) {
logger.log(Level.WARNING, e.getMessage(), e);
}
// the whole message
out.add(km);
// print inbound message
if (printMessage) {
logger.info("Inbound protocol message: ");
String printMsg = ProtocolMessageUtil.toString(km);
logger.info(printMsg);
}
}
}