public interface LinkError { static final Symbol DETACH_FORCED = Symbol.valueOf("amqp:link:detach-forced"); static final Symbol TRANSFER_LIMIT_EXCEEDED = Symbol.valueOf("amqp:link:transfer-limit-exceeded"); static final Symbol MESSAGE_SIZE_EXCEEDED = Symbol.valueOf("amqp:link:message-size-exceeded"); static final Symbol REDIRECT = Symbol.valueOf("amqp:link:redirect"); static final Symbol STOLEN = Symbol.valueOf("amqp:link:stolen"); }
/** * Search for a given Symbol in a given array of Symbol object. * * @param symbols the set of Symbols to search. * @param key the value to try and find in the Symbol array. * @return true if the key is found in the given Symbol array. */ public static boolean contains(Symbol[] symbols, Symbol key) { if (symbols == null || symbols.length == 0) { return false; } for (Symbol symbol : symbols) { if (symbol.equals(key)) { return true; } } return false; }
/** * Given a message annotation name, lookup and return the value associated with that annotation * name. If the message annotations have not been created yet then this method will always return * null. * * @param key the Symbol name that should be looked up in the message annotations. * @return the value of the annotation if it exists, or null if not set or not accessible. */ public Object getDeliveryAnnotation(String key) { if (deliveryAnnotationsMap == null) { return null; } return deliveryAnnotationsMap.get(Symbol.valueOf(key)); }
/** * Given a message annotation name, lookup and return the value associated with that annotation * name. If the message annotations have not been created yet then this method will always return * null. * * @param key the Symbol name that should be looked up in the message annotations. * @return the value of the annotation if it exists, or null if not set or not accessible. */ public Object getMessageAnnotation(String key) { if (messageAnnotationsMap == null) { return null; } return messageAnnotationsMap.get(Symbol.valueOf(key)); }
/** * Given an ErrorCondition instance create a new Exception that best matches the error type. * * @param endpoint The target of the error. * @param errorCondition The ErrorCondition returned from the remote peer. * @param defaultException The default exception to throw if no error information is provided from * the remote. * @return a new Exception instance that best matches the ErrorCondition value. */ public static Exception convertToException( Endpoint endpoint, ErrorCondition errorCondition, Exception defaultException) { Exception remoteError = defaultException; if (errorCondition != null && errorCondition.getCondition() != null) { Symbol error = errorCondition.getCondition(); String message = extractErrorMessage(errorCondition); if (error.equals(AmqpError.UNAUTHORIZED_ACCESS)) { remoteError = new JMSSecurityException(message); } else if (error.equals(AmqpError.RESOURCE_LIMIT_EXCEEDED)) { remoteError = new ResourceAllocationException(message); } else if (error.equals(AmqpError.NOT_FOUND)) { if (endpoint instanceof Connection) { remoteError = new JmsResourceNotFoundException(message); } else { remoteError = new InvalidDestinationException(message); } } else if (error.equals(TransactionErrors.TRANSACTION_ROLLBACK)) { remoteError = new TransactionRolledBackException(message); } else if (error.equals(ConnectionError.REDIRECT)) { remoteError = createRedirectException(error, message, errorCondition); } else if (error.equals(AmqpError.INVALID_FIELD)) { Map<?, ?> info = errorCondition.getInfo(); if (info != null && CONTAINER_ID.equals(info.get(INVALID_FIELD))) { remoteError = new InvalidClientIDException(message); } else { remoteError = new JMSException(message); } } else { remoteError = new JMSException(message); } } else if (remoteError == null) { remoteError = new JMSException("Unknown error from remote peer"); } return remoteError; }
/** Generated by generate-described-types.xsl, which resides in this package. */ public class DetachFrame extends ListDescribedType { public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:detach:list"); public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000016L); private static final int FIELD_HANDLE = 0; private static final int FIELD_CLOSED = 1; private static final int FIELD_ERROR = 2; public DetachFrame(Object... fields) { super(3); int i = 0; for (Object field : fields) { getFields()[i++] = field; } } @Override public Symbol getDescriptor() { return DESCRIPTOR_SYMBOL; } public DetachFrame setHandle(Object o) { getFields()[FIELD_HANDLE] = o; return this; } public DetachFrame setClosed(Object o) { getFields()[FIELD_CLOSED] = o; return this; } public DetachFrame setError(Object o) { getFields()[FIELD_ERROR] = o; return this; } }
/** Generated by generate-list-sections.xsl, which resides in this package. */ public class PropertiesDescribedType extends ListDescribedType { public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:properties:list"); public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000073L); private static final int FIELD_MESSAGE_ID = 0; private static final int FIELD_USER_ID = 1; private static final int FIELD_TO = 2; private static final int FIELD_SUBJECT = 3; private static final int FIELD_REPLY_TO = 4; private static final int FIELD_CORRELATION_ID = 5; private static final int FIELD_CONTENT_TYPE = 6; private static final int FIELD_CONTENT_ENCODING = 7; private static final int FIELD_ABSOLUTE_EXPIRY_TIME = 8; private static final int FIELD_CREATION_TIME = 9; private static final int FIELD_GROUP_ID = 10; private static final int FIELD_GROUP_SEQUENCE = 11; private static final int FIELD_REPLY_TO_GROUP_ID = 12; public PropertiesDescribedType(Object... fields) { super(13); int i = 0; for (Object field : fields) { getFields()[i++] = field; } } @Override public Symbol getDescriptor() { return DESCRIPTOR_SYMBOL; } public PropertiesDescribedType setMessageId(Object o) { getFields()[FIELD_MESSAGE_ID] = o; return this; } public PropertiesDescribedType setUserId(Object o) { getFields()[FIELD_USER_ID] = o; return this; } public PropertiesDescribedType setTo(Object o) { getFields()[FIELD_TO] = o; return this; } public PropertiesDescribedType setSubject(Object o) { getFields()[FIELD_SUBJECT] = o; return this; } public PropertiesDescribedType setReplyTo(Object o) { getFields()[FIELD_REPLY_TO] = o; return this; } public PropertiesDescribedType setCorrelationId(Object o) { getFields()[FIELD_CORRELATION_ID] = o; return this; } public PropertiesDescribedType setContentType(Object o) { getFields()[FIELD_CONTENT_TYPE] = o; return this; } public PropertiesDescribedType setContentEncoding(Object o) { getFields()[FIELD_CONTENT_ENCODING] = o; return this; } public PropertiesDescribedType setAbsoluteExpiryTime(Object o) { getFields()[FIELD_ABSOLUTE_EXPIRY_TIME] = o; return this; } public PropertiesDescribedType setCreationTime(Object o) { getFields()[FIELD_CREATION_TIME] = o; return this; } public PropertiesDescribedType setGroupId(Object o) { getFields()[FIELD_GROUP_ID] = o; return this; } public PropertiesDescribedType setGroupSequence(Object o) { getFields()[FIELD_GROUP_SEQUENCE] = o; return this; } public PropertiesDescribedType setReplyToGroupId(Object o) { getFields()[FIELD_REPLY_TO_GROUP_ID] = o; return this; } }
public final class FlowType extends AbstractDescribedType<Flow, List> implements DescribedTypeConstructor<Flow> { private static final Object[] DESCRIPTORS = { UnsignedLong.valueOf(0x0000000000000013L), Symbol.valueOf("amqp:flow:list"), }; private static final UnsignedLong DESCRIPTOR = UnsignedLong.valueOf(0x0000000000000013L); private FlowType(EncoderImpl encoder) { super(encoder); } public UnsignedLong getDescriptor() { return DESCRIPTOR; } @Override protected List wrap(Flow val) { return new FlowWrapper(val); } public static class FlowWrapper extends AbstractList { private Flow _flow; public FlowWrapper(Flow flow) { _flow = flow; } public Object get(final int index) { switch (index) { case 0: return _flow.getNextIncomingId(); case 1: return _flow.getIncomingWindow(); case 2: return _flow.getNextOutgoingId(); case 3: return _flow.getOutgoingWindow(); case 4: return _flow.getHandle(); case 5: return _flow.getDeliveryCount(); case 6: return _flow.getLinkCredit(); case 7: return _flow.getAvailable(); case 8: return _flow.getDrain(); case 9: return _flow.getEcho(); case 10: return _flow.getProperties(); } throw new IllegalStateException("Unknown index " + index); } public int size() { return _flow.getProperties() != null ? 11 : _flow.getEcho() ? 10 : _flow.getDrain() ? 9 : _flow.getAvailable() != null ? 8 : _flow.getLinkCredit() != null ? 7 : _flow.getDeliveryCount() != null ? 6 : _flow.getHandle() != null ? 5 : 4; } } public Flow newInstance(Object described) { List l = (List) described; Flow o = new Flow(); if (l.size() <= 3) { throw new DecodeException("The outgoing-window field cannot be omitted"); } switch (11 - l.size()) { case 0: o.setProperties((Map) l.get(10)); case 1: Boolean echo = (Boolean) l.get(9); o.setEcho(echo == null ? false : echo); case 2: Boolean drain = (Boolean) l.get(8); o.setDrain(drain == null ? false : drain); case 3: o.setAvailable((UnsignedInteger) l.get(7)); case 4: o.setLinkCredit((UnsignedInteger) l.get(6)); case 5: o.setDeliveryCount((UnsignedInteger) l.get(5)); case 6: o.setHandle((UnsignedInteger) l.get(4)); case 7: o.setOutgoingWindow((UnsignedInteger) l.get(3)); case 8: o.setNextOutgoingId((UnsignedInteger) l.get(2)); case 9: o.setIncomingWindow((UnsignedInteger) l.get(1)); case 10: o.setNextIncomingId((UnsignedInteger) l.get(0)); } return o; } public Class<Flow> getTypeClass() { return Flow.class; } public static void register(Decoder decoder, EncoderImpl encoder) { FlowType type = new FlowType(encoder); for (Object descriptor : DESCRIPTORS) { decoder.register(descriptor, type); } encoder.register(type); } }
/** * Perform a proper delivery annotation set on the AMQP Message based on a Symbol key and the * target value to append to the current delivery annotations. * * @param key The name of the Symbol whose value is being set. * @param value The new value to set in the delivery annotations of this message. */ public void setDeliveryAnnotation(String key, Object value) { checkReadOnly(); lazyCreateDeliveryAnnotations(); deliveryAnnotationsMap.put(Symbol.valueOf(key), value); }
/** * Perform a proper annotation set on the AMQP Message based on a Symbol key and the target value * to append to the current annotations. * * @param key The name of the Symbol whose value is being set. * @param value The new value to set in the annotations of this message. */ public void setMessageAnnotation(String key, Object value) { checkReadOnly(); lazyCreateMessageAnnotations(); messageAnnotationsMap.put(Symbol.valueOf(key), value); }
public class AmqpSupport { // Symbols used for connection capabilities public static final Symbol SOLE_CONNECTION_CAPABILITY = Symbol.valueOf("sole-connection-for-container"); public static final Symbol ANONYMOUS_RELAY = Symbol.valueOf("ANONYMOUS-RELAY"); // Symbols used to announce connection error information public static final Symbol CONNECTION_OPEN_FAILED = Symbol.valueOf("amqp:connection-establishment-failed"); public static final Symbol INVALID_FIELD = Symbol.valueOf("invalid-field"); public static final Symbol CONTAINER_ID = Symbol.valueOf("container-id"); // Symbols used to announce connection redirect ErrorCondition 'info' public static final Symbol PATH = Symbol.valueOf("path"); public static final Symbol SCHEME = Symbol.valueOf("scheme"); public static final Symbol PORT = Symbol.valueOf("port"); public static final Symbol NETWORK_HOST = Symbol.valueOf("network-host"); public static final Symbol OPEN_HOSTNAME = Symbol.valueOf("hostname"); // Symbols used for connection properties public static final Symbol QUEUE_PREFIX = Symbol.valueOf("queue-prefix"); public static final Symbol TOPIC_PREFIX = Symbol.valueOf("topic-prefix"); public static final Symbol PRODUCT = Symbol.valueOf("product"); public static final Symbol VERSION = Symbol.valueOf("version"); public static final Symbol PLATFORM = Symbol.valueOf("platform"); // Symbols used for receivers. public static final Symbol COPY = Symbol.getSymbol("copy"); public static final Symbol JMS_NO_LOCAL_SYMBOL = Symbol.valueOf("no-local"); public static final Symbol JMS_SELECTOR_SYMBOL = Symbol.valueOf("jms-selector"); // Delivery states public static final Rejected REJECTED = new Rejected(); public static final Modified MODIFIED_FAILED = new Modified(); public static final Modified MODIFIED_FAILED_UNDELIVERABLE = new Modified(); // Temporary Destination constants public static final Symbol DYNAMIC_NODE_LIFETIME_POLICY = Symbol.valueOf("lifetime-policy"); public static final String TEMP_QUEUE_CREATOR = "temp-queue-creator:"; public static final String TEMP_TOPIC_CREATOR = "temp-topic-creator:"; // ----- Static initializer -----------------------------------------------// static { MODIFIED_FAILED.setDeliveryFailed(true); MODIFIED_FAILED_UNDELIVERABLE.setDeliveryFailed(true); MODIFIED_FAILED_UNDELIVERABLE.setUndeliverableHere(true); } // ----- Utility Methods --------------------------------------------------// /** * Given an ErrorCondition instance create a new Exception that best matches the error type. * * @param endpoint The target of the error. * @param errorCondition The ErrorCondition returned from the remote peer. * @return a new Exception instance that best matches the ErrorCondition value. */ public static Exception convertToException(Endpoint endpoint, ErrorCondition errorCondition) { return convertToException(endpoint, errorCondition, null); } /** * Given an ErrorCondition instance create a new Exception that best matches the error type. * * @param endpoint The target of the error. * @param errorCondition The ErrorCondition returned from the remote peer. * @param defaultException The default exception to throw if no error information is provided from * the remote. * @return a new Exception instance that best matches the ErrorCondition value. */ public static Exception convertToException( Endpoint endpoint, ErrorCondition errorCondition, Exception defaultException) { Exception remoteError = defaultException; if (errorCondition != null && errorCondition.getCondition() != null) { Symbol error = errorCondition.getCondition(); String message = extractErrorMessage(errorCondition); if (error.equals(AmqpError.UNAUTHORIZED_ACCESS)) { remoteError = new JMSSecurityException(message); } else if (error.equals(AmqpError.RESOURCE_LIMIT_EXCEEDED)) { remoteError = new ResourceAllocationException(message); } else if (error.equals(AmqpError.NOT_FOUND)) { if (endpoint instanceof Connection) { remoteError = new JmsResourceNotFoundException(message); } else { remoteError = new InvalidDestinationException(message); } } else if (error.equals(TransactionErrors.TRANSACTION_ROLLBACK)) { remoteError = new TransactionRolledBackException(message); } else if (error.equals(ConnectionError.REDIRECT)) { remoteError = createRedirectException(error, message, errorCondition); } else if (error.equals(AmqpError.INVALID_FIELD)) { Map<?, ?> info = errorCondition.getInfo(); if (info != null && CONTAINER_ID.equals(info.get(INVALID_FIELD))) { remoteError = new InvalidClientIDException(message); } else { remoteError = new JMSException(message); } } else { remoteError = new JMSException(message); } } else if (remoteError == null) { remoteError = new JMSException("Unknown error from remote peer"); } return remoteError; } /** * Attempt to read and return the embedded error message in the given ErrorCondition object. If no * message can be extracted a generic message is returned. * * @param errorCondition The ErrorCondition to extract the error message from. * @return an error message extracted from the given ErrorCondition. */ public static String extractErrorMessage(ErrorCondition errorCondition) { String message = "Received error from remote peer without description"; if (errorCondition != null) { if (errorCondition.getDescription() != null && !errorCondition.getDescription().isEmpty()) { message = errorCondition.getDescription(); } Symbol condition = errorCondition.getCondition(); if (condition != null) { message = message + " [condition = " + condition + "]"; } } return message; } /** * When a redirect type exception is received this method is called to create the appropriate * redirect exception type containing the error details needed. * * @param error the Symbol that defines the redirection error type. * @param message the basic error message that should used or amended for the returned exception. * @param condition the ErrorCondition that describes the redirection. * @return an Exception that captures the details of the redirection error. */ public static Exception createRedirectException( Symbol error, String message, ErrorCondition condition) { Exception result = null; Map<?, ?> info = condition.getInfo(); if (info == null) { result = new IOException(message + " : Redirection information not set."); } else { String hostname = (String) info.get(OPEN_HOSTNAME); String path = (String) info.get(PATH); String scheme = (String) info.get(SCHEME); String networkHost = (String) info.get(NETWORK_HOST); if (networkHost == null || networkHost.isEmpty()) { result = new IOException(message + " : Redirection information not set."); } int port = 0; try { port = Integer.parseInt(info.get(PORT).toString()); } catch (Exception ex) { result = new IOException(message + " : Redirection information not set."); } result = new ProviderRedirectedException(message, scheme, hostname, networkHost, port, path); } return result; } }
/** Set of useful methods and definitions used in the AMQP protocol handling */ public class AmqpSupport { // Identification values used to locating JMS selector types. public static final UnsignedLong JMS_SELECTOR_CODE = UnsignedLong.valueOf(0x0000468C00000004L); public static final Symbol JMS_SELECTOR_NAME = Symbol.valueOf("apache.org:selector-filter:string"); public static final Object[] JMS_SELECTOR_FILTER_IDS = new Object[] {JMS_SELECTOR_CODE, JMS_SELECTOR_NAME}; public static final UnsignedLong NO_LOCAL_CODE = UnsignedLong.valueOf(0x0000468C00000003L); public static final Symbol NO_LOCAL_NAME = Symbol.valueOf("apache.org:no-local-filter:list"); public static final Object[] NO_LOCAL_FILTER_IDS = new Object[] {NO_LOCAL_CODE, NO_LOCAL_NAME}; // Capabilities used to identify destination type in some requests. public static final Symbol TEMP_QUEUE_CAPABILITY = Symbol.valueOf("temporary-queue"); public static final Symbol TEMP_TOPIC_CAPABILITY = Symbol.valueOf("temporary-topic"); // Symbols used to announce connection information to remote peer. public static final Symbol INVALID_FIELD = Symbol.valueOf("invalid-field"); public static final Symbol CONTAINER_ID = Symbol.valueOf("container-id"); // Symbols used to announce connection information to remote peer. public static final Symbol ANONYMOUS_RELAY = Symbol.valueOf("ANONYMOUS-RELAY"); public static final Symbol QUEUE_PREFIX = Symbol.valueOf("queue-prefix"); public static final Symbol TOPIC_PREFIX = Symbol.valueOf("topic-prefix"); public static final Symbol CONNECTION_OPEN_FAILED = Symbol.valueOf("amqp:connection-establishment-failed"); public static final Symbol PRODUCT = Symbol.valueOf("product"); public static final Symbol VERSION = Symbol.valueOf("version"); public static final Symbol PLATFORM = Symbol.valueOf("platform"); // Symbols used in configuration of newly opened links. public static final Symbol COPY = Symbol.getSymbol("copy"); // Lifetime policy symbols public static final Symbol LIFETIME_POLICY = Symbol.valueOf("lifetime-policy"); /** * Search for a given Symbol in a given array of Symbol object. * * @param symbols the set of Symbols to search. * @param key the value to try and find in the Symbol array. * @return true if the key is found in the given Symbol array. */ public static boolean contains(Symbol[] symbols, Symbol key) { if (symbols == null || symbols.length == 0) { return false; } for (Symbol symbol : symbols) { if (symbol.equals(key)) { return true; } } return false; } /** * Search for a particular filter using a set of known indentification values in the Map of * filters. * * @param filters The filters map that should be searched. * @param filterIds The aliases for the target filter to be located. * @return the filter if found in the mapping or null if not found. */ public static Map.Entry<Symbol, DescribedType> findFilter( Map<Symbol, Object> filters, Object[] filterIds) { if (filterIds == null || filterIds.length == 0) { StringBuilder ids = new StringBuilder(); if (filterIds != null) { for (Object filterId : filterIds) { ids.append(filterId).append(" "); } } throw new IllegalArgumentException("Invalid Filter Ids array passed: " + ids); } if (filters == null || filters.isEmpty()) { return null; } for (Map.Entry<Symbol, Object> filter : filters.entrySet()) { if (filter.getValue() instanceof DescribedType) { DescribedType describedType = ((DescribedType) filter.getValue()); Object descriptor = describedType.getDescriptor(); for (Object filterId : filterIds) { if (descriptor.equals(filterId)) { return new AbstractMap.SimpleImmutableEntry<>(filter.getKey(), describedType); } } } } return null; } }