All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.NioMessage Maven / Gradle / Ivy

There is a newer version: 5.4.1.Final
Show newest version

package org.jgroups;


import org.jgroups.util.ByteArray;
import org.jgroups.util.Util;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.function.Supplier;

/**
 * A {@link Message} with a (heap-based or direct) {@link java.nio.ByteBuffer} as payload.
*
* Note that the payload of an NioMessage must not be modified after sending it (ie. {@link JChannel#send(Message)}; * serialization depends on position and limit to be correct. * * @since 5.0 * @author Bela Ban */ public class NioMessage extends BaseMessage { /** The payload */ protected ByteBuffer buf; /** * If true, use direct memory when creating {@link ByteBuffer} payloads, e.g. on {@link #setArray(byte[], int, int)}, * {@link #setArray(ByteArray)}, {@link #setObject(Object)} or when getting read from the network * ({@link #readPayload(DataInput)}).
* Unless this flag is set to true, a direct {@link ByteBuffer} payload will become a heap-based payload by a * receiver when sent over the network. This may be useful if we want to use off-heap (direct) memory only for * sending, but not receiving of messages.
* If we want the receiver to create a direct-memory based message, set this flag to true before sending the message. */ protected boolean use_direct_memory_for_allocations; public NioMessage() { } /** * Constructs a message given a destination address * @param dest The Address of the receiver. If it is null, then the message is sent to all cluster members. * Otherwise, it is sent to a single member. */ public NioMessage(Address dest) { super(dest); } /** * Constructs a message given a destination and source address and the payload byte buffer * @param dest The Address of the receiver. If it is null, then the message is sent to all cluster members. * Otherwise, it is sent to a single member. * @param buf The payload. Note that this buffer must not be modified (e.g. buf[0]='x' is not * allowed) since we don't copy the contents. */ public NioMessage(Address dest, ByteBuffer buf) { super(dest); this.buf=buf; } /** Returns the byte buffer. Do not read from/write to it, or else retransmissions will fail! Use {@link ByteBuffer#duplicate()} before, to create a copy, if the buffer needs to be read from */ public ByteBuffer getBuf() {return buf;} public NioMessage setBuf(ByteBuffer b) {this.buf=b; return this;} public Supplier create() {return NioMessage::new;} public short getType() {return Message.NIO_MSG;} public boolean useDirectMemory() {return use_direct_memory_for_allocations;} public NioMessage useDirectMemory(boolean b) {use_direct_memory_for_allocations=b; return this;} public boolean hasPayload() {return buf != null;} public boolean hasArray() {return buf != null && buf.hasArray();} public boolean isDirect() {return buf != null && buf.isDirect();} public int getOffset() {return hasArray()? buf.arrayOffset()+buf.position() : 0;} public int getLength() {return buf != null? buf.remaining() : 0;} public byte[] getArray() { return buf != null? (isDirect()?Util.bufferToArray(buf) : buf.array()) : null; } /** * Sets the internal buffer to point to a subset of a given buffer.

* * Note that the byte[] buffer passed as argument must not be modified. Reason: if we retransmit the * message, it would still have a ref to the original byte[] buffer passed in as argument, and so we would * retransmit a changed byte[] buffer ! * * * @param b The reference to a given buffer. If null, we'll reset the buffer to null * @param offset The initial position * @param length The number of bytes */ public NioMessage setArray(byte[] b, int offset, int length) { if(b != null) buf=createBuffer(b, offset, length); return this; } /** * Sets the buffer

* Note that the byte[] buffer passed as argument must not be modified. Reason: if we retransmit the * message, it would still have a ref to the original byte[] buffer passed in as argument, and so we would * retransmit a changed byte[] buffer ! */ public NioMessage setArray(ByteArray b) { if(b != null) this.buf=createBuffer(b.getArray(), b.getOffset(), b.getLength()); return this; } public T getObject() { return getObject(null); } /** * Tries to unmarshal the byte buffer payload into an object * @return The object */ public T getObject(ClassLoader loader) { if(buf == null) return null; try { return isFlagSet(Flag.SERIALIZED)? Util.objectFromByteBuffer(buf, loader) : (T)getArray(); } catch(Exception ex) { throw new IllegalArgumentException(ex); } } /** * Takes an object and uses Java serialization to generate the byte[] buffer which is set in the * message. Parameter 'obj' has to be serializable (e.g. implementing Serializable, * Externalizable or Streamable, or be a basic type (e.g. Integer, Short etc)). */ public NioMessage setObject(Object obj) { clearFlag(Flag.SERIALIZED); if(obj == null) { buf=null; return this; } if(obj instanceof byte[]) return setArray((byte[])obj, 0, ((byte[])obj).length); if(obj instanceof ByteArray) return setArray((ByteArray)obj); if(obj instanceof ByteBuffer) return setBuf((ByteBuffer)obj); try { ByteArray tmp=Util.objectToBuffer(obj); setFlag(Flag.SERIALIZED); return setArray(tmp); } catch(Exception ex) { throw new IllegalArgumentException(ex); } } /** * Create a copy of the message.
* Note that for headers, only the arrays holding references to the headers are copied, not the headers themselves ! * The consequence is that the headers array of the copy hold the *same* references as the original, so do *not* * modify the headers ! If you want to change a header, copy it and call {@link NioMessage#putHeader(short,Header)} again. * @param copy_payload Copy the buffer * @param copy_headers Copy the headers * @return Message with specified data */ public NioMessage copy(boolean copy_payload, boolean copy_headers) { NioMessage retval=(NioMessage)super.copy(copy_payload, copy_headers); retval.useDirectMemory(use_direct_memory_for_allocations); return retval; } /* ----------------------------------- Interface Streamable ------------------------------- */ public int size() {return super.size() +sizeOfPayload();} public String toString() { return String.format("%s %s", super.toString(), use_direct_memory_for_allocations? "(direct)" : ""); } @Override protected Message copyPayload(Message copy) { if(buf != null) ((NioMessage)copy).buf=buf.duplicate(); return copy; } protected int sizeOfPayload() { return Global.INT_SIZE + getLength() + Global.BYTE_SIZE; // for use_direct_memory_for_allocations } public void writePayload(DataOutput out) throws IOException { out.writeBoolean(use_direct_memory_for_allocations); out.writeInt(buf != null? getLength() : -1); if(buf != null) { if(buf.hasArray()) { byte[] buffer=buf.array(); int offset=buf.arrayOffset() + buf.position(), length=buf.remaining(); out.write(buffer, offset, length); } else { // We need to duplicate the buffer, or else writing its contents to the output stream would modify // position; this would break potential retransmission. // We still need a transfer buffer as there is no way to transfer contents of a ByteBuffer directly to // an output stream; once we have a transport that directly supports ByteBuffers, we can change this ByteBuffer copy=buf.duplicate(); byte[] transfer_buf=new byte[Math.max(copy.remaining()/10, 128)]; while(copy.remaining() > 0) { int bytes=Math.min(transfer_buf.length, copy.remaining()); copy.get(transfer_buf, 0, bytes); out.write(transfer_buf, 0, bytes); } } } } public void readPayload(DataInput in) throws IOException { use_direct_memory_for_allocations=in.readBoolean(); int len=in.readInt(); if(len < 0) return; // unfortunately, we cannot create a ByteBuffer and read directly into it from an input stream (no such API) byte[] tmp=new byte[len]; in.readFully(tmp, 0, tmp.length); buf=createBuffer(tmp, 0, tmp.length); } protected ByteBuffer createBuffer(byte[] array, int offset, int length) { return use_direct_memory_for_allocations? Util.wrapDirect(array, offset, length) : ByteBuffer.wrap(array, offset, length); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy