package io.craft.atom.protocol.rpc; import io.craft.atom.protocol.ProtocolEncoder; import io.craft.atom.protocol.ProtocolException; import io.craft.atom.protocol.rpc.api.SerializationRegistry; import io.craft.atom.protocol.rpc.model.RpcBody; import io.craft.atom.protocol.rpc.model.RpcHeader; import io.craft.atom.protocol.rpc.model.RpcMessage; import io.craft.atom.protocol.rpc.spi.Serialization; import io.craft.atom.util.Assert; import io.craft.atom.util.ByteUtil; /** * A {@link ProtocolEncoder} which encodes a {@code RpcMessage} object into bytes follow the generic RPC format. * <p> * thread safe. * * @author mindwind * @version 1.0, Jul 17, 2014 */ public class RpcEncoder implements ProtocolEncoder<RpcMessage> { private SerializationRegistry registry = SerializationRegistry.getInstance(); // ~ -------------------------------------------------------------------------------------------------------------- public RpcEncoder() {} // ~ -------------------------------------------------------------------------------------------------------------- @Override public byte[] encode(RpcMessage rm) throws ProtocolException { if (rm == null) return null; RpcHeader rh = rm.getHeader(); RpcBody rb = rm.getBody(); Assert.notNull(rh); Assert.notNull(rb); Serialization<RpcBody> serializer = registry.lookup(rh.getSt()); if (serializer == null) throw new ProtocolException("No mapping `serializer`!"); byte[] body = encodeBody(rb, serializer); byte[] encoded = new byte[rh.getHeaderSize() + body.length]; rh.setBodySize(body.length); encodeHeader(encoded, rh); System.arraycopy(body, 0, encoded, rh.getHeaderSize(), body.length); return encoded; } private byte[] encodeBody(RpcBody rb, Serialization<RpcBody> serializer) { return serializer.serialize(rb); } private void encodeHeader(byte[] b, RpcHeader rh) { // magic ByteUtil.short2bytes(rh.getMagic(), b, 0); // header siez ByteUtil.short2bytes(rh.getHeaderSize(), b, 2); // version b[4] = rh.getVersion(); // st | hb | tw | rr b[5] = (byte) (rh.getSt() | rh.getHb() | rh.getOw() | rh.getRp()); // status code b[6] = rh.getStatusCode(); // message id ByteUtil.long2bytes(rh.getId(), b, 8); // body size ByteUtil.int2bytes(rh.getBodySize(), b, 16); } }