blob: 06e27cc47a4ee087a547fbb3a0863268a7ec3e1f [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.client.impl;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.qpid.protonj2.client.DeliveryState;
import org.apache.qpid.protonj2.types.Symbol;
import org.apache.qpid.protonj2.types.messaging.Accepted;
import org.apache.qpid.protonj2.types.messaging.Modified;
import org.apache.qpid.protonj2.types.messaging.Rejected;
import org.apache.qpid.protonj2.types.messaging.Released;
import org.apache.qpid.protonj2.types.transactions.TransactionalState;
import org.apache.qpid.protonj2.types.transport.ErrorCondition;
/**
* Client internal implementation of a DeliveryState type.
*/
public abstract class ClientDeliveryState implements DeliveryState {
//----- Abstract methods for nested types
/**
* Returns the Proton version of the specific {@link org.apache.qpid.protonj2.client.DeliveryState} that
* this type represents.
*
* @return the Proton state object that this type maps to.
*/
abstract org.apache.qpid.protonj2.types.transport.DeliveryState getProtonDeliveryState();
//----- Create Delivery State from Proton instance
static DeliveryState fromProtonType(org.apache.qpid.protonj2.types.messaging.Outcome outcome) {
if (outcome == null) {
return null;
}
if (outcome instanceof Accepted) {
return ClientAccepted.getInstance();
} else if (outcome instanceof Released) {
return ClientReleased.getInstance();
} else if (outcome instanceof Rejected) {
return ClientRejected.fromProtonType((Rejected) outcome);
} else if (outcome instanceof Modified) {
return ClientModified.fromProtonType((Modified) outcome);
}
throw new IllegalArgumentException("Cannot map to unknown Proton Outcome to a DeliveryStateType: " + outcome);
}
static DeliveryState fromProtonType(org.apache.qpid.protonj2.types.transport.DeliveryState state) {
if (state == null) {
return null;
}
switch (state.getType()) {
case Accepted:
return ClientAccepted.getInstance();
case Released:
return ClientReleased.getInstance();
case Rejected:
return ClientRejected.fromProtonType((Rejected) state);
case Modified:
return ClientModified.fromProtonType((Modified) state);
case Transactional:
return ClientTransactional.fromProtonType((TransactionalState) state);
default:
throw new IllegalArgumentException("Cannot map to unknown Proton Delivery State type");
}
}
static DeliveryState.Type fromOutcomeSymbol(Symbol outcome) {
if (outcome == null) {
return null;
}
try {
return DeliveryState.Type.valueOf(outcome.toString().toUpperCase());
} catch (Throwable error) {
throw new IllegalArgumentException("Cannot map outcome name to unknown Proton DeliveryState.Type");
}
}
static org.apache.qpid.protonj2.types.transport.DeliveryState asProtonType(DeliveryState state) {
if (state == null) {
return null;
} else if (state instanceof ClientDeliveryState) {
return ((ClientDeliveryState) state).getProtonDeliveryState();
} else {
switch (state.getType()) {
case ACCEPTED:
return Accepted.getInstance();
case RELEASED:
return Released.getInstance();
case REJECTED:
return new Rejected(); // TODO - How do we aggregate the different values into one DeliveryState Object
case MODIFIED:
return new Modified(); // TODO - How do we aggregate the different values into one DeliveryState Object
case TRANSACTIONAL:
throw new IllegalArgumentException("Cannot manually enlist delivery in AMQP Transactions");
default:
throw new UnsupportedOperationException("Client does not support the given Delivery State type: " + state.getType());
}
}
}
//----- Delivery State implementations
/**
* Client defined {@link Accepted} delivery state definition
*/
public static class ClientAccepted extends ClientDeliveryState {
private static final ClientAccepted INSTANCE = new ClientAccepted();
@Override
public Type getType() {
return Type.ACCEPTED;
}
@Override
org.apache.qpid.protonj2.types.transport.DeliveryState getProtonDeliveryState() {
return Accepted.getInstance();
}
/**
* @return a singleton instance of the accepted type.
*/
public static ClientAccepted getInstance() {
return INSTANCE;
}
}
/**
* Client defined {@link Released} delivery state definition
*/
public static class ClientReleased extends ClientDeliveryState {
private static final ClientReleased INSTANCE = new ClientReleased();
@Override
public Type getType() {
return Type.RELEASED;
}
@Override
org.apache.qpid.protonj2.types.transport.DeliveryState getProtonDeliveryState() {
return Released.getInstance();
}
/**
* @return a singleton instance of the released type.
*/
public static ClientReleased getInstance() {
return INSTANCE;
}
}
/**
* Client defined {@link Rejected} delivery state definition
*/
public static class ClientRejected extends ClientDeliveryState {
private final Rejected rejected = new Rejected();
ClientRejected(Rejected rejected) {
if (rejected.getError() != null) {
rejected.setError(rejected.getError().copy());
}
}
/**
* Create a new Rejected outcome with the given description of the rejection cause.
*
* @param condition
* the condition that defines the rejection outcome.
* @param description
* the description of the underlying cause of the rejection.
*/
public ClientRejected(String condition, String description) {
if (condition != null || description != null) {
rejected.setError(new ErrorCondition(Symbol.valueOf(condition), description));
}
}
/**
* Create a new Rejected outcome with the given description of the rejection cause.
*
* @param condition
* the condition that defines the rejection outcome.
* @param description
* the description of the underlying cause of the rejection.
* @param info
* additional information to be provide to the remote about the rejection.
*/
public ClientRejected(String condition, String description, Map<String, Object> info) {
if (condition != null || description != null) {
rejected.setError(new ErrorCondition(
Symbol.valueOf(condition), description, ClientConversionSupport.toSymbolKeyedMap(info)));
}
}
@Override
public Type getType() {
return Type.RELEASED;
}
@Override
org.apache.qpid.protonj2.types.transport.DeliveryState getProtonDeliveryState() {
return rejected;
}
static ClientRejected fromProtonType(Rejected rejected) {
return new ClientRejected(rejected);
}
}
/**
* Client defined {@link Modified} delivery state definition
*/
public static class ClientModified extends ClientDeliveryState {
private final Modified modified = new Modified();
ClientModified(Modified modified) {
this.modified.setDeliveryFailed(modified.isDeliveryFailed());
this.modified.setUndeliverableHere(modified.isUndeliverableHere());
this.modified.setMessageAnnotations(new LinkedHashMap<>(modified.getMessageAnnotations()));
}
/**
* Create a new instance with the given outcome values.
*
* @param failed
* has the delivery failed
* @param undeliverable
* is the delivery no longer deliverable to this client.
*/
public ClientModified(boolean failed, boolean undeliverable) {
modified.setDeliveryFailed(failed);
modified.setUndeliverableHere(undeliverable);
}
/**
* Create a new instance with the given outcome values.
*
* @param failed
* has the delivery failed
* @param undeliverable
* is the delivery no longer deliverable to this client.
* @param annotations
* updated annotation values to provide to the remote.
*/
public ClientModified(boolean failed, boolean undeliverable, Map<String, Object> annotations) {
modified.setDeliveryFailed(failed);
modified.setUndeliverableHere(undeliverable);
modified.setMessageAnnotations(ClientConversionSupport.toSymbolKeyedMap(annotations));
}
@Override
public Type getType() {
return Type.MODIFIED;
}
@Override
org.apache.qpid.protonj2.types.transport.DeliveryState getProtonDeliveryState() {
return modified;
}
static ClientModified fromProtonType(Modified modified) {
return new ClientModified(modified);
}
}
/**
* Client defined {@link TransactionalState} delivery state definition
*/
public static class ClientTransactional extends ClientDeliveryState {
private final TransactionalState txnState = new TransactionalState();
ClientTransactional(TransactionalState txnState) {
this.txnState.setOutcome(txnState.getOutcome());
this.txnState.setTxnId(txnState.getTxnId().copy());
}
@Override
public Type getType() {
return Type.TRANSACTIONAL;
}
@Override
org.apache.qpid.protonj2.types.transport.DeliveryState getProtonDeliveryState() {
return txnState;
}
static ClientTransactional fromProtonType(TransactionalState txnState) {
return new ClientTransactional(txnState);
}
}
}