blob: fc50ef0c27237888ad13e6d35f3d056da7515339 [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.Binary;
import org.apache.qpid.protonj2.types.Symbol;
import org.apache.qpid.protonj2.types.UnsignedLong;
import org.apache.qpid.protonj2.types.messaging.Source;
import org.apache.qpid.protonj2.types.messaging.Target;
import org.apache.qpid.protonj2.types.messaging.Terminus;
import org.apache.qpid.protonj2.types.transactions.Coordinator;
public final class Attach implements Performative {
public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000012L);
public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:attach:list");
private static final long UINT_MAX = 0xFFFFFFFFL;
private static int NAME = 1;
private static int HANDLE = 2;
private static int ROLE = 4;
private static int SENDER_SETTLE_MODE = 8;
private static int RECEIVER_SETTLE_MODE = 16;
private static int SOURCE = 32;
private static int TARGET = 64;
private static int UNSETTLED = 128;
private static int INCOMPLETE_UNSETTLED = 256;
private static int INITIAL_DELIVERY_COUNT = 512;
private static int MAX_MESSAGE_SIZE = 1024;
private static int OFFERED_CAPABILITIES = 2048;
private static int DESIRED_CAPABILITIES = 4096;
private static int PROPERTIES = 8192;
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 String name;
private long handle;
private Role role = Role.SENDER;
private SenderSettleMode sndSettleMode = SenderSettleMode.MIXED;
private ReceiverSettleMode rcvSettleMode = ReceiverSettleMode.FIRST;
private Source source;
private Terminus target;
private Map<Binary, DeliveryState> unsettled;
private boolean incompleteUnsettled;
private long initialDeliveryCount;
private UnsignedLong maxMessageSize;
private Symbol[] offeredCapabilities;
private Symbol[] desiredCapabilities;
private Map<Symbol, Object> properties;
@Override
public PerformativeType getPerformativeType() {
return PerformativeType.ATTACH;
}
@Override
public Attach copy() {
Attach copy = new Attach();
copy.name = name;
copy.handle = handle;
copy.role = role;
copy.sndSettleMode = sndSettleMode;
copy.rcvSettleMode = rcvSettleMode;
copy.source = source;
copy.target = target;
if (unsettled != null) {
copy.unsettled = new LinkedHashMap<>(unsettled);
}
copy.incompleteUnsettled = incompleteUnsettled;
copy.initialDeliveryCount = initialDeliveryCount;
copy.maxMessageSize = maxMessageSize;
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 hasName() {
return (modified & NAME) == NAME;
}
public boolean hasHandle() {
return (modified & HANDLE) == HANDLE;
}
public boolean hasRole() {
return (modified & ROLE) == ROLE;
}
public boolean hasSenderSettleMode() {
return (modified & SENDER_SETTLE_MODE) == SENDER_SETTLE_MODE;
}
public boolean hasReceiverSettleMode() {
return (modified & RECEIVER_SETTLE_MODE) == RECEIVER_SETTLE_MODE;
}
public boolean hasSource() {
return (modified & SOURCE) == SOURCE;
}
public boolean hasTargetOrCoordinator() {
return (modified & TARGET) == TARGET;
}
public boolean hasTarget() {
return (modified & TARGET) == TARGET && target instanceof Target;
}
public boolean hasCoordinator() {
return (modified & TARGET) == TARGET && target instanceof Coordinator;
}
public boolean hasUnsettled() {
return (modified & UNSETTLED) == UNSETTLED;
}
public boolean hasIncompleteUnsettled() {
return (modified & INCOMPLETE_UNSETTLED) == INCOMPLETE_UNSETTLED;
}
public boolean hasInitialDeliveryCount() {
return (modified & INITIAL_DELIVERY_COUNT) == INITIAL_DELIVERY_COUNT;
}
public boolean hasMaxMessageSize() {
return (modified & MAX_MESSAGE_SIZE) == MAX_MESSAGE_SIZE;
}
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 getName() {
return name;
}
public Attach setName(String name) {
if (name == null) {
throw new NullPointerException("the name field is mandatory");
}
modified |= NAME;
this.name = name;
return this;
}
public long getHandle() {
return handle;
}
public Attach setHandle(int handle) {
modified |= HANDLE;
this.handle = Integer.toUnsignedLong(handle);
return this;
}
public Attach setHandle(long handle) {
if (handle < 0 || handle > UINT_MAX) {
throw new IllegalArgumentException("The Handle value given is out of range: " + handle);
} else {
modified |= HANDLE;
}
this.handle = handle;
return this;
}
public Role getRole() {
return role;
}
public Attach setRole(Role role) {
if (role == null) {
throw new NullPointerException("Role cannot be null");
}
modified |= ROLE;
this.role = role;
return this;
}
public SenderSettleMode getSenderSettleMode() {
return sndSettleMode;
}
public Attach setSenderSettleMode(SenderSettleMode sndSettleMode) {
if (sndSettleMode != null) {
modified |= SENDER_SETTLE_MODE;
} else {
modified &= ~SENDER_SETTLE_MODE;
}
this.sndSettleMode = sndSettleMode == null ? SenderSettleMode.MIXED : sndSettleMode;
return this;
}
public ReceiverSettleMode getReceiverSettleMode() {
return rcvSettleMode;
}
public Attach setReceiverSettleMode(ReceiverSettleMode rcvSettleMode) {
if (rcvSettleMode != null) {
modified |= RECEIVER_SETTLE_MODE;
} else {
modified &= ~RECEIVER_SETTLE_MODE;
}
this.rcvSettleMode = rcvSettleMode == null ? ReceiverSettleMode.FIRST : rcvSettleMode;
return this;
}
public Source getSource() {
return source;
}
public Attach setSource(Source source) {
if (source != null) {
modified |= SOURCE;
} else {
modified &= ~SOURCE;
}
this.source = source;
return this;
}
@SuppressWarnings("unchecked")
public <T extends Terminus> T getTarget() {
return (T) target;
}
public Attach setTarget(Terminus target) {
if (target instanceof Target) {
setTarget((Target) target);
} else if (target instanceof Coordinator) {
setTarget((Coordinator) target);
} else {
throw new IllegalArgumentException("Cannot set Target terminus to given value: " + target);
}
return this;
}
public Attach setTarget(Target target) {
if (target != null) {
modified |= TARGET;
} else {
modified &= ~TARGET;
}
this.target = target;
return this;
}
public Attach setTarget(Coordinator target) {
if (target != null) {
modified |= TARGET;
} else {
modified &= ~TARGET;
}
this.target = target;
return this;
}
public Attach setCoordinator(Coordinator target) {
if (target != null) {
modified |= TARGET;
} else {
modified &= ~TARGET;
}
this.target = target;
return this;
}
public Map<Binary, DeliveryState> getUnsettled() {
return unsettled;
}
public Attach setUnsettled(Map<Binary, DeliveryState> unsettled) {
if (unsettled != null) {
modified |= UNSETTLED;
} else {
modified &= ~UNSETTLED;
}
this.unsettled = unsettled;
return this;
}
public boolean getIncompleteUnsettled() {
return incompleteUnsettled;
}
public Attach setIncompleteUnsettled(boolean incompleteUnsettled) {
this.modified |= INCOMPLETE_UNSETTLED;
this.incompleteUnsettled = incompleteUnsettled;
return this;
}
public long getInitialDeliveryCount() {
return initialDeliveryCount;
}
public Attach setInitialDeliveryCount(int initialDeliveryCount) {
modified |= INITIAL_DELIVERY_COUNT;
this.initialDeliveryCount = Integer.toUnsignedLong(initialDeliveryCount);
return this;
}
public Attach setInitialDeliveryCount(long initialDeliveryCount) {
if (initialDeliveryCount < 0 || initialDeliveryCount > UINT_MAX) {
throw new IllegalArgumentException("The initial delivery count value given is out of range: " + handle);
} else {
modified |= INITIAL_DELIVERY_COUNT;
}
this.initialDeliveryCount = initialDeliveryCount;
return this;
}
public UnsignedLong getMaxMessageSize() {
return maxMessageSize;
}
public Attach setMaxMessageSize(long maxMessageSize) {
return setMaxMessageSize(UnsignedLong.valueOf(maxMessageSize));
}
public Attach setMaxMessageSize(UnsignedLong maxMessageSize) {
if (maxMessageSize != null) {
modified |= MAX_MESSAGE_SIZE;
} else {
modified &= ~MAX_MESSAGE_SIZE;
}
this.maxMessageSize = maxMessageSize;
return this;
}
public Symbol[] getOfferedCapabilities() {
return offeredCapabilities;
}
public Attach setOfferedCapabilities(Symbol... offeredCapabilities) {
if (offeredCapabilities != null) {
modified |= OFFERED_CAPABILITIES;
} else {
modified &= ~OFFERED_CAPABILITIES;
}
this.offeredCapabilities = offeredCapabilities;
return this;
}
public Symbol[] getDesiredCapabilities() {
return desiredCapabilities;
}
public Attach 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 Attach 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.handleAttach(this, payload, channel, context);
}
@Override
public String toString() {
return "Attach{" +
"name='" + name + '\'' +
", handle=" + (hasHandle() ? handle : "null") +
", role=" + (hasRole() ? role : "null") +
", sndSettleMode=" + (hasSenderSettleMode() ? sndSettleMode : "null") +
", rcvSettleMode=" + (hasReceiverSettleMode() ? rcvSettleMode : "null") +
", source=" + source +
", target=" + target +
", unsettled=" + unsettled +
", incompleteUnsettled=" + (hasIncompleteUnsettled() ? incompleteUnsettled : "null") +
", initialDeliveryCount=" + (hasInitialDeliveryCount() ? initialDeliveryCount : "null") +
", maxMessageSize=" + maxMessageSize +
", offeredCapabilities=" + (offeredCapabilities == null ? "null" : Arrays.asList(offeredCapabilities)) +
", desiredCapabilities=" + (desiredCapabilities == null ? "null" : Arrays.asList(desiredCapabilities)) +
", properties=" + properties + '}';
}
}