blob: 894ac0e29861b826cc8f4ee255866f027fa4823e [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 Begin implements Performative {
public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000011L);
public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:begin:list");
private static final long UINT_MAX = 0xFFFFFFFFL;
private static int REMOTE_CHANNEL = 1;
private static int NEXT_OUTGOING_ID = 2;
private static int INCOMING_WINDOW = 4;
private static int OUTGOING_WINDOW = 8;
private static int HANDLE_MAX = 16;
private static int OFFERED_CAPABILITIES = 32;
private static int DESIRED_CAPABILITIES = 64;
private static int PROPERTIES = 128;
private int modified = 0;
// 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 int remoteChannel;
private long nextOutgoingId;
private long incomingWindow;
private long outgoingWindow;
private long handleMax = UnsignedInteger.MAX_VALUE.longValue();
private Symbol[] offeredCapabilities;
private Symbol[] desiredCapabilities;
private Map<Symbol, Object> properties;
@Override
public PerformativeType getPerformativeType() {
return PerformativeType.BEGIN;
}
@Override
public Begin copy() {
Begin copy = new Begin();
copy.remoteChannel = remoteChannel;
copy.nextOutgoingId = nextOutgoingId;
copy.incomingWindow = incomingWindow;
copy.outgoingWindow = outgoingWindow;
copy.handleMax = handleMax;
if (offeredCapabilities != null) {
copy.offeredCapabilities = Arrays.copyOf(offeredCapabilities, offeredCapabilities.length);
}
if (desiredCapabilities != null) {
copy.desiredCapabilities = Arrays.copyOf(desiredCapabilities, desiredCapabilities.length);
}
if (properties != null) {
copy.properties = new LinkedHashMap<>(properties);
}
copy.modified = modified;
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 hasRemoteChannel() {
return (modified & REMOTE_CHANNEL) == REMOTE_CHANNEL;
}
public boolean hasNextOutgoingId() {
return (modified & NEXT_OUTGOING_ID) == NEXT_OUTGOING_ID;
}
public boolean hasIncomingWindow() {
return (modified & INCOMING_WINDOW) == INCOMING_WINDOW;
}
public boolean hasOutgoingWindow() {
return (modified & OUTGOING_WINDOW) == OUTGOING_WINDOW;
}
public boolean hasHandleMax() {
return (modified & HANDLE_MAX) == HANDLE_MAX;
}
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 int getRemoteChannel() {
return remoteChannel;
}
public Begin setRemoteChannel(int remoteChannel) {
if (remoteChannel < 0 || remoteChannel > UnsignedShort.MAX_VALUE.intValue()) {
throw new IllegalArgumentException("Remote channel value given is out of range: " + remoteChannel);
} else {
modified |= REMOTE_CHANNEL;
}
this.remoteChannel = remoteChannel;
return this;
}
public long getNextOutgoingId() {
return nextOutgoingId;
}
public Begin setNextOutgoingId(int nextOutgoingId) {
modified |= NEXT_OUTGOING_ID;
this.nextOutgoingId = Integer.toUnsignedLong(nextOutgoingId);
return this;
}
public Begin setNextOutgoingId(long nextOutgoingId) {
if (nextOutgoingId < 0 || nextOutgoingId > UINT_MAX) {
throw new IllegalArgumentException("Next Outgoing Id value given is out of range: " + nextOutgoingId);
} else {
modified |= NEXT_OUTGOING_ID;
}
this.nextOutgoingId = nextOutgoingId;
return this;
}
public long getIncomingWindow() {
return incomingWindow;
}
public Begin setIncomingWindow(int incomingWindow) {
modified |= INCOMING_WINDOW;
this.incomingWindow = Integer.toUnsignedLong(incomingWindow);
return this;
}
public Begin setIncomingWindow(long incomingWindow) {
if (incomingWindow < 0 || incomingWindow > UINT_MAX) {
throw new IllegalArgumentException("Incoming Window value given is out of range: " + incomingWindow);
} else {
modified |= INCOMING_WINDOW;
}
this.incomingWindow = incomingWindow;
return this;
}
public long getOutgoingWindow() {
return outgoingWindow;
}
public Begin setOutgoingWindow(int outgoingWindow) {
modified |= OUTGOING_WINDOW;
this.outgoingWindow = Integer.toUnsignedLong(outgoingWindow);
return this;
}
public Begin setOutgoingWindow(long outgoingWindow) {
if (outgoingWindow < 0 || outgoingWindow > UINT_MAX) {
throw new IllegalArgumentException("Incoming Window value given is out of range: " + outgoingWindow);
} else {
modified |= OUTGOING_WINDOW;
}
this.outgoingWindow = outgoingWindow;
return this;
}
public long getHandleMax() {
return handleMax;
}
public Begin setHandleMax(int handleMax) {
modified |= HANDLE_MAX;
this.handleMax = Integer.toUnsignedLong(handleMax);
return this;
}
public Begin setHandleMax(long handleMax) {
if (handleMax < 0 || handleMax > UINT_MAX) {
throw new IllegalArgumentException("Handle Max value given is out of range: " + handleMax);
} else {
modified |= HANDLE_MAX;
}
this.handleMax = handleMax;
return this;
}
public Symbol[] getOfferedCapabilities() {
return offeredCapabilities;
}
public Begin setOfferedCapabilities(Symbol... offeredCapabilities) {
if (offeredCapabilities != null) {
modified |= OFFERED_CAPABILITIES;
} else {
modified &= ~OFFERED_CAPABILITIES;
}
this.offeredCapabilities = offeredCapabilities;
return this;
}
public Symbol[] getDesiredCapabilities() {
return desiredCapabilities;
}
public Begin 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 Begin setProperties(Map<Symbol, Object> properties) {
if (properties != null) {
modified |= PROPERTIES;
} else {
modified &= ~PROPERTIES;
}
this.properties = properties;
return this;
}
@Override
public <E> void invoke(PerformativeHandler<E> handler, ProtonBuffer payload, int channel, E context) {
handler.handleBegin(this, payload, channel, context);
}
@Override
public String toString() {
return "Begin{" +
"remoteChannel=" + (hasRemoteChannel() ? remoteChannel : "null") +
", nextOutgoingId=" + (hasNextOutgoingId() ? nextOutgoingId : "null") +
", incomingWindow=" + (hasIncomingWindow() ? incomingWindow : "null") +
", outgoingWindow=" + (hasOutgoingWindow() ? outgoingWindow : "null") +
", handleMax=" + (hasHandleMax() ? handleMax : "null") +
", offeredCapabilities=" + (offeredCapabilities == null ? "null" : Arrays.asList(offeredCapabilities)) +
", desiredCapabilities=" + (desiredCapabilities == null ? "null" : Arrays.asList(desiredCapabilities)) +
", properties=" + properties +
'}';
}
}