/** * Encodes given object to a byte array and returns flags that describe the type of serialized * object. * * @param obj Object to serialize. * @param out Output stream to which object should be written. * @return Serialization flags. * @throws GridException If JDK serialization failed. */ private int encodeObj(Object obj, ByteArrayOutputStream out) throws GridException { int flags = 0; byte[] data = null; if (obj instanceof String) { data = ((String) obj).getBytes(); } else if (obj instanceof Boolean) { data = new byte[] {(byte) ((Boolean) obj ? '1' : '0')}; flags |= BOOLEAN_FLAG; } else if (obj instanceof Integer) { data = U.intToBytes((Integer) obj); flags |= INT_FLAG; } else if (obj instanceof Long) { data = U.longToBytes((Long) obj); flags |= LONG_FLAG; } else if (obj instanceof Date) { data = U.longToBytes(((Date) obj).getTime()); flags |= DATE_FLAG; } else if (obj instanceof Byte) { data = new byte[] {(Byte) obj}; flags |= BYTE_FLAG; } else if (obj instanceof Float) { data = U.intToBytes(Float.floatToIntBits((Float) obj)); flags |= FLOAT_FLAG; } else if (obj instanceof Double) { data = U.longToBytes(Double.doubleToLongBits((Double) obj)); flags |= DOUBLE_FLAG; } else if (obj instanceof byte[]) { data = (byte[]) obj; flags |= BYTE_ARR_FLAG; } else { jdkMarshaller.marshal(obj, out); flags |= SERIALIZED_FLAG; } if (data != null) out.write(data, 0, data.length); return flags; }
/** * Parses custom packet serialized by hessian marshaller. * * @param ses Session. * @param buf Buffer containing not parsed bytes. * @param state Parser state. * @return Parsed message. * @throws IOException If packet parsing or deserialization failed. */ @Nullable private GridClientMessage parseCustomPacket(GridNioSession ses, ByteBuffer buf, ParserState state) throws IOException { assert state.packetType() == PacketType.GRIDGAIN; assert state.packet() == null; ByteArrayOutputStream tmp = state.buffer(); int len = state.index(); while (buf.remaining() > 0) { byte b = buf.get(); if (len == 0) { tmp.write(b); if (tmp.size() == 4) { len = U.bytesToInt(tmp.toByteArray(), 0); tmp.reset(); if (len == 0) return PING_MESSAGE; else if (len < 0) throw new IOException( "Failed to parse incoming packet (invalid packet length) [ses=" + ses + ", len=" + len + ']'); state.index(len); } } else { tmp.write(b); if (tmp.size() == len) return marshaller.unmarshal(tmp.toByteArray()); } } return null; }
/** * Encodes memcache message to a raw byte array. * * @param msg Message being serialized. * @return Serialized message. * @throws GridException If serialization failed. */ private ByteBuffer encodeMemcache(GridTcpRestPacket msg) throws GridException { GridByteArrayList res = new GridByteArrayList(HDR_LEN); int keyLength = 0; int keyFlags = 0; if (msg.key() != null) { ByteArrayOutputStream rawKey = new ByteArrayOutputStream(); keyFlags = encodeObj(msg.key(), rawKey); msg.key(rawKey.toByteArray()); keyLength = rawKey.size(); } int dataLength = 0; int valFlags = 0; if (msg.value() != null) { ByteArrayOutputStream rawVal = new ByteArrayOutputStream(); valFlags = encodeObj(msg.value(), rawVal); msg.value(rawVal.toByteArray()); dataLength = rawVal.size(); } int flagsLength = 0; if (msg.addFlags()) // || keyFlags > 0 || valFlags > 0) flagsLength = FLAGS_LENGTH; res.add(MEMCACHE_RES_FLAG); res.add(msg.operationCode()); // Cast is required due to packet layout. res.add((short) keyLength); // Cast is required due to packet layout. res.add((byte) flagsLength); // Data type is always 0x00. res.add((byte) 0x00); res.add((short) msg.status()); res.add(keyLength + flagsLength + dataLength); res.add(msg.opaque(), 0, msg.opaque().length); // CAS, unused. res.add(0L); assert res.size() == HDR_LEN; if (flagsLength > 0) { res.add((short) keyFlags); res.add((short) valFlags); } assert msg.key() == null || msg.key() instanceof byte[]; assert msg.value() == null || msg.value() instanceof byte[]; if (keyLength > 0) res.add((byte[]) msg.key(), 0, ((byte[]) msg.key()).length); if (dataLength > 0) res.add((byte[]) msg.value(), 0, ((byte[]) msg.value()).length); return ByteBuffer.wrap(res.entireArray()); }
/** * Parses memcache protocol message. * * @param ses Session. * @param buf Buffer containing not parsed bytes. * @param state Current parser state. * @return Parsed packet.s * @throws IOException If packet cannot be parsed. * @throws GridException If deserialization error occurred. */ @Nullable private GridClientMessage parseMemcachePacket( GridNioSession ses, ByteBuffer buf, ParserState state) throws IOException, GridException { assert state.packetType() == PacketType.MEMCACHE; assert state.packet() != null; assert state.packet() instanceof GridTcpRestPacket; GridTcpRestPacket req = (GridTcpRestPacket) state.packet(); ByteArrayOutputStream tmp = state.buffer(); int i = state.index(); while (buf.remaining() > 0) { byte b = buf.get(); if (i == 0) req.requestFlag(b); else if (i == 1) req.operationCode(b); else if (i == 2 || i == 3) { tmp.write(b); if (i == 3) { req.keyLength(U.bytesToShort(tmp.toByteArray(), 0)); tmp.reset(); } } else if (i == 4) req.extrasLength(b); else if (i >= 8 && i <= 11) { tmp.write(b); if (i == 11) { req.totalLength(U.bytesToInt(tmp.toByteArray(), 0)); tmp.reset(); } } else if (i >= 12 && i <= 15) { tmp.write(b); if (i == 15) { req.opaque(tmp.toByteArray()); tmp.reset(); } } else if (i >= HDR_LEN && i < HDR_LEN + req.extrasLength()) { tmp.write(b); if (i == HDR_LEN + req.extrasLength() - 1) { req.extras(tmp.toByteArray()); tmp.reset(); } } else if (i >= HDR_LEN + req.extrasLength() && i < HDR_LEN + req.extrasLength() + req.keyLength()) { tmp.write(b); if (i == HDR_LEN + req.extrasLength() + req.keyLength() - 1) { req.key(tmp.toByteArray()); tmp.reset(); } } else if (i >= HDR_LEN + req.extrasLength() + req.keyLength() && i < HDR_LEN + req.totalLength()) { tmp.write(b); if (i == HDR_LEN + req.totalLength() - 1) { req.value(tmp.toByteArray()); tmp.reset(); } } if (i == HDR_LEN + req.totalLength() - 1) // Assembled the packet. return assemble(ses, req); i++; } state.index(i); return null; }