diff options
author | Robert Godfrey <rgodfrey@apache.org> | 2015-02-13 22:18:48 +0000 |
---|---|---|
committer | Robert Godfrey <rgodfrey@apache.org> | 2015-02-13 22:18:48 +0000 |
commit | 6b17c57341c1b822d7f888e76aae1104f1599795 (patch) | |
tree | 3a2c935c1c6085e4ff6eb47c2782e0bad8f24ff9 | |
parent | 928fed665a842440179db42ef090be91217284ce (diff) | |
download | qpid-python-6b17c57341c1b822d7f888e76aae1104f1599795.tar.gz |
QPID-6338 : [Java AMQP 1.0 Client] validate sections in created Message
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1659700 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Message.java | 179 |
1 files changed, 173 insertions, 6 deletions
diff --git a/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Message.java b/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Message.java index e8ac1de6c1..212342cd96 100644 --- a/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Message.java +++ b/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Message.java @@ -20,21 +20,89 @@ */ package org.apache.qpid.amqp_1_0.client; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + import org.apache.qpid.amqp_1_0.type.Binary; import org.apache.qpid.amqp_1_0.type.DeliveryState; import org.apache.qpid.amqp_1_0.type.Section; +import org.apache.qpid.amqp_1_0.type.messaging.AmqpSequence; import org.apache.qpid.amqp_1_0.type.messaging.AmqpValue; import org.apache.qpid.amqp_1_0.type.messaging.ApplicationProperties; +import org.apache.qpid.amqp_1_0.type.messaging.Data; +import org.apache.qpid.amqp_1_0.type.messaging.DeliveryAnnotations; +import org.apache.qpid.amqp_1_0.type.messaging.Footer; import org.apache.qpid.amqp_1_0.type.messaging.Header; +import org.apache.qpid.amqp_1_0.type.messaging.MessageAnnotations; import org.apache.qpid.amqp_1_0.type.messaging.Properties; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - public class Message { + + private static final Map<Class<? extends Section>, Collection<Class<? extends Section>>> VALID_NEXT_SECTIONS = new HashMap<>(); + + static + { + VALID_NEXT_SECTIONS.put(null, Arrays.asList(Header.class, + DeliveryAnnotations.class, + MessageAnnotations.class, + Properties.class, + ApplicationProperties.class, + AmqpValue.class, + AmqpSequence.class, + Data.class)); + + VALID_NEXT_SECTIONS.put(Header.class, Arrays.asList(DeliveryAnnotations.class, + MessageAnnotations.class, + Properties.class, + ApplicationProperties.class, + AmqpValue.class, + AmqpSequence.class, + Data.class)); + + VALID_NEXT_SECTIONS.put(DeliveryAnnotations.class, Arrays.asList(MessageAnnotations.class, + Properties.class, + ApplicationProperties.class, + AmqpValue.class, + AmqpSequence.class, + Data.class)); + + VALID_NEXT_SECTIONS.put(MessageAnnotations.class, Arrays.asList(Properties.class, + ApplicationProperties.class, + AmqpValue.class, + AmqpSequence.class, + Data.class)); + + VALID_NEXT_SECTIONS.put(Properties.class, Arrays.asList(ApplicationProperties.class, + AmqpValue.class, + AmqpSequence.class, + Data.class)); + + + VALID_NEXT_SECTIONS.put(ApplicationProperties.class, Arrays.asList(AmqpValue.class, + AmqpSequence.class, + Data.class)); + + VALID_NEXT_SECTIONS.put(AmqpValue.class, Arrays.<Class<? extends Section>>asList(Footer.class, null)); + + VALID_NEXT_SECTIONS.put(AmqpSequence.class, Arrays.asList(AmqpSequence.class, + Footer.class, null)); + + VALID_NEXT_SECTIONS.put(Data.class, Arrays.asList(Data.class, Footer.class, null)); + + VALID_NEXT_SECTIONS.put(Footer.class, Collections.<Class<? extends Section>>singletonList(null)); + + + } + + private Binary _deliveryTag; private List<Section> _payload = new ArrayList<Section>(); private Boolean _resume; @@ -49,7 +117,7 @@ public class Message public Message(Collection<Section> sections) { - _payload.addAll(sections); + _payload.addAll(validateOrReorder(sections)); } public Message(Section section) @@ -63,6 +131,105 @@ public class Message } + private static Collection<Section> validateOrReorder(final Collection<Section> providedSections) + { + Collection<Section> validatedSections; + if(providedSections == null) + { + validatedSections = Collections.emptyList(); + } + else if(isValidOrder(providedSections)) + { + validatedSections = providedSections; + } + else + { + validatedSections = reorderSections(providedSections); + } + return validatedSections; + } + + private static Collection<Section> reorderSections(final Collection<Section> providedSections) + { + Collection<Section> validSections = new ArrayList<>(); + List<Section> originalSection = new ArrayList<>(providedSections); + validSections.addAll(getAndRemoveSections(Header.class, originalSection, false)); + validSections.addAll(getAndRemoveSections(DeliveryAnnotations.class, originalSection, false)); + validSections.addAll(getAndRemoveSections(MessageAnnotations.class, originalSection, false)); + validSections.addAll(getAndRemoveSections(Properties.class, originalSection, false)); + validSections.addAll(getAndRemoveSections(ApplicationProperties.class, originalSection, false)); + + final List<AmqpValue> valueSections = getAndRemoveSections(AmqpValue.class, originalSection, false); + final List<AmqpSequence> sequenceSections = getAndRemoveSections(AmqpSequence.class, originalSection, true); + final List<Data> dataSections = getAndRemoveSections(Data.class, originalSection, true); + + if(valueSections.isEmpty() && sequenceSections.isEmpty() && dataSections.isEmpty()) + { + throw new IllegalArgumentException("Message must contain one of Data, AmqpValue or AmqpSequence"); + } + if((!valueSections.isEmpty() && (!sequenceSections.isEmpty() || !dataSections.isEmpty())) + || (!sequenceSections.isEmpty() && !dataSections.isEmpty())) + { + throw new IllegalArgumentException("Only one type of content Data, AmqpValue or AmqpSequence can be used"); + } + validSections.addAll(valueSections); + validSections.addAll(sequenceSections); + validSections.addAll(dataSections); + + validSections.addAll(getAndRemoveSections(Footer.class, originalSection, false)); + + if(!originalSection.isEmpty()) + { + throw new IllegalArgumentException("Invalid section type: " + originalSection.get(0).getClass().getName()); + } + return validSections; + } + + private static <T extends Section> List<T> getAndRemoveSections(Class<T> clazz, + List<Section> sections, + boolean allowMultiple) + { + List<T> desiredSections = new ArrayList<>(); + ListIterator<Section> iterator = sections.listIterator(); + while(iterator.hasNext()) + { + Section s = iterator.next(); + if(s.getClass() == clazz) + { + desiredSections.add((T)s); + iterator.remove(); + } + } + if(desiredSections.size() > 1 && !allowMultiple) + { + throw new IllegalArgumentException("Multiple " + clazz.getSimpleName() + " sections are not allowed"); + } + return desiredSections; + } + + private static boolean isValidOrder(final Collection<Section> providedSections) + { + Class<? extends Section> previousSection = null; + final Iterator<? extends Section> it = providedSections.iterator(); + while(it.hasNext()) + { + Collection<Class<? extends Section>> validSections = VALID_NEXT_SECTIONS.get(previousSection); + Class<? extends Section> sectionClass = it.next().getClass(); + if(validSections == null || !validSections.contains(sectionClass)) + { + return false; + } + else + { + previousSection = sectionClass; + } + } + Collection<Class<? extends Section>> validSections = VALID_NEXT_SECTIONS.get(previousSection); + return validSections != null && validSections.contains(null); + } + + + public Binary getDeliveryTag() { return _deliveryTag; |