Java tutorial
/* * Copyright (c) 2015 The Jupiter Project * * 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.jupiter.transport.netty.handler; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ReplayingDecoder; import org.jupiter.common.util.Signal; import org.jupiter.common.util.SystemClock; import org.jupiter.common.util.SystemPropertyUtil; import org.jupiter.transport.JProtocolHeader; import org.jupiter.transport.exception.IoSignals; import org.jupiter.transport.payload.JRequestBytes; import org.jupiter.transport.payload.JResponseBytes; import java.util.List; /** * ************************************************************************************************** * Protocol * ? * 2 1 1 8 4 * * * MAGIC Sign Status Invoke Id Body Length Body Content * * * * ?16 * = 2 // magic = (short) 0xbabe * + 1 // ??, ?4???request/response/heartbeat, ?4??? * + 1 // ??, ?? * + 8 // ? id, long , ?jupiter?id?48?, ?16? * + 4 // ? body , int * * jupiter * org.jupiter.transport.netty.handler * * @author jiachun.fjc */ public class ProtocolDecoder extends ReplayingDecoder<ProtocolDecoder.State> { // ???, 5M private static final int MAX_BODY_SIZE = SystemPropertyUtil.getInt("jupiter.io.decoder.max.body.size", 1024 * 1024 * 5); /** * Cumulate {@link ByteBuf}s by add them to a CompositeByteBuf and so do no memory copy whenever possible. * Be aware that CompositeByteBuf use a more complex indexing implementation so depending on your use-case * and the decoder implementation this may be slower then just use the {@link #MERGE_CUMULATOR}. */ private static final boolean USE_COMPOSITE_BUF = SystemPropertyUtil .getBoolean("jupiter.io.decoder.composite.buf", false); public ProtocolDecoder() { super(State.HEADER_MAGIC); if (USE_COMPOSITE_BUF) { setCumulator(COMPOSITE_CUMULATOR); } } // ?? private final JProtocolHeader header = new JProtocolHeader(); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { switch (state()) { case HEADER_MAGIC: checkMagic(in.readShort()); // MAGIC checkpoint(State.HEADER_SIGN); case HEADER_SIGN: header.sign(in.readByte()); // ?? checkpoint(State.HEADER_STATUS); case HEADER_STATUS: header.status(in.readByte()); // ?? checkpoint(State.HEADER_ID); case HEADER_ID: header.id(in.readLong()); // ?id checkpoint(State.HEADER_BODY_LENGTH); case HEADER_BODY_LENGTH: header.bodyLength(in.readInt()); // ? checkpoint(State.BODY); case BODY: switch (header.messageCode()) { case JProtocolHeader.HEARTBEAT: break; case JProtocolHeader.REQUEST: { int length = checkBodyLength(header.bodyLength()); byte[] bytes = new byte[length]; in.readBytes(bytes); JRequestBytes request = new JRequestBytes(header.id()); request.timestamp(SystemClock.millisClock().now()); request.bytes(header.serializerCode(), bytes); out.add(request); break; } case JProtocolHeader.RESPONSE: { int length = checkBodyLength(header.bodyLength()); byte[] bytes = new byte[length]; in.readBytes(bytes); JResponseBytes response = new JResponseBytes(header.id()); response.status(header.status()); response.bytes(header.serializerCode(), bytes); out.add(response); break; } default: throw IoSignals.ILLEGAL_SIGN; } checkpoint(State.HEADER_MAGIC); } } private static void checkMagic(short magic) throws Signal { if (magic != JProtocolHeader.MAGIC) { throw IoSignals.ILLEGAL_MAGIC; } } private static int checkBodyLength(int size) throws Signal { if (size > MAX_BODY_SIZE) { throw IoSignals.BODY_TOO_LARGE; } return size; } enum State { HEADER_MAGIC, HEADER_SIGN, HEADER_STATUS, HEADER_ID, HEADER_BODY_LENGTH, BODY } }