/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You 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.apache.geode.internal.tcp; import org.apache.geode.distributed.internal.DMStats; import org.apache.geode.distributed.internal.DistributionMessage; import org.apache.geode.distributed.internal.ReplyProcessor21; import org.apache.geode.internal.InternalDataSerializer; import org.apache.geode.internal.Version; import java.io.IOException; import java.nio.ByteBuffer; /** * This class is currently used for reading direct ack responses It should probably be used for all * of the reading done in Connection. * */ public abstract class MsgReader { protected final Connection conn; protected final Header header = new Header(); private final ByteBufferInputStream bbis; public MsgReader(Connection conn, Version version) { this.conn = conn; this.bbis = version == null ? new ByteBufferInputStream() : new VersionedByteBufferInputStream(version); } public Header readHeader() throws IOException { ByteBuffer nioInputBuffer = readAtLeast(Connection.MSG_HEADER_BYTES); int nioMessageLength = nioInputBuffer.getInt(); /* nioMessageVersion = */ Connection.calcHdrVersion(nioMessageLength); nioMessageLength = Connection.calcMsgByteSize(nioMessageLength); byte nioMessageType = nioInputBuffer.get(); short nioMsgId = nioInputBuffer.getShort(); boolean directAck = (nioMessageType & Connection.DIRECT_ACK_BIT) != 0; if (directAck) { // logger.info("DEBUG: msg from " + getRemoteAddress() + " is direct ack" ); nioMessageType &= ~Connection.DIRECT_ACK_BIT; // clear the ack bit } header.nioMessageLength = nioMessageLength; header.nioMessageType = nioMessageType; header.nioMsgId = nioMsgId; return header; } /** * Block until you can read a message. Returns null if the message was a message chunk. * * @return the message, or null if we only received a chunk of the message * @throws ClassNotFoundException * @throws IOException * @throws InterruptedException */ public DistributionMessage readMessage(Header header) throws IOException, ClassNotFoundException, InterruptedException { ByteBuffer nioInputBuffer = readAtLeast(header.nioMessageLength); this.getStats().incMessagesBeingReceived(true, header.nioMessageLength); long startSer = this.getStats().startMsgDeserialization(); try { bbis.setBuffer(nioInputBuffer); DistributionMessage msg = null; ReplyProcessor21.initMessageRPId(); // add serialization stats msg = (DistributionMessage) InternalDataSerializer.readDSFID(bbis); return msg; } finally { this.getStats().endMsgDeserialization(startSer); this.getStats().decMessagesBeingReceived(header.nioMessageLength); } } public void readChunk(Header header, MsgDestreamer md) throws IOException, ClassNotFoundException, InterruptedException { ByteBuffer nioInputBuffer = readAtLeast(header.nioMessageLength); this.getStats().incMessagesBeingReceived(md.size() == 0, header.nioMessageLength); md.addChunk(nioInputBuffer, header.nioMessageLength); } public abstract ByteBuffer readAtLeast(int bytes) throws IOException; protected DMStats getStats() { return conn.owner.getConduit().stats; } public static class Header { int nioMessageLength; byte nioMessageType; short nioMsgId; public Header() {} public int getNioMessageLength() { return nioMessageLength; } public byte getNioMessageType() { return nioMessageType; } public short getNioMessageId() { return nioMsgId; } } public void close() {} }