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

org.jgroups.NioMessage Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

The 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 - 2024 Weber Informatics LLC | Privacy Policy