io.aeron.ChannelUriStringBuilder Maven / Gradle / Ivy
Show all versions of aeron-client Show documentation
/*
* Copyright 2014-2023 Real Logic Limited.
*
* Licensed 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
*
* https://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 io.aeron;
import io.aeron.logbuffer.LogBufferDescriptor;
import static io.aeron.ChannelUri.SPY_QUALIFIER;
import static io.aeron.CommonContext.*;
import static io.aeron.logbuffer.FrameDescriptor.FRAME_ALIGNMENT;
import static io.aeron.logbuffer.LogBufferDescriptor.TERM_MAX_LENGTH;
import static org.agrona.SystemUtil.*;
/**
* Typesafe means of building a channel URI associated with a {@link Publication} or {@link Subscription}.
*
* @see Aeron#addPublication(String, int)
* @see Aeron#addSubscription(String, int)
* @see ChannelUri
*/
public final class ChannelUriStringBuilder
{
/**
* Can be used when the likes of session-id wants to reference another entity such as a tagged publication.
*
* For example {@code session-id=tag:777} where the publication uses {@code tags=777}.
*/
public static final String TAG_PREFIX = "tag:";
private final StringBuilder sb = new StringBuilder(64);
private String prefix;
private String media;
private String endpoint;
private String networkInterface;
private String controlEndpoint;
private String controlMode;
private String tags;
private String alias;
private String cc;
private String fc;
private Boolean reliable;
private Integer ttl;
private Integer mtu;
private Integer termLength;
private Integer initialTermId;
private Integer termId;
private Integer termOffset;
private Long sessionId;
private Long groupTag;
private Long linger;
private Boolean sparse;
private Boolean eos;
private Boolean tether;
private Boolean group;
private Boolean rejoin;
private Boolean ssc;
private boolean isSessionIdTagged;
private Integer socketSndbufLength;
private Integer socketRcvbufLength;
private Integer receiverWindowLength;
private String mediaReceiveTimestampOffset;
private String channelReceiveTimestampOffset;
private String channelSendTimestampOffset;
/**
* Default constructor
*/
public ChannelUriStringBuilder()
{
}
/**
* Constructs the ChannelUriStringBuilder with the initial values derived from the supplied URI. Will parse the
* incoming URI during this process, so could through an exception at this point of the URI is badly formed.
*
* @param initialUri initial values for the builder.
*/
public ChannelUriStringBuilder(final String initialUri)
{
this(ChannelUri.parse(initialUri));
}
/**
* Constructs the ChannelUriStringBuilder with the initial values derived from the supplied ChannelUri.
*
* @param channelUri initial values for the builder.
*/
public ChannelUriStringBuilder(final ChannelUri channelUri)
{
isSessionIdTagged = false;
prefix(channelUri);
media(channelUri);
endpoint(channelUri);
networkInterface(channelUri);
controlEndpoint(channelUri);
controlMode(channelUri);
tags(channelUri);
alias(channelUri);
congestionControl(channelUri);
flowControl(channelUri);
reliable(channelUri);
ttl(channelUri);
mtu(channelUri);
termLength(channelUri);
initialTermId(channelUri);
termId(channelUri);
termOffset(channelUri);
sessionId(channelUri);
group(channelUri);
linger(channelUri);
sparse(channelUri);
eos(channelUri);
tether(channelUri);
groupTag(channelUri);
rejoin(channelUri);
spiesSimulateConnection(channelUri);
socketRcvbufLength(channelUri);
socketSndbufLength(channelUri);
receiverWindowLength(channelUri);
mediaReceiveTimestampOffset(channelUri);
channelReceiveTimestampOffset(channelUri);
channelSendTimestampOffset(channelUri);
}
/**
* Clear out all the values thus setting back to the initial state.
*
* @return this for a fluent API.
*/
public ChannelUriStringBuilder clear()
{
prefix = null;
media = null;
endpoint = null;
networkInterface = null;
controlEndpoint = null;
controlMode = null;
tags = null;
alias = null;
cc = null;
fc = null;
reliable = null;
ttl = null;
mtu = null;
termLength = null;
initialTermId = null;
termId = null;
termOffset = null;
sessionId = null;
groupTag = null;
linger = null;
sparse = null;
eos = null;
tether = null;
group = null;
rejoin = null;
isSessionIdTagged = false;
socketRcvbufLength = null;
socketSndbufLength = null;
receiverWindowLength = null;
mediaReceiveTimestampOffset = null;
channelReceiveTimestampOffset = null;
channelSendTimestampOffset = null;
return this;
}
/**
* Validates that the collection of set parameters are valid together.
*
* @return this for a fluent API.
* @throws IllegalStateException if the combination of params is invalid.
*/
public ChannelUriStringBuilder validate()
{
if (null == media)
{
throw new IllegalStateException("media type is mandatory");
}
if (CommonContext.UDP_MEDIA.equals(media) && (null == endpoint && null == controlEndpoint))
{
throw new IllegalStateException("either 'endpoint' or 'control' must be specified for UDP.");
}
final boolean anyNonNull = null != initialTermId || null != termId || null != termOffset;
final boolean anyNull = null == initialTermId || null == termId || null == termOffset;
if (anyNonNull)
{
if (anyNull)
{
throw new IllegalStateException(
"either all or none of the parameters ['initialTermId', 'termId', 'termOffset'] must be provided");
}
if (termId - initialTermId < 0)
{
throw new IllegalStateException(
"difference greater than 2^31 - 1: termId=" + termId + " - initialTermId=" + initialTermId);
}
if (null != termLength && termOffset > termLength)
{
throw new IllegalStateException("termOffset=" + termOffset + " > termLength=" + termLength);
}
}
return this;
}
/**
* Set the prefix for taking an additional action such as spying on an outgoing publication with "aeron-spy".
*
* @param prefix to be applied to the URI before the scheme.
* @return this for a fluent API.
* @see ChannelUri#SPY_QUALIFIER
*/
public ChannelUriStringBuilder prefix(final String prefix)
{
if (null != prefix && !prefix.isEmpty() && !prefix.equals(SPY_QUALIFIER))
{
throw new IllegalArgumentException("invalid prefix: " + prefix);
}
this.prefix = prefix;
return this;
}
/**
* Set the prefix value to be what is in the {@link ChannelUri}.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see ChannelUri#SPY_QUALIFIER
*/
public ChannelUriStringBuilder prefix(final ChannelUri channelUri)
{
return prefix(channelUri.prefix());
}
/**
* Get the prefix for the additional action to be taken on the request.
*
* @return the prefix for the additional action to be taken on the request.
*/
public String prefix()
{
return prefix;
}
/**
* Set the media for this channel. Valid values are "udp" and "ipc".
*
* @param media for this channel.
* @return this for a fluent API.
*/
public ChannelUriStringBuilder media(final String media)
{
switch (media)
{
case CommonContext.UDP_MEDIA:
case CommonContext.IPC_MEDIA:
break;
default:
throw new IllegalArgumentException("invalid media: " + media);
}
this.media = media;
return this;
}
/**
* Set the endpoint value to be what is in the {@link ChannelUri}.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
*/
public ChannelUriStringBuilder media(final ChannelUri channelUri)
{
return media(channelUri.media());
}
/**
* The media over which the channel transmits.
*
* @return the media over which the channel transmits.
*/
public String media()
{
return media;
}
/**
* Set the endpoint address:port pairing for the channel. This is the address the publication sends to and the
* address the subscription receives from.
*
* @param endpoint address and port for the channel.
* @return this for a fluent API.
* @see CommonContext#ENDPOINT_PARAM_NAME
*/
public ChannelUriStringBuilder endpoint(final String endpoint)
{
this.endpoint = endpoint;
return this;
}
/**
* Set the endpoint value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#ENDPOINT_PARAM_NAME
*/
public ChannelUriStringBuilder endpoint(final ChannelUri channelUri)
{
return endpoint(channelUri.get(ENDPOINT_PARAM_NAME));
}
/**
* Get the endpoint address:port pairing for the channel.
*
* @return the endpoint address:port pairing for the channel.
* @see CommonContext#ENDPOINT_PARAM_NAME
*/
public String endpoint()
{
return endpoint;
}
/**
* Set the address of the local interface in the form host:[port]/[subnet mask] for routing traffic.
*
* @param networkInterface for routing traffic.
* @return this for a fluent API.
* @see CommonContext#INTERFACE_PARAM_NAME
*/
public ChannelUriStringBuilder networkInterface(final String networkInterface)
{
this.networkInterface = networkInterface;
return this;
}
/**
* Set the network interface value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#INTERFACE_PARAM_NAME
*/
public ChannelUriStringBuilder networkInterface(final ChannelUri channelUri)
{
return networkInterface(channelUri.get(INTERFACE_PARAM_NAME));
}
/**
* Get the address of the local interface in the form host:[port]/[subnet mask] for routing traffic.
*
* @return the address of the local interface in the form host:[port]/[subnet mask] for routing traffic.
* @see CommonContext#INTERFACE_PARAM_NAME
*/
public String networkInterface()
{
return networkInterface;
}
/**
* Set the control address:port pair for dynamically joining a multi-destination-cast publication.
*
* @param controlEndpoint for joining MDC control socket.
* @return this for a fluent API.
* @see CommonContext#MDC_CONTROL_PARAM_NAME
*/
public ChannelUriStringBuilder controlEndpoint(final String controlEndpoint)
{
this.controlEndpoint = controlEndpoint;
return this;
}
/**
* Set the control endpoint value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#MDC_CONTROL_PARAM_NAME
*/
public ChannelUriStringBuilder controlEndpoint(final ChannelUri channelUri)
{
return controlEndpoint(channelUri.get(MDC_CONTROL_PARAM_NAME));
}
/**
* Get the control address:port pair for dynamically joining a multi-destination-cast publication.
*
* @return the control address:port pair for dynamically joining a multi-destination-cast publication.
* @see CommonContext#MDC_CONTROL_PARAM_NAME
*/
public String controlEndpoint()
{
return controlEndpoint;
}
/**
* Set the control mode for multi-destination-cast. Set to "manual" for allowing control from the publication API.
*
* @param controlMode for taking control of MDC.
* @return this for a fluent API.
* @see Publication#addDestination(String)
* @see Publication#removeDestination(String)
* @see CommonContext#MDC_CONTROL_MODE_PARAM_NAME
* @see CommonContext#MDC_CONTROL_MODE_MANUAL
* @see CommonContext#MDC_CONTROL_MODE_DYNAMIC
*/
public ChannelUriStringBuilder controlMode(final String controlMode)
{
if (null != controlMode &&
!controlMode.equals(CommonContext.MDC_CONTROL_MODE_MANUAL) &&
!controlMode.equals(CommonContext.MDC_CONTROL_MODE_DYNAMIC))
{
throw new IllegalArgumentException("invalid control mode: " + controlMode);
}
this.controlMode = controlMode;
return this;
}
/**
* Set the control mode to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#MDC_CONTROL_MODE_PARAM_NAME
*/
public ChannelUriStringBuilder controlMode(final ChannelUri channelUri)
{
return controlMode(channelUri.get(MDC_CONTROL_MODE_PARAM_NAME));
}
/**
* Get the control mode for multi-destination-cast.
*
* @return the control mode for multi-destination-cast.
* @see CommonContext#MDC_CONTROL_MODE_PARAM_NAME
* @see CommonContext#MDC_CONTROL_MODE_MANUAL
* @see CommonContext#MDC_CONTROL_MODE_DYNAMIC
*/
public String controlMode()
{
return controlMode;
}
/**
* Set the subscription semantics for if loss is acceptable, or not, for a reliable message delivery.
*
* @param isReliable false if loss can be gap-filled.
* @return this for a fluent API.
* @see CommonContext#RELIABLE_STREAM_PARAM_NAME
*/
public ChannelUriStringBuilder reliable(final Boolean isReliable)
{
this.reliable = isReliable;
return this;
}
/**
* Set the reliable value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#RELIABLE_STREAM_PARAM_NAME
*/
public ChannelUriStringBuilder reliable(final ChannelUri channelUri)
{
final String reliableValue = channelUri.get(RELIABLE_STREAM_PARAM_NAME);
if (null == reliableValue)
{
reliable = null;
return this;
}
else
{
return reliable(Boolean.valueOf(reliableValue));
}
}
/**
* Get the subscription semantics for if loss is acceptable, or not, for a reliable message delivery.
*
* @return the subscription semantics for if loss is acceptable, or not, for a reliable message delivery.
* @see CommonContext#RELIABLE_STREAM_PARAM_NAME
*/
public Boolean reliable()
{
return reliable;
}
/**
* Set the Time To Live (TTL) for a multicast datagram. Valid values are 0-255 for the number of hops the datagram
* can progress along.
*
* @param ttl value for a multicast datagram.
* @return this for a fluent API.
* @see CommonContext#TTL_PARAM_NAME
*/
public ChannelUriStringBuilder ttl(final Integer ttl)
{
if (null != ttl && (ttl < 0 || ttl > 255))
{
throw new IllegalArgumentException("TTL not in range 0-255: " + ttl);
}
this.ttl = ttl;
return this;
}
/**
* Set the ttl value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#TTL_PARAM_NAME
*/
public ChannelUriStringBuilder ttl(final ChannelUri channelUri)
{
final String ttlValue = channelUri.get(TTL_PARAM_NAME);
if (null == ttlValue)
{
ttl = null;
return this;
}
else
{
try
{
return ttl(Integer.valueOf(ttlValue));
}
catch (final NumberFormatException ex)
{
throw new IllegalArgumentException("'ttl' must be a value integer", ex);
}
}
}
/**
* Get the Time To Live (TTL) for a multicast datagram.
*
* @return the Time To Live (TTL) for a multicast datagram.
* @see CommonContext#TTL_PARAM_NAME
*/
public Integer ttl()
{
return ttl;
}
/**
* Set the maximum transmission unit (MTU) including Aeron header for a datagram payload. If this is greater
* than the network MTU for UDP then the packet will be fragmented and can amplify the impact of loss.
*
* @param mtu the maximum transmission unit including Aeron header for a datagram payload.
* @return this for a fluent API.
* @see CommonContext#MTU_LENGTH_PARAM_NAME
*/
public ChannelUriStringBuilder mtu(final Integer mtu)
{
if (null != mtu)
{
if (mtu < 32 || mtu > 65504)
{
throw new IllegalArgumentException("MTU not in range 32-65504: " + mtu);
}
if ((mtu & (FRAME_ALIGNMENT - 1)) != 0)
{
throw new IllegalArgumentException("MTU not a multiple of FRAME_ALIGNMENT: mtu=" + mtu);
}
}
this.mtu = mtu;
return this;
}
/**
* Set the mtu value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#MTU_LENGTH_PARAM_NAME
*/
public ChannelUriStringBuilder mtu(final ChannelUri channelUri)
{
final String mtuValue = channelUri.get(MTU_LENGTH_PARAM_NAME);
if (null == mtuValue)
{
mtu = null;
return this;
}
else
{
final long value = parseSize(MTU_LENGTH_PARAM_NAME, mtuValue);
if (value > Integer.MAX_VALUE)
{
throw new IllegalStateException(MTU_LENGTH_PARAM_NAME + " " + value + " > " + Integer.MAX_VALUE);
}
return mtu((int)value);
}
}
/**
* Get the maximum transmission unit (MTU) including Aeron header for a datagram payload. If this is greater
* than the network MTU for UDP then the packet will be fragmented and can amplify the impact of loss.
*
* @return the maximum transmission unit (MTU) including Aeron header for a datagram payload.
* @see CommonContext#MTU_LENGTH_PARAM_NAME
*/
public Integer mtu()
{
return mtu;
}
/**
* Set the length of buffer used for each term of the log. Valid values are powers of 2 in the 64K - 1G range.
*
* @param termLength of the buffer used for each term of the log.
* @return this for a fluent API.
* @see CommonContext#TERM_LENGTH_PARAM_NAME
*/
public ChannelUriStringBuilder termLength(final Integer termLength)
{
if (null != termLength)
{
LogBufferDescriptor.checkTermLength(termLength);
}
this.termLength = termLength;
return this;
}
/**
* Set the termLength value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#TERM_LENGTH_PARAM_NAME
*/
public ChannelUriStringBuilder termLength(final ChannelUri channelUri)
{
final String termLengthValue = channelUri.get(TERM_LENGTH_PARAM_NAME);
if (null == termLengthValue)
{
termLength = null;
return this;
}
else
{
final long value = parseSize(TERM_LENGTH_PARAM_NAME, termLengthValue);
if (value > Integer.MAX_VALUE)
{
throw new IllegalStateException(
"term length more than max length of " + TERM_MAX_LENGTH + ": value=" + value);
}
return termLength((int)value);
}
}
/**
* Get the length of buffer used for each term of the log.
*
* @return the length of buffer used for each term of the log.
* @see CommonContext#TERM_LENGTH_PARAM_NAME
*/
public Integer termLength()
{
return termLength;
}
/**
* Set the initial term id at which a publication will start.
*
* @param initialTermId the initial term id at which a publication will start.
* @return this for a fluent API.
* @see CommonContext#INITIAL_TERM_ID_PARAM_NAME
*/
public ChannelUriStringBuilder initialTermId(final Integer initialTermId)
{
this.initialTermId = initialTermId;
return this;
}
/**
* Set the initialTermId value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#INITIAL_TERM_ID_PARAM_NAME
*/
public ChannelUriStringBuilder initialTermId(final ChannelUri channelUri)
{
final String initialTermIdValue = channelUri.get(INITIAL_TERM_ID_PARAM_NAME);
if (null == initialTermIdValue)
{
initialTermId = null;
return this;
}
else
{
try
{
return initialTermId(Integer.valueOf(initialTermIdValue));
}
catch (final NumberFormatException ex)
{
throw new IllegalArgumentException("'initial-term-id' must be a valid integer", ex);
}
}
}
/**
* the initial term id at which a publication will start.
*
* @return the initial term id at which a publication will start.
* @see CommonContext#INITIAL_TERM_ID_PARAM_NAME
*/
public Integer initialTermId()
{
return initialTermId;
}
/**
* Set the current term id at which a publication will start. This when combined with the initial term can
* establish a starting position.
*
* @param termId at which a publication will start.
* @return this for a fluent API.
* @see CommonContext#TERM_ID_PARAM_NAME
*/
public ChannelUriStringBuilder termId(final Integer termId)
{
this.termId = termId;
return this;
}
/**
* Set the termId value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#TERM_ID_PARAM_NAME
*/
public ChannelUriStringBuilder termId(final ChannelUri channelUri)
{
final String termIdValue = channelUri.get(TERM_ID_PARAM_NAME);
if (null == termIdValue)
{
termId = null;
return this;
}
else
{
try
{
return termId(Integer.valueOf(termIdValue));
}
catch (final NumberFormatException ex)
{
throw new IllegalArgumentException("'term-id' must be a valid integer", ex);
}
}
}
/**
* Get the current term id at which a publication will start.
*
* @return the current term id at which a publication will start.
* @see CommonContext#TERM_ID_PARAM_NAME
*/
public Integer termId()
{
return termId;
}
/**
* Set the offset within a term at which a publication will start. This when combined with the term id can establish
* a starting position.
*
* @param termOffset within a term at which a publication will start.
* @return this for a fluent API.
* @see CommonContext#TERM_OFFSET_PARAM_NAME
*/
public ChannelUriStringBuilder termOffset(final Integer termOffset)
{
if (null != termOffset)
{
if ((termOffset < 0 || termOffset > TERM_MAX_LENGTH))
{
throw new IllegalArgumentException("term offset not in range 0-1g: " + termOffset);
}
if (0 != (termOffset & (FRAME_ALIGNMENT - 1)))
{
throw new IllegalArgumentException("term offset not multiple of FRAME_ALIGNMENT: " + termOffset);
}
}
this.termOffset = termOffset;
return this;
}
/**
* Set the termOffset value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#TERM_OFFSET_PARAM_NAME
*/
public ChannelUriStringBuilder termOffset(final ChannelUri channelUri)
{
final String termOffsetValue = channelUri.get(TERM_OFFSET_PARAM_NAME);
if (null == termOffsetValue)
{
termOffset = null;
return this;
}
else
{
try
{
return termOffset(Integer.valueOf(termOffsetValue));
}
catch (final NumberFormatException ex)
{
throw new IllegalArgumentException("'term-offset' must be a valid integer", ex);
}
}
}
/**
* Get the offset within a term at which a publication will start.
*
* @return the offset within a term at which a publication will start.
* @see CommonContext#TERM_OFFSET_PARAM_NAME
*/
public Integer termOffset()
{
return termOffset;
}
/**
* Set the session id for a publication or restricted subscription.
*
* @param sessionId for the publication or a restricted subscription.
* @return this for a fluent API.
* @see CommonContext#SESSION_ID_PARAM_NAME
*/
public ChannelUriStringBuilder sessionId(final Integer sessionId)
{
this.sessionId = null != sessionId ? sessionId.longValue() : null;
return this;
}
/**
* Set the session id for a publication or restricted subscription from a formatted string. Supports a format of
* either a string encoded signed 32-bit number or 'tag:' followed by a signed 64 bit value.
*
* @param sessionIdStr for the publication or a restricted subscription.
* @return this for a fluent API.
* @see CommonContext#SESSION_ID_PARAM_NAME
*/
public ChannelUriStringBuilder sessionId(final String sessionIdStr)
{
if (null != sessionIdStr)
{
if (ChannelUri.isTagged(sessionIdStr))
{
taggedSessionId(ChannelUri.getTag(sessionIdStr));
}
else
{
isSessionIdTagged(false);
try
{
sessionId(Integer.valueOf(sessionIdStr));
}
catch (final NumberFormatException ex)
{
throw new IllegalArgumentException("'session-id' must be a valid integer", ex);
}
}
}
else
{
sessionId((Integer)null);
}
return this;
}
/**
* Set the session id for a publication or restricted subscription as a tag referenced value.
*
* @param sessionId for the publication or a restricted subscription.
* @return this for a fluent API.
* @see CommonContext#SESSION_ID_PARAM_NAME
*/
public ChannelUriStringBuilder taggedSessionId(final Long sessionId)
{
isSessionIdTagged(true);
this.sessionId = sessionId;
return this;
}
/**
* Set the sessionId value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#SESSION_ID_PARAM_NAME
*/
public ChannelUriStringBuilder sessionId(final ChannelUri channelUri)
{
return sessionId(channelUri.get(SESSION_ID_PARAM_NAME));
}
/**
* Get the session id for a publication or restricted subscription.
*
* @return the session id for a publication or restricted subscription.
* @see CommonContext#SESSION_ID_PARAM_NAME
* @deprecated this method will not correctly handle tagged sessionId values that are outside the range of
* a signed 32-bit number. If this is called and a tagged value outside this range is currently held in this
* object, then the result will be the same as {@link Long#intValue()}.
*/
@Deprecated
public Integer sessionId()
{
return null != sessionId ? sessionId.intValue() : null;
}
/**
* Set the time a network publication will linger in nanoseconds after being drained. This time is so that tail
* loss can be recovered.
*
* @param lingerNs time for the publication after it is drained.
* @return this for a fluent API.
* @see CommonContext#LINGER_PARAM_NAME
*/
public ChannelUriStringBuilder linger(final Long lingerNs)
{
if (null != lingerNs && lingerNs < 0)
{
throw new IllegalArgumentException("linger value cannot be negative: " + lingerNs);
}
this.linger = lingerNs;
return this;
}
/**
* Set the linger value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#LINGER_PARAM_NAME
*/
public ChannelUriStringBuilder linger(final ChannelUri channelUri)
{
final String lingerValue = channelUri.get(LINGER_PARAM_NAME);
if (null == lingerValue)
{
linger = null;
return this;
}
else
{
return linger(parseDuration(LINGER_PARAM_NAME, lingerValue));
}
}
/**
* Get the time a network publication will linger in nanoseconds after being drained. This time is so that tail
* loss can be recovered.
*
* @return the time in nanoseconds a publication will linger after being drained.
* @see CommonContext#LINGER_PARAM_NAME
*/
public Long linger()
{
return linger;
}
/**
* Set to indicate if a term log buffer should be sparse on disk or not. Sparse saves space at the potential
* expense of latency.
*
* @param isSparse true if the term buffer log is sparse on disk.
* @return this for a fluent API.
* @see CommonContext#SPARSE_PARAM_NAME
*/
public ChannelUriStringBuilder sparse(final Boolean isSparse)
{
this.sparse = isSparse;
return this;
}
/**
* Set the sparse value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#SPARSE_PARAM_NAME
*/
public ChannelUriStringBuilder sparse(final ChannelUri channelUri)
{
final String sparseValue = channelUri.get(SPARSE_PARAM_NAME);
if (null == sparseValue)
{
sparse = null;
return this;
}
else
{
return sparse(Boolean.valueOf(sparseValue));
}
}
/**
* Should term log buffer be sparse on disk or not. Sparse saves space at the potential expense of latency.
*
* @return true if the term buffer log is sparse on disk.
* @see CommonContext#SPARSE_PARAM_NAME
*/
public Boolean sparse()
{
return sparse;
}
/**
* Set to indicate if an EOS should be sent on the media or not.
*
* @param eos true if the EOS should be sent.
* @return this for a fluent API.
* @see CommonContext#EOS_PARAM_NAME
*/
public ChannelUriStringBuilder eos(final Boolean eos)
{
this.eos = eos;
return this;
}
/**
* Set the eos value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#EOS_PARAM_NAME
*/
public ChannelUriStringBuilder eos(final ChannelUri channelUri)
{
final String eosValue = channelUri.get(EOS_PARAM_NAME);
if (null == eosValue)
{
eos = null;
return this;
}
else
{
return eos(Boolean.valueOf(eosValue));
}
}
/**
* Should an EOS flag be sent on the media or not.
*
* @return true if the EOS param should be set.
* @see CommonContext#EOS_PARAM_NAME
*/
public Boolean eos()
{
return eos;
}
/**
* Should the subscription channel be tethered or not for local flow control.
*
* @param tether value to be set for the tether param.
* @return this for a fluent API.
* @see CommonContext#TETHER_PARAM_NAME
*/
public ChannelUriStringBuilder tether(final Boolean tether)
{
this.tether = tether;
return this;
}
/**
* Set the tether value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#TETHER_PARAM_NAME
*/
public ChannelUriStringBuilder tether(final ChannelUri channelUri)
{
final String tetherValue = channelUri.get(TETHER_PARAM_NAME);
if (null == tetherValue)
{
tether = null;
return this;
}
else
{
return tether(Boolean.valueOf(tetherValue));
}
}
/**
* Should the subscription channel be tethered or not for local flow control.
*
* @return value of the tether param.
* @see CommonContext#TETHER_PARAM_NAME
*/
public Boolean tether()
{
return tether;
}
/**
* Is the receiver likely to be part of a group. This informs behaviour such as loss handling.
*
* @param group value to be set for the group param.
* @return this for a fluent API.
* @see CommonContext#GROUP_PARAM_NAME
* @see #controlMode()
* @see #controlEndpoint()
*/
public ChannelUriStringBuilder group(final Boolean group)
{
this.group = group;
return this;
}
/**
* Set the group value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#GROUP_PARAM_NAME
*/
public ChannelUriStringBuilder group(final ChannelUri channelUri)
{
final String groupValue = channelUri.get(GROUP_PARAM_NAME);
if (null == groupValue)
{
group = null;
return this;
}
else
{
return group(Boolean.valueOf(groupValue));
}
}
/**
* Is the receiver likely to be part of a group. This informs behaviour such as loss handling.
*
* @return value of the group param.
* @see CommonContext#GROUP_PARAM_NAME
* @see #controlMode()
* @see #controlEndpoint()
*/
public Boolean group()
{
return group;
}
/**
* Set the tags for a channel used by a publication or subscription. Tags can be used to identify or tag a
* channel so that a configuration can be referenced and reused.
*
* @param tags for the channel, publication or subscription.
* @return this for a fluent API.
* @see CommonContext#TAGS_PARAM_NAME
* @see CommonContext#TAG_PREFIX
*/
public ChannelUriStringBuilder tags(final String tags)
{
this.tags = tags;
return this;
}
/**
* Set the tags to be value which is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#TAGS_PARAM_NAME
*/
public ChannelUriStringBuilder tags(final ChannelUri channelUri)
{
return tags(channelUri.get(TAGS_PARAM_NAME));
}
/**
* Set the tags to the specified channel and publication/subscription tag {@link ChannelUri}. The
* publication/subscription may be null. If channel tag is null, then the pubSubTag must be null.
*
* @param channelTag optional value for the channel tag.
* @param pubSubTag option value for the publication/subscription tag.
* @return this for a fluent API.
* @throws IllegalArgumentException if channelTag is null and pubSubTag is not.
* @see CommonContext#TAGS_PARAM_NAME
*/
public ChannelUriStringBuilder tags(final Long channelTag, final Long pubSubTag)
{
if (null == channelTag && null != pubSubTag)
{
throw new IllegalArgumentException("null == channelTag && null != pubSubTag");
}
if (null == channelTag)
{
return tags((String)null);
}
return tags(channelTag + (null != pubSubTag ? "," + pubSubTag : ""));
}
/**
* Get the tags for a channel used by a publication or subscription. Tags can be used to identify or tag a
* channel so that a configuration can be referenced and reused.
*
* @return the tags for a channel, publication or subscription.
* @see CommonContext#TAGS_PARAM_NAME
* @see CommonContext#TAG_PREFIX
*/
public String tags()
{
return tags;
}
/**
* Toggle the value for {@link #sessionId()} being tagged or not.
*
* @param isSessionIdTagged for session id
* @return this for a fluent API.
* @see CommonContext#TAGS_PARAM_NAME
* @see CommonContext#TAG_PREFIX
*/
public ChannelUriStringBuilder isSessionIdTagged(final boolean isSessionIdTagged)
{
this.isSessionIdTagged = isSessionIdTagged;
return this;
}
/**
* Is the value for {@link #sessionId()} a tag.
*
* @return whether the value for {@link #sessionId()} a tag reference or not.
* @see CommonContext#TAGS_PARAM_NAME
* @see CommonContext#TAG_PREFIX
*/
public boolean isSessionIdTagged()
{
return isSessionIdTagged;
}
/**
* Set the alias for a URI. Aliases are not interpreted by Aeron and are to be used by the application.
*
* @param alias for the URI.
* @return this for a fluent API.
* @see CommonContext#ALIAS_PARAM_NAME
*/
public ChannelUriStringBuilder alias(final String alias)
{
this.alias = alias;
return this;
}
/**
* Set the alias to be value which is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#TAGS_PARAM_NAME
*/
public ChannelUriStringBuilder alias(final ChannelUri channelUri)
{
return alias(channelUri.get(ALIAS_PARAM_NAME));
}
/**
* Get the alias present in the URI.
*
* @return alias for the URI.
* @see CommonContext#ALIAS_PARAM_NAME
*/
public String alias()
{
return alias;
}
/**
* Set the congestion control algorithm to be used on a stream.
*
* @param congestionControl for the URI.
* @return this for a fluent API.
* @see CommonContext#CONGESTION_CONTROL_PARAM_NAME
*/
public ChannelUriStringBuilder congestionControl(final String congestionControl)
{
this.cc = congestionControl;
return this;
}
/**
* Set the congestion control to be value which is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#CONGESTION_CONTROL_PARAM_NAME
*/
public ChannelUriStringBuilder congestionControl(final ChannelUri channelUri)
{
return congestionControl(channelUri.get(CONGESTION_CONTROL_PARAM_NAME));
}
/**
* Get the congestion control algorithm to be used on a stream.
*
* @return congestion control strategy for the channel.
* @see CommonContext#CONGESTION_CONTROL_PARAM_NAME
*/
public String congestionControl()
{
return cc;
}
/**
* Set the flow control strategy to be used on a stream.
*
* @param flowControl for the URI.
* @return this for a fluent API.
* @see CommonContext#FLOW_CONTROL_PARAM_NAME
*/
public ChannelUriStringBuilder flowControl(final String flowControl)
{
this.fc = flowControl;
return this;
}
/**
* Set tagged flow control settings to be used on a stream. All specified values may be null and the default
* specified in the MediaDriver.Context will be used instead.
*
* @param groupTag receiver tag for this stream.
* @param minGroupSize group size required to allow publications for this channel to be moved to connected status.
* @param timeout timeout receivers, default is ns, but allows suffixing of time units (e.g. 5s).
* @return this for fluent API.
*/
public ChannelUriStringBuilder taggedFlowControl(
final Long groupTag, final Integer minGroupSize, final String timeout)
{
String flowControlValue = "tagged";
if (null != groupTag || null != minGroupSize)
{
flowControlValue += ",g:";
if (null != groupTag)
{
flowControlValue += groupTag;
}
if (null != minGroupSize)
{
flowControlValue += ("/" + minGroupSize);
}
}
if (null != timeout)
{
flowControlValue += (",t:" + timeout);
}
return flowControl(flowControlValue);
}
/**
* Set min flow control settings to be used on stream. All specified values may be null and the default
* specified in the MediaDriver.Context will be used instead.
*
* @param minGroupSize group size required to allow publications for this stream to be moved to connected status.
* @param timeout timeout receivers, default is ns, but allows suffixing of time units (e.g. 5s).
* @return this for fluent API.
*/
public ChannelUriStringBuilder minFlowControl(final Integer minGroupSize, final String timeout)
{
String flowControlValue = "min";
if (null != minGroupSize)
{
flowControlValue += (",g:/" + minGroupSize);
}
if (null != timeout)
{
flowControlValue += (",t:" + timeout);
}
return flowControl(flowControlValue);
}
/**
* Set the flow control to be value which is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#FLOW_CONTROL_PARAM_NAME
*/
public ChannelUriStringBuilder flowControl(final ChannelUri channelUri)
{
return flowControl(channelUri.get(FLOW_CONTROL_PARAM_NAME));
}
/**
* Get the flow control strategy to be used on a stream.
*
* @return flow control strategy for the stream.
* @see CommonContext#FLOW_CONTROL_PARAM_NAME
*/
public String flowControl()
{
return fc;
}
/**
* Set the group tag (gtag) to be sent in SMs (Status Messages).
*
* @param groupTag to be sent in SMs
* @return this for fluent API.
* @see CommonContext#GROUP_TAG_PARAM_NAME
*/
public ChannelUriStringBuilder groupTag(final Long groupTag)
{
this.groupTag = groupTag;
return this;
}
/**
* Set the group tag (gtag) to be the value which is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#GROUP_TAG_PARAM_NAME
*/
public ChannelUriStringBuilder groupTag(final ChannelUri channelUri)
{
final String groupTagValue = channelUri.get(GROUP_TAG_PARAM_NAME);
if (null == groupTagValue)
{
groupTag = null;
return this;
}
else
{
try
{
return groupTag(Long.valueOf(groupTagValue));
}
catch (final NumberFormatException ex)
{
throw new IllegalArgumentException("'gtag' must be a valid long value", ex);
}
}
}
/**
* Get the group tag (gtag) to be sent in SMs (Status Messages).
*
* @return receiver tag to be sent in SMs.
* @see CommonContext#GROUP_TAG_PARAM_NAME
*/
public Long groupTag()
{
return groupTag;
}
/**
* Set the subscription semantics for if a stream should be rejoined after going unavailable.
*
* @param rejoin false if stream is not to be rejoined.
* @return this for a fluent API.
* @see CommonContext#REJOIN_PARAM_NAME
*/
public ChannelUriStringBuilder rejoin(final Boolean rejoin)
{
this.rejoin = rejoin;
return this;
}
/**
* Set the rejoin value to be what is in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#REJOIN_PARAM_NAME
*/
public ChannelUriStringBuilder rejoin(final ChannelUri channelUri)
{
final String rejoinValue = channelUri.get(REJOIN_PARAM_NAME);
if (null == rejoinValue)
{
rejoin = null;
return this;
}
else
{
return rejoin(Boolean.valueOf(rejoinValue));
}
}
/**
* Get the subscription semantics for if a stream should be rejoined after going unavailable.
*
* @return the subscription semantics for if a stream should be rejoined after going unavailable.
* @see CommonContext#REJOIN_PARAM_NAME
*/
public Boolean rejoin()
{
return rejoin;
}
/**
* Set the publication semantics for whether the presence of spy subscriptions simulate a connection.
*
* @param spiesSimulateConnection true if the presence of spy subscriptions simulate a connection.
* @return this for a fluent API.
* @see CommonContext#SPIES_SIMULATE_CONNECTION_PARAM_NAME
*/
public ChannelUriStringBuilder spiesSimulateConnection(final Boolean spiesSimulateConnection)
{
this.ssc = spiesSimulateConnection;
return this;
}
/**
* Set the publication semantics for whether the presence of spy subscriptions simulate a connection to be what is
* in the {@link ChannelUri} which may be null.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#SPIES_SIMULATE_CONNECTION_PARAM_NAME
*/
public ChannelUriStringBuilder spiesSimulateConnection(final ChannelUri channelUri)
{
final String sscValue = channelUri.get(SPIES_SIMULATE_CONNECTION_PARAM_NAME);
if (null == sscValue)
{
ssc = null;
return this;
}
else
{
return spiesSimulateConnection(Boolean.valueOf(sscValue));
}
}
/**
* Get the publication semantics for whether the presence of spy subscriptions simulate a connection.
*
* @return true if the presence of spy subscriptions simulate a connection, otherwise false.
* @see CommonContext#SPIES_SIMULATE_CONNECTION_PARAM_NAME
*/
public Boolean spiesSimulateConnection()
{
return ssc;
}
/**
* Initialise a channel for restarting a publication at a given position.
*
* @param position at which the publication should be started.
* @param initialTermId what which the stream would start.
* @param termLength for the stream.
* @return this for a fluent API.
*/
public ChannelUriStringBuilder initialPosition(final long position, final int initialTermId, final int termLength)
{
if (position < 0)
{
throw new IllegalArgumentException("invalid position=" + position + " < 0");
}
if (0 != (position & (FRAME_ALIGNMENT - 1)))
{
throw new IllegalArgumentException(
"invalid position=" + position + " does not have frame alignment=" + FRAME_ALIGNMENT);
}
final int bitsToShift = LogBufferDescriptor.positionBitsToShift(termLength);
this.initialTermId = initialTermId;
this.termId = LogBufferDescriptor.computeTermIdFromPosition(position, bitsToShift, initialTermId);
this.termOffset = (int)(position & (termLength - 1));
this.termLength = termLength;
return this;
}
/**
* Set the underlying OS send buffer length.
*
* @param socketSndbufLength parameter to be passed as SO_SNDBUF value.
* @return this for a fluent API.
* @see CommonContext#SOCKET_SNDBUF_PARAM_NAME
*/
public ChannelUriStringBuilder socketSndbufLength(final Integer socketSndbufLength)
{
this.socketSndbufLength = socketSndbufLength;
return this;
}
/**
* Set the underlying OS send buffer length from an existing {@link ChannelUri} which may be (null).
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#SOCKET_SNDBUF_PARAM_NAME
*/
public ChannelUriStringBuilder socketSndbufLength(final ChannelUri channelUri)
{
final String valueStr = channelUri.get(SOCKET_SNDBUF_PARAM_NAME);
if (null == valueStr)
{
this.socketSndbufLength = null;
return this;
}
else
{
final long value = parseSize(SOCKET_SNDBUF_PARAM_NAME, valueStr);
if (value > Integer.MAX_VALUE)
{
throw new IllegalStateException("value exceeds maximum permitted: value=" + value);
}
return socketSndbufLength((int)value);
}
}
/**
* Get the underling OS send buffer length setting
*
* @return underlying OS send buffer length setting or null if not specified.
* @see CommonContext#SOCKET_SNDBUF_PARAM_NAME
*/
public Integer socketSndbufLength()
{
return socketSndbufLength;
}
/**
* Set the underlying OS receive buffer length.
*
* @param socketRcvbufLength parameter to be passed as SO_SNDBUF value.
* @return this for a fluent API.
* @see CommonContext#SOCKET_RCVBUF_PARAM_NAME
*/
public ChannelUriStringBuilder socketRcvbufLength(final Integer socketRcvbufLength)
{
this.socketRcvbufLength = socketRcvbufLength;
return this;
}
/**
* Set the underlying OS receive buffer length from an existing {@link ChannelUri}, which may have a null value for
* this field.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#SOCKET_RCVBUF_PARAM_NAME
*/
public ChannelUriStringBuilder socketRcvbufLength(final ChannelUri channelUri)
{
final String valueStr = channelUri.get(SOCKET_RCVBUF_PARAM_NAME);
if (null == valueStr)
{
this.socketRcvbufLength = null;
return this;
}
else
{
final long value = parseSize(SOCKET_RCVBUF_PARAM_NAME, valueStr);
if (value > Integer.MAX_VALUE)
{
throw new IllegalStateException("value exceeds maximum permitted: value=" + value);
}
return socketRcvbufLength((int)value);
}
}
/**
* Get the underling OS receive buffer length setting.
*
* @return underlying OS receive buffer length setting or null if not specified.
* @see CommonContext#SOCKET_RCVBUF_PARAM_NAME
*/
public Integer socketRcvbufLength()
{
return socketRcvbufLength;
}
/**
* Set the flow control initial receiver window length for this channel.
*
* @param receiverWindowLength initial receiver window length.
* @return this for a fluent API.
* @see CommonContext#RECEIVER_WINDOW_LENGTH_PARAM_NAME
*/
public ChannelUriStringBuilder receiverWindowLength(final Integer receiverWindowLength)
{
this.receiverWindowLength = receiverWindowLength;
return this;
}
/**
* Set the flow control initial receiver window length for this channel from an existing {@link ChannelUri},
* which may have a null value for this field.
*
* @param channelUri to read the value from.
* @return this for a fluent API.
* @see CommonContext#RECEIVER_WINDOW_LENGTH_PARAM_NAME
*/
public ChannelUriStringBuilder receiverWindowLength(final ChannelUri channelUri)
{
final String valueStr = channelUri.get(RECEIVER_WINDOW_LENGTH_PARAM_NAME);
if (null == valueStr)
{
this.receiverWindowLength = null;
return this;
}
else
{
final long value = parseSize(RECEIVER_WINDOW_LENGTH_PARAM_NAME, valueStr);
if (value > Integer.MAX_VALUE)
{
throw new IllegalStateException("value exceeds maximum permitted: value=" + value);
}
return receiverWindowLength((int)value);
}
}
/**
* Get the receiver window length to be used as the initial receiver window for flow control.
*
* @return receiver window length.
* @see CommonContext#SOCKET_RCVBUF_PARAM_NAME
*/
public Integer receiverWindowLength()
{
return receiverWindowLength;
}
/**
* Offset into a message to store the media receive timestamp. May also be the special value 'reserved' which means
* to store the timestamp in the reserved value field.
*
* @return current mediaReceiveTimestampOffset value either as string representation of an integer index or the
* special value 'reserved'
*/
public String mediaReceiveTimestampOffset()
{
return mediaReceiveTimestampOffset;
}
/**
* Offset into a message to store the media receive timestamp. May also be the special value 'reserved' which means
* to store the timestamp in the reserved value field.
*
* @param timestampOffset to use as the offset.
* @return this for a fluent API.
* @throws IllegalArgumentException if the string is not null and doesn't represent an int or the 'reserved' value.
*/
public ChannelUriStringBuilder mediaReceiveTimestampOffset(final String timestampOffset)
{
if (null != timestampOffset && !RESERVED_OFFSET.equals(timestampOffset))
{
try
{
Integer.parseInt(timestampOffset);
}
catch (final NumberFormatException ex)
{
throw new IllegalArgumentException(
"mediaReceiveTimestampOffset must be a number or the value '" + RESERVED_OFFSET + "'");
}
}
this.mediaReceiveTimestampOffset = timestampOffset;
return this;
}
/**
* Offset into a message to store the media receive timestamp. May also be the special value 'reserved' which means
* to store the timestamp in the reserved value field.
*
* @param channelUri the existing URI to extract the mediaReceiveTimestampOffset from
* @return this for a fluent API.
*/
public ChannelUriStringBuilder mediaReceiveTimestampOffset(final ChannelUri channelUri)
{
return mediaReceiveTimestampOffset(channelUri.get(MEDIA_RCV_TIMESTAMP_OFFSET_PARAM_NAME));
}
/**
* Offset into a message to store the channel receive timestamp. May also be the special value 'reserved' which
* means to store the timestamp in the reserved value field.
*
* @return current channelReceiveTimestampOffset value either as string representation of an integer index or
* the special value 'reserved'
*/
public String channelReceiveTimestampOffset()
{
return channelReceiveTimestampOffset;
}
/**
* Offset into a message to store the channel receive timestamp. May also be the special value 'reserved' which
* means to store the timestamp in the reserved value field.
*
* @param timestampOffset to use as the offset.
* @return this for a fluent API.
* @throws IllegalArgumentException if the string doesn't represent an int or the 'reserved' value.
*/
public ChannelUriStringBuilder channelReceiveTimestampOffset(final String timestampOffset)
{
if (null != timestampOffset && !RESERVED_OFFSET.equals(timestampOffset))
{
try
{
Integer.parseInt(timestampOffset);
}
catch (final NumberFormatException ex)
{
throw new IllegalArgumentException(
"channelReceiveTimestampOffset must be a number or the value '" + RESERVED_OFFSET + "'");
}
}
this.channelReceiveTimestampOffset = timestampOffset;
return this;
}
/**
* Offset into a message to store the channel receive timestamp. May also be the special value 'reserved' which
* means to store the timestamp in the reserved value field.
*
* @param channelUri the existing URI to extract the receiveTimestampOffset from.
* @return this for a fluent API.
*/
public ChannelUriStringBuilder channelReceiveTimestampOffset(final ChannelUri channelUri)
{
return channelReceiveTimestampOffset(channelUri.get(CHANNEL_RECEIVE_TIMESTAMP_OFFSET_PARAM_NAME));
}
/**
* Offset into a message to store the channel send timestamp. May also be the special value 'reserved' which means
* to store the timestamp in the reserved value field.
*
* @return current sendTimestampOffset value either as string representation of an integer index or the special
* value 'reserved'.
*/
public String channelSendTimestampOffset()
{
return channelSendTimestampOffset;
}
/**
* Offset into a message to store the channel send timestamp. May also be the special value 'reserved' which means
* to store the timestamp in the reserved value field.
*
* @param timestampOffset to use as the offset.
* @return this for a fluent API.
* @throws IllegalArgumentException if the string is not null doesn't represent an int or the 'reserved' value.
*/
public ChannelUriStringBuilder channelSendTimestampOffset(final String timestampOffset)
{
if (null != timestampOffset && !RESERVED_OFFSET.equals(timestampOffset))
{
try
{
Integer.parseInt(timestampOffset);
}
catch (final NumberFormatException ex)
{
throw new IllegalArgumentException(
"channelSendTimestampOffset must be a number or the value '" + RESERVED_OFFSET + "' found: " +
timestampOffset);
}
}
this.channelSendTimestampOffset = timestampOffset;
return this;
}
/**
* Offset into a message to store the channel send timestamp. May also be the special value 'reserved' which means
* to store the timestamp in the reserved value field.
*
* @param channelUri the existing URI to extract the channelSendTimestampOffset from.
* @return this for a fluent API.
*/
public ChannelUriStringBuilder channelSendTimestampOffset(final ChannelUri channelUri)
{
return channelSendTimestampOffset(channelUri.get(CHANNEL_SEND_TIMESTAMP_OFFSET_PARAM_NAME));
}
/**
* Build a channel URI String for the given parameters.
*
* @return a channel URI String for the given parameters.
*/
@SuppressWarnings("MethodLength")
public String build()
{
sb.setLength(0);
if (null != prefix && !prefix.isEmpty())
{
sb.append(prefix).append(':');
}
sb.append(ChannelUri.AERON_SCHEME).append(':').append(media).append('?');
if (null != tags)
{
sb.append(TAGS_PARAM_NAME).append('=').append(tags).append('|');
}
if (null != endpoint)
{
sb.append(ENDPOINT_PARAM_NAME).append('=').append(endpoint).append('|');
}
if (null != networkInterface)
{
sb.append(INTERFACE_PARAM_NAME).append('=').append(networkInterface).append('|');
}
if (null != controlEndpoint)
{
sb.append(MDC_CONTROL_PARAM_NAME).append('=').append(controlEndpoint).append('|');
}
if (null != controlMode)
{
sb.append(MDC_CONTROL_MODE_PARAM_NAME).append('=').append(controlMode).append('|');
}
if (null != mtu)
{
sb.append(MTU_LENGTH_PARAM_NAME).append('=').append(mtu.intValue()).append('|');
}
if (null != termLength)
{
sb.append(TERM_LENGTH_PARAM_NAME).append('=').append(termLength.intValue()).append('|');
}
if (null != initialTermId)
{
sb.append(INITIAL_TERM_ID_PARAM_NAME).append('=').append(initialTermId.intValue()).append('|');
}
if (null != termId)
{
sb.append(TERM_ID_PARAM_NAME).append('=').append(termId.intValue()).append('|');
}
if (null != termOffset)
{
sb.append(TERM_OFFSET_PARAM_NAME).append('=').append(termOffset.intValue()).append('|');
}
if (null != sessionId)
{
sb.append(SESSION_ID_PARAM_NAME).append('=').append(prefixTag(isSessionIdTagged, sessionId)).append('|');
}
if (null != ttl)
{
sb.append(TTL_PARAM_NAME).append('=').append(ttl.intValue()).append('|');
}
if (null != reliable)
{
sb.append(RELIABLE_STREAM_PARAM_NAME).append('=').append(reliable).append('|');
}
if (null != linger)
{
sb.append(LINGER_PARAM_NAME).append('=').append(linger).append('|');
}
if (null != alias)
{
sb.append(ALIAS_PARAM_NAME).append('=').append(alias).append('|');
}
if (null != cc)
{
sb.append(CONGESTION_CONTROL_PARAM_NAME).append('=').append(cc).append('|');
}
if (null != fc)
{
sb.append(FLOW_CONTROL_PARAM_NAME).append('=').append(fc).append('|');
}
if (null != groupTag)
{
sb.append(GROUP_TAG_PARAM_NAME).append('=').append(groupTag).append('|');
}
if (null != sparse)
{
sb.append(SPARSE_PARAM_NAME).append('=').append(sparse).append('|');
}
if (null != eos)
{
sb.append(EOS_PARAM_NAME).append('=').append(eos).append('|');
}
if (null != tether)
{
sb.append(TETHER_PARAM_NAME).append('=').append(tether).append('|');
}
if (null != group)
{
sb.append(GROUP_PARAM_NAME).append('=').append(group).append('|');
}
if (null != rejoin)
{
sb.append(REJOIN_PARAM_NAME).append('=').append(rejoin).append('|');
}
if (null != ssc)
{
sb.append(SPIES_SIMULATE_CONNECTION_PARAM_NAME).append('=').append(ssc).append('|');
}
if (null != socketSndbufLength)
{
sb.append(SOCKET_SNDBUF_PARAM_NAME).append('=').append(socketSndbufLength).append('|');
}
if (null != socketRcvbufLength)
{
sb.append(SOCKET_RCVBUF_PARAM_NAME).append('=').append(socketRcvbufLength).append('|');
}
if (null != receiverWindowLength)
{
sb.append(RECEIVER_WINDOW_LENGTH_PARAM_NAME).append('=').append(receiverWindowLength).append('|');
}
if (null != mediaReceiveTimestampOffset)
{
sb.append(MEDIA_RCV_TIMESTAMP_OFFSET_PARAM_NAME)
.append('=')
.append(mediaReceiveTimestampOffset)
.append('|');
}
if (null != channelReceiveTimestampOffset)
{
sb.append(CHANNEL_RECEIVE_TIMESTAMP_OFFSET_PARAM_NAME)
.append('=')
.append(channelReceiveTimestampOffset)
.append('|');
}
if (null != channelSendTimestampOffset)
{
sb.append(CHANNEL_SEND_TIMESTAMP_OFFSET_PARAM_NAME)
.append('=')
.append(channelSendTimestampOffset)
.append('|');
}
final char lastChar = sb.charAt(sb.length() - 1);
if (lastChar == '|' || lastChar == '?')
{
sb.setLength(sb.length() - 1);
}
return sb.toString();
}
/**
* {@inheritDoc}
*/
public String toString()
{
return build();
}
private static String prefixTag(final boolean isTagged, final Long value)
{
return isTagged ? TAG_PREFIX + value : value.toString();
}
}