blob: 94260cf6a4c562f32c61e4bc1a3776adc417abd9 [file] [log] [blame]
/*
* 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.qpid.protonj2.types.transport;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.qpid.protonj2.buffer.ProtonBuffer;
import org.apache.qpid.protonj2.types.Symbol;
import org.apache.qpid.protonj2.types.UnsignedInteger;
import org.apache.qpid.protonj2.types.UnsignedLong;
import org.apache.qpid.protonj2.types.UnsignedShort;
public final class Open implements Performative {
public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000010L);
public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:open:list");
private static final long UINT_MAX = 0xFFFFFFFFL;
private static int CONTAINER_ID = 1;
private static int HOSTNAME = 2;
private static int MAX_FRAME_SIZE = 4;
private static int CHANNEL_MAX = 8;
private static int IDLE_TIMEOUT = 16;
private static int OUTGOING_LOCALES = 32;
private static int INCOMING_LOCALES = 64;
private static int OFFERED_CAPABILITIES = 128;
private static int DESIRED_CAPABILITIES = 256;
private static int PROPERTIES = 512;
private int modified = CONTAINER_ID;
// TODO - Consider using the matching signed types instead of next largest
// for these values as in most cases we don't actually care about sign.
// In the cases we do care we could just do the math and make these
// interfaces simpler and not check all over the place for overflow.
private String containerId = "";
private String hostname;
private long maxFrameSize = UnsignedInteger.MAX_VALUE.longValue();
private int channelMax = UnsignedShort.MAX_VALUE.intValue();
private long idleTimeout;
private Symbol[] outgoingLocales;
private Symbol[] incomingLocales;
private Symbol[] offeredCapabilities;
private Symbol[] desiredCapabilities;
private Map<Symbol, Object> properties;
@Override
public Open copy() {
Open copy = new Open();
copy.setContainerId(containerId);
if (hasHostname()) {
copy.setHostname(hostname);
}
if (hasMaxFrameSize()) {
copy.setMaxFrameSize(maxFrameSize);
}
if (hasChannelMax()) {
copy.setChannelMax(channelMax);
}
if (hasIdleTimeout()) {
copy.setIdleTimeout(idleTimeout);
}
if (hasOutgoingLocales()) {
copy.setOutgoingLocales(Arrays.copyOf(outgoingLocales, outgoingLocales.length));
}
if (hasIncomingLocales()) {
copy.setIncomingLocales(Arrays.copyOf(incomingLocales, incomingLocales.length));
}
if (hasOfferedCapabilites()) {
copy.setOfferedCapabilities(Arrays.copyOf(offeredCapabilities, offeredCapabilities.length));
}
if (hasDesiredCapabilites()) {
copy.setOfferedCapabilities(Arrays.copyOf(desiredCapabilities, desiredCapabilities.length));
}
if (hasProperties()) {
copy.setProperties(new LinkedHashMap<>(properties));
}
return copy;
}
//----- Query the state of the Header object -----------------------------//
public boolean isEmpty() {
return modified == 0;
}
public int getElementCount() {
return 32 - Integer.numberOfLeadingZeros(modified);
}
public boolean hasContainerId() {
return (modified & CONTAINER_ID) == CONTAINER_ID;
}
public boolean hasHostname() {
return (modified & HOSTNAME) == HOSTNAME;
}
public boolean hasMaxFrameSize() {
return (modified & MAX_FRAME_SIZE) == MAX_FRAME_SIZE;
}
public boolean hasChannelMax() {
return (modified & CHANNEL_MAX) == CHANNEL_MAX;
}
public boolean hasIdleTimeout() {
return (modified & IDLE_TIMEOUT) == IDLE_TIMEOUT;
}
public boolean hasOutgoingLocales() {
return (modified & OUTGOING_LOCALES) == OUTGOING_LOCALES;
}
public boolean hasIncomingLocales() {
return (modified & INCOMING_LOCALES) == INCOMING_LOCALES;
}
public boolean hasOfferedCapabilites() {
return (modified & OFFERED_CAPABILITIES) == OFFERED_CAPABILITIES;
}
public boolean hasDesiredCapabilites() {
return (modified & DESIRED_CAPABILITIES) == DESIRED_CAPABILITIES;
}
public boolean hasProperties() {
return (modified & PROPERTIES) == PROPERTIES;
}
//----- Access to the member data with state checks
public String getContainerId() {
return containerId;
}
public Open setContainerId(String containerId) {
if (containerId == null) {
throw new NullPointerException("the container-id field is mandatory");
}
modified |= CONTAINER_ID;
this.containerId = containerId;
return this;
}
public String getHostname() {
return hostname;
}
public Open setHostname(String hostname) {
if (hostname == null) {
modified &= ~HOSTNAME;
} else {
modified |= HOSTNAME;
}
this.hostname = hostname;
return this;
}
public long getMaxFrameSize() {
return maxFrameSize;
}
public Open setMaxFrameSize(int maxFrameSize) {
modified |= MAX_FRAME_SIZE;
this.maxFrameSize = Integer.toUnsignedLong(maxFrameSize);
return this;
}
public Open setMaxFrameSize(long maxFrameSize) {
if (maxFrameSize < 0 || maxFrameSize > UINT_MAX) {
throw new IllegalArgumentException(String.format(
"Given max frame size value %d larger than this implementations limit of %d",
maxFrameSize, Integer.MAX_VALUE));
} else {
modified |= MAX_FRAME_SIZE;
}
this.maxFrameSize = maxFrameSize;
return this;
}
public int getChannelMax() {
return channelMax;
}
public Open setChannelMax(short channelMax) {
modified |= CHANNEL_MAX;
this.channelMax = Short.toUnsignedInt(channelMax);
return this;
}
public Open setChannelMax(int channelMax) {
if (channelMax < 0 || channelMax > UnsignedShort.MAX_VALUE.intValue()) {
throw new IllegalArgumentException("The Channel Max value given is out of range: " + channelMax);
} else {
modified |= CHANNEL_MAX;
}
this.channelMax = channelMax;
return this;
}
public long getIdleTimeout() {
return idleTimeout;
}
public Open setIdleTimeout(int idleTimeOut) {
modified |= IDLE_TIMEOUT;
this.idleTimeout = Integer.toUnsignedLong(idleTimeOut);
return this;
}
public Open setIdleTimeout(long idleTimeOut) {
if (idleTimeOut < 0 || idleTimeOut > UINT_MAX) {
throw new IllegalArgumentException("The Idle Timeout value given is out of range: " + idleTimeOut);
} else {
modified |= IDLE_TIMEOUT;
}
this.idleTimeout = idleTimeOut;
return this;
}
public Symbol[] getOutgoingLocales() {
return outgoingLocales;
}
public Open setOutgoingLocales(Symbol... outgoingLocales) {
if (outgoingLocales != null) {
modified |= OUTGOING_LOCALES;
} else {
modified &= ~OUTGOING_LOCALES;
}
this.outgoingLocales = outgoingLocales;
return this;
}
public Symbol[] getIncomingLocales() {
return incomingLocales;
}
public Open setIncomingLocales(Symbol... incomingLocales) {
if (incomingLocales != null) {
modified |= INCOMING_LOCALES;
} else {
modified &= ~INCOMING_LOCALES;
}
this.incomingLocales = incomingLocales;
return this;
}
public Symbol[] getOfferedCapabilities() {
return offeredCapabilities;
}
public Open setOfferedCapabilities(Symbol... offeredCapabilities) {
if (offeredCapabilities != null) {
modified |= OFFERED_CAPABILITIES;
} else {
modified &= ~OFFERED_CAPABILITIES;
}
this.offeredCapabilities = offeredCapabilities;
return this;
}
public Symbol[] getDesiredCapabilities() {
return desiredCapabilities;
}
public Open setDesiredCapabilities(Symbol... desiredCapabilities) {
if (desiredCapabilities != null) {
modified |= DESIRED_CAPABILITIES;
} else {
modified &= ~DESIRED_CAPABILITIES;
}
this.desiredCapabilities = desiredCapabilities;
return this;
}
public Map<Symbol, Object> getProperties() {
return properties;
}
public Open setProperties(Map<Symbol, Object> properties) {
if (properties != null) {
modified |= PROPERTIES;
} else {
modified &= ~PROPERTIES;
}
this.properties = properties;
return this;
}
@Override
public PerformativeType getPerformativeType() {
return PerformativeType.OPEN;
}
@Override
public <E> void invoke(PerformativeHandler<E> handler, ProtonBuffer payload, int channel, E context) {
handler.handleOpen(this, payload, channel, context);
}
@Override
public String toString() {
return "Open{" +
" containerId='" + containerId + '\'' +
", hostname='" + hostname + '\'' +
", maxFrameSize=" + (hasMaxFrameSize() ? maxFrameSize : "null") +
", channelMax=" + (hasChannelMax() ? channelMax : "null") +
", idleTimeOut=" + (hasIdleTimeout() ? idleTimeout : "null") +
", outgoingLocales=" + (outgoingLocales == null ? "null" : Arrays.asList(outgoingLocales)) +
", incomingLocales=" + (incomingLocales == null ? "null" : Arrays.asList(incomingLocales)) +
", offeredCapabilities=" + (offeredCapabilities == null ? "null" : Arrays.asList(offeredCapabilities)) +
", desiredCapabilities=" + (desiredCapabilities == null ? "null" : Arrays.asList(desiredCapabilities)) +
", properties=" + properties +
'}';
}
}