diff options
author | Keith Wall <kwall@apache.org> | 2015-03-03 14:56:40 +0000 |
---|---|---|
committer | Keith Wall <kwall@apache.org> | 2015-03-03 14:56:40 +0000 |
commit | 9dc57fe738f366d875c2319dafdfa2c50ce2f20b (patch) | |
tree | be6634866a966f358fcb1ba6ba29dfb5c9c340c1 | |
parent | fe37626d4fd8fb3ee5b3146a5159024a3d6d3357 (diff) | |
download | qpid-python-9dc57fe738f366d875c2319dafdfa2c50ce2f20b.tar.gz |
merge from trunk
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/QPID-6262-JavaBrokerNIO@1663717 13f79535-47bb-0310-9956-ffa450edef68
227 files changed, 5619 insertions, 1291 deletions
diff --git a/qpid/java/README.txt b/qpid/java/README.txt index 5213799662..34e17db9ba 100644 --- a/qpid/java/README.txt +++ b/qpid/java/README.txt @@ -7,7 +7,7 @@ Some initial helper info can be found below. ==== Building the code and running the tests ==== -Here are some example Maven build commands that you may find usefull. +Here are some example Maven build commands that you may find useful. Clean previous builds output and install all modules to local repository without running any of the unit or system tests. diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/AmqpMessageImpl.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/AmqpMessageImpl.java index d780c67a76..0afbb5c56f 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/AmqpMessageImpl.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/AmqpMessageImpl.java @@ -27,6 +27,7 @@ import java.util.ListIterator; import org.apache.qpid.amqp_1_0.jms.AmqpMessage; import org.apache.qpid.amqp_1_0.type.Section; +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.DeliveryAnnotations; import org.apache.qpid.amqp_1_0.type.messaging.Footer; @@ -36,6 +37,8 @@ import org.apache.qpid.amqp_1_0.type.messaging.Properties; public class AmqpMessageImpl extends MessageImpl implements AmqpMessage { + private static final List<Section> EMPTY_MESSAGE = + Collections.<Section>singletonList(new AmqpValue(null)); private List<Section> _sections; protected AmqpMessageImpl(Header header, @@ -57,7 +60,7 @@ public class AmqpMessageImpl extends MessageImpl implements AmqpMessage new DeliveryAnnotations(new HashMap()), new MessageAnnotations(new HashMap()), new Properties(), new ApplicationProperties(new HashMap()), new Footer(Collections.EMPTY_MAP), session); - _sections = new ArrayList<Section>(); + _sections = EMPTY_MESSAGE; } public int getSectionCount() diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/ConnectionFactoryImpl.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/ConnectionFactoryImpl.java index 3bf9efd3d9..e92cd15ce5 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/ConnectionFactoryImpl.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/ConnectionFactoryImpl.java @@ -771,6 +771,16 @@ public class ConnectionFactoryImpl implements ConnectionFactory, TopicConnection return _sslEnabledProtocols; } + public SSLContext getSslContext() + { + return _sslContext; + } + + public void setSslContext(final SSLContext sslContext) + { + _sslContext = sslContext; + } + public void setSslEnabledProtocols(final String sslEnabledProtocols) { _sslEnabledProtocols = sslEnabledProtocols; diff --git a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageFactory.java b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageFactory.java index d120e4eadf..ef48e2a8a5 100644 --- a/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageFactory.java +++ b/qpid/java/amqp-1-0-client-jms/src/main/java/org/apache/qpid/amqp_1_0/jms/impl/MessageFactory.java @@ -226,6 +226,13 @@ class MessageFactory messageAnnotations, properties,appProperties,body,footer, _session); } } + else if(body.size() == 0) + { + message = new AmqpMessageImpl(header, + deliveryAnnotations, + messageAnnotations, properties,appProperties, + Collections.<Section>singletonList(new AmqpValue(null)),footer, _session); + } else { message = new AmqpMessageImpl(header, 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..c4f9783c89 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,12 @@ public class Message public Message(Collection<Section> sections) { - _payload.addAll(sections); + this(sections, true); + } + + public Message(Collection<Section> sections, boolean validate) + { + _payload.addAll(validate ? validateOrReorder(sections) : sections); } public Message(Section section) @@ -63,6 +136,106 @@ 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); + Section next = it.next(); + Class<? extends Section> sectionClass = 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; diff --git a/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Receiver.java b/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Receiver.java index 1d9ec0fc66..5d4374fec5 100644 --- a/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Receiver.java +++ b/qpid/java/amqp-1-0-client/src/main/java/org/apache/qpid/amqp_1_0/client/Receiver.java @@ -38,8 +38,10 @@ import org.apache.qpid.amqp_1_0.transport.ReceivingLinkListener; import org.apache.qpid.amqp_1_0.type.AmqpErrorException; 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.ErrorCondition; import org.apache.qpid.amqp_1_0.type.Outcome; import org.apache.qpid.amqp_1_0.type.Section; +import org.apache.qpid.amqp_1_0.type.Symbol; import org.apache.qpid.amqp_1_0.type.UnsignedInteger; import org.apache.qpid.amqp_1_0.type.messaging.Accepted; import org.apache.qpid.amqp_1_0.type.messaging.Modified; @@ -58,6 +60,20 @@ import org.apache.qpid.amqp_1_0.type.transport.Transfer; public class Receiver implements DeliveryStateHandler { + private static final ErrorCondition UNKNOWN_ERROR_CONDITION = new ErrorCondition() + { + @Override + public Symbol getValue() + { + return Symbol.valueOf("Unknown"); + } + + @Override + public String toString() + { + return getValue().toString(); + } + }; private ReceivingLinkEndpoint _endpoint; private int _id; private static final UnsignedInteger DEFAULT_INITIAL_CREDIT = UnsignedInteger.valueOf(100); @@ -196,16 +212,20 @@ public class Receiver implements DeliveryStateHandler { throw new ConnectionErrorException(AmqpError.INTERNAL_ERROR,"Interrupted while waiting for detach following failed attach"); } - throw new ConnectionErrorException(getError().getCondition(), - getError().getDescription() == null - ? "AMQP error: '" + getError().getCondition().toString() + + Error error = getError() == null + ? new Error(UNKNOWN_ERROR_CONDITION, "Unknown") + : getError(); + + + ErrorCondition condition = error.getCondition() == null ? UNKNOWN_ERROR_CONDITION : error.getCondition(); + + throw new ConnectionErrorException(condition, + error.getDescription() == null + ? "AMQP error: '" + condition.toString() + "' when attempting to create a receiver" + (source != null ? " from: '" + source.getAddress() +"'" : "") - : getError().getDescription()); - } - else - { - + : error.getDescription()); } } @@ -318,7 +338,7 @@ public class Receiver implements DeliveryStateHandler // todo - throw a sensible error e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } - m = new Message(sections); + m = new Message(sections, false); m.setDeliveryTag(deliveryTag); m.setResume(resume); m.setReceiver(this); diff --git a/qpid/java/amqp-1-0-common/src/main/java/org/apache/qpid/amqp_1_0/transport/ConnectionEndpoint.java b/qpid/java/amqp-1-0-common/src/main/java/org/apache/qpid/amqp_1_0/transport/ConnectionEndpoint.java index 17f334153d..e5a82eb2a3 100644 --- a/qpid/java/amqp-1-0-common/src/main/java/org/apache/qpid/amqp_1_0/transport/ConnectionEndpoint.java +++ b/qpid/java/amqp-1-0-common/src/main/java/org/apache/qpid/amqp_1_0/transport/ConnectionEndpoint.java @@ -451,6 +451,7 @@ public class ConnectionEndpoint implements DescribedTypeConstructorRegistry.Sour if (!_closedForInput) { _closedForInput = true; + _logger.received(_remoteAddress,(short)-1,"Underlying connection closed"); switch (_state) { case UNOPENED: @@ -466,7 +467,6 @@ public class ConnectionEndpoint implements DescribedTypeConstructorRegistry.Sour break; default: } - if (_receivingSessions != null) { for (int i = 0; i < _receivingSessions.length; i++) diff --git a/qpid/java/amqp-1-0-common/src/main/java/org/apache/qpid/amqp_1_0/type/messaging/codec/AmqpValueConstructor.java b/qpid/java/amqp-1-0-common/src/main/java/org/apache/qpid/amqp_1_0/type/messaging/codec/AmqpValueConstructor.java index 2000880361..30de72604b 100644 --- a/qpid/java/amqp-1-0-common/src/main/java/org/apache/qpid/amqp_1_0/type/messaging/codec/AmqpValueConstructor.java +++ b/qpid/java/amqp-1-0-common/src/main/java/org/apache/qpid/amqp_1_0/type/messaging/codec/AmqpValueConstructor.java @@ -25,8 +25,8 @@ package org.apache.qpid.amqp_1_0.type.messaging.codec; import org.apache.qpid.amqp_1_0.codec.DescribedTypeConstructor; import org.apache.qpid.amqp_1_0.codec.DescribedTypeConstructorRegistry; -import org.apache.qpid.amqp_1_0.type.*; -import org.apache.qpid.amqp_1_0.type.messaging.*; +import org.apache.qpid.amqp_1_0.type.Symbol; +import org.apache.qpid.amqp_1_0.type.UnsignedLong; import org.apache.qpid.amqp_1_0.type.messaging.AmqpValue; public class AmqpValueConstructor extends DescribedTypeConstructor<AmqpValue> @@ -49,16 +49,7 @@ public class AmqpValueConstructor extends DescribedTypeConstructor<AmqpValue> public AmqpValue construct(Object underlying) { - - if(underlying instanceof Object) - { - return new AmqpValue((Object)underlying); - } - else - { - // TODO - error - return null; - } + return new AmqpValue(underlying); } diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAReplicaVirtualHostImpl.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAReplicaVirtualHostImpl.java index 57b1d84a26..205ff57fab 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAReplicaVirtualHostImpl.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAReplicaVirtualHostImpl.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.virtualhost.berkeleydb; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -42,6 +43,8 @@ import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.VirtualHostAlias; import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.model.port.AmqpPort; +import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.LinkRegistry; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.stats.StatisticsCounter; @@ -81,6 +84,15 @@ public class BDBHAReplicaVirtualHostImpl extends AbstractConfiguredObject<BDBHAR @ManagedAttributeField private int _housekeepingThreadCount; + @ManagedAttributeField + private List<String> _enabledConnectionValidators; + + @ManagedAttributeField + private List<String> _disabledConnectionValidators; + + @ManagedAttributeField + private List<String> _globalAddressDomains; + @ManagedObjectFactoryConstructor public BDBHAReplicaVirtualHostImpl(final Map<String, Object> attributes, VirtualHostNode<?> virtualHostNode) { @@ -162,6 +174,12 @@ public class BDBHAReplicaVirtualHostImpl extends AbstractConfiguredObject<BDBHAR } @Override + public String getRedirectHost(final AmqpPort<?> port) + { + return null; + } + + @Override public boolean isQueue_deadLetterQueueEnabled() { return false; @@ -448,6 +466,47 @@ public class BDBHAReplicaVirtualHostImpl extends AbstractConfiguredObject<BDBHAR { } + @Override + public boolean authoriseCreateConnection(final AMQConnectionModel<?, ?> connection) + { + return false; + } + + @Override + public List<String> getEnabledConnectionValidators() + { + return _enabledConnectionValidators; + } + + @Override + public List<String> getDisabledConnectionValidators() + { + return _disabledConnectionValidators; + } + + @Override + public List<String> getGlobalAddressDomains() + { + return _globalAddressDomains; + } + + @Override + public String getLocalAddress(final String routingAddress) + { + String localAddress = routingAddress; + if(getGlobalAddressDomains() != null) + { + for(String domain : getGlobalAddressDomains()) + { + if(localAddress.length() > routingAddress.length() - domain.length() && routingAddress.startsWith(domain + "/")) + { + localAddress = routingAddress.substring(domain.length()); + } + } + } + return localAddress; + } + private void throwUnsupportedForReplica() { throw new IllegalStateException("The virtual host state of " + getState() diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNode.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNode.java index bb9f564d64..d8a2ba22a9 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNode.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHARemoteReplicationNode.java @@ -25,7 +25,7 @@ import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.RemoteReplicationNode; -@ManagedObject(category=false, managesChildren=false, creatable=false) +@ManagedObject(category=false, creatable=false) public interface BDBHARemoteReplicationNode<X extends BDBHARemoteReplicationNode<X>> extends RemoteReplicationNode<X> { String GROUP_NAME = "groupName"; diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb/add.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb/add.js index 7b12d10343..323b8e9750 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb/add.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb/add.js @@ -34,10 +34,11 @@ define(["dojo/_base/xhr", show: function (data) { this.containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode); - parser.parse(this.containerNode); - - registry.byId("addVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); - registry.byId("addVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + parser.parse(this.containerNode).then(function(instances) + { + registry.byId("addVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); + registry.byId("addVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + }); } }; } diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb/edit.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb/edit.js index e0dac745c2..076a27a3ae 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb/edit.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb/edit.js @@ -22,10 +22,12 @@ define(["dijit/registry", "qpid/common/util", "dojo/domReady!"], return { show: function(data) { - util.buildEditUI(data.containerNode, "virtualhost/sizemonitoring/edit.html", "editVirtualHost.", null, null); - - registry.byId("editVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); - registry.byId("editVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + util.parseHtmlIntoDiv(data.containerNode, "virtualhost/sizemonitoring/edit.html", + function() + { + registry.byId("editVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); + registry.byId("editVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + }); } }; } diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js index 3f36d56397..ebe6b6822a 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js @@ -22,10 +22,12 @@ define(["qpid/common/util", "qpid/common/metadata", "dijit/registry", "dojo/domR return { show: function(data) { - util.buildEditUI(data.containerNode, "virtualhost/bdb_ha/edit.html", "editVirtualHost.", null, null); - - registry.byId("editVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); - registry.byId("editVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + util.parseHtmlIntoDiv(data.containerNode, "virtualhost/bdb_ha/edit.html", + function() + { + registry.byId("editVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); + registry.byId("editVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + }); } }; } diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js index 3bc3305e1f..c0b079cf4c 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js @@ -27,10 +27,13 @@ define(["qpid/common/util", "dojo/query", "dojo/domReady!"], function BDB(data) { - util.buildUI(data.containerNode, data.parent, "virtualhost/bdb_ha/show.html", fields, this); - - this[localTransactionSynchronizationPolicy]= query("." + localTransactionSynchronizationPolicy, data.containerNode)[0]; - this[remoteTransactionSynchronizationPolicy]= query("."+ remoteTransactionSynchronizationPolicy, data.containerNode)[0]; + var that = this; + util.buildUI(data.containerNode, data.parent, "virtualhost/bdb_ha/show.html", fields, this, + function() + { + that[localTransactionSynchronizationPolicy]= query("." + localTransactionSynchronizationPolicy, data.containerNode)[0]; + that[remoteTransactionSynchronizationPolicy]= query("."+ remoteTransactionSynchronizationPolicy, data.containerNode)[0]; + }); } BDB.prototype.update = function(data) diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb/edit.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb/edit.js index 35ecbec315..4c70b4a22d 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb/edit.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb/edit.js @@ -22,8 +22,11 @@ define(["qpid/common/util", "dijit/registry", "dojo/domReady!"], return { show: function(data) { - util.buildEditUI(data.containerNode, "virtualhostnode/filebased/edit.html", "editVirtualHostNode.", ["storePath"], data.data); - registry.byId("editVirtualHostNode.storePath").set("disabled", !(data.data.state == "STOPPED" || data.data.state == "ERRORED")); + util.parseHtmlIntoDiv(data.containerNode, "virtualhostnode/filebased/edit.html", + function() + { + registry.byId("editVirtualHostNode.storePath").set("disabled", !(data.data.state == "STOPPED" || data.data.state == "ERRORED")); + }); } }; } diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add.js index 6431ddb6db..9b2b26d560 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add.js @@ -37,15 +37,21 @@ define(["dojo/_base/xhr", var that=this; this.containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode); - parser.parse(this.containerNode); - - // lookup field - this.groupChoice = registry.byId("addVirtualHostNode.group"); - this.virtualHostNodeBdbhaTypeFieldsContainer = dom.byId("addVirtualHostNode.bdbha.typeFields"); - - // add callback - this.groupChoice.on("change", function(type){that._groupChoiceChanged(type, that.virtualHostNodeBdbhaTypeFieldsContainer, "qpid/management/virtualhostnode/bdb_ha/add/");}); + parser.parse(this.containerNode).then(function(instances) + { + // lookup field + that.groupChoice = registry.byId("addVirtualHostNode.group"); + that.virtualHostNodeBdbhaTypeFieldsContainer = dom.byId("addVirtualHostNode.bdbha.typeFields"); + // add callback + that.groupChoice.on("change", + function(type) + { + that._groupChoiceChanged(type, + that.virtualHostNodeBdbhaTypeFieldsContainer, + "qpid/management/virtualhostnode/bdb_ha/add/"); + }); + }); }, _groupChoiceChanged: function(type, typeFieldsContainer, urlStem) { diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/existinggroup/add.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/existinggroup/add.js index 532c37f65b..be43e5f28b 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/existinggroup/add.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/existinggroup/add.js @@ -33,15 +33,15 @@ define(["dojo/_base/xhr", show: function(data) { this.containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode); - parser.parse(this.containerNode); - - registry.byId("addVirtualHostNode.groupName").set("regExpGen", util.nameOrContextVarRegexp); - registry.byId("addVirtualHostNode.helperNodeName").set("regExpGen", util.nameOrContextVarRegexp); - registry.byId("addVirtualHostNode.helperAddress").set("regExpGen", util.nodeAddressOrContextVarRegexp); - registry.byId("addVirtualHostNode.address").set("regExpGen", util.nodeAddressOrContextVarRegexp); - - dom.byId("addVirtualHostNode.uploadFields").style.display = "none"; + parser.parse(this.containerNode).then(function(instances) + { + registry.byId("addVirtualHostNode.groupName").set("regExpGen", util.nameOrContextVarRegexp); + registry.byId("addVirtualHostNode.helperNodeName").set("regExpGen", util.nameOrContextVarRegexp); + registry.byId("addVirtualHostNode.helperAddress").set("regExpGen", util.nodeAddressOrContextVarRegexp); + registry.byId("addVirtualHostNode.address").set("regExpGen", util.nodeAddressOrContextVarRegexp); + dom.byId("addVirtualHostNode.uploadFields").style.display = "none"; + }); } }; } diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js index c1aa9ffe4f..841f2051f5 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js @@ -37,8 +37,15 @@ define(["dojo/_base/xhr", var that=this; this.containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode); - parser.parse(this.containerNode); + parser.parse(this.containerNode).then(function(instances) + { + that._postParse(data); + }); + }, + _postParse: function(data) + { + var that=this; this.addVirtualHostNodeAddress = registry.byId("addVirtualHostNode.address"); this.addVirtualHostNodeAddress.set("regExpGen", util.nodeAddressOrContextVarRegexp); @@ -72,7 +79,6 @@ define(["dojo/_base/xhr", registry.byId("addVirtualHostNode.groupName").set("regExpGen", util.nameOrContextVarRegexp); dom.byId("addVirtualHostNode.uploadFields").style.display = "block"; - }, _updatePermittedNodesJson: function () { diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/edit.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/edit.js index b1399a59cb..e3d69577dc 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/edit.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/edit.js @@ -26,14 +26,16 @@ define(["qpid/common/util", "dojo/domReady!"], function (util, registry, Memory, ObjectStore, win) { - var fields = [ "storePath", "name", "groupName", "address", - "designatedPrimary", "priority", "quorumOverride"]; - return { show: function(data) { + var that = this; + util.parseHtmlIntoDiv(data.containerNode, "virtualhostnode/bdb_ha/edit.html", + function(){that._postParse(data);}); + }, + _postParse: function(data) + { var node = data.data; - util.buildEditUI(data.containerNode, "virtualhostnode/bdb_ha/edit.html", "editVirtualHostNode.", fields, node); if ( !(data.data.state == "ERRORED" || data.data.state == "STOPPED")) { registry.byId("editVirtualHostNode.storePath").set("disabled", true); diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/show.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/show.js index 9538b6b5b6..5338916812 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/show.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/show.js @@ -82,11 +82,14 @@ define(["dojo/_base/xhr", function BDBHA(data) { - var containerNode = data.containerNode; this.parent = data.parent; var that = this; - util.buildUI(data.containerNode, data.parent, "virtualhostnode/bdb_ha/show.html", nodeFields, this); - + util.buildUI(data.containerNode, data.parent, "virtualhostnode/bdb_ha/show.html", nodeFields, this, function(){that._postParse(data);}); + }; + BDBHA.prototype._postParse = function(data) + { + var that = this; + var containerNode = data.containerNode; this.designatedPrimaryContainer = findNode("designatedPrimaryContainer", containerNode); this.priorityContainer = findNode("priorityContainer", containerNode); this.quorumOverrideContainer = findNode("quorumOverrideContainer", containerNode); diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html index 0faae4323e..cfff12dcf2 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html @@ -117,11 +117,11 @@ <div data-dojo-type="dojo/store/Memory" data-dojo-id="nodePriorityStore" data-dojo-props="data: [ {id: '0', name: 'Never'}, - {id: '1', name: 'Default', selected: '1'}, + {id: '1', name: 'Default'}, {id: '2', name: 'High'}, {id: '3', name: 'Highest'} ]"></div> - <input id="editVirtualHostNode.priority" data-dojo-type="dijit/form/FilteringSelect" value="1" + <input id="editVirtualHostNode.priority" data-dojo-type="dijit/form/FilteringSelect" data-dojo-props=" name: 'priority', required: false, @@ -135,9 +135,9 @@ <div class="formLabel-labelCell tableContainer-labelCell">Required minimum number of nodes: </div> <div class="formLabel-controlCell tableContainer-valueCell"> <div data-dojo-type="dojo/store/Memory" data-dojo-id="nodeQuorumOverrideStore" - data-dojo-props="data: [{id: '0', name: 'Majority', selected: '1'}]"></div> + data-dojo-props="data: [{id: '0', name: 'Majority'}]"></div> <input type="text" id="editVirtualHostNode.quorumOverride" - data-dojo-type="dijit/form/FilteringSelect" value="0" + data-dojo-type="dijit/form/FilteringSelect" data-dojo-props=" name: 'quorumOverride', required: false, diff --git a/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/validation/AttributeAnnotationValidator.java b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/validation/AttributeAnnotationValidator.java index a831e1ebd9..c09a2b4f72 100644 --- a/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/validation/AttributeAnnotationValidator.java +++ b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/validation/AttributeAnnotationValidator.java @@ -278,6 +278,13 @@ public class AttributeAnnotationValidator extends AbstractProcessor return true; } + + if(typeUtils.isSameType(type,elementUtils.getTypeElement("java.lang.Object").asType())) + { + return true; + } + + if(typeUtils.isSameType(type, elementUtils.getTypeElement("java.lang.String").asType())) { return true; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java index 6c50fe7cfd..e88763dd1d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java @@ -23,9 +23,12 @@ package org.apache.qpid.server; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.URL; import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; +import java.util.HashSet; import java.util.Properties; +import java.util.Set; import java.util.concurrent.TimeoutException; import javax.security.auth.Subject; @@ -34,6 +37,7 @@ import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; +import org.apache.qpid.common.QpidProperties; import org.apache.qpid.server.configuration.BrokerProperties; import org.apache.qpid.server.configuration.updater.TaskExecutor; import org.apache.qpid.server.configuration.updater.TaskExecutorImpl; @@ -154,6 +158,8 @@ public class Broker implements BrokerShutdownProvider private void startupImpl(final BrokerOptions options) throws Exception { + populateSystemPropertiesFromDefaults(options.getInitialSystemProperties()); + String storeLocation = options.getConfigurationStoreLocation(); String storeType = options.getConfigurationStoreType(); @@ -321,6 +327,37 @@ public class Broker implements BrokerShutdownProvider } } + public static void populateSystemPropertiesFromDefaults(final String initialProperties) throws IOException + { + URL initialPropertiesLocation; + if(initialProperties == null) + { + initialPropertiesLocation = Broker.class.getClassLoader().getResource("system.properties"); + } + else + { + initialPropertiesLocation = (new File(initialProperties)).toURI().toURL(); + } + + Properties props = new Properties(QpidProperties.asProperties()); + if(initialPropertiesLocation != null) + { + + try(InputStream inStream = initialPropertiesLocation.openStream()) + { + props.load(inStream); + } + } + + Set<String> propertyNames = new HashSet<>(props.stringPropertyNames()); + propertyNames.removeAll(System.getProperties().stringPropertyNames()); + for (String propName : propertyNames) + { + System.setProperty(propName, props.getProperty(propName)); + } + } + + private class ShutdownService implements Runnable { public void run() diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java index 59075dfb57..ff3d9063f0 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java @@ -78,6 +78,7 @@ public class BrokerOptions private boolean _overwriteConfigurationStore; private Map<String, String> _configProperties = new HashMap<String,String>(); private boolean _startupLoggedToSystemOut = true; + private String _initialSystemProperties; public Map<String, Object> convertToSystemConfigAttributes() { @@ -390,4 +391,24 @@ public class BrokerOptions { this._startupLoggedToSystemOut = startupLoggedToSystemOut; } + + /** + * Get the location of initial JVM system properties to set. This can be URL or a file path + * + * @return the location of initial JVM system properties to set. + */ + public String getInitialSystemProperties() + { + return _initialSystemProperties; + } + + /** + * Set the location of initial properties file to set as JVM system properties. This can be URL or a file path + * + * @param initialSystemProperties the location of initial JVM system properties. + */ + public void setInitialSystemProperties(String initialSystemProperties) + { + _initialSystemProperties = initialSystemProperties; + } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java index 76c6b6007f..6012e2e8db 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.binding; -import java.security.AccessControlException; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -45,10 +44,8 @@ import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.Queue; import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.StateTransition; -import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.util.StateChangeListener; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; public class BindingImpl extends AbstractConfiguredObject<BindingImpl> @@ -108,26 +105,6 @@ public class BindingImpl } } - @Override - protected void onCreate() - { - super.onCreate(); - try - { - _queue.getVirtualHost().getSecurityManager().authoriseCreateBinding(this); - } - catch(AccessControlException e) - { - deleted(); - throw e; - } - if (isDurable()) - { - _queue.getVirtualHost().getDurableConfigurationStore().create(asObjectRecord()); - } - - } - private static Map<String, Object> enhanceWithDurable(Map<String, Object> attributes, final AMQQueue queue, final ExchangeImpl exchange) @@ -263,12 +240,6 @@ public class BindingImpl { _arguments = arguments; BindingImpl.super.setAttribute(ARGUMENTS, getActualAttributes().get(ARGUMENTS), arguments); - if (isDurable()) - { - VirtualHostImpl<?, ?, ?> vhost = - (VirtualHostImpl<?, ?, ?>) _exchange.getParent(VirtualHost.class); - vhost.getDurableConfigurationStore().update(true, asObjectRecord()); - } } } ); @@ -278,6 +249,8 @@ public class BindingImpl @Override public void validateOnCreate() { + _queue.getVirtualHost().getSecurityManager().authoriseCreateBinding(this); + AMQQueue queue = getAMQQueue(); Map<String, Object> arguments = getArguments(); if (arguments!=null && !arguments.isEmpty() && FilterSupport.argumentsContainFilter(arguments)) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/BrokerProperties.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/BrokerProperties.java index 765e1e4fa5..d6dbe37a6b 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/BrokerProperties.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/BrokerProperties.java @@ -48,6 +48,7 @@ public class BrokerProperties public static final String PROPERTY_QPID_HOME = "QPID_HOME"; public static final String PROPERTY_QPID_WORK = "QPID_WORK"; public static final String PROPERTY_LOG_RECORDS_BUFFER_SIZE = "qpid.broker_log_records_buffer_size"; + public static final String POSIX_FILE_PERMISSIONS = "qpid.default_posix_file_permissions"; private BrokerProperties() { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/store/StoreConfigurationChangeListener.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/store/StoreConfigurationChangeListener.java index 21715f7406..d5bbe16446 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/store/StoreConfigurationChangeListener.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/configuration/store/StoreConfigurationChangeListener.java @@ -25,7 +25,6 @@ import java.util.Collection; import org.apache.qpid.server.model.ConfigurationChangeListener; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.VirtualHostNode; import org.apache.qpid.server.store.DurableConfigurationStore; public class StoreConfigurationChangeListener implements ConfigurationChangeListener @@ -43,7 +42,10 @@ public class StoreConfigurationChangeListener implements ConfigurationChangeList { if (newState == State.DELETED) { - _store.remove(object.asObjectRecord()); + if(object.isDurable()) + { + _store.remove(object.asObjectRecord()); + } object.removeChangeListener(this); } } @@ -51,20 +53,23 @@ public class StoreConfigurationChangeListener implements ConfigurationChangeList @Override public void childAdded(ConfiguredObject<?> object, ConfiguredObject<?> child) { - // exclude VirtualHostNode children from storing in broker store - if (!(object instanceof VirtualHostNode)) + if (!object.managesChildStorage()) { - child.addChangeListener(this); - _store.update(true,child.asObjectRecord()); + if(object.isDurable() && child.isDurable()) + { + child.addChangeListener(this); + _store.update(true, child.asObjectRecord()); - Class<? extends ConfiguredObject> categoryClass = child.getCategoryClass(); - Collection<Class<? extends ConfiguredObject>> childTypes = child.getModel().getChildTypes(categoryClass); + Class<? extends ConfiguredObject> categoryClass = child.getCategoryClass(); + Collection<Class<? extends ConfiguredObject>> childTypes = + child.getModel().getChildTypes(categoryClass); - for(Class<? extends ConfiguredObject> childClass : childTypes) - { - for (ConfiguredObject<?> grandchild : child.getChildren(childClass)) + for (Class<? extends ConfiguredObject> childClass : childTypes) { - childAdded(child, grandchild); + for (ConfiguredObject<?> grandchild : child.getChildren(childClass)) + { + childAdded(child, grandchild); + } } } } @@ -74,14 +79,20 @@ public class StoreConfigurationChangeListener implements ConfigurationChangeList @Override public void childRemoved(ConfiguredObject object, ConfiguredObject child) { - _store.remove(child.asObjectRecord()); + if(child.isDurable()) + { + _store.remove(child.asObjectRecord()); + } child.removeChangeListener(this); } @Override public void attributeSet(ConfiguredObject object, String attributeName, Object oldAttributeValue, Object newAttributeValue) { - _store.update(false, object.asObjectRecord()); + if(object.isDurable()) + { + _store.update(false, object.asObjectRecord()); + } } @Override diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 6587bc76b2..cf23e3dd91 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -177,17 +177,6 @@ public abstract class AbstractExchange<T extends AbstractExchange<T>> } @Override - protected void onCreate() - { - super.onCreate(); - if(isDurable()) - { - getVirtualHost().getDurableConfigurationStore().create(asObjectRecord()); - } - - } - - @Override public EventLogger getEventLogger() { return _virtualHost.getEventLogger(); @@ -213,12 +202,6 @@ public abstract class AbstractExchange<T extends AbstractExchange<T>> throw new RequiredExchangeException(getName()); } - if (isDurable() && !isAutoDelete()) - { - getVirtualHost().getDurableConfigurationStore().remove(asObjectRecord()); - - } - if(_closed.compareAndSet(false,true)) { List<BindingImpl> bindings = new ArrayList<BindingImpl>(_bindings); @@ -241,11 +224,6 @@ public abstract class AbstractExchange<T extends AbstractExchange<T>> } _closeTaskList.clear(); - if (isDurable() && !isAutoDelete()) - { - getVirtualHost().getDurableConfigurationStore().remove(asObjectRecord()); - - } } deleted(); } @@ -665,10 +643,6 @@ public abstract class AbstractExchange<T extends AbstractExchange<T>> doRemoveBinding(b); queue.removeBinding(b); - if (b.isDurable()) - { - _virtualHost.getDurableConfigurationStore().remove(b.asObjectRecord()); - } b.delete(); } @@ -905,10 +879,6 @@ public abstract class AbstractExchange<T extends AbstractExchange<T>> protected void changeAttributes(final Map<String, Object> attributes) { super.changeAttributes(attributes); - if (isDurable() && getState() != State.DELETED) - { - this.getVirtualHost().getDurableConfigurationStore().update(false, asObjectRecord()); - } } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultDestination.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultDestination.java index 127a8d9e52..fcc34ee4de 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultDestination.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultDestination.java @@ -62,7 +62,8 @@ public class DefaultDestination implements MessageDestination final AMQQueue q = _virtualHost.getQueue(routingAddress); if(q == null) { - if(routingAddress != null && routingAddress.contains("/") && !routingAddress.startsWith("/")) + routingAddress = _virtualHost.getLocalAddress(routingAddress); + if(routingAddress.contains("/") && !routingAddress.startsWith("/")) { String[] parts = routingAddress.split("/",2); ExchangeImpl exchange = _virtualHost.getExchange(parts[0]); @@ -71,7 +72,7 @@ public class DefaultDestination implements MessageDestination return exchange.send(message, parts[1], instanceProperties, txn, postEnqueueAction); } } - else if(routingAddress == null || !routingAddress.contains("/")) + else if(!routingAddress.contains("/")) { ExchangeImpl exchange = _virtualHost.getExchange(routingAddress); if(exchange != null) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java index 597fc44e4c..de796a846a 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersBinding.java @@ -87,6 +87,12 @@ class HeadersBinding +"' with arguments: " + _binding.getArguments()); _filter = new MessageFilter() { + @Override + public String getName() + { + return ""; + } + @Override public boolean matches(Filterable message) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/ArrivalTimeFilter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/ArrivalTimeFilter.java new file mode 100644 index 0000000000..dbd6a5f6f6 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/ArrivalTimeFilter.java @@ -0,0 +1,46 @@ +/* + * + * 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.server.filter; + +import org.apache.qpid.common.AMQPFilterTypes; + +public final class ArrivalTimeFilter implements MessageFilter +{ + private final long _startingFrom; + + public ArrivalTimeFilter(final long startingFrom) + { + _startingFrom = startingFrom; + } + + @Override + public String getName() + { + return AMQPFilterTypes.REPLAY_PERIOD.toString(); + } + + @Override + public boolean matches(final Filterable message) + { + return message.getArrivalTime() >= _startingFrom; + } + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/ArrivalTimeFilterFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/ArrivalTimeFilterFactory.java new file mode 100644 index 0000000000..8c55c8ac76 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/ArrivalTimeFilterFactory.java @@ -0,0 +1,52 @@ +/* + * + * 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.server.filter; + +import java.util.List; + +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.server.plugin.MessageFilterFactory; +import org.apache.qpid.server.plugin.PluggableService; + +@PluggableService +public final class ArrivalTimeFilterFactory implements MessageFilterFactory +{ + + @Override + public MessageFilter newInstance(final List<String> arguments) + { + if(arguments == null || arguments.size() != 1) + { + throw new IllegalArgumentException("Cannot create a filter from these arguments: " + arguments); + } + String arg = arguments.get(0); + long startingFrom= Long.parseLong(arg); + + return new ArrivalTimeFilter(startingFrom); + } + + @Override + public String getType() + { + return AMQPFilterTypes.REPLAY_PERIOD.toString(); + } + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterManager.java index 69fc520a8f..ad14fa423a 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterManager.java @@ -14,26 +14,62 @@ * "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. - * + * under the License. * + * */ package org.apache.qpid.server.filter; -// -// Based on like named file from r450141 of the Apache ActiveMQ project <http://www.activemq.org/site/home.html> -// import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; -public interface FilterManager +public class FilterManager { - void add(MessageFilter filter); - void remove(MessageFilter filter); + private final Map<String, MessageFilter> _filters = new ConcurrentHashMap<>(); + + public FilterManager() + { + } + + public void add(String name, MessageFilter filter) + { + _filters.put(name, filter); + } + + public boolean allAllow(Filterable msg) + { + for (MessageFilter filter : _filters.values()) + { + if (!filter.matches(msg)) + { + return false; + } + } + return true; + } + + public Iterator<MessageFilter> filters() + { + return _filters.values().iterator(); + } + + public boolean hasFilters() + { + return !_filters.isEmpty(); + } + + public boolean hasFilter(final String name) + { + return _filters.containsKey(name); + } - boolean allAllow(Filterable msg); + @Override + public String toString() + { + return _filters.toString(); + } - Iterator<MessageFilter> filters(); - boolean hasFilters(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java index a159a8506b..28f7fe3554 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterManagerFactory.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.filter; +import java.util.Map; + import org.apache.log4j.Logger; import org.apache.qpid.common.AMQPFilterTypes; @@ -27,8 +29,6 @@ import org.apache.qpid.filter.SelectorParsingException; import org.apache.qpid.filter.selector.ParseException; import org.apache.qpid.filter.selector.TokenMgrError; -import java.util.Map; - public class FilterManagerFactory { @@ -54,20 +54,13 @@ public class FilterManagerFactory if (selector instanceof String && !selector.equals("")) { - manager = new SimpleFilterManager(); + manager = new FilterManager(); try { - manager.add(new JMSSelectorFilter((String)selector)); - } - catch (ParseException e) - { - throw new AMQInvalidArgumentException("Cannot parse JMS selector \"" + selector + "\"", e); - } - catch (SelectorParsingException e) - { - throw new AMQInvalidArgumentException("Cannot parse JMS selector \"" + selector + "\"", e); + MessageFilter filter = new JMSSelectorFilter((String)selector); + manager.add(filter.getName(), filter); } - catch (TokenMgrError e) + catch (ParseException | SelectorParsingException | TokenMgrError e) { throw new AMQInvalidArgumentException("Cannot parse JMS selector \"" + selector + "\"", e); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterSupport.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterSupport.java index d0b1670a45..6b8ae2f552 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterSupport.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/FilterSupport.java @@ -26,12 +26,14 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; + import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.filter.SelectorParsingException; import org.apache.qpid.filter.selector.ParseException; import org.apache.qpid.filter.selector.TokenMgrError; import org.apache.qpid.server.consumer.ConsumerImpl; import org.apache.qpid.server.message.MessageSource; +import org.apache.qpid.server.plugin.PluggableService; import org.apache.qpid.server.queue.AMQQueue; public class FilterSupport @@ -57,15 +59,7 @@ public class FilterSupport { selector = new JMSSelectorFilter(selectorString); } - catch (ParseException e) - { - throw new AMQInvalidArgumentException("Cannot parse JMS selector \"" + selectorString + "\"", e); - } - catch (SelectorParsingException e) - { - throw new AMQInvalidArgumentException("Cannot parse JMS selector \"" + selectorString + "\"", e); - } - catch (TokenMgrError e) + catch (ParseException | SelectorParsingException | TokenMgrError e) { throw new AMQInvalidArgumentException("Cannot parse JMS selector \"" + selectorString + "\"", e); } @@ -119,6 +113,7 @@ public class FilterSupport } } + @PluggableService public static final class NoLocalFilter implements MessageFilter { private final MessageSource _queue; @@ -128,6 +123,12 @@ public class FilterSupport _queue = queue; } + @Override + public String getName() + { + return AMQPFilterTypes.NO_LOCAL.toString(); + } + public boolean matches(Filterable message) { @@ -165,6 +166,8 @@ public class FilterSupport { return _queue != null ? _queue.hashCode() : 0; } + + } static final class CompoundFilter implements MessageFilter @@ -178,6 +181,12 @@ public class FilterSupport _jmsSelectorFilter = jmsSelectorFilter; } + @Override + public String getName() + { + return ""; + } + public boolean matches(Filterable message) { return _noLocalFilter.matches(message) && _jmsSelectorFilter.matches(message); @@ -216,5 +225,7 @@ public class FilterSupport result = 31 * result + (_jmsSelectorFilter != null ? _jmsSelectorFilter.hashCode() : 0); return result; } + + } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/Filterable.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/Filterable.java index 589e888059..295f9ae074 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/Filterable.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/Filterable.java @@ -34,6 +34,10 @@ public interface Filterable Object getConnectionReference(); + long getMessageNumber(); + + long getArrivalTime(); + public class Factory { @@ -41,6 +45,7 @@ public interface Filterable { return new Filterable() { + @Override public AMQMessageHeader getMessageHeader() { @@ -64,6 +69,18 @@ public interface Filterable { return message.getConnectionReference(); } + + @Override + public long getMessageNumber() + { + return message.getMessageNumber(); + } + + @Override + public long getArrivalTime() + { + return message.getArrivalTime(); + } }; } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java index 744e4e4e9d..a36049cd23 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilter.java @@ -25,14 +25,18 @@ import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.apache.log4j.Logger; + +import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.filter.BooleanExpression; import org.apache.qpid.filter.FilterableMessage; import org.apache.qpid.filter.SelectorParsingException; import org.apache.qpid.filter.selector.ParseException; import org.apache.qpid.filter.selector.SelectorParser; import org.apache.qpid.filter.selector.TokenMgrError; +import org.apache.qpid.server.plugin.PluggableService; +@PluggableService public class JMSSelectorFilter implements MessageFilter { private final static Logger _logger = org.apache.log4j.Logger.getLogger(JMSSelectorFilter.class); @@ -46,6 +50,12 @@ public class JMSSelectorFilter implements MessageFilter _matcher = new SelectorParser().parse(selector); } + @Override + public String getName() + { + return AMQPFilterTypes.JMS_SELECTOR.toString(); + } + public boolean matches(Filterable message) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilterFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilterFactory.java new file mode 100644 index 0000000000..233edc78cd --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilterFactory.java @@ -0,0 +1,57 @@ +/* + * + * 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.server.filter; + +import java.util.List; + +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.filter.SelectorParsingException; +import org.apache.qpid.filter.selector.ParseException; +import org.apache.qpid.filter.selector.TokenMgrError; +import org.apache.qpid.server.plugin.MessageFilterFactory; +import org.apache.qpid.server.plugin.PluggableService; + +@PluggableService +public final class JMSSelectorFilterFactory implements MessageFilterFactory +{ + public String getType() + { + return AMQPFilterTypes.JMS_SELECTOR.toString(); + } + + @Override + public MessageFilter newInstance(final List<String> arguments) + { + if(arguments == null || arguments.size() != 1) + { + throw new IllegalArgumentException("Cannot create a filter from these arguments: " + arguments); + } + String arg = arguments.get(0); + try + { + return new JMSSelectorFilter(arg); + } + catch (ParseException | TokenMgrError | SelectorParsingException e) + { + throw new IllegalArgumentException("Cannot create an JMS Selector from '" + arg + "'", e); + } + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/MessageFilter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/MessageFilter.java index d7dbbea166..226d646efd 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/MessageFilter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/MessageFilter.java @@ -22,5 +22,6 @@ package org.apache.qpid.server.filter; public interface MessageFilter { + String getName(); boolean matches(Filterable message); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java deleted file mode 100644 index 111fb6a333..0000000000 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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.server.filter; - -import org.apache.log4j.Logger; - -import java.util.Iterator; -import java.util.concurrent.ConcurrentLinkedQueue; - -public class SimpleFilterManager implements FilterManager -{ - private final Logger _logger = Logger.getLogger(SimpleFilterManager.class); - - private final ConcurrentLinkedQueue<MessageFilter> _filters; - private String _toString = ""; - - public SimpleFilterManager() - { - _logger.debug("Creating SimpleFilterManager"); - _filters = new ConcurrentLinkedQueue<MessageFilter>(); - } - - public SimpleFilterManager(JMSSelectorFilter messageFilter) - { - this(); - add(messageFilter); - } - - public void add(MessageFilter filter) - { - _filters.add(filter); - updateStringValue(); - } - - public void remove(MessageFilter filter) - { - _filters.remove(filter); - updateStringValue(); - } - - public boolean allAllow(Filterable msg) - { - for (MessageFilter filter : _filters) - { - if (!filter.matches(msg)) - { - return false; - } - } - return true; - } - - @Override - public Iterator<MessageFilter> filters() - { - return _filters.iterator(); - } - - public boolean hasFilters() - { - return !_filters.isEmpty(); - } - - - @Override - public String toString() - { - return _toString; - } - - private void updateStringValue() - { - StringBuilder toString = new StringBuilder(); - for (MessageFilter filter : _filters) - { - toString.append(filter.toString()); - toString.append(","); - } - - if (_filters.size() > 0) - { - //Remove the last ',' - toString.deleteCharAt(toString.length()-1); - } - _toString = toString.toString(); - } -} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java index aef769dc4f..76608cffbf 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java @@ -122,8 +122,11 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im private final TaskExecutor _taskExecutor; private final Class<? extends ConfiguredObject> _category; + private final Class<? extends ConfiguredObject> _typeClass; private final Class<? extends ConfiguredObject> _bestFitInterface; private final Model _model; + private final boolean _managesChildStorage; + @ManagedAttributeField private long _createdTime; @@ -206,6 +209,8 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im _model = model; _category = ConfiguredObjectTypeRegistry.getCategory(getClass()); + Class<? extends ConfiguredObject> typeClass = model.getTypeRegistry().getTypeClass(getClass()); + _typeClass = typeClass == null ? _category : typeClass; _attributeTypes = model.getTypeRegistry().getAttributeTypes(getClass()); _automatedFields = model.getTypeRegistry().getAutomatedFields(getClass()); @@ -242,6 +247,7 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im } _type = ConfiguredObjectTypeRegistry.getType(getClass()); + _managesChildStorage = managesChildren(_category) || managesChildren(_typeClass); _bestFitInterface = calculateBestFitInterface(); if(attributes.get(TYPE) != null && !_type.equals(attributes.get(TYPE))) @@ -315,6 +321,11 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im } } + private boolean managesChildren(final Class<? extends ConfiguredObject> clazz) + { + return clazz.getAnnotation(ManagedObject.class).managesChildren(); + } + private Class<? extends ConfiguredObject> calculateBestFitInterface() { Set<Class<? extends ConfiguredObject>> candidates = new HashSet<Class<? extends ConfiguredObject>>(); @@ -1056,11 +1067,24 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im return _model; } + @Override public Class<? extends ConfiguredObject> getCategoryClass() { return _category; } + @Override + public Class<? extends ConfiguredObject> getTypeClass() + { + return _typeClass; + } + + @Override + public boolean managesChildStorage() + { + return _managesChildStorage; + } + public Map<String,String> getContext() { return _context == null ? Collections.<String,String>emptyMap() : Collections.unmodifiableMap(_context); @@ -1219,8 +1243,7 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im if(attr != null && (attr.isAutomated() || attr.isDerived())) { Object value = attr.getValue((X)this); - if(value != null && attr.isSecure() && - !SecurityManager.isSystemProcess()) + if(value != null && !SecurityManager.isSystemProcess() && attr.isSecureValue(value)) { return SECURE_VALUES.get(value.getClass()); } @@ -1620,8 +1643,9 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { Object desired = attributes.get(name); Object expected = getAttribute(name); - if(((_attributes.get(name) != null && !_attributes.get(name).equals(attributes.get(name))) - || attributes.get(name) != null) + Object currentValue = _attributes.get(name); + if(((currentValue != null && !currentValue.equals(desired)) + || (currentValue == null && desired != null)) && changeAttribute(name, expected, desired)) { attributeSet(name, expected, desired); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AttributeValueConverter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AttributeValueConverter.java index 15e804e6f5..24e62ce7de 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AttributeValueConverter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AttributeValueConverter.java @@ -50,6 +50,25 @@ abstract class AttributeValueConverter<T> } }; + static final AttributeValueConverter<Object> OBJECT_CONVERTER = new AttributeValueConverter<Object>() + { + @Override + public Object convert(final Object value, final ConfiguredObject object) + { + if(value instanceof String) + { + return AbstractConfiguredObject.interpolate(object, (String) value); + } + else if(value == null) + { + return null; + } + else + { + return value; + } + } + }; static final AttributeValueConverter<UUID> UUID_CONVERTER = new AttributeValueConverter<UUID>() { @Override @@ -398,7 +417,17 @@ abstract class AttributeValueConverter<T> } else if(Map.class.isAssignableFrom(type)) { - return (AttributeValueConverter<X>) MAP_CONVERTER; + if(returnType instanceof ParameterizedType) + { + Type keyType = ((ParameterizedType) returnType).getActualTypeArguments()[0]; + Type valueType = ((ParameterizedType) returnType).getActualTypeArguments()[1]; + + return (AttributeValueConverter<X>) new GenericMapConverter(keyType,valueType); + } + else + { + return (AttributeValueConverter<X>) MAP_CONVERTER; + } } else if(Collection.class.isAssignableFrom(type)) { @@ -416,6 +445,10 @@ abstract class AttributeValueConverter<T> { return (AttributeValueConverter<X>) new ConfiguredObjectConverter(type); } + else if(Object.class == type) + { + return (AttributeValueConverter<X>) OBJECT_CONVERTER; + } throw new IllegalArgumentException("Cannot create attribute converter of type " + type.getName()); } @@ -575,6 +608,62 @@ abstract class AttributeValueConverter<T> } } + public static class GenericMapConverter extends AttributeValueConverter<Map> + { + + private final AttributeValueConverter<?> _keyConverter; + private final AttributeValueConverter<?> _valueConverter; + + + public GenericMapConverter(final Type keyType, final Type valueType) + { + _keyConverter = getConverter(getRawType(keyType), keyType); + + _valueConverter = getConverter(getRawType(valueType), valueType); + } + + + @Override + public Map convert(final Object value, final ConfiguredObject object) + { + if(value instanceof Map) + { + Map<?,?> original = (Map<?,?>)value; + Map converted = new LinkedHashMap(original.size()); + for(Map.Entry<?,?> entry : original.entrySet()) + { + converted.put(_keyConverter.convert(entry.getKey(),object), + _valueConverter.convert(entry.getValue(), object)); + } + return Collections.unmodifiableMap(converted); + } + else if(value == null) + { + return null; + } + else + { + if(value instanceof String) + { + String interpolated = AbstractConfiguredObject.interpolate(object, (String) value); + ObjectMapper objectMapper = new ObjectMapper(); + try + { + return convert(objectMapper.readValue(interpolated, Map.class), object); + } + catch (IOException e) + { + // fall through to the non-JSON single object case + } + } + + throw new IllegalArgumentException("Cannot convert type " + value.getClass() + " to a Map"); + } + + } + } + + static final class EnumConverter<X extends Enum<X>> extends AttributeValueConverter<X> { private final Class<X> _klazz; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java index 9fca898dc0..342b7ac0ba 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java @@ -28,6 +28,7 @@ import java.lang.reflect.Type; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.regex.Pattern; import org.apache.log4j.Logger; @@ -37,6 +38,7 @@ public class ConfiguredAutomatedAttribute<C extends ConfiguredObject, T> extend private final ManagedAttribute _annotation; private final Method _validValuesMethod; + private final Pattern _secureValuePattern; ConfiguredAutomatedAttribute(final Class<C> clazz, final Method getter, @@ -53,6 +55,16 @@ public class ConfiguredAutomatedAttribute<C extends ConfiguredObject, T> extend validValuesMethod = getValidValuesMethod(validValue, clazz); } _validValuesMethod = validValuesMethod; + + String secureValueFilter = _annotation.secureValueFilter(); + if (secureValueFilter == null || "".equals(secureValueFilter)) + { + _secureValuePattern = null; + } + else + { + _secureValuePattern = Pattern.compile(secureValueFilter); + } } private Method getValidValuesMethod(final String validValue, final Class<C> clazz) @@ -140,6 +152,11 @@ public class ConfiguredAutomatedAttribute<C extends ConfiguredObject, T> extend return _annotation.description(); } + public Pattern getSecureValueFilter() + { + return _secureValuePattern; + } + public Collection<String> validValues() { if(_validValuesMethod != null) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredDerivedAttribute.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredDerivedAttribute.java index 71488edb8c..20fd0264c6 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredDerivedAttribute.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredDerivedAttribute.java @@ -21,10 +21,12 @@ package org.apache.qpid.server.model; import java.lang.reflect.Method; +import java.util.regex.Pattern; public class ConfiguredDerivedAttribute<C extends ConfiguredObject, T> extends ConfiguredObjectAttribute<C,T> { private final DerivedAttribute _annotation; + private final Pattern _secureValuePattern; ConfiguredDerivedAttribute(final Class<C> clazz, final Method getter, @@ -32,6 +34,16 @@ public class ConfiguredDerivedAttribute<C extends ConfiguredObject, T> extends { super(clazz, getter); _annotation = annotation; + + String secureValueFilter = _annotation.secureValueFilter(); + if (secureValueFilter == null || "".equals(secureValueFilter)) + { + _secureValuePattern = null; + } + else + { + _secureValuePattern = Pattern.compile(secureValueFilter); + } } public boolean isAutomated() @@ -72,4 +84,10 @@ public class ConfiguredDerivedAttribute<C extends ConfiguredObject, T> extends return _annotation.description(); } + @Override + public Pattern getSecureValueFilter() + { + return _secureValuePattern; + } + } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java index 89fda6798b..bfe9c8b15d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java @@ -239,6 +239,9 @@ public interface ConfiguredObject<X extends ConfiguredObject<X>> void setAttributes(Map<String, Object> attributes) throws IllegalStateException, AccessControlException, IllegalArgumentException; Class<? extends ConfiguredObject> getCategoryClass(); + Class<? extends ConfiguredObject> getTypeClass(); + + boolean managesChildStorage(); <C extends ConfiguredObject<C>> C findConfiguredObject(Class<C> clazz, String name); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectAttribute.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectAttribute.java index 73b7839a8e..94610a6cb5 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectAttribute.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectAttribute.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.model; import java.lang.reflect.Method; import java.lang.reflect.Type; +import java.util.regex.Pattern; public abstract class ConfiguredObjectAttribute<C extends ConfiguredObject, T> extends ConfiguredObjectAttributeOrStatistic<C,T> { @@ -49,6 +50,25 @@ public abstract class ConfiguredObjectAttribute<C extends ConfiguredObject, T> e public abstract String getDescription(); + public abstract Pattern getSecureValueFilter(); + + public boolean isSecureValue(Object value) + { + if (isSecure()) + { + Pattern filter = getSecureValueFilter(); + if (filter == null) + { + return true; + } + else + { + return filter.matcher(String.valueOf(value)).matches(); + } + } + return false; + } + public T convert(final Object value, C object) { final AttributeValueConverter<T> converter = getConverter(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryImpl.java index 27d914c639..5026df0e19 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryImpl.java @@ -156,7 +156,7 @@ public class ConfiguredObjectFactoryImpl implements ConfiguredObjectFactory factory = categoryFactories.get(_defaultTypes.get(category)); if(factory == null) { - throw new NoFactoryForTypeException(category, _defaultTypes.get(category)); + throw new NoFactoryForTypeException(category, type); } } return factory; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectTypeRegistry.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectTypeRegistry.java index d134c43bda..d0c6fb041e 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectTypeRegistry.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectTypeRegistry.java @@ -385,7 +385,7 @@ public class ConfiguredObjectTypeRegistry return null; } - private Class<? extends ConfiguredObject> getTypeClass(final Class<? extends ConfiguredObject> clazz) + public Class<? extends ConfiguredObject> getTypeClass(final Class<? extends ConfiguredObject> clazz) { String typeName = getType(clazz); Class<? extends ConfiguredObject> typeClass = null; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/DerivedAttribute.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/DerivedAttribute.java index e5c17a17e4..6de6bf25c3 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/DerivedAttribute.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/DerivedAttribute.java @@ -32,4 +32,5 @@ public @interface DerivedAttribute boolean persist() default false; String description() default ""; boolean oversize() default false; + String secureValueFilter() default ""; } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttribute.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttribute.java index 05b2c610ba..2f96299703 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttribute.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttribute.java @@ -37,4 +37,5 @@ public @interface ManagedAttribute String[] validValues() default {}; boolean oversize() default false; String oversizedAltText() default ""; + String secureValueFilter() default ""; } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java index 46fbaac3f2..ba1f262cfc 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java @@ -21,6 +21,8 @@ package org.apache.qpid.server.model; import java.util.Collection; +import java.util.List; +import java.util.Map; import org.apache.qpid.server.queue.QueueEntryVisitor; import org.apache.qpid.server.store.MessageDurability; @@ -48,6 +50,8 @@ public interface Queue<X extends Queue<X>> extends ConfiguredObject<X> String QUEUE_FLOW_STOPPED = "queueFlowStopped"; String MAXIMUM_MESSAGE_TTL = "maximumMessageTtl"; String MINIMUM_MESSAGE_TTL = "minimumMessageTtl"; + String DEFAULT_FILTERS = "defaultFilters"; + String ENSURE_NONDESTRUCTIVE_CONSUMERS = "ensureNondestructiveConsumers"; String QUEUE_MINIMUM_ESTIMATED_MEMORY_FOOTPRINT = "queue.minimumEstimatedMemoryFootprint"; @ManagedContextDefault( name = QUEUE_MINIMUM_ESTIMATED_MEMORY_FOOTPRINT) @@ -67,6 +71,9 @@ public interface Queue<X extends Queue<X>> extends ConfiguredObject<X> @ManagedAttribute( defaultValue = "NONE" ) ExclusivityPolicy getExclusive(); + @ManagedAttribute( defaultValue = "false" ) + boolean isEnsureNondestructiveConsumers(); + @DerivedAttribute( persist = true ) String getOwner(); @@ -155,6 +162,9 @@ public interface Queue<X extends Queue<X>> extends ConfiguredObject<X> @ManagedAttribute long getMaximumMessageTtl(); + @ManagedAttribute + Map<String, Map<String,List<String>>> getDefaultFilters(); + //children Collection<? extends Binding> getBindings(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/RemoteReplicationNode.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/RemoteReplicationNode.java index 21cbfcf194..3b751a3a10 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/RemoteReplicationNode.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/RemoteReplicationNode.java @@ -20,9 +20,6 @@ */ package org.apache.qpid.server.model; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.ManagedObject; - @ManagedObject(category=true, managesChildren=false, creatable=false) public interface RemoteReplicationNode<X extends RemoteReplicationNode<X>> extends ConfiguredObject<X> { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java index a69808180d..c1a05a9e35 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.model; +import org.apache.qpid.server.configuration.BrokerProperties; import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.LogRecorder; import org.apache.qpid.server.store.DurableConfigurationStore; @@ -37,6 +38,9 @@ public interface SystemConfig<X extends SystemConfig<X>> extends ConfiguredObjec String INITIAL_CONFIGURATION_LOCATION = "initialConfigurationLocation"; String STARTUP_LOGGED_TO_SYSTEM_OUT = "startupLoggedToSystemOut"; + @ManagedContextDefault(name = BrokerProperties.POSIX_FILE_PERMISSIONS) + String DEFAULT_POSIX_FILE_PERMISSIONS = "rw-r-----"; + @ManagedAttribute(defaultValue = "false") boolean isManagementMode(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java index 79f37b66cb..cc758ba7c9 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java @@ -22,14 +22,16 @@ package org.apache.qpid.server.model; import java.security.AccessControlException; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.qpid.server.configuration.updater.TaskExecutor; import org.apache.qpid.server.message.MessageInstance; +import org.apache.qpid.server.model.port.AmqpPort; import org.apache.qpid.server.store.MessageStore; -@ManagedObject( managesChildren = true, defaultType = "ProvidedStore") +@ManagedObject( defaultType = "ProvidedStore") public interface VirtualHost<X extends VirtualHost<X, Q, E>, Q extends Queue<?>, E extends Exchange<?> > extends ConfiguredObject<X> { @@ -42,6 +44,9 @@ public interface VirtualHost<X extends VirtualHost<X, Q, E>, Q extends Queue<?>, String STORE_TRANSACTION_OPEN_TIMEOUT_WARN = "storeTransactionOpenTimeoutWarn"; String HOUSE_KEEPING_THREAD_COUNT = "houseKeepingThreadCount"; String MODEL_VERSION = "modelVersion"; + String ENABLED_CONNECTION_VALIDATORS = "enabledConnectionValidators"; + String DISABLED_CONNECTION_VALIDATORS = "disabledConnectionValidators"; + String GLOBAL_ADDRESS_DOMAINS = "globalAddressDomains"; @ManagedContextDefault( name = "queue.deadLetterQueueEnabled") public static final boolean DEFAULT_DEAD_LETTER_QUEUE_ENABLED = false; @@ -88,6 +93,21 @@ public interface VirtualHost<X extends VirtualHost<X, Q, E>, Q extends Queue<?>, @DerivedAttribute( persist = true ) String getModelVersion(); + @ManagedContextDefault( name = "virtualhost.enabledConnectionValidators") + String DEFAULT_ENABLED_VALIDATORS = "[]"; + + @ManagedAttribute( defaultValue = "${virtualhost.enabledConnectionValidators}") + List<String> getEnabledConnectionValidators(); + + @ManagedContextDefault( name = "virtualhost.disabledConnectionValidators") + String DEFAULT_DISABLED_VALIDATORS = "[]"; + + @ManagedAttribute( defaultValue = "${virtualhost.disabledConnectionValidators}") + List<String> getDisabledConnectionValidators(); + + @ManagedAttribute( defaultValue = "[]") + List<String> getGlobalAddressDomains(); + @ManagedStatistic long getQueueCount(); @@ -129,6 +149,8 @@ public interface VirtualHost<X extends VirtualHost<X, Q, E>, Q extends Queue<?>, void delete(); + String getRedirectHost(AmqpPort<?> port); + public static interface Transaction { void dequeue(MessageInstance entry); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostNode.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostNode.java index fa35e725c9..3bc19ef7bd 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostNode.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostNode.java @@ -24,7 +24,7 @@ import java.util.Collection; import org.apache.qpid.server.store.DurableConfigurationStore; -@ManagedObject(category=true, managesChildren=false) +@ManagedObject(category=true, managesChildren=true) public interface VirtualHostNode<X extends VirtualHostNode<X>> extends ConfiguredObject<X> { String QPID_INITIAL_CONFIG_VIRTUALHOST_CONFIG_VAR = "qpid.initial_config_virtualhost_config"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/ConnectionAdapter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/ConnectionAdapter.java index eae438754b..0cbb80d722 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/ConnectionAdapter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/ConnectionAdapter.java @@ -80,7 +80,7 @@ public final class ConnectionAdapter extends AbstractConfiguredObject<Connection { Map<String,Object> attributes = new HashMap<String, Object>(); attributes.put(ID, UUID.randomUUID()); - attributes.put(NAME, _connection.getRemoteAddressString().replaceAll("/", "")); + attributes.put(NAME, "[" + _connection.getConnectionId() + "] " + _connection.getRemoteAddressString().replaceAll("/", "")); attributes.put(DURABLE, false); return attributes; } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProvider.java index 631ed3e8f7..cb9727f3f6 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProvider.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProvider.java @@ -25,7 +25,7 @@ import org.apache.qpid.server.model.GroupProvider; import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.model.ManagedObject; -@ManagedObject( category = false, type = "GroupFile" ) +@ManagedObject( category = false, type = "GroupFile", managesChildren = true ) public interface FileBasedGroupProvider<X extends FileBasedGroupProvider<X>> extends GroupProvider<X>, GroupManagingGroupProvider { String PATH="path"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java index 19aec414de..327b7ddfe9 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java @@ -34,6 +34,7 @@ import java.util.UUID; import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.BrokerProperties; import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.model.AbstractConfiguredObject; import org.apache.qpid.server.model.Broker; @@ -50,6 +51,7 @@ import org.apache.qpid.server.security.access.Operation; import org.apache.qpid.server.security.auth.UsernamePrincipal; import org.apache.qpid.server.security.group.FileGroupDatabase; import org.apache.qpid.server.security.group.GroupPrincipal; +import org.apache.qpid.server.util.FileHelper; public class FileBasedGroupProviderImpl extends AbstractConfiguredObject<FileBasedGroupProviderImpl> implements FileBasedGroupProvider<FileBasedGroupProviderImpl> @@ -162,9 +164,11 @@ public class FileBasedGroupProviderImpl { throw new IllegalConfigurationException(String.format("Cannot create groups file at '%s'",_path)); } + try { - file.createNewFile(); + String posixFileAttributes = getContextValue(String.class, BrokerProperties.POSIX_FILE_PERMISSIONS); + new FileHelper().createNewFile(file, posixFileAttributes); } catch (IOException e) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java index e3ded3006d..7046f2973e 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java @@ -21,14 +21,14 @@ package org.apache.qpid.server.model.adapter; -import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.channels.OverlappingFileLockException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -38,6 +38,9 @@ import java.util.Set; import java.util.TreeMap; import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.BrokerProperties; +import org.apache.qpid.server.util.BaseAction; +import org.apache.qpid.server.util.FileHelper; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.ObjectMapper; @@ -118,7 +121,7 @@ public class FileSystemPreferencesProviderImpl FileSystemPreferencesStore store = new FileSystemPreferencesStore(new File(_path)); // we need to check and create file if it does not exist every time on open - store.createIfNotExist(); + store.createIfNotExist(getContextValue(String.class, BrokerProperties.POSIX_FILE_PERMISSIONS)); store.open(); _store = store; _open = true; @@ -184,6 +187,7 @@ public class FileSystemPreferencesProviderImpl if(_store != null) { + _store.close(); _store.delete(); deleted(); _authenticationProvider.setPreferencesProvider(null); @@ -280,7 +284,7 @@ public class FileSystemPreferencesProviderImpl else { FileSystemPreferencesStore store = new FileSystemPreferencesStore(new File(_path)); - store.createIfNotExist(); + store.createIfNotExist(getContextValue(String.class, BrokerProperties.POSIX_FILE_PERMISSIONS)); store.open(); _store = store; } @@ -334,9 +338,9 @@ public class FileSystemPreferencesProviderImpl { private final ObjectMapper _objectMapper; private final Map<String, Map<String, Object>> _preferences; + private final FileHelper _fileHelper; private File _storeFile; private FileLock _storeLock; - private RandomAccessFile _storeRAF; public FileSystemPreferencesStore(File preferencesFile) { @@ -345,9 +349,10 @@ public class FileSystemPreferencesProviderImpl _objectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); _objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); _preferences = new TreeMap<String, Map<String, Object>>(); + _fileHelper = new FileHelper(); } - public void createIfNotExist() + public void createIfNotExist(String filePermissions) { if (!_storeFile.exists()) { @@ -358,7 +363,8 @@ public class FileSystemPreferencesProviderImpl } try { - if (_storeFile.createNewFile() && !_storeFile.exists()) + Path path = _fileHelper.createNewFile(_storeFile, filePermissions); + if (!Files.exists(path)) { throw new IllegalConfigurationException(String.format("Cannot create preferences store file at '%s'", _storeFile.getAbsolutePath())); } @@ -391,43 +397,20 @@ public class FileSystemPreferencesProviderImpl } try { - _storeRAF = new RandomAccessFile(_storeFile, "rw"); - FileChannel fileChannel = _storeRAF.getChannel(); - try - { - _storeLock = fileChannel.tryLock(); - } - catch (OverlappingFileLockException e) - { - _storeLock = null; - } - if (_storeLock == null) + getFileLock(_storeFile.getPath() + ".lck"); + if (_storeFile.length() > 0) { - throw new IllegalConfigurationException("Cannot get lock on store file " + _storeFile.getName() - + " is another instance running?"); - } - long fileSize = fileChannel.size(); - if (fileSize > 0) - { - ByteBuffer buffer = ByteBuffer.allocate((int) fileSize); - fileChannel.read(buffer); - buffer.rewind(); - buffer.flip(); - byte[] data = buffer.array(); - try - { - Map<String, Map<String, Object>> preferencesMap = _objectMapper.readValue(data, - new TypeReference<Map<String, Map<String, Object>>>() - { - }); - _preferences.putAll(preferencesMap); - } - catch (JsonProcessingException e) - { - throw new IllegalConfigurationException("Cannot parse preferences json in " + _storeFile.getName(), e); - } + Map<String, Map<String, Object>> preferencesMap = _objectMapper.readValue(_storeFile, + new TypeReference<Map<String, Map<String, Object>>>() + { + }); + _preferences.putAll(preferencesMap); } } + catch (JsonProcessingException e) + { + throw new IllegalConfigurationException("Cannot parse preferences json in " + _storeFile.getName(), e); + } catch (IOException e) { throw new IllegalConfigurationException("Cannot load preferences from " + _storeFile.getName(), e); @@ -443,6 +426,7 @@ public class FileSystemPreferencesProviderImpl if (_storeLock != null) { _storeLock.release(); + _storeLock.channel().close(); } } catch (IOException e) @@ -452,22 +436,7 @@ public class FileSystemPreferencesProviderImpl finally { _storeLock = null; - try - { - if (_storeRAF != null) - { - _storeRAF.close(); - } - } - catch (IOException e) - { - LOGGER.error("Cannot close preferences file", e); - } - finally - { - _storeRAF = null; - _preferences.clear(); - } + _preferences.clear(); } } } @@ -544,16 +513,14 @@ public class FileSystemPreferencesProviderImpl checkStoreOpened(); try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - _objectMapper.writeValue(baos, _preferences); - FileChannel channel = _storeRAF.getChannel(); - long currentSize = channel.size(); - channel.position(0); - channel.write(ByteBuffer.wrap(baos.toByteArray())); - if (currentSize > baos.size()) + _fileHelper.writeFileSafely(_storeFile.toPath(), new BaseAction<File, IOException>() { - channel.truncate(baos.size()); - } + @Override + public void performAction(File file) throws IOException + { + _objectMapper.writeValue(file, _preferences); + } + }); } catch (IOException e) { @@ -569,5 +536,32 @@ public class FileSystemPreferencesProviderImpl } } + private void getFileLock(String lockFilePath) + { + File lockFile = new File(lockFilePath); + try + { + lockFile.createNewFile(); + lockFile.deleteOnExit(); + + @SuppressWarnings("resource") + FileOutputStream out = new FileOutputStream(lockFile); + FileChannel channel = out.getChannel(); + _storeLock = channel.tryLock(); + } + catch (IOException ioe) + { + throw new IllegalStateException("Cannot create the lock file " + lockFile.getName(), ioe); + } + catch(OverlappingFileLockException e) + { + _storeLock = null; + } + + if(_storeLock == null) + { + throw new IllegalStateException("Cannot get lock on file " + lockFile.getAbsolutePath() + ". Is another instance running?"); + } + } } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/ConnectionValidator.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/ConnectionValidator.java new file mode 100644 index 0000000000..11f8944863 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/ConnectionValidator.java @@ -0,0 +1,28 @@ +/* + * + * 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.server.plugin; + +import org.apache.qpid.server.protocol.AMQConnectionModel; + +public interface ConnectionValidator extends Pluggable +{ + boolean validateConnectionCreation(AMQConnectionModel<?, ?> connection); +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/MessageFilterFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/MessageFilterFactory.java new file mode 100644 index 0000000000..372642310e --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/MessageFilterFactory.java @@ -0,0 +1,30 @@ +/* + * + * 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.server.plugin; + +import java.util.List; + +import org.apache.qpid.server.filter.MessageFilter; + +public interface MessageFilterFactory extends Pluggable +{ + MessageFilter newInstance(List<String> arguments); +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/QpidServiceLoader.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/QpidServiceLoader.java index f70afb12ba..e6100efda7 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/QpidServiceLoader.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/QpidServiceLoader.java @@ -19,8 +19,11 @@ package org.apache.qpid.server.plugin; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.ServiceLoader; import org.apache.log4j.Logger; @@ -47,6 +50,16 @@ public class QpidServiceLoader return instancesOf(clazz, true); } + public <C extends Pluggable> Map<String,C> getInstancesByType(Class<C> clazz) + { + Map<String,C> instances = new HashMap<>(); + for(C instance : instancesOf(clazz)) + { + instances.put(instance.getType(), instance); + } + return Collections.unmodifiableMap(instances); + } + private <C extends Pluggable> Iterable<C> instancesOf(Class<C> clazz, boolean atLeastOne) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java index 60999fb2be..639d569e8f 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java @@ -30,7 +30,9 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; @@ -52,6 +54,7 @@ import org.apache.qpid.server.consumer.ConsumerTarget; import org.apache.qpid.server.exchange.ExchangeImpl; import org.apache.qpid.server.virtualhost.VirtualHostUnavailableException; import org.apache.qpid.server.filter.FilterManager; +import org.apache.qpid.server.filter.MessageFilter; import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.LogMessage; import org.apache.qpid.server.logging.LogSubject; @@ -75,6 +78,8 @@ import org.apache.qpid.server.model.Queue; import org.apache.qpid.server.model.QueueNotificationListener; import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.StateTransition; +import org.apache.qpid.server.plugin.MessageFilterFactory; +import org.apache.qpid.server.plugin.QpidServiceLoader; import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.security.SecurityManager; @@ -186,6 +191,9 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> @ManagedAttributeField private MessageDurability _messageDurability; + @ManagedAttributeField + private Map<String, Map<String,List<String>>> _defaultFilters; + private Object _exclusiveOwner; // could be connection, session, Principal or a String for the container name private final Set<NotificationCheck> _notificationChecks = @@ -241,12 +249,15 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> private long _minimumMessageTtl; @ManagedAttributeField private long _maximumMessageTtl; + @ManagedAttributeField + private boolean _ensureNondestructiveConsumers; private final AtomicBoolean _recovering = new AtomicBoolean(true); private final ConcurrentLinkedQueue<EnqueueRequest> _postRecoveryQueue = new ConcurrentLinkedQueue<>(); private final QueueRunner _queueRunner = new QueueRunner(this); private boolean _closing; + private final ConcurrentMap<String,MessageFilter> _defaultFiltersMap = new ConcurrentHashMap<>(); protected AbstractQueue(Map<String, Object> attributes, VirtualHostImpl virtualHost) { @@ -283,11 +294,7 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> }); } - if (isDurable()) - { - _virtualHost.getDurableConfigurationStore().create(asObjectRecord()); - } - else if(getMessageDurability() != MessageDurability.NEVER) + if(!isDurable() && getMessageDurability() != MessageDurability.NEVER) { Subject.doAs(SecurityManager.getSubjectWithAddedSystemRights(), new PrivilegedAction<Object>() @@ -351,17 +358,9 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> case PRINCIPAL: _exclusiveOwner = sessionModel.getConnectionModel().getAuthorizedPrincipal(); - if(isDurable()) - { - _virtualHost.getDurableConfigurationStore().update(false,asObjectRecord()); - } break; case CONTAINER: _exclusiveOwner = sessionModel.getConnectionModel().getRemoteContainerName(); - if(isDurable()) - { - _virtualHost.getDurableConfigurationStore().update(false,asObjectRecord()); - } break; case CONNECTION: _exclusiveOwner = sessionModel.getConnectionModel(); @@ -450,6 +449,40 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> } _maxAsyncDeliveries = getContextValue(Integer.class, Queue.MAX_ASYNCHRONOUS_DELIVERIES); + + if(_defaultFilters != null) + { + QpidServiceLoader qpidServiceLoader = new QpidServiceLoader(); + final Map<String, MessageFilterFactory> messageFilterFactories = + qpidServiceLoader.getInstancesByType(MessageFilterFactory.class); + + for (Map.Entry<String,Map<String,List<String>>> entry : _defaultFilters.entrySet()) + { + String name = String.valueOf(entry.getKey()); + Map<String, List<String>> filterValue = entry.getValue(); + if(filterValue.size() == 1) + { + String filterTypeName = String.valueOf(filterValue.keySet().iterator().next()); + MessageFilterFactory filterFactory = messageFilterFactories.get(filterTypeName); + if(filterFactory != null) + { + List<String> filterArguments = filterValue.values().iterator().next(); + _defaultFiltersMap.put(name, filterFactory.newInstance(filterArguments)); + } + else + { + throw new IllegalArgumentException("Unknown filter type " + filterTypeName + ", known types are: " + messageFilterFactories.keySet()); + } + } + else + { + throw new IllegalArgumentException("Filter value should be a map with one entry, having the type as key and the value being the filter arguments, not " + filterValue); + + } + + } + } + updateAlertChecks(); } @@ -555,6 +588,12 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> } @Override + public Map<String, Map<String, List<String>>> getDefaultFilters() + { + return _defaultFilters; + } + + @Override public final MessageDurability getMessageDurability() { return _messageDurability; @@ -573,6 +612,14 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> } @Override + public boolean isEnsureNondestructiveConsumers() + { + return _ensureNondestructiveConsumers; + } + + + + @Override public Collection<String> getAvailableAttributes() { return new ArrayList<String>(_arguments.keySet()); @@ -603,7 +650,7 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> @Override public synchronized QueueConsumerImpl addConsumer(final ConsumerTarget target, - final FilterManager filters, + FilterManager filters, final Class<? extends ServerMessage> messageClass, final String consumerName, EnumSet<ConsumerImpl.Option> optionSet) @@ -699,6 +746,26 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> { throw new ExistingConsumerPreventsExclusive(); } + if(!_defaultFiltersMap.isEmpty()) + { + if(filters == null) + { + filters = new FilterManager(); + } + for (Map.Entry<String,MessageFilter> filter : _defaultFiltersMap.entrySet()) + { + if(!filters.hasFilter(filter.getKey())) + { + filters.add(filter.getKey(), filter.getValue()); + } + } + } + + if(_ensureNondestructiveConsumers) + { + optionSet = EnumSet.copyOf(optionSet); + optionSet.removeAll(EnumSet.of(ConsumerImpl.Option.SEES_REQUEUES, ConsumerImpl.Option.ACQUIRES)); + } QueueConsumerImpl consumer = new QueueConsumerImpl(this, target, diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueArgumentsConverter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueArgumentsConverter.java index 49732e8345..367a12057d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueArgumentsConverter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueArgumentsConverter.java @@ -62,11 +62,16 @@ public class QueueArgumentsConverter public static final String QPID_LAST_VALUE_QUEUE = "qpid.last_value_queue"; + public static final String QPID_DEFAULT_FILTERS = "qpid.default_filters"; + + public static final String QPID_ENSURE_NONDESTRUCTIVE_CONSUMERS = "qpid.ensure_nondestructive_consumers"; /** * No-local queue argument is used to support the no-local feature of Durable Subscribers. */ public static final String QPID_NO_LOCAL = "no-local"; + static final Map<String, String> ATTRIBUTE_MAPPINGS = new LinkedHashMap<String, String>(); + static { ATTRIBUTE_MAPPINGS.put(X_QPID_MINIMUM_ALERT_REPEAT_GAP, Queue.ALERT_REPEAT_GAP); @@ -99,6 +104,8 @@ public class QueueArgumentsConverter ATTRIBUTE_MAPPINGS.put(QPID_NO_LOCAL, Queue.NO_LOCAL); ATTRIBUTE_MAPPINGS.put(QPID_MESSAGE_DURABILITY, Queue.MESSAGE_DURABILITY); + ATTRIBUTE_MAPPINGS.put(QPID_DEFAULT_FILTERS, Queue.DEFAULT_FILTERS); + ATTRIBUTE_MAPPINGS.put(QPID_ENSURE_NONDESTRUCTIVE_CONSUMERS, Queue.ENSURE_NONDESTRUCTIVE_CONSUMERS); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index 452c5ff14f..917c951b6d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -371,11 +371,16 @@ public abstract class QueueEntryImpl implements QueueEntry } } - private void dequeue() + private boolean dequeue() { EntryState state = _state; - if((state.getState() == State.ACQUIRED) &&_stateUpdater.compareAndSet(this, state, DEQUEUED_STATE)) + while(state.getState() == State.ACQUIRED && !_stateUpdater.compareAndSet(this, state, DEQUEUED_STATE)) + { + state = _state; + } + + if(state.getState() == State.ACQUIRED) { if (state instanceof ConsumerAcquiredState || state instanceof LockedAcquiredState) { @@ -387,7 +392,11 @@ public abstract class QueueEntryImpl implements QueueEntry { notifyStateChange(state.getState() , QueueEntry.State.DEQUEUED); } - + return true; + } + else + { + return false; } } @@ -420,9 +429,10 @@ public abstract class QueueEntryImpl implements QueueEntry public void delete() { - dequeue(); - - dispose(); + if(dequeue()) + { + dispose(); + } } public int routeToAlternate(final Action<? super MessageInstance> action, ServerTransaction txn) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java index 0607f4b3d3..8b6a83d443 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java @@ -62,7 +62,7 @@ public interface FileKeyStore<X extends FileKeyStore<X>> extends KeyStore<X> @ManagedAttribute(defaultValue = "${this:path}") String getDescription(); - @ManagedAttribute( mandatory = true, secure = true, oversize = true, oversizedAltText = OVER_SIZED_ATTRIBUTE_ALTERNATIVE_TEXT) + @ManagedAttribute( mandatory = true, secure = true, oversize = true, oversizedAltText = OVER_SIZED_ATTRIBUTE_ALTERNATIVE_TEXT, secureValueFilter = "^data\\:.*") String getStoreUrl(); @DerivedAttribute diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStore.java index 78509182b5..f239b83f27 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStore.java @@ -31,7 +31,7 @@ public interface NonJavaKeyStore<X extends NonJavaKeyStore<X>> extends KeyStore< @ManagedAttribute(defaultValue = "${this:subjectName}") String getDescription(); - @ManagedAttribute( mandatory = true, secure = true, oversize = true, oversizedAltText = OVER_SIZED_ATTRIBUTE_ALTERNATIVE_TEXT ) + @ManagedAttribute( mandatory = true, secure = true, oversize = true, oversizedAltText = OVER_SIZED_ATTRIBUTE_ALTERNATIVE_TEXT, secureValueFilter = "^data\\:.*") String getPrivateKeyUrl(); @ManagedAttribute( mandatory = true, oversize = true, oversizedAltText = OVER_SIZED_ATTRIBUTE_ALTERNATIVE_TEXT ) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java index cb5bc54cd2..2c692ddf4d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java @@ -22,6 +22,8 @@ package org.apache.qpid.server.security.auth.database; import org.apache.log4j.Logger; import org.apache.qpid.server.security.auth.UsernamePrincipal; +import org.apache.qpid.server.util.BaseAction; +import org.apache.qpid.server.util.FileHelper; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; @@ -36,7 +38,6 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Random; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; @@ -45,9 +46,9 @@ public abstract class AbstractPasswordFilePrincipalDatabase<U extends PasswordPr protected static final String DEFAULT_ENCODING = "utf-8"; private final Pattern _regexp = Pattern.compile(":"); - private final Map<String, U> _userMap = new HashMap<String, U>(); + private final Map<String, U> _userMap = new HashMap<>(); private final ReentrantLock _userUpdate = new ReentrantLock(); - private final Random _random = new Random(); + private final FileHelper _fileHelper = new FileHelper(); private File _passwordFile; public final void open(File passwordFile) throws IOException @@ -181,7 +182,7 @@ public abstract class AbstractPasswordFilePrincipalDatabase<U extends PasswordPr try { _userUpdate.lock(); - final Map<String, U> newUserMap = new HashMap<String, U>(); + final Map<String, U> newUserMap = new HashMap<>(); BufferedReader reader = null; try @@ -224,71 +225,33 @@ public abstract class AbstractPasswordFilePrincipalDatabase<U extends PasswordPr protected abstract Logger getLogger(); - protected File createTempFileOnSameFilesystem() - { - File liveFile = _passwordFile; - File tmp; - - do - { - tmp = new File(liveFile.getPath() + _random.nextInt() + ".tmp"); - } - while(tmp.exists()); - tmp.deleteOnExit(); - return tmp; - } - - protected void swapTempFileToLive(final File temp) throws IOException + protected void savePasswordFile() throws IOException { - File live = _passwordFile; - // Remove any existing ".old" file - final File old = new File(live.getAbsoluteFile() + ".old"); - if (old.exists()) + try { - old.delete(); - } + _userUpdate.lock(); - // Create an new ".old" file - if(!live.renameTo(old)) - { - //unable to rename the existing file to the backup name - getLogger().error("Could not backup the existing password file"); - throw new IOException("Could not backup the existing password file"); + _fileHelper.writeFileSafely(_passwordFile.toPath(), new BaseAction<File,IOException>() + { + @Override + public void performAction(File file) throws IOException + { + writeToFile(file); + } + }); } - - // Move temp file to be the new "live" file - if(!temp.renameTo(live)) + finally { - //failed to rename the new file to the required filename - if(!old.renameTo(live)) - { - //unable to return the backup to required filename - getLogger().error( - "Could not rename the new password file into place, and unable to restore original file"); - throw new IOException("Could not rename the new password file into place, and unable to restore original file"); - } - - getLogger().error("Could not rename the new password file into place"); - throw new IOException("Could not rename the new password file into place"); + _userUpdate.unlock(); } } - protected void savePasswordFile() throws IOException + private void writeToFile(File tmp) throws IOException { - try - { - _userUpdate.lock(); - - BufferedReader reader = null; - PrintStream writer = null; - - File tmp = createTempFileOnSameFilesystem(); - - try + try(PrintStream writer = new PrintStream(tmp); + BufferedReader reader = new BufferedReader(new FileReader(_passwordFile))) { - writer = new PrintStream(tmp); - reader = new BufferedReader(new FileReader(_passwordFile)); String line; while ((line = reader.readLine()) != null) @@ -346,32 +309,6 @@ public abstract class AbstractPasswordFilePrincipalDatabase<U extends PasswordPr getLogger().error("Unable to create the new password file: " + e); throw new IOException("Unable to create the new password file",e); } - finally - { - - try - { - if (reader != null) - { - reader.close(); - } - } - finally - { - if (writer != null) - { - writer.close(); - } - } - - } - - swapTempFileToLive(tmp); - } - finally - { - _userUpdate.unlock(); - } } protected abstract U createUserFromPassword(Principal principal, char[] passwd); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/Base64MD5PasswordDatabaseAuthenticationManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/Base64MD5PasswordDatabaseAuthenticationManager.java index 6fe649ff04..0b5e17306c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/Base64MD5PasswordDatabaseAuthenticationManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/Base64MD5PasswordDatabaseAuthenticationManager.java @@ -28,7 +28,7 @@ import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -@ManagedObject( category = false, type = "Base64MD5PasswordFile" ) +@ManagedObject( category = false, managesChildren = true, type = "Base64MD5PasswordFile" ) public class Base64MD5PasswordDatabaseAuthenticationManager extends PrincipalDatabaseAuthenticationManager<Base64MD5PasswordDatabaseAuthenticationManager> { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainPasswordDatabaseAuthenticationManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainPasswordDatabaseAuthenticationManager.java index e6d2fcf44c..b86bfac0ad 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainPasswordDatabaseAuthenticationManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainPasswordDatabaseAuthenticationManager.java @@ -28,7 +28,7 @@ import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -@ManagedObject( category = false, type = "PlainPasswordFile" ) +@ManagedObject( category = false, managesChildren = true, type = "PlainPasswordFile" ) public class PlainPasswordDatabaseAuthenticationManager extends PrincipalDatabaseAuthenticationManager<PlainPasswordDatabaseAuthenticationManager> { public static final String PROVIDER_TYPE = "PlainPasswordFile"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index d3c9635502..cf165ff4af 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -23,6 +23,8 @@ package org.apache.qpid.server.security.auth.manager; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.security.AccessControlException; import java.security.Principal; import java.util.Collection; @@ -40,6 +42,7 @@ import javax.security.sasl.SaslServer; import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.BrokerProperties; import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.model.AbstractConfiguredObject; import org.apache.qpid.server.model.Broker; @@ -56,6 +59,7 @@ import org.apache.qpid.server.security.auth.AuthenticationResult; import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; import org.apache.qpid.server.security.auth.UsernamePrincipal; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.util.FileHelper; public abstract class PrincipalDatabaseAuthenticationManager<T extends PrincipalDatabaseAuthenticationManager<T>> extends AbstractAuthenticationManager<T> @@ -96,7 +100,11 @@ public abstract class PrincipalDatabaseAuthenticationManager<T extends Principal { try { - passwordFile.createNewFile(); + Path path = new FileHelper().createNewFile(passwordFile, getContextValue(String.class, BrokerProperties.POSIX_FILE_PERMISSIONS)); + if (!Files.exists(path)) + { + throw new IllegalConfigurationException(String.format("Cannot create password file at '%s'", _path)); + } } catch (IOException e) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/group/FileGroupDatabase.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/group/FileGroupDatabase.java index 0a02ce38fc..1e9e646e35 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/group/FileGroupDatabase.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/group/FileGroupDatabase.java @@ -34,6 +34,8 @@ import java.util.concurrent.ConcurrentSkipListSet; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.apache.qpid.server.util.BaseAction; +import org.apache.qpid.server.util.FileHelper; import org.apache.qpid.server.util.ServerScopedRuntimeException; /** @@ -232,9 +234,9 @@ public class FileGroupDatabase implements GroupDatabase } } - private synchronized void writeGroupFile(String groupFile) throws IOException + private synchronized void writeGroupFile(final String groupFile) throws IOException { - Properties propertiesFile = new Properties(); + final Properties propertiesFile = new Properties(); for (String group : _groupToUserMap.keySet()) { @@ -244,19 +246,19 @@ public class FileGroupDatabase implements GroupDatabase propertiesFile.setProperty(group + ".users", userList); } - String comment = "Written " + new Date(); - FileOutputStream fileOutputStream = new FileOutputStream(groupFile); - try - { - propertiesFile.store(fileOutputStream, comment); - } - finally + + new FileHelper().writeFileSafely(new File(groupFile).toPath(), new BaseAction<File, IOException>() { - if(fileOutputStream != null) + @Override + public void performAction(File file) throws IOException { - fileOutputStream.close(); + String comment = "Written " + new Date(); + try(FileOutputStream fileOutputStream = new FileOutputStream(file)) + { + propertiesFile.store(fileOutputStream, comment); + } } - } + }); } private void validatePropertyNameIsGroupName(String propertyName) diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/JsonFileConfigStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/JsonFileConfigStore.java index 0de6543713..ad671d7e99 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/JsonFileConfigStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/JsonFileConfigStore.java @@ -27,6 +27,8 @@ import java.io.IOException; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.channels.OverlappingFileLockException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -40,6 +42,9 @@ import java.util.Map; import java.util.UUID; import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.BrokerProperties; +import org.apache.qpid.server.util.BaseAction; +import org.apache.qpid.server.util.FileHelper; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.Version; @@ -85,6 +90,7 @@ public class JsonFileConfigStore implements DurableConfigurationStore private final Map<String, List<UUID>> _idsByType = new HashMap<String, List<UUID>>(); private final ObjectMapper _objectMapper = new ObjectMapper(); private final Class<? extends ConfiguredObject> _rootClass; + private final FileHelper _fileHelper; private Map<String,Class<? extends ConfiguredObject>> _classNameMapping; private String _directoryName; @@ -123,6 +129,7 @@ public class JsonFileConfigStore implements DurableConfigurationStore _objectMapper.registerModule(_module); _objectMapper.enable(SerializationConfig.Feature.INDENT_OUTPUT); _rootClass = rootClass; + _fileHelper = new FileHelper(); } @Override @@ -173,7 +180,7 @@ public class JsonFileConfigStore implements DurableConfigurationStore _directoryName = fileFromSettings.getParent(); _configFileName = fileFromSettings.getName(); _backupFileName = fileFromSettings.getName() + ".bak"; - _tempFileName = fileFromSettings.getName() + ".tmp";; + _tempFileName = fileFromSettings.getName() + ".tmp"; _lockFileName = fileFromSettings.getName() + ".lck"; } @@ -191,56 +198,45 @@ public class JsonFileConfigStore implements DurableConfigurationStore checkDirectoryIsWritable(_directoryName); getFileLock(); - if(!fileExists(_configFileName)) + Path storeFile = new File(_directoryName, _configFileName).toPath(); + Path backupFile = new File(_directoryName, _backupFileName).toPath(); + if(!Files.exists(storeFile)) { - if(!fileExists(_backupFileName)) + if(!Files.exists(backupFile)) { - File newFile = new File(_directoryName, _configFileName); try { - _objectMapper.writeValue(newFile, Collections.emptyMap()); + String posixFileAttributes = _parent.getContextValue(String.class, BrokerProperties.POSIX_FILE_PERMISSIONS); + storeFile = _fileHelper.createNewFile(storeFile, posixFileAttributes); + _objectMapper.writeValue(storeFile.toFile(), Collections.emptyMap()); } catch (IOException e) { - throw new StoreException("Could not write configuration file " + newFile, e); + throw new StoreException("Could not write configuration file " + storeFile, e); } } else { - renameFile(_backupFileName, _configFileName); + try + { + _fileHelper.atomicFileMoveOrReplace(backupFile, storeFile); + } + catch (IOException e) + { + throw new StoreException("Could not move backup to configuration file " + storeFile, e); + } } } - deleteFileIfExists(_backupFileName); - } - - private void renameFile(String fromFileName, String toFileName) - { - File toFile = deleteFileIfExists(toFileName); - File fromFile = new File(_directoryName, fromFileName); - if(!fromFile.renameTo(toFile)) + try { - throw new StoreException("Cannot rename file " + fromFile.getAbsolutePath() + " to " + toFile.getAbsolutePath()); + Files.deleteIfExists(backupFile); } - } - - private File deleteFileIfExists(final String toFileName) - { - File toFile = new File(_directoryName, toFileName); - if(toFile.exists()) + catch (IOException e) { - if(!toFile.delete()) - { - throw new StoreException("Cannot delete file " + toFile.getAbsolutePath()); - } + throw new StoreException("Could not delete backup file " + backupFile, e); } - return toFile; - } - private boolean fileExists(String fileName) - { - File file = new File(_directoryName, fileName); - return file.exists(); } private void getFileLock() @@ -396,7 +392,7 @@ public class JsonFileConfigStore implements DurableConfigurationStore private void save() { UUID rootId = getRootId(); - Map<String, Object> data = null; + final Map<String, Object> data; if (rootId == null) { @@ -409,15 +405,18 @@ public class JsonFileConfigStore implements DurableConfigurationStore try { - deleteFileIfExists(_tempFileName); - deleteFileIfExists(_backupFileName); - - File tmpFile = new File(_directoryName, _tempFileName); - _objectMapper.writeValue(tmpFile, data); - renameFile(_configFileName, _backupFileName); - renameFile(tmpFile.getName(),_configFileName); - tmpFile.delete(); - deleteFileIfExists(_backupFileName); + Path tmpFile = new File(_directoryName, _tempFileName).toPath(); + _fileHelper.writeFileSafely( new File(_directoryName, _configFileName).toPath(), + new File(_directoryName, _backupFileName).toPath(), + tmpFile, + new BaseAction<File, IOException>() + { + @Override + public void performAction(File file) throws IOException + { + _objectMapper.writeValue(file, data); + } + }); } catch (IOException e) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/VirtualHostStoreUpgraderAndRecoverer.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/VirtualHostStoreUpgraderAndRecoverer.java index 10d8a5d61c..c59fd821c3 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/VirtualHostStoreUpgraderAndRecoverer.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/VirtualHostStoreUpgraderAndRecoverer.java @@ -20,8 +20,10 @@ */ package org.apache.qpid.server.store; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; @@ -30,14 +32,19 @@ import java.util.UUID; import org.apache.qpid.server.configuration.BrokerProperties; import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.configuration.store.StoreConfigurationChangeListener; import org.apache.qpid.server.filter.FilterSupport; import org.apache.qpid.server.model.Binding; +import org.apache.qpid.server.model.ConfigurationChangeListener; +import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.Exchange; import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.UUIDGenerator; import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.model.VirtualHostNode; import org.apache.qpid.server.queue.QueueArgumentsConverter; +import org.apache.qpid.server.util.Action; public class VirtualHostStoreUpgraderAndRecoverer { @@ -509,12 +516,100 @@ public class VirtualHostStoreUpgraderAndRecoverer } - public void perform(DurableConfigurationStore durableConfigurationStore) + public void perform(final DurableConfigurationStore durableConfigurationStore) { String virtualHostCategory = VirtualHost.class.getSimpleName(); GenericStoreUpgrader upgraderHandler = new GenericStoreUpgrader(virtualHostCategory, VirtualHost.MODEL_VERSION, durableConfigurationStore, _upgraders); upgraderHandler.upgrade(); new GenericRecoverer(_virtualHostNode).recover(upgraderHandler.getRecords()); + + final StoreConfigurationChangeListener configChangeListener = new StoreConfigurationChangeListener(durableConfigurationStore); + if(_virtualHostNode.getVirtualHost() != null) + { + applyRecursively(_virtualHostNode.getVirtualHost(), new Action<ConfiguredObject<?>>() + { + @Override + public void performAction(final ConfiguredObject<?> object) + { + object.addChangeListener(configChangeListener); + } + }); + } + _virtualHostNode.addChangeListener(new ConfigurationChangeListener() + { + @Override + public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState) + { + + } + + @Override + public void childAdded(final ConfiguredObject<?> object, final ConfiguredObject<?> child) + { + if(child instanceof VirtualHost) + { + applyRecursively(child, new Action<ConfiguredObject<?>>() + { + @Override + public void performAction(final ConfiguredObject<?> object) + { + if(object.isDurable()) + { + durableConfigurationStore.update(true, object.asObjectRecord()); + object.addChangeListener(configChangeListener); + } + } + }); + + } + } + + @Override + public void childRemoved(final ConfiguredObject<?> object, final ConfiguredObject<?> child) + { + if(child instanceof VirtualHost) + { + child.removeChangeListener(configChangeListener); + } + } + + @Override + public void attributeSet(final ConfiguredObject<?> object, + final String attributeName, + final Object oldAttributeValue, + final Object newAttributeValue) + { + + } + }); + } + + private void applyRecursively(final ConfiguredObject<?> object, final Action<ConfiguredObject<?>> action) + { + applyRecursively(object, action, new HashSet<ConfiguredObject<?>>()); + } + + private void applyRecursively(final ConfiguredObject<?> object, + final Action<ConfiguredObject<?>> action, + final HashSet<ConfiguredObject<?>> visited) + { + if(!visited.contains(object)) + { + visited.add(object); + action.performAction(object); + for(Class<? extends ConfiguredObject> childClass : object.getModel().getChildTypes(object.getCategoryClass())) + { + Collection<? extends ConfiguredObject> children = object.getChildren(childClass); + if(children != null) + { + for(ConfiguredObject<?> child : children) + { + applyRecursively(child, action, visited); + } + } + } + } } + } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/transport/SelectorThread.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/transport/SelectorThread.java index 8d35e1a94f..d2351b5500 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/transport/SelectorThread.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/transport/SelectorThread.java @@ -36,8 +36,13 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import org.slf4j.LoggerFactory; + + public class SelectorThread extends Thread { + private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(SelectorThread.class); + public static final String IO_THREAD_NAME_PREFIX = "NCS-"; private final Queue<Runnable> _tasks = new ConcurrentLinkedQueue<>(); private final Queue<NonBlockingConnection> _unregisteredConnections = new ConcurrentLinkedQueue<>(); @@ -165,7 +170,8 @@ public class SelectorThread extends Thread NonBlockingConnection connection = iterator.next(); int period = connection.getTicker().getTimeToNextTick(currentTime); - if (period < 0 || connection.isStateChanged()) + + if (period <= 0 || connection.isStateChanged()) { toBeScheduled.add(connection); connection.getSocketChannel().register(_selector, 0).cancel(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/Action.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/Action.java index 0d53b4d03b..715709a1b2 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/Action.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/Action.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.server.util; -public interface Action<T> +public interface Action<T> extends BaseAction<T, RuntimeException> { void performAction(T object); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/BaseAction.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/BaseAction.java new file mode 100644 index 0000000000..f7dbcb4d3c --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/BaseAction.java @@ -0,0 +1,26 @@ +/* + * + * 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.server.util; + +public interface BaseAction<T, E extends Exception> +{ + void performAction(T object) throws E; +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/FileHelper.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/FileHelper.java new file mode 100644 index 0000000000..0e1a28f220 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/FileHelper.java @@ -0,0 +1,133 @@ +/* + * + * 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.server.util; + +import java.io.File; +import java.io.IOException; +import java.nio.file.AtomicMoveNotSupportedException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.PosixFileAttributeView; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.Set; + +public class FileHelper +{ + + public void writeFileSafely(Path targetFile, BaseAction<File, IOException> operation) throws IOException + { + String name = targetFile.toFile().getName(); + writeFileSafely(targetFile, + targetFile.resolveSibling(name + ".bak"), + targetFile.resolveSibling(name + ".tmp"), + operation); + } + + public void writeFileSafely(Path targetFile, Path backupFile, Path tmpFile, BaseAction<File, IOException> write) throws IOException + { + Files.deleteIfExists(tmpFile); + Files.deleteIfExists(backupFile); + + Set<PosixFilePermission> permissions = null; + if (Files.exists(targetFile) && isPosixFileSystem(targetFile)) + { + permissions = Files.getPosixFilePermissions(targetFile); + } + + tmpFile = createNewFile(tmpFile, permissions); + + write.performAction(tmpFile.toFile()); + + atomicFileMoveOrReplace(targetFile, backupFile); + + if (permissions != null) + { + Files.setPosixFilePermissions(backupFile, permissions); + } + + atomicFileMoveOrReplace(tmpFile, targetFile); + + Files.deleteIfExists(tmpFile); + Files.deleteIfExists(backupFile); + } + + public Path createNewFile(File newFile, String posixFileAttributes) throws IOException + { + return createNewFile(newFile.toPath(), posixFileAttributes); + } + + public Path createNewFile(Path newFile, String posixFileAttributes) throws IOException + { + Set<PosixFilePermission> permissions = posixFileAttributes == null ? null : PosixFilePermissions.fromString(posixFileAttributes); + return createNewFile(newFile, permissions ); + } + + public Path createNewFile(Path newFile, Set<PosixFilePermission> permissions) throws IOException + { + if (!Files.exists(newFile)) + { + newFile = Files.createFile(newFile); + } + + if (permissions != null && isPosixFileSystem(newFile)) + { + Files.setPosixFilePermissions(newFile, permissions); + } + + return newFile; + } + + public boolean isPosixFileSystem(Path path) throws IOException + { + while (!Files.exists(path)) + { + path = path.getParent(); + + if (path == null) + { + return false; + } + } + return Files.getFileStore(path).supportsFileAttributeView(PosixFileAttributeView.class); + } + + public Path atomicFileMoveOrReplace(Path sourceFile, Path targetFile) throws IOException + { + try + { + return Files.move(sourceFile, targetFile, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING); + } + catch(AtomicMoveNotSupportedException e) + { + if (sourceFile.toFile().renameTo(targetFile.toFile())) + { + return targetFile; + } + else + { + throw new RuntimeException("Atomic move is unsupported and rename from : '" + + sourceFile + "' to: '" + targetFile + "' failed."); + } + } + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java index dce902b126..06917f0161 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java @@ -63,6 +63,8 @@ import org.apache.qpid.server.message.MessageSource; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.model.*; import org.apache.qpid.server.model.adapter.ConnectionAdapter; +import org.apache.qpid.server.model.port.AmqpPort; +import org.apache.qpid.server.plugin.ConnectionValidator; import org.apache.qpid.server.plugin.QpidServiceLoader; import org.apache.qpid.server.plugin.SystemNodeCreator; import org.apache.qpid.server.protocol.AMQConnectionModel; @@ -75,7 +77,6 @@ import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.access.Operation; import org.apache.qpid.server.stats.StatisticsCounter; import org.apache.qpid.server.store.ConfiguredObjectRecord; -import org.apache.qpid.server.store.ConfiguredObjectRecordImpl; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.store.Event; import org.apache.qpid.server.store.EventListener; @@ -94,6 +95,8 @@ import org.apache.qpid.server.util.MapValueConverter; public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> extends AbstractConfiguredObject<X> implements VirtualHostImpl<X, AMQQueue<?>, ExchangeImpl<?>>, IConnectionRegistry.RegistryChangeListener, EventListener { + private final Collection<ConnectionValidator> _connectionValidators = new ArrayList<>(); + private static enum BlockingType { STORE, FILESYSTEM }; private static final String USE_ASYNC_RECOVERY = "use_async_message_store_recovery"; @@ -162,6 +165,14 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte @ManagedAttributeField private int _housekeepingThreadCount; + @ManagedAttributeField + private List<String> _enabledConnectionValidators; + + @ManagedAttributeField + private List<String> _disabledConnectionValidators; + + @ManagedAttributeField + private List<String> _globalAddressDomains; private boolean _useAsyncRecoverer; @@ -212,6 +223,13 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte { throw new IllegalArgumentException(getClass().getSimpleName() + " must be durable"); } + if(getGlobalAddressDomains() != null) + { + for(String domain : getGlobalAddressDomains()) + { + validateGlobalAddressDomain(domain); + } + } } @Override @@ -230,6 +248,26 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte throw new IntegrityViolationException("Cannot delete default virtual host '" + getName() + "'"); } } + if(changedAttributes.contains(GLOBAL_ADDRESS_DOMAINS)) + { + VirtualHost<?, ?, ?> virtualHost = (VirtualHost<?, ?, ?>) proxyForValidation; + if(virtualHost.getGlobalAddressDomains() != null) + { + for(String name : virtualHost.getGlobalAddressDomains()) + { + validateGlobalAddressDomain(name); + } + } + } + } + + private void validateGlobalAddressDomain(final String name) + { + String regex = "/(/?)([\\w_\\-:.\\$]+/)*[\\w_\\-:.\\$]+"; + if(!name.matches(regex)) + { + throw new IllegalArgumentException("'"+name+"' is not a valid global address domain"); + } } @Override @@ -243,8 +281,17 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte { super.validateOnCreate(); validateMessageStoreCreation(); + if(getGlobalAddressDomains() != null) + { + for(String name : getGlobalAddressDomains()) + { + validateGlobalAddressDomain(name); + } + } } + + private void validateMessageStoreCreation() { MessageStore store = createMessageStore(); @@ -293,10 +340,20 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte _messageStore.addEventListener(this, Event.PERSISTENT_MESSAGE_SIZE_OVERFULL); _messageStore.addEventListener(this, Event.PERSISTENT_MESSAGE_SIZE_UNDERFULL); - addChangeListener(new StoreUpdatingChangeListener()); + _fileSystemMaxUsagePercent = getContextValue(Integer.class, Broker.STORE_FILESYSTEM_MAX_USAGE_PERCENT); - _fileSystemMaxUsagePercent = getContextValue(Integer.class, Broker.STORE_FILESYSTEM_MAX_USAGE_PERCENT); + QpidServiceLoader serviceLoader = new QpidServiceLoader(); + for(ConnectionValidator validator : serviceLoader.instancesOf(ConnectionValidator.class)) + { + if((_enabledConnectionValidators.isEmpty() + && (_disabledConnectionValidators.isEmpty()) || !_disabledConnectionValidators.contains(validator.getType())) + || _enabledConnectionValidators.contains(validator.getType())) + { + _connectionValidators.add(validator); + } + + } } private void checkVHostStateIsActive() @@ -438,6 +495,20 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte return _eventLogger; } + @Override + public boolean authoriseCreateConnection(final AMQConnectionModel<?, ?> connection) + { + getSecurityManager().authoriseCreateConnection(connection); + for(ConnectionValidator validator : _connectionValidators) + { + if(!validator.validateConnectionCreation(connection)) + { + return false; + } + } + return true; + } + /** * Initialise a housekeeping task to iterate over queues cleaning expired messages with no consumers * and checking for idle or open transactions that have exceeded the permitted thresholds. @@ -526,9 +597,42 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte } @Override + public List<String> getEnabledConnectionValidators() + { + return _enabledConnectionValidators; + } + + @Override + public List<String> getDisabledConnectionValidators() + { + return _disabledConnectionValidators; + } + + @Override + public List<String> getGlobalAddressDomains() + { + return _globalAddressDomains; + } + + @Override public AMQQueue<?> getQueue(String name) { - return (AMQQueue<?>) getChildByName(Queue.class, name); + AMQQueue<?> childByName = (AMQQueue<?>) getChildByName(Queue.class, name); + if(childByName == null && getGlobalAddressDomains() != null) + { + for(String domain : getGlobalAddressDomains()) + { + if(name.startsWith(domain + "/")) + { + childByName = (AMQQueue<?>) getChildByName(Queue.class,name.substring(domain.length())); + if(childByName != null) + { + break; + } + } + } + } + return childByName; } @Override @@ -556,14 +660,6 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte { int purged = queue.deleteAndReturnCount(); - if (queue.isDurable() && !(queue.getLifetimePolicy() - == LifetimePolicy.DELETE_ON_CONNECTION_CLOSE - || queue.getLifetimePolicy() - == LifetimePolicy.DELETE_ON_SESSION_END)) - { - DurableConfigurationStore store = getDurableConfigurationStore(); - store.remove(queue.asObjectRecord()); - } return purged; } @@ -614,7 +710,22 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte @Override public ExchangeImpl getExchange(String name) { - return getChildByName(ExchangeImpl.class,name); + ExchangeImpl childByName = getChildByName(ExchangeImpl.class, name); + if(childByName == null && getGlobalAddressDomains() != null) + { + for(String domain : getGlobalAddressDomains()) + { + if(name.startsWith(domain + "/")) + { + childByName = getChildByName(ExchangeImpl.class,name.substring(domain.length())); + if(childByName != null) + { + break; + } + } + } + } + return childByName; } @Override @@ -671,6 +782,23 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte exchange.deleteWithChecks(); } + @Override + public String getLocalAddress(final String routingAddress) + { + String localAddress = routingAddress; + if(getGlobalAddressDomains() != null) + { + for(String domain : getGlobalAddressDomains()) + { + if(localAddress.length() > routingAddress.length() - domain.length() && routingAddress.startsWith(domain + "/")) + { + localAddress = routingAddress.substring(domain.length()); + } + } + } + return localAddress; + } + public SecurityManager getSecurityManager() { return _broker.getSecurityManager(); @@ -886,6 +1014,12 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte } } + @Override + public String getRedirectHost(final AmqpPort<?> port) + { + return null; + } + private class VirtualHostHouseKeepingTask extends HouseKeepingTask { public VirtualHostHouseKeepingTask() @@ -1390,14 +1524,6 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte return total; } - @Override - protected void onCreate() - { - super.onCreate(); - ConfiguredObjectRecord record = asObjectRecord(); - getDurableConfigurationStore().create(new ConfiguredObjectRecordImpl(record.getId(), record.getType(), record.getAttributes())); - } - @StateTransition( currentState = { State.UNINITIALIZED,State.ERRORED }, desiredState = State.ACTIVE ) private void onActivate() { @@ -1509,44 +1635,6 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte onActivate(); } - private class StoreUpdatingChangeListener implements ConfigurationChangeListener - { - @Override - public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState) - { - if (object == AbstractVirtualHost.this && isDurable() && newState == State.DELETED) - { - getDurableConfigurationStore().remove(asObjectRecord()); - object.removeChangeListener(this); - } - } - - @Override - public void childAdded(final ConfiguredObject<?> object, final ConfiguredObject<?> child) - { - - } - - @Override - public void childRemoved(final ConfiguredObject<?> object, final ConfiguredObject<?> child) - { - - } - - @Override - public void attributeSet(final ConfiguredObject<?> object, - final String attributeName, - final Object oldAttributeValue, - final Object newAttributeValue) - { - if (object == AbstractVirtualHost.this && isDurable() && getState() != State.DELETED && isAttributePersisted(attributeName) - && !(attributeName.equals(VirtualHost.DESIRED_STATE) && newAttributeValue.equals(State.DELETED))) - { - getDurableConfigurationStore().update(false, asObjectRecord()); - } - } - } - private class FileSystemSpaceChecker extends HouseKeepingTask { private boolean _fileSystemFull; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 29729b6c7d..dff8a80dd9 100755 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -33,6 +33,7 @@ import org.apache.qpid.server.message.MessageDestination; import org.apache.qpid.server.message.MessageSource; import org.apache.qpid.server.model.NoFactoryForTypeException; import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.LinkRegistry; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.security.SecurityManager; @@ -108,4 +109,7 @@ public interface VirtualHostImpl< X extends VirtualHostImpl<X,Q,E>, Q extends AM EventLogger getEventLogger(); + boolean authoriseCreateConnection(AMQConnectionModel<?, ?> connection); + + String getLocalAddress(String routingAddress); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHost.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHost.java new file mode 100644 index 0000000000..5e87b2e511 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHost.java @@ -0,0 +1,32 @@ +/* + * + * 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.server.virtualhostnode; + +import org.apache.qpid.server.exchange.ExchangeImpl; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.NonStandardVirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; + +public interface RedirectingVirtualHost<X extends RedirectingVirtualHost<X>> + extends VirtualHostImpl<X, AMQQueue<?>, ExchangeImpl<?>>, + NonStandardVirtualHost<X,AMQQueue<?>,ExchangeImpl<?>> +{ +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java new file mode 100644 index 0000000000..cacc981e9b --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java @@ -0,0 +1,517 @@ +/* + * + * 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.server.virtualhostnode; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ScheduledFuture; + +import org.apache.qpid.server.connection.IConnectionRegistry; +import org.apache.qpid.server.exchange.ExchangeImpl; +import org.apache.qpid.server.logging.EventLogger; +import org.apache.qpid.server.message.MessageDestination; +import org.apache.qpid.server.message.MessageSource; +import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Connection; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.ManagedAttributeField; +import org.apache.qpid.server.model.ManagedObject; +import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHostAlias; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.model.port.AmqpPort; +import org.apache.qpid.server.protocol.AMQConnectionModel; +import org.apache.qpid.server.protocol.LinkRegistry; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.stats.StatisticsCounter; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.txn.DtxRegistry; +import org.apache.qpid.server.virtualhost.ExchangeIsAlternateException; +import org.apache.qpid.server.virtualhost.HouseKeepingTask; +import org.apache.qpid.server.virtualhost.RequiredExchangeException; + +@ManagedObject( category = false, type = RedirectingVirtualHostImpl.TYPE, register = false ) +class RedirectingVirtualHostImpl + extends AbstractConfiguredObject<RedirectingVirtualHostImpl> + implements RedirectingVirtualHost<RedirectingVirtualHostImpl> +{ + public static final String TYPE = "REDIRECTOR"; + private final StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived; + + @ManagedAttributeField + private boolean _queue_deadLetterQueueEnabled; + + @ManagedAttributeField + private long _housekeepingCheckPeriod; + + @ManagedAttributeField + private long _storeTransactionIdleTimeoutClose; + + @ManagedAttributeField + private long _storeTransactionIdleTimeoutWarn; + + @ManagedAttributeField + private long _storeTransactionOpenTimeoutClose; + + @ManagedAttributeField + private long _storeTransactionOpenTimeoutWarn; + @ManagedAttributeField + private int _housekeepingThreadCount; + + @ManagedAttributeField + private List<String> _enabledConnectionValidators; + + @ManagedAttributeField + private List<String> _disabledConnectionValidators; + + @ManagedAttributeField + private List<String> _globalAddressDomains; + + @ManagedObjectFactoryConstructor + public RedirectingVirtualHostImpl(final Map<String, Object> attributes, VirtualHostNode<?> virtualHostNode) + { + super(parentsMap(virtualHostNode), attributes); + + _messagesDelivered = new StatisticsCounter("messages-delivered-" + getName()); + _dataDelivered = new StatisticsCounter("bytes-delivered-" + getName()); + _messagesReceived = new StatisticsCounter("messages-received-" + getName()); + _dataReceived = new StatisticsCounter("bytes-received-" + getName()); + setState(State.UNAVAILABLE); + } + + @Override + protected void validateChange(final ConfiguredObject<?> proxyForValidation, final Set<String> changedAttributes) + { + super.validateChange(proxyForValidation, changedAttributes); + + throwUnsupportedForRedirector(); + } + + @Override + public String getModelVersion() + { + return BrokerModel.MODEL_VERSION; + } + + @Override + protected <C extends ConfiguredObject> C addChild(final Class<C> childClass, + final Map<String, Object> attributes, + final ConfiguredObject... otherParents) + { + throwUnsupportedForRedirector(); + return null; + } + + @Override + public ExchangeImpl createExchange(final Map<String, Object> attributes) + { + throwUnsupportedForRedirector(); + return null; + } + + @Override + public void removeExchange(final ExchangeImpl<?> exchange, final boolean force) + throws ExchangeIsAlternateException, RequiredExchangeException + { + throwUnsupportedForRedirector(); + } + + @Override + public MessageDestination getMessageDestination(final String name) + { + return null; + } + + @Override + public ExchangeImpl<?> getExchange(final String name) + { + return null; + } + + @Override + public AMQQueue<?> createQueue(final Map<String, Object> attributes) + { + throwUnsupportedForRedirector(); + return null; + } + + @Override + public void executeTransaction(final TransactionalOperation op) + { + throwUnsupportedForRedirector(); + } + + @Override + public Collection<String> getExchangeTypeNames() + { + return getObjectFactory().getSupportedTypes(Exchange.class); + } + + @Override + public String getRedirectHost(final AmqpPort<?> port) + { + return ((RedirectingVirtualHostNode<?>)(getParent(VirtualHostNode.class))).getRedirects().get(port); + } + + @Override + public boolean isQueue_deadLetterQueueEnabled() + { + return false; + } + + @Override + public long getHousekeepingCheckPeriod() + { + return 0; + } + + @Override + public long getStoreTransactionIdleTimeoutClose() + { + return 0; + } + + @Override + public long getStoreTransactionIdleTimeoutWarn() + { + return 0; + } + + @Override + public long getStoreTransactionOpenTimeoutClose() + { + return 0; + } + + @Override + public long getStoreTransactionOpenTimeoutWarn() + { + return 0; + } + + @Override + public int getHousekeepingThreadCount() + { + return 0; + } + + @Override + public long getQueueCount() + { + return 0; + } + + @Override + public long getExchangeCount() + { + return 0; + } + + @Override + public long getConnectionCount() + { + return 0; + } + + @Override + public long getBytesIn() + { + return 0; + } + + @Override + public long getBytesOut() + { + return 0; + } + + @Override + public long getMessagesIn() + { + return 0; + } + + @Override + public long getMessagesOut() + { + return 0; + } + + @Override + public Collection<VirtualHostAlias> getAliases() + { + return Collections.emptyList(); + } + + @Override + public Collection<Connection> getConnections() + { + return Collections.emptyList(); + } + + @Override + public IConnectionRegistry getConnectionRegistry() + { + return null; + } + + @Override + public AMQQueue<?> getQueue(final String name) + { + return null; + } + + @Override + public MessageSource getMessageSource(final String name) + { + return null; + } + + @Override + public AMQQueue<?> getQueue(final UUID id) + { + return null; + } + + @Override + public Collection<AMQQueue<?>> getQueues() + { + return Collections.emptyList(); + } + + @Override + public int removeQueue(final AMQQueue<?> queue) + { + throwUnsupportedForRedirector(); + return 0; + } + + @Override + public Collection<ExchangeImpl<?>> getExchanges() + { + return Collections.emptyList(); + } + + @Override + public DurableConfigurationStore getDurableConfigurationStore() + { + return null; + } + + @Override + public ExchangeImpl<?> getExchange(final UUID id) + { + return null; + } + + @Override + public MessageDestination getDefaultDestination() + { + return null; + } + + @Override + public MessageStore getMessageStore() + { + return null; + } + + @Override + public void setTargetSize(final long targetSize) + { + + } + + @Override + public long getTotalQueueDepthBytes() + { + return 0l; + } + + @Override + public org.apache.qpid.server.security.SecurityManager getSecurityManager() + { + return null; + } + + @Override + public void scheduleHouseKeepingTask(final long period, final HouseKeepingTask task) + { + } + + @Override + public long getHouseKeepingTaskCount() + { + return 0; + } + + @Override + public long getHouseKeepingCompletedTaskCount() + { + return 0; + } + + @Override + public int getHouseKeepingPoolSize() + { + return 0; + } + + @Override + public void setHouseKeepingPoolSize(final int newSize) + { + } + + @Override + public int getHouseKeepingActiveCount() + { + return 0; + } + + @Override + public DtxRegistry getDtxRegistry() + { + return null; + } + + @Override + public LinkRegistry getLinkRegistry(final String remoteContainerId) + { + return null; + } + + @Override + public ScheduledFuture<?> scheduleTask(final long delay, final Runnable timeoutTask) + { + throwUnsupportedForRedirector(); + return null; + } + + @Override + public boolean getDefaultDeadLetterQueueEnabled() + { + return false; + } + + @Override + public EventLogger getEventLogger() + { + return null; + } + + @Override + public void registerMessageReceived(final long messageSize, final long timestamp) + { + throwUnsupportedForRedirector(); + } + + @Override + public void registerMessageDelivered(final long messageSize) + { + throwUnsupportedForRedirector(); + } + + @Override + public StatisticsCounter getMessageDeliveryStatistics() + { + return _messagesDelivered; + } + + @Override + public StatisticsCounter getMessageReceiptStatistics() + { + return _messagesReceived; + } + + @Override + public StatisticsCounter getDataDeliveryStatistics() + { + return _dataDelivered; + } + + @Override + public StatisticsCounter getDataReceiptStatistics() + { + return _dataReceived; + } + + @Override + public void resetStatistics() + { + } + + @Override + public boolean authoriseCreateConnection(final AMQConnectionModel<?, ?> connection) + { + return false; + } + + @Override + public List<String> getEnabledConnectionValidators() + { + return _enabledConnectionValidators; + } + + @Override + public List<String> getDisabledConnectionValidators() + { + return _disabledConnectionValidators; + } + + @Override + public List<String> getGlobalAddressDomains() + { + return _globalAddressDomains; + } + + @Override + public String getLocalAddress(final String routingAddress) + { + String localAddress = routingAddress; + if(getGlobalAddressDomains() != null) + { + for(String domain : getGlobalAddressDomains()) + { + if(localAddress.length() > routingAddress.length() - domain.length() && routingAddress.startsWith(domain + "/")) + { + localAddress = routingAddress.substring(domain.length()); + } + } + } + return localAddress; + } + + private void throwUnsupportedForRedirector() + { + throw new IllegalStateException("The virtual host state of " + getState() + + " does not permit this operation."); + } + + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNode.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNode.java new file mode 100644 index 0000000000..636681db72 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNode.java @@ -0,0 +1,36 @@ +/* + * + * 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.server.virtualhostnode; + +import java.util.Map; + +import org.apache.qpid.server.model.ManagedAttribute; +import org.apache.qpid.server.model.ManagedObject; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.VirtualHostNode; + +@ManagedObject(type= RedirectingVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE, category=false, validChildTypes = "org.apache.qpid.server.virtualhostnode.RedirectingVirtualHostNodeImpl#getSupportedChildTypes()") +public interface RedirectingVirtualHostNode<X extends RedirectingVirtualHostNode<X>> extends VirtualHostNode<X> +{ + + @ManagedAttribute( defaultValue = "{}") + Map<Port<?>, String> getRedirects(); +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeImpl.java new file mode 100644 index 0000000000..c94d113514 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeImpl.java @@ -0,0 +1,124 @@ +/* + * + * 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.server.virtualhostnode; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.ManagedAttributeField; +import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.RemoteReplicationNode; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.StateTransition; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.store.DurableConfigurationStore; + + +public class RedirectingVirtualHostNodeImpl + extends AbstractConfiguredObject<RedirectingVirtualHostNodeImpl> implements RedirectingVirtualHostNode<RedirectingVirtualHostNodeImpl> +{ + private static final Logger LOGGER = LoggerFactory.getLogger(RedirectingVirtualHostImpl.class); + public static final String VIRTUAL_HOST_NODE_TYPE = "Redirector"; + + + @ManagedAttributeField + private String _virtualHostInitialConfiguration; + + @ManagedAttributeField + private Map<Port<?>,String> _redirects; + + private RedirectingVirtualHostImpl _virtualHost; + + @ManagedObjectFactoryConstructor + public RedirectingVirtualHostNodeImpl(Map<String, Object> attributes, Broker<?> parent) + { + super(Collections.<Class<? extends ConfiguredObject>,ConfiguredObject<?>>singletonMap(Broker.class, parent), + attributes); + } + + @StateTransition( currentState = {State.UNINITIALIZED, State.STOPPED, State.ERRORED }, desiredState = State.ACTIVE ) + protected void doActivate() + { + try + { + _virtualHost = new RedirectingVirtualHostImpl(Collections.<String,Object>singletonMap(ConfiguredObject.NAME,getName()), this); + _virtualHost.create(); + setState(State.ACTIVE); + } + catch(RuntimeException e) + { + setState(State.ERRORED); + if (getParent(Broker.class).isManagementMode()) + { + LOGGER.warn("Failed to make " + this + " active.", e); + } + else + { + throw e; + } + } + } + + @Override + public String getVirtualHostInitialConfiguration() + { + return _virtualHostInitialConfiguration; + } + + @Override + public VirtualHost<?, ?, ?> getVirtualHost() + { + return _virtualHost; + } + + @Override + public DurableConfigurationStore getConfigurationStore() + { + return null; + } + + @Override + public Collection<? extends RemoteReplicationNode> getRemoteReplicationNodes() + { + return Collections.emptySet(); + } + + @Override + public Map<Port<?>, String> getRedirects() + { + return _redirects; + } + + public static Map<String, Collection<String>> getSupportedChildTypes() + { + Collection<String> validVhostTypes = Collections.singleton(RedirectingVirtualHostImpl.TYPE); + return Collections.singletonMap(VirtualHost.class.getSimpleName(), validVhostTypes); + } + +} diff --git a/qpid/java/broker-core/src/main/resources/system.properties b/qpid/java/broker-core/src/main/resources/system.properties deleted file mode 100644 index 661b0cba77..0000000000 --- a/qpid/java/broker-core/src/main/resources/system.properties +++ /dev/null @@ -1,20 +0,0 @@ -# -# 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. -# - - diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/BrokerOptionsTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/BrokerOptionsTest.java index 8c115c6e62..2846950bc1 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/BrokerOptionsTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/BrokerOptionsTest.java @@ -309,4 +309,14 @@ public class BrokerOptionsTest extends QpidTestCase assertEquals("unexpected number of entries", 2, props.keySet().size()); assertEquals("value", props.get("name")); } + + + public void testSetInitialSystemProperties() + { + assertNull("Unexpected default value for initial system properties", _options.getInitialSystemProperties()); + + _options.setInitialSystemProperties("test.properties"); + + assertEquals("test.properties", _options.getInitialSystemProperties()); + } } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/BrokerTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/BrokerTest.java new file mode 100644 index 0000000000..195414c7d7 --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/BrokerTest.java @@ -0,0 +1,101 @@ +/* + * + * 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.server; + + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + + +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.test.utils.TestFileUtils; +import org.apache.qpid.util.FileUtils; +import org.codehaus.jackson.map.ObjectMapper; + +public class BrokerTest extends QpidTestCase +{ + private static final String INITIAL_SYSTEM_PROPERTY = "test"; + private static final String INITIAL_SYSTEM_PROPERTY_VALUE = "testValue"; + + private File _initialSystemProperties; + private File _initialConfiguration; + private File _brokerWork; + private Broker _broker; + + @Override + public void setUp() throws Exception + { + super.setUp(); + + // create empty initial configuration + Map<String,Object> initialConfig = new HashMap<>(); + initialConfig.put(ConfiguredObject.NAME, "test"); + initialConfig.put(org.apache.qpid.server.model.Broker.MODEL_VERSION, BrokerModel.MODEL_VERSION); + + ObjectMapper mapper = new ObjectMapper(); + String config = mapper.writeValueAsString(initialConfig); + _initialConfiguration = TestFileUtils.createTempFile(this, ".initial-config.json", config); + _brokerWork = TestFileUtils.createTestDirectory("qpid-work", true); + _initialSystemProperties = TestFileUtils.createTempFile(this, ".initial-system.properties", + INITIAL_SYSTEM_PROPERTY + "=" + INITIAL_SYSTEM_PROPERTY_VALUE + + "\nQPID_WORK=" + _brokerWork.getAbsolutePath() + "_test"); + setTestSystemProperty("QPID_WORK", _brokerWork.getAbsolutePath()); + } + + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + if (_broker != null) + { + _broker.shutdown(); + } + System.clearProperty(INITIAL_SYSTEM_PROPERTY); + FileUtils.delete(_brokerWork, true); + FileUtils.delete(_initialSystemProperties, false); + FileUtils.delete(_initialConfiguration, false); + } + } + + public void testInitialSystemPropertiesAreSetOnBrokerStartup() throws Exception + { + BrokerOptions options = new BrokerOptions(); + options.setInitialSystemProperties(_initialSystemProperties.getAbsolutePath()); + options.setSkipLoggingConfiguration(true); + options.setStartupLoggedToSystemOut(true); + options.setInitialConfigurationLocation(_initialConfiguration.getAbsolutePath()); + _broker = new Broker(); + _broker.startup(options); + + // test JVM system property should be set from initial system config file + assertEquals("Unexpected JVM system property", INITIAL_SYSTEM_PROPERTY_VALUE, System.getProperty(INITIAL_SYSTEM_PROPERTY)); + + // existing system property should not be overridden + assertEquals("Unexpected QPID_WORK system property", _brokerWork.getAbsolutePath(), System.getProperty("QPID_WORK")); + } +} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/binding/BindingImplTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/binding/BindingImplTest.java index 93fa9114fb..d004f16466 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/binding/BindingImplTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/binding/BindingImplTest.java @@ -35,6 +35,8 @@ import org.apache.qpid.server.model.Binding; import org.apache.qpid.server.model.BrokerModel; import org.apache.qpid.server.model.Model; import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.test.utils.QpidTestCase; public class BindingImplTest extends QpidTestCase @@ -57,7 +59,11 @@ public class BindingImplTest extends QpidTestCase attributes.put(Binding.ARGUMENTS, arguments); attributes.put(Binding.NAME, getTestName()); AMQQueue queue = mock(AMQQueue.class); + VirtualHostImpl vhost = mock(VirtualHostImpl.class); + SecurityManager securityManager = mock(SecurityManager.class); + when(vhost.getSecurityManager()).thenReturn(securityManager); when(queue.getTaskExecutor()).thenReturn(_taskExecutor); + when(queue.getVirtualHost()).thenReturn(vhost); when(queue.getModel()).thenReturn(_model); ExchangeImpl exchange = mock(ExchangeImpl.class); when(exchange.getTaskExecutor()).thenReturn(_taskExecutor); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/StoreConfigurationChangeListenerTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/StoreConfigurationChangeListenerTest.java index 14ff640c57..f5a9217ef3 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/StoreConfigurationChangeListenerTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/StoreConfigurationChangeListenerTest.java @@ -57,6 +57,7 @@ public class StoreConfigurationChangeListenerTest extends QpidTestCase notifyBrokerStarted(); UUID id = UUID.randomUUID(); ConfiguredObject object = mock(VirtualHost.class); + when(object.isDurable()).thenReturn(true); when(object.getId()).thenReturn(id); ConfiguredObjectRecord record = mock(ConfiguredObjectRecord.class); when(object.asObjectRecord()).thenReturn(record); @@ -69,11 +70,13 @@ public class StoreConfigurationChangeListenerTest extends QpidTestCase notifyBrokerStarted(); Broker broker = mock(Broker.class); when(broker.getCategoryClass()).thenReturn(Broker.class); + when(broker.isDurable()).thenReturn(true); VirtualHost child = mock(VirtualHost.class); when(child.getCategoryClass()).thenReturn(VirtualHost.class); Model model = mock(Model.class); when(model.getChildTypes(any(Class.class))).thenReturn(Collections.<Class<? extends ConfiguredObject>>emptyList()); when(child.getModel()).thenReturn(model); + when(child.isDurable()).thenReturn(true); _listener.childAdded(broker, child); verify(_store).update(eq(true), any(ConfiguredObjectRecord.class)); } @@ -83,15 +86,17 @@ public class StoreConfigurationChangeListenerTest extends QpidTestCase notifyBrokerStarted(); Broker broker = mock(Broker.class); when(broker.getCategoryClass()).thenReturn(Broker.class); + when(broker.isDurable()).thenReturn(true); _listener.attributeSet(broker, Broker.CONNECTION_SESSION_COUNT_LIMIT, null, 1); verify(_store).update(eq(false),any(ConfiguredObjectRecord.class)); } - public void testChildAddedForVirtualHostNode() + public void testChildAddedWhereParentManagesChildStorage() { notifyBrokerStarted(); VirtualHostNode<?> object = mock(VirtualHostNode.class); + when(object.managesChildStorage()).thenReturn(true); VirtualHost<?,?,?> virtualHost = mock(VirtualHost.class); _listener.childAdded(object, virtualHost); verifyNoMoreInteractions(_store); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java index ca440bc432..d625fcba75 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java @@ -38,7 +38,6 @@ import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.Filterable; import org.apache.qpid.server.filter.MessageFilter; -import org.apache.qpid.server.filter.SimpleFilterManager; import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.message.MessageInstance; import org.apache.qpid.server.message.ServerMessage; @@ -103,16 +102,23 @@ public class MockConsumer implements ConsumerTarget { if(_messageIds != null) { - SimpleFilterManager filters = new SimpleFilterManager(); - filters.add(new MessageFilter() + FilterManager filters = new FilterManager(); + MessageFilter filter = new MessageFilter() { @Override + public String getName() + { + return ""; + } + + @Override public boolean matches(final Filterable message) { final String messageId = message.getMessageHeader().getMessageId(); return _messageIds.contains(messageId); } - }); + }; + filters.add(filter.getName(), filter); return filters; } else diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java index 4485d5cc85..c21a386eaa 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java @@ -45,6 +45,7 @@ import org.mockito.stubbing.Answer; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.configuration.store.StoreConfigurationChangeListener; import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; import org.apache.qpid.server.configuration.updater.TaskExecutor; import org.apache.qpid.server.connection.IConnectionRegistry.RegistryChangeListener; @@ -66,6 +67,7 @@ public class VirtualHostTest extends QpidTestCase private VirtualHostNode<?> _virtualHostNode; private DurableConfigurationStore _configStore; private VirtualHost<?, ?, ?> _virtualHost; + private StoreConfigurationChangeListener _storeConfigurationChangeListener; @Override protected void setUp() throws Exception @@ -79,9 +81,13 @@ public class VirtualHostTest extends QpidTestCase when(_broker.getTaskExecutor()).thenReturn(_taskExecutor); _virtualHostNode = mock(VirtualHostNode.class); + when(_virtualHostNode.isDurable()).thenReturn(true); _configStore = mock(DurableConfigurationStore.class); + _storeConfigurationChangeListener = new StoreConfigurationChangeListener(_configStore); + when(_virtualHostNode.getConfigurationStore()).thenReturn(_configStore); + // Virtualhost needs the EventLogger from the SystemContext. when(_virtualHostNode.getParent(Broker.class)).thenReturn(_broker); @@ -122,7 +128,7 @@ public class VirtualHostTest extends QpidTestCase assertEquals("Unexpected name", virtualHostName, virtualHost.getName()); assertEquals("Unexpected state", State.ACTIVE, virtualHost.getState()); - verify(_configStore).create(matchesRecord(virtualHost.getId(), virtualHost.getType())); + verify(_configStore).update(eq(true),matchesRecord(virtualHost.getId(), virtualHost.getType())); } public void testDeleteVirtualHost() @@ -170,7 +176,7 @@ public class VirtualHostTest extends QpidTestCase virtualHost.start(); assertEquals("Unexpected state", State.ACTIVE, virtualHost.getState()); - verify(_configStore, times(1)).create(matchesRecord(virtualHost.getId(), virtualHost.getType())); + verify(_configStore, times(1)).update(eq(true), matchesRecord(virtualHost.getId(), virtualHost.getType())); verify(_configStore, times(2)).update(eq(false), matchesRecord(virtualHost.getId(), virtualHost.getType())); } @@ -293,7 +299,7 @@ public class VirtualHostTest extends QpidTestCase assertNotNull(queue.getId()); assertEquals(queueName, queue.getName()); - verify(_configStore).create(matchesRecord(queue.getId(), queue.getType())); + verify(_configStore).update(eq(true),matchesRecord(queue.getId(), queue.getType())); } public void testCreateNonDurableQueue() @@ -396,7 +402,10 @@ public class VirtualHostTest extends QpidTestCase attributes.put(VirtualHost.TYPE, TestMemoryVirtualHost.VIRTUAL_HOST_TYPE); TestMemoryVirtualHost host = new TestMemoryVirtualHost(attributes, _virtualHostNode); + host.addChangeListener(_storeConfigurationChangeListener); host.create(); + // Fire the child added event on the node + _storeConfigurationChangeListener.childAdded(_virtualHostNode,host); _virtualHost = host; return host; } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/singleton/AbstractConfiguredObjectTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/singleton/AbstractConfiguredObjectTest.java index 46f205116a..081fbe4edf 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/singleton/AbstractConfiguredObjectTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/singleton/AbstractConfiguredObjectTest.java @@ -22,14 +22,18 @@ import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import javax.security.auth.Subject; import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.ConfigurationChangeListener; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.Model; +import org.apache.qpid.server.model.State; import org.apache.qpid.server.store.ConfiguredObjectRecord; import org.apache.qpid.test.utils.QpidTestCase; @@ -476,4 +480,84 @@ public class AbstractConfiguredObjectTest extends QpidTestCase } + + public void testAttributeSetListenerFiring() + { + final String objectName = "listenerFiring"; + + Map<String, Object> attributes = new HashMap<>(); + attributes.put(ConfiguredObject.NAME, objectName); + attributes.put(TestSingleton.STRING_VALUE, "first"); + + final TestSingleton object = _model.getObjectFactory().create(TestSingleton.class, attributes); + + final AtomicInteger listenerCount = new AtomicInteger(); + final LinkedHashMap<String, String> updates = new LinkedHashMap<>(); + object.addChangeListener(new NoopConfigurationChangeListener() + { + @Override + public void attributeSet(final ConfiguredObject<?> object, + final String attributeName, + final Object oldAttributeValue, + final Object newAttributeValue) + { + listenerCount.incrementAndGet(); + String delta = String.valueOf(oldAttributeValue) + "=>" + String.valueOf(newAttributeValue); + updates.put(attributeName, delta); + } + }); + + // Set updated value (should cause listener to fire) + object.setAttributes(Collections.singletonMap(TestSingleton.STRING_VALUE, "second")); + + assertEquals(1, listenerCount.get()); + String delta = updates.remove(TestSingleton.STRING_VALUE); + assertEquals("first=>second", delta); + + // Set unchanged value (should not cause listener to fire) + object.setAttributes(Collections.singletonMap(TestSingleton.STRING_VALUE, "second")); + assertEquals(1, listenerCount.get()); + + // Set value to null (should cause listener to fire) + object.setAttributes(Collections.singletonMap(TestSingleton.STRING_VALUE, null)); + assertEquals(2, listenerCount.get()); + delta = updates.remove(TestSingleton.STRING_VALUE); + assertEquals("second=>null", delta); + + // Set to null again (should not cause listener to fire) + object.setAttributes(Collections.singletonMap(TestSingleton.STRING_VALUE, null)); + assertEquals(2, listenerCount.get()); + + // Set updated value (should cause listener to fire) + object.setAttributes(Collections.singletonMap(TestSingleton.STRING_VALUE, "third")); + assertEquals(3, listenerCount.get()); + delta = updates.remove(TestSingleton.STRING_VALUE); + assertEquals("null=>third", delta); + } + + private static class NoopConfigurationChangeListener implements ConfigurationChangeListener + { + @Override + public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState) + { + } + + @Override + public void childAdded(final ConfiguredObject<?> object, final ConfiguredObject<?> child) + { + } + + @Override + public void childRemoved(final ConfiguredObject<?> object, final ConfiguredObject<?> child) + { + } + + @Override + public void attributeSet(final ConfiguredObject<?> object, + final String attributeName, + final Object oldAttributeValue, + final Object newAttributeValue) + { + } + } } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/LastValueQueueListTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/LastValueQueueListTest.java index 799fc71d74..2427470707 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/LastValueQueueListTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/LastValueQueueListTest.java @@ -93,6 +93,7 @@ public class LastValueQueueListTest extends TestCase ServerMessage message = createTestServerMessage(null); QueueEntry addedEntry = _list.add(message); + addedEntry.acquire(); addedEntry.delete(); int numberOfEntries = countEntries(_list); @@ -113,6 +114,7 @@ public class LastValueQueueListTest extends TestCase ServerMessage message = createTestServerMessage(TEST_KEY_VALUE); QueueEntry addedEntry = _list.add(message); + addedEntry.acquire(); addedEntry.delete(); int numberOfEntries = countEntries(_list); @@ -173,6 +175,7 @@ public class LastValueQueueListTest extends TestCase assertEquals(1, countEntries(_list)); assertEquals(1, _list.getLatestValuesMap().size()); + addedEntry.acquire(); addedEntry.delete(); assertEquals(0, countEntries(_list)); @@ -193,7 +196,9 @@ public class LastValueQueueListTest extends TestCase assertEquals(2, countEntries(_list)); assertEquals(2, _list.getLatestValuesMap().size()); + addedEntry1.acquire(); addedEntry1.delete(); + addedEntry2.acquire(); addedEntry2.delete(); assertEquals(0, countEntries(_list)); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java index 40b6c1bebd..2101a2297f 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java @@ -113,6 +113,7 @@ public abstract class QueueEntryImplTestBase extends TestCase */ private void delete() { + _queueEntry.acquire(); _queueEntry.delete(); assertTrue("Queue entry should be in DELETED state after invoking of delete method", _queueEntry.isDeleted()); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java index a0ab7cd454..7f5ea06dcf 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java @@ -196,6 +196,7 @@ public abstract class QueueEntryListTestBase extends TestCase final QueueEntry head = getTestList().getHead(); final QueueEntry first = getTestList().next(head); + first.acquire(); first.delete(); final QueueEntry second = getTestList().next(head); @@ -226,6 +227,7 @@ public abstract class QueueEntryListTestBase extends TestCase assertNull(list.next(queueEntry2)); //'delete' the 2nd QueueEntry + queueEntry2.acquire(); queueEntry2.delete(); assertTrue("Deleting node should have succeeded", queueEntry2.isDeleted()); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java index a2d314d629..a27db98400 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java @@ -109,6 +109,7 @@ public class SimpleQueueEntryImplTest extends QueueEntryImplTestBase public void testTraverseWithDeletedEntries() { // Delete 2nd queue entry + _queueEntry2.acquire(); _queueEntry2.delete(); assertTrue(_queueEntry2.isDeleted()); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryTest.java index d9a176c688..f88ce5f5f9 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryTest.java @@ -137,6 +137,7 @@ public class SortedQueueEntryTest extends QueueEntryImplTestBase public void testTraverseWithDeletedEntries() { // Delete 2nd queue entry + _queueEntry3.acquire(); _queueEntry3.delete(); assertTrue(_queueEntry3.isDeleted()); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.java index 28d22a5a44..73d14a843f 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.java @@ -155,7 +155,7 @@ public class StandardQueueEntryListTest extends QueueEntryListTestBase public void testScavenge() throws Exception { - OrderedQueueEntryList sqel = new StandardQueueEntryList(null); + OrderedQueueEntryList sqel = new StandardQueueEntryList(mock(StandardQueueImpl.class)); ConcurrentMap<Integer,QueueEntry> entriesMap = new ConcurrentHashMap<Integer,QueueEntry>(); @@ -215,6 +215,7 @@ public class StandardQueueEntryListTest extends QueueEntryListTestBase { QueueEntry entry = entriesMap.remove(pos); boolean wasDeleted = entry.isDeleted(); + entry.acquire(); entry.delete(); return entry.isDeleted() && !wasDeleted; } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/FileHelperTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/FileHelperTest.java new file mode 100644 index 0000000000..9d47ed496a --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/FileHelperTest.java @@ -0,0 +1,138 @@ +/* + * + * 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.server.util; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFileAttributeView; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.Set; + +import org.apache.qpid.test.utils.QpidTestCase; + +public class FileHelperTest extends QpidTestCase +{ + private static final String TEST_FILE_PERMISSIONS = "rwxr-x---"; + private File _testFile; + private FileHelper _fileHelper; + + @Override + public void setUp() throws Exception + { + super.setUp(); + _testFile = new File(TMP_FOLDER, "test-" + System.currentTimeMillis()); + _fileHelper = new FileHelper(); + } + + @Override + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + Files.deleteIfExists(_testFile.toPath()); + } + } + + public void testCreateNewFile() throws Exception + { + assertFalse("File should not exist", _testFile.exists()); + Path path = _fileHelper.createNewFile(_testFile, TEST_FILE_PERMISSIONS); + assertTrue("File was not created", path.toFile().exists()); + if (Files.getFileStore(path).supportsFileAttributeView(PosixFileAttributeView.class)) + { + assertPermissions(path); + } + } + + public void testCreateNewFileUsingRelativePath() throws Exception + { + _testFile = new File("./tmp-" + System.currentTimeMillis()); + assertFalse("File should not exist", _testFile.exists()); + Path path = _fileHelper.createNewFile(_testFile, TEST_FILE_PERMISSIONS); + assertTrue("File was not created", path.toFile().exists()); + if (Files.getFileStore(path).supportsFileAttributeView(PosixFileAttributeView.class)) + { + assertPermissions(path); + } + } + + public void testWriteFileSafely() throws Exception + { + Path path = _fileHelper.createNewFile(_testFile, TEST_FILE_PERMISSIONS); + _fileHelper.writeFileSafely(path, new BaseAction<File, IOException>() + { + @Override + public void performAction(File file) throws IOException + { + Files.write(file.toPath(), "test".getBytes("UTF8")); + assertEquals("Unexpected name", _testFile.getAbsolutePath() + ".tmp", file.getPath()); + } + }); + + assertTrue("File was not created", path.toFile().exists()); + + if (Files.getFileStore(path).supportsFileAttributeView(PosixFileAttributeView.class)) + { + assertPermissions(path); + } + + String content = new String(Files.readAllBytes(path), "UTF-8"); + assertEquals("Unexpected file content", "test", content); + } + + public void testAtomicFileMoveOrReplace() throws Exception + { + Path path = _fileHelper.createNewFile(_testFile, TEST_FILE_PERMISSIONS); + Files.write(path, "test".getBytes("UTF8")); + _testFile = _fileHelper.atomicFileMoveOrReplace(path, path.resolveSibling(_testFile.getName() + ".target")).toFile(); + + assertFalse("File was not moved", path.toFile().exists()); + assertTrue("Target file does not exist", _testFile.exists()); + + if (Files.getFileStore(_testFile.toPath()).supportsFileAttributeView(PosixFileAttributeView.class)) + { + assertPermissions(_testFile.toPath()); + } + } + + + private void assertPermissions(Path path) throws IOException + { + Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(path); + assertTrue("Unexpected owner read permission", permissions.contains(PosixFilePermission.OWNER_READ)); + assertTrue("Unexpected owner write permission", permissions.contains(PosixFilePermission.OWNER_WRITE)); + assertTrue("Unexpected owner exec permission", permissions.contains(PosixFilePermission.OWNER_EXECUTE)); + assertTrue("Unexpected group read permission", permissions.contains(PosixFilePermission.GROUP_READ)); + assertFalse("Unexpected group write permission", permissions.contains(PosixFilePermission.GROUP_WRITE)); + assertTrue("Unexpected group exec permission", permissions.contains(PosixFilePermission.GROUP_EXECUTE)); + assertFalse("Unexpected others read permission", permissions.contains(PosixFilePermission.OTHERS_READ)); + assertFalse("Unexpected others write permission", permissions.contains(PosixFilePermission.OTHERS_WRITE)); + assertFalse("Unexpected others exec permission", permissions.contains(PosixFilePermission.OTHERS_EXECUTE)); + } +} diff --git a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java index 78228c209f..6e2a6cac7d 100644 --- a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java +++ b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java @@ -184,7 +184,8 @@ public class ServerConnectionDelegate extends ServerDelegate vhostName = ""; } - vhost = ((AmqpPort)sconn.getPort()).getVirtualHost(vhostName); + AmqpPort port = (AmqpPort) sconn.getPort(); + vhost = port.getVirtualHost(vhostName); @@ -193,14 +194,28 @@ public class ServerConnectionDelegate extends ServerDelegate if (vhost.getState() != State.ACTIVE) { sconn.setState(Connection.State.CLOSING); - sconn.invoke(new ConnectionClose(ConnectionCloseCode.CONNECTION_FORCED, "Virtual host '"+vhostName+"' is not active")); + final String redirectHost = vhost.getRedirectHost(port); + if(redirectHost == null) + { + sconn.invoke(new ConnectionClose(ConnectionCloseCode.CONNECTION_FORCED, + "Virtual host '" + vhostName + "' is not active")); + } + else + { + sconn.invoke(new ConnectionRedirect(redirectHost, new ArrayList<Object>())); + } return; } sconn.setVirtualHost(vhost); try { - vhost.getSecurityManager().authoriseCreateConnection(sconn); + if(!vhost.authoriseCreateConnection(sconn)) + { + sconn.setState(Connection.State.CLOSING); + sconn.invoke(new ConnectionClose(ConnectionCloseCode.CONNECTION_FORCED, "Connection not authorized")); + return; + } } catch (AccessControlException e) { @@ -215,7 +230,8 @@ public class ServerConnectionDelegate extends ServerDelegate else { sconn.setState(Connection.State.CLOSING); - sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, "Unknown virtualhost '"+vhostName+"'")); + sconn.invoke(new ConnectionClose(ConnectionCloseCode.INVALID_PATH, + "Unknown virtualhost '" + vhostName + "'")); } } diff --git a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSessionDelegate.java b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSessionDelegate.java index c42630d0c6..dd634c36ff 100644 --- a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSessionDelegate.java +++ b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSessionDelegate.java @@ -33,6 +33,7 @@ import java.util.UUID; import org.apache.log4j.Logger; +import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.protocol.ServerProtocolEngine; @@ -40,8 +41,10 @@ import org.apache.qpid.server.consumer.ConsumerImpl; import org.apache.qpid.server.exchange.ExchangeImpl; import org.apache.qpid.server.virtualhost.VirtualHostUnavailableException; import org.apache.qpid.server.filter.AMQInvalidArgumentException; +import org.apache.qpid.server.filter.ArrivalTimeFilter; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.FilterManagerFactory; +import org.apache.qpid.server.filter.MessageFilter; import org.apache.qpid.server.logging.messages.ChannelMessages; import org.apache.qpid.server.logging.messages.ExchangeMessages; import org.apache.qpid.server.message.InstanceProperties; @@ -259,6 +262,43 @@ public class ServerSessionDelegate extends SessionDelegate return; } + + if(method.hasArguments() && method.getArguments().containsKey(AMQPFilterTypes.REPLAY_PERIOD.toString())) + { + Object value = method.getArguments().get(AMQPFilterTypes.REPLAY_PERIOD.toString()); + final long period; + if(value instanceof Number) + { + period = ((Number)value).longValue(); + } + else if(value instanceof String) + { + try + { + period = Long.parseLong(value.toString()); + } + catch (NumberFormatException e) + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "Cannot parse value " + value + " as a number for filter " + AMQPFilterTypes.REPLAY_PERIOD.toString()); + return; + } + } + else + { + exception(session, method, ExecutionErrorCode.ILLEGAL_ARGUMENT, "Cannot parse value " + value + " as a number for filter " + AMQPFilterTypes.REPLAY_PERIOD.toString()); + return; + } + final long startingFrom = System.currentTimeMillis() - (1000l * period); + if(filterManager == null) + { + filterManager = new FilterManager(); + } + MessageFilter filter = new ArrivalTimeFilter(startingFrom); + filterManager.add(filter.getName(), filter); + + } + + ConsumerTarget_0_10 target = new ConsumerTarget_0_10((ServerSession)session, destination, method.getAcceptMode(), method.getAcquireMode(), @@ -1609,4 +1649,5 @@ public class ServerSessionDelegate extends SessionDelegate { } } + } diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java index 9631530f90..18ebc94187 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java @@ -59,11 +59,11 @@ import org.apache.qpid.server.consumer.ConsumerImpl; import org.apache.qpid.server.consumer.ConsumerTarget; import org.apache.qpid.server.exchange.ExchangeImpl; import org.apache.qpid.server.filter.AMQInvalidArgumentException; +import org.apache.qpid.server.filter.ArrivalTimeFilter; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.FilterManagerFactory; import org.apache.qpid.server.filter.Filterable; import org.apache.qpid.server.filter.MessageFilter; -import org.apache.qpid.server.filter.SimpleFilterManager; import org.apache.qpid.server.flow.FlowCreditManager; import org.apache.qpid.server.logging.LogMessage; import org.apache.qpid.server.logging.LogSubject; @@ -673,7 +673,7 @@ public class AMQChannel * @param tag the tag chosen by the client (if null, server will generate one) * @param sources the queues to subscribe to * @param acks Are acks enabled for this subscriber - * @param filters Filters to apply to this subscriber + * @param arguments Filters to apply to this subscriber * * @param exclusive Flag requesting exclusive access to the queue * @return the consumer tag. This is returned to the subscriber and used in subsequent unsubscribe requests @@ -681,7 +681,7 @@ public class AMQChannel * @throws org.apache.qpid.AMQException if something goes wrong */ public AMQShortString consumeFromSource(AMQShortString tag, Collection<MessageSource> sources, boolean acks, - FieldTable filters, boolean exclusive, boolean noLocal) + FieldTable arguments, boolean exclusive, boolean noLocal) throws MessageSource.ExistingConsumerPreventsExclusive, MessageSource.ExistingExclusiveConsumer, AMQInvalidArgumentException, @@ -700,19 +700,19 @@ public class AMQChannel ConsumerTarget_0_8 target; EnumSet<ConsumerImpl.Option> options = EnumSet.noneOf(ConsumerImpl.Option.class); - if(filters != null && Boolean.TRUE.equals(filters.get(AMQPFilterTypes.NO_CONSUME.getValue()))) + if(arguments != null && Boolean.TRUE.equals(arguments.get(AMQPFilterTypes.NO_CONSUME.getValue()))) { - target = ConsumerTarget_0_8.createBrowserTarget(this, tag, filters, _noAckCreditManager); + target = ConsumerTarget_0_8.createBrowserTarget(this, tag, arguments, _noAckCreditManager); } else if(acks) { - target = ConsumerTarget_0_8.createAckTarget(this, tag, filters, _creditManager); + target = ConsumerTarget_0_8.createAckTarget(this, tag, arguments, _creditManager); options.add(ConsumerImpl.Option.ACQUIRES); options.add(ConsumerImpl.Option.SEES_REQUEUES); } else { - target = ConsumerTarget_0_8.createNoAckTarget(this, tag, filters, _noAckCreditManager); + target = ConsumerTarget_0_8.createNoAckTarget(this, tag, arguments, _noAckCreditManager); options.add(ConsumerImpl.Option.ACQUIRES); options.add(ConsumerImpl.Option.SEES_REQUEUES); } @@ -732,23 +732,66 @@ public class AMQChannel try { - FilterManager filterManager = FilterManagerFactory.createManager(FieldTable.convertToMap(filters)); + FilterManager filterManager = FilterManagerFactory.createManager(FieldTable.convertToMap(arguments)); if(noLocal) { if(filterManager == null) { - filterManager = new SimpleFilterManager(); + filterManager = new FilterManager(); } final Object connectionReference = getConnectionReference(); - filterManager.add(new MessageFilter() + MessageFilter filter = new MessageFilter() { + + @Override + public String getName() + { + return AMQPFilterTypes.NO_LOCAL.toString(); + } + @Override public boolean matches(final Filterable message) { return message.getConnectionReference() != connectionReference; } - }); + }; + filterManager.add(filter.getName(), filter); + } + + if(arguments != null && arguments.containsKey(AMQPFilterTypes.REPLAY_PERIOD.toString())) + { + Object value = arguments.get(AMQPFilterTypes.REPLAY_PERIOD.toString()); + final long period; + if(value instanceof Number) + { + period = ((Number)value).longValue(); + } + else if(value instanceof String) + { + try + { + period = Long.parseLong(value.toString()); + } + catch (NumberFormatException e) + { + throw new AMQInvalidArgumentException("Cannot parse value " + value + " as a number for filter " + AMQPFilterTypes.REPLAY_PERIOD.toString()); + } + } + else + { + throw new AMQInvalidArgumentException("Cannot parse value " + value + " as a number for filter " + AMQPFilterTypes.REPLAY_PERIOD.toString()); + } + + final long startingFrom = System.currentTimeMillis() - (1000l * period); + if(filterManager == null) + { + filterManager = new FilterManager(); + } + MessageFilter filter = new ArrivalTimeFilter(startingFrom); + filterManager.add(filter.getName(), filter); + } + for(MessageSource source : sources) { ConsumerImpl sub = diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolEngine.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolEngine.java index 659207d9e8..d58ac36ff5 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolEngine.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolEngine.java @@ -1565,7 +1565,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, virtualHostStr = virtualHostName == null ? null : virtualHostName.toString(); } - VirtualHostImpl virtualHost = ((AmqpPort)getPort()).getVirtualHost(virtualHostStr); + VirtualHostImpl<?,?,?> virtualHost = ((AmqpPort)getPort()).getVirtualHost(virtualHostStr); if (virtualHost == null) { @@ -1578,8 +1578,16 @@ public class AMQProtocolEngine implements ServerProtocolEngine, // Check virtualhost access if (virtualHost.getState() != State.ACTIVE) { - closeConnection(AMQConstant.CONNECTION_FORCED, - "Virtual host '" + virtualHost.getName() + "' is not active",0); + String redirectHost = virtualHost.getRedirectHost(getPort()); + if(redirectHost != null) + { + closeConnection(0, new AMQFrame(0,new ConnectionRedirectBody(getProtocolVersion(),AMQShortString.valueOf(redirectHost), null))); + } + else + { + closeConnection(AMQConstant.CONNECTION_FORCED, + "Virtual host '" + virtualHost.getName() + "' is not active", 0); + } } else @@ -1587,21 +1595,29 @@ public class AMQProtocolEngine implements ServerProtocolEngine, setVirtualHost(virtualHost); try { - virtualHost.getSecurityManager().authoriseCreateConnection(this); - if (getContextKey() == null) + + if(virtualHost.authoriseCreateConnection(this)) { - setContextKey(new AMQShortString(Long.toString(System.currentTimeMillis()))); - } + if (getContextKey() == null) + { + setContextKey(new AMQShortString(Long.toString(System.currentTimeMillis()))); + } + + MethodRegistry methodRegistry = getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createConnectionOpenOkBody(virtualHostName); - MethodRegistry methodRegistry = getMethodRegistry(); - AMQMethodBody responseBody = methodRegistry.createConnectionOpenOkBody(virtualHostName); + writeFrame(responseBody.generateFrame(0)); + _state = ConnectionState.OPEN; - writeFrame(responseBody.generateFrame(0)); - _state = ConnectionState.OPEN; + } + else + { + closeConnection(AMQConstant.ACCESS_REFUSED, "Connection refused",0); + } } catch (AccessControlException e) { - closeConnection(AMQConstant.ACCESS_REFUSED, e.getMessage(),0); + closeConnection(AMQConstant.ACCESS_REFUSED, e.getMessage(), 0); } } } @@ -1767,7 +1783,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, _logger.info("Locale selected: " + locale); SubjectCreator subjectCreator = getSubjectCreator(); - SaslServer ss = null; + SaslServer ss; try { ss = subjectCreator.createSaslServer(String.valueOf(mechanism), diff --git a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java index 6a202998f4..fe36ba91cb 100644 --- a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java +++ b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java @@ -65,8 +65,8 @@ import org.apache.qpid.filter.selector.ParseException; import org.apache.qpid.server.binding.BindingImpl; import org.apache.qpid.server.consumer.ConsumerImpl; import org.apache.qpid.server.exchange.ExchangeImpl; +import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.filter.JMSSelectorFilter; -import org.apache.qpid.server.filter.SimpleFilterManager; import org.apache.qpid.server.message.MessageInstance; import org.apache.qpid.server.message.MessageSource; import org.apache.qpid.server.model.ExclusivityPolicy; @@ -154,15 +154,7 @@ public class SendingLink_1_0 implements SendingLinkListener, Link_1_0, DeliveryS actualFilters.put(entry.getKey(), entry.getValue()); } - catch (ParseException e) - { - Error error = new Error(); - error.setCondition(AmqpError.INVALID_FIELD); - error.setDescription("Invalid JMS Selector: " + selectorFilter.getValue()); - error.setInfo(Collections.singletonMap(Symbol.valueOf("field"), Symbol.valueOf("filter"))); - throw new AmqpErrorException(error); - } - catch (SelectorParsingException e) + catch (ParseException | SelectorParsingException e) { Error error = new Error(); error.setCondition(AmqpError.INVALID_FIELD); @@ -374,8 +366,16 @@ public class SendingLink_1_0 implements SendingLinkListener, Link_1_0, DeliveryS { name = getEndpoint().getName(); } + + FilterManager filters = null; + if(messageFilter != null) + { + filters = new FilterManager(); + filters.add(messageFilter.getName(), messageFilter); + } + _consumer = _queue.addConsumer(_target, - messageFilter == null ? null : new SimpleFilterManager(messageFilter), + filters, Message_1_0.class, name, options); } catch (MessageSource.ExistingExclusiveConsumer e) diff --git a/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/add.js b/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/add.js index 7b12d10343..323b8e9750 100644 --- a/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/add.js +++ b/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/add.js @@ -34,10 +34,11 @@ define(["dojo/_base/xhr", show: function (data) { this.containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode); - parser.parse(this.containerNode); - - registry.byId("addVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); - registry.byId("addVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + parser.parse(this.containerNode).then(function(instances) + { + registry.byId("addVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); + registry.byId("addVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + }); } }; } diff --git a/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/edit.js b/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/edit.js index a8b68a0c16..c1018313b8 100644 --- a/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/edit.js +++ b/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/edit.js @@ -22,10 +22,12 @@ define(["qpid/common/util", "dijit/registry", "dojo/domReady!"], return { show: function(data) { - util.buildEditUI(data.containerNode, "virtualhost/sizemonitoring/edit.html", "editVirtualHost.", null, null); - - registry.byId("editVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); - registry.byId("editVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + util.parseHtmlIntoDiv(data.containerNode, "virtualhost/sizemonitoring/edit.html", + function() + { + registry.byId("editVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); + registry.byId("editVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + }); } }; } diff --git a/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhostnode/derby/edit.js b/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhostnode/derby/edit.js index 5fa0443185..a7f5d05719 100644 --- a/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhostnode/derby/edit.js +++ b/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhostnode/derby/edit.js @@ -22,8 +22,11 @@ define(["qpid/common/util", "dijit/registry", "dojo/domReady!"], return { show: function(data) { - util.buildEditUI(data.containerNode, "virtualhostnode/filebased/edit.html", "editVirtualHostNode.", ["storePath"], data.data); - registry.byId("editVirtualHostNode.storePath").set("disabled", data.data.state != "STOPPED"); + util.parseHtmlIntoDiv(data.containerNode, "virtualhostnode/filebased/edit.html", + function() + { + registry.byId("editVirtualHostNode.storePath").set("disabled", data.data.state != "STOPPED"); + }); } }; } diff --git a/qpid/java/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js b/qpid/java/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js index 31e5db5035..3d15cdbc37 100644 --- a/qpid/java/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js +++ b/qpid/java/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js @@ -40,13 +40,15 @@ define(["dojo/_base/xhr", sync: true, load: function(template) { containerNode.innerHTML = template; - parser.parse(containerNode); + parser.parse(containerNode).then(function(instances) + { + for(var i=0; i<fieldNames.length;i++) + { + var fieldName = fieldNames[i]; + that[fieldName]= query("." + fieldName, containerNode)[0]; + } + }); }}); - for(var i=0; i<fieldNames.length;i++) - { - var fieldName = fieldNames[i]; - this[fieldName]= query("." + fieldName, containerNode)[0]; - } } BoneCP.prototype.update=function(data) diff --git a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/add.js b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/add.js index beb298e988..8de6206373 100644 --- a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/add.js +++ b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/add.js @@ -36,12 +36,18 @@ define(["dojo/_base/xhr", return { show: function (data) { + var that = this; this.containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances) + { + that._postParse(data); + }); + }, + _postParse: function (data) + { + var that = this; registry.byId("addVirtualHost.connectionUrl").set("regExpGen", util.jdbcUrlOrContextVarRegexp); registry.byId("addVirtualHost.username").set("regExpGen", util.nameOrContextVarRegexp); - var poolTypes = json.parse(poolTypeJsonString); var poolTypesData = []; for (var i =0 ; i < poolTypes.length; i++) diff --git a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/edit.js b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/edit.js index 90fc246276..4a2a3763bd 100644 --- a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/edit.js +++ b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/edit.js @@ -29,12 +29,15 @@ define(["qpid/common/util", function (util, poolTypeJsonString, array, json, string, Memory, dom, domConstruct, registry) { - var fieldNames = ["connectionUrl", "username", "connectionPoolType"]; return { show: function(data) { - util.buildEditUI(data.containerNode, "virtualhost/jdbc/edit.html", "editVirtualHost.", fieldNames, data.data); - + var that = this; + util.parseHtmlIntoDiv(data.containerNode, "virtualhost/jdbc/edit.html", + function(){that._postParse(data)}); + }, + _postParse: function(data) + { registry.byId("editVirtualHost.connectionUrl").set("regExpGen", util.jdbcUrlOrContextVarRegexp); registry.byId("editVirtualHost.username").set("regExpGen", util.nameOrContextVarRegexp); diff --git a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/show.js b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/show.js index d3fdf50769..b717f2091d 100644 --- a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/show.js +++ b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhost/jdbc/show.js @@ -25,9 +25,12 @@ define(["qpid/common/util", "dojo/query", "dojo/_base/array", "dojo/dom-construc function JDBC(data) { - util.buildUI(data.containerNode, data.parent, "virtualhostnode/jdbc/show.html", fieldNames, this); - this.usernameAttributeContainer=query(".usernameAttributeContainer", data.containerNode)[0]; - this.connectionPoolTypeAttributeContainer=query(".connectionPoolTypeAttributeContainer", data.containerNode)[0]; + var that = this; + util.buildUI(data.containerNode, data.parent, "virtualhostnode/jdbc/show.html", fieldNames, this, function() + { + that.usernameAttributeContainer=query(".usernameAttributeContainer", data.containerNode)[0]; + that.connectionPoolTypeAttributeContainer=query(".connectionPoolTypeAttributeContainer", data.containerNode)[0]; + }); } JDBC.prototype.update = function(data) diff --git a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/add.js b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/add.js index d5a7b43aae..071c0c8b23 100644 --- a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/add.js +++ b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/add.js @@ -38,9 +38,16 @@ define(["dojo/_base/xhr", return { show: function (data) { + var that = this; this.containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances) + { + that._postParse(data); + }); + }, + _postParse: function(data) + { + var that = this; registry.byId("addVirtualHostNode.connectionUrl").set("regExpGen", util.jdbcUrlOrContextVarRegexp); registry.byId("addVirtualHostNode.username").set("regExpGen", util.nameOrContextVarRegexp); diff --git a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/edit.js b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/edit.js index 828369cae0..cccfa95d4c 100644 --- a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/edit.js +++ b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/edit.js @@ -28,12 +28,14 @@ define(["qpid/common/util", "dojo/domReady!"], function (util, poolTypeJsonString, array, json, string, Memory, dom, domConstruct, registry) { - var fieldNames = ["connectionUrl", "username", "connectionPoolType"]; return { show: function(data) { - util.buildEditUI(data.containerNode, "virtualhostnode/jdbc/edit.html", "editVirtualHostNode.", fieldNames, data.data); - + var that = this; + util.parseHtmlIntoDiv(data.containerNode, "virtualhostnode/jdbc/edit.html", function(){ that._postParse(data);}); + }, + _postParse: function(data) + { registry.byId("editVirtualHostNode.connectionUrl").set("regExpGen", util.jdbcUrlOrContextVarRegexp); registry.byId("editVirtualHostNode.username").set("regExpGen", util.nameOrContextVarRegexp); diff --git a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/show.js b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/show.js index 15c237d0a2..019962fc64 100644 --- a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/show.js +++ b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/virtualhostnode/jdbc/show.js @@ -27,10 +27,13 @@ define(["qpid/common/util", "dojo/query", "dojo/_base/array", "dojo/dom-construc function Jdbc(data) { this.parent = data.parent; - util.buildUI(data.containerNode, data.parent, "virtualhostnode/jdbc/show.html", fieldNames, this); - - this.usernameAttributeContainer=query(".usernameAttributeContainer", data.containerNode)[0]; - this.connectionPoolTypeAttributeContainer=query(".connectionPoolTypeAttributeContainer", data.containerNode)[0]; + var that = this; + util.buildUI(data.containerNode, data.parent, "virtualhostnode/jdbc/show.html", fieldNames, this, + function() + { + that.usernameAttributeContainer=query(".usernameAttributeContainer", data.containerNode)[0]; + that.connectionPoolTypeAttributeContainer=query(".connectionPoolTypeAttributeContainer", data.containerNode)[0]; + }); } Jdbc.prototype.update=function(data) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java index 4e340c7b72..69920ff488 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java @@ -69,6 +69,7 @@ import org.apache.qpid.server.management.plugin.servlet.rest.LogoutServlet; import org.apache.qpid.server.management.plugin.servlet.rest.MessageContentServlet; import org.apache.qpid.server.management.plugin.servlet.rest.MessageServlet; import org.apache.qpid.server.management.plugin.servlet.rest.MetaDataServlet; +import org.apache.qpid.server.management.plugin.servlet.rest.QueueReportServlet; import org.apache.qpid.server.management.plugin.servlet.rest.RestServlet; import org.apache.qpid.server.management.plugin.servlet.rest.SaslServlet; import org.apache.qpid.server.management.plugin.servlet.rest.StructureServlet; @@ -304,6 +305,8 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem root.addServlet(new ServletHolder(new StructureServlet()), "/service/structure"); root.addServlet(new ServletHolder(new MessageServlet()), "/service/message/*"); root.addServlet(new ServletHolder(new MessageContentServlet()), "/service/message-content/*"); + root.addServlet(new ServletHolder(new QueueReportServlet()), "/service/queuereport/*"); + root.addServlet(new ServletHolder(new LogRecordsServlet()), "/service/logrecords"); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueBinaryReport.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueBinaryReport.java new file mode 100644 index 0000000000..d842de3f1b --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueBinaryReport.java @@ -0,0 +1,28 @@ +/* + * + * 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.server.management.plugin.report; + +public abstract class QueueBinaryReport extends QueueReport<byte[]> +{ + public QueueBinaryReport() + { + } +} diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueReport.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueReport.java new file mode 100644 index 0000000000..23b24aaf8d --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueReport.java @@ -0,0 +1,161 @@ +/* + * + * 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.server.management.plugin.report; + +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.VirtualHost; + +/** + * <p> + * The QueueReport class provides an extension point for installations to provide custom management reporting on + * queues through the REST API. + * </p> + * + * <p> + * A custom QueueReport must extend either {@link org.apache.qpid.server.management.plugin.report.QueueTextReport} + * or {@link org.apache.qpid.server.management.plugin.report.QueueBinaryReport}. The report implementation must + * define a {@link #getName() name} which is unique amongst all installed reports. The report class must be present + * in the classpath of the broker, and a provider-configuration file named + * org.apache.qpid.server.management.plugin.report.QueueReport must be added in the resource directory + * META-INF/services directory with the binary name of the implementation (as described in + * {@link java.util.ServiceLoader ServiceLoader}). + * </p> + * + * <h3>Running reports</h3> + * <p> + * The report can be run using the URL: + * {@code http://<broker>/service/queuereport/<virtualhost name>/<queue name>/<report name>[?param1=x¶m2=y...]} + * </p> + * + * <h4>Report Parameters</h4> + * + * <p> + * Reports can take parameters from the query string of the HTTP request. For every parameter in the query string + * the system will look for a setter on the report object with either a String or String[] parameter. Thus if + * the query string contains {@code foo=bar}, then the system will look for a setter {@code setFoo(String value)} or + * {@code setFoo(String[] value)}. If the same parameter occurs multiple times in the query string then only the + * array variant of the setter will be called. + * </p> + * <p> + * Setters for the parameters are guaranteed to be called before the first message is added to the report. + * </p> + * + * <p> + * NOTE: In order to comply with the requirements of the {@link java.util.ServiceLoader ServiceLoader} api, all + * implementations of QueueReport MUST provide a public no-args constructor. + * </p> + * @param <T> + */ +public abstract class QueueReport<T> +{ + private Queue<?> _queue; + + QueueReport() + { + + } + + /** + * Gets the name of the report. + * <p> + * The name of the report must be unique amongst all installed implementations. The name of the report + * is examined by the Qpid immediately upon construction. The name should not change during + * the lifetime of the object (the value is only meaningful to the system at the time of initial construction) + * and all instances of the same concrete implementation should have the same name. + * </p> + * @return the name of the report + */ + public abstract String getName(); + + /** + * Get the name of the queue against which the report is being run. + * + * @return the name of the queue + */ + public final String getQueueName() + { + return _queue.getName(); + } + + final void setQueue(final Queue<?> queue) + { + _queue = queue; + } + + /** + * Get the name of the virtual host against which the report is being run. + * + * @return the name of the virtual host + */ + public final String getVirtualHostName() + { + return _queue.getParent(VirtualHost.class).getName(); + } + + /** + * + * The value returned by getContentType() will be used to set the Content-Type HTTP header field + * + * @return the value to use for the content-type HTTP header field + */ + public abstract String getContentType(); + + /** + * Called by the system to add a message to the report. + * + * <p> + * The method is called by the system for every message on the queue, or until {@link #isComplete()} returns true. + * </p> + * @param reportableMessage the message to add to the report + */ + public abstract void addMessage(final ReportableMessage reportableMessage); + + /** + * Informs the system if the report is complete (i.e. does not need to report on any more messages). + * + * <p> + * This method will be called by the system after each message is {@link #addMessage(ReportableMessage) added} + * to the report. If a report is only interested in some messages, and can determine that the addition of more + * messages will not vary the content of the report, then it can return true. + * </p> + * <p> + * If this method always returns false, then all messages from the queue will be added to the report. + * </p> + * <p> + * NOTE: Retrieving content or properties of the message may require it to be reloaded from disk, and so care + * should be taken by reports to only access properties/content of the message if it is going to be required + * for the report production. + * </p> + * + * @return true if the report does not want to report on any more messages in the queue + */ + public abstract boolean isComplete(); + + /** + * Called by the system to get the content of the report to retrun to the user. + * <p> + * The system guarantees to only call this method once + * </p> + * @return the report content. + */ + public abstract T getReport(); + +} diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueTextReport.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueTextReport.java new file mode 100644 index 0000000000..09bc5c4229 --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueTextReport.java @@ -0,0 +1,28 @@ +/* + * + * 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.server.management.plugin.report; + +public abstract class QueueTextReport extends QueueReport<String> +{ + public QueueTextReport() + { + } +} diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportRunner.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportRunner.java new file mode 100644 index 0000000000..2a05cfc9a1 --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportRunner.java @@ -0,0 +1,408 @@ +/* + * + * 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.server.management.plugin.report; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.QueueEntryVisitor; + +public class ReportRunner<T> +{ + private static final Logger LOGGER = LoggerFactory.getLogger(ReportRunner.class); + + private static final Set<Class> IMMUTABLE_CLASSES = new HashSet<>(Arrays.<Class>asList( + Boolean.class, + Byte.class, + Short.class, + Character.class, + Integer.class, + Long.class, + Float.class, + Double.class, + UUID.class, + Date.class, + String.class + )); + + private ReportRunner(final QueueReport<T> report) + { + _report = report; + } + + public boolean isBinaryReport() + { + return _report instanceof QueueBinaryReport; + } + + public static ReportRunner<?> createRunner(final String reportName, final Map<String, String[]> parameterMap) + { + QueueReport<?> report = getReport(reportName); + setReportParameters(report, parameterMap); + return new ReportRunner<>(report); + } + + private static void setReportParameters(final QueueReport<?> report, final Map<String, String[]> parameterMap) + { + if(parameterMap != null && !parameterMap.isEmpty()) + { + Class<? extends QueueReport> clazz = report.getClass(); + for(Map.Entry<String,String[]> entry : parameterMap.entrySet()) + { + String key = entry.getKey(); + String[] value = entry.getValue(); + if(isValidName(key)) + { + + StringBuilder setterName = new StringBuilder("set"); + setterName.append(key.substring(0,1).toUpperCase()); + if(key.length()>1) + { + setterName.append(key.substring(1)); + } + Method method = null; + try + { + + if (value == null || value.length == 0 || value.length == 1) + { + try + { + method = clazz.getMethod(setterName.toString(), String.class); + method.invoke(report, value == null || value.length == 0 ? null : value[0]); + } + catch (NoSuchMethodException | IllegalAccessException e) + { + method = null; + } + } + if (method == null) + { + try + { + method = clazz.getMethod(setterName.toString(), String[].class); + method.invoke(report, new Object[] { value }); + } + catch (NoSuchMethodException | IllegalAccessException e) + { + LOGGER.info("Unknown parameter '" + + key + + "' (no setter) for report " + + report.getName()); + } + } + } + catch (InvocationTargetException e) + { + LOGGER.info("Error setting parameter '" + key + "' for report " + report.getName(), e); + } + } + else + { + LOGGER.info("Invalid parameter name '" + key + "' running report " + report.getName()); + } + } + } + } + + private static boolean isValidName(final String key) + { + if(key != null && key.length() != 0) + { + if(Character.isJavaIdentifierStart(key.charAt(0))) + { + for(int i = 1; i < key.length(); i++) + { + if(!Character.isJavaIdentifierPart(key.charAt(i))) + { + return false; + } + } + return true; + } + + } + return false; + + } + + private static QueueReport<?> getReport(final String reportName) + { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + for (final QueueReport report : ServiceLoader.load(QueueReport.class, classLoader)) + { + if (report.getName().equals(reportName)) + { + try + { + return report.getClass().newInstance(); + } + catch (InstantiationException | IllegalAccessException e) + { + // can't happen as by definition must have public noargs constructor + } + } + } + throw new IllegalArgumentException("Unknown report: " + reportName); + } + + public String getContentType() + { + return _report.getContentType(); + } + + + private static class ReportVisitor implements QueueEntryVisitor + { + + private final QueueReport _report; + + public ReportVisitor(final QueueReport report) + { + _report = report; + } + + @Override + public boolean visit(final QueueEntry entry) + { + _report.addMessage(convertMessage(entry.getMessage())); + return _report.isComplete(); + } + + + } + + + private static ReportableMessage convertMessage(final ServerMessage message) + { + return new ReportableMessage() + { + @Override + public String getInitialRoutingAddress() + { + return message.getInitialRoutingAddress(); + } + + @Override + public ReportableMessageHeader getMessageHeader() + { + return convertMessageHeader(message.getMessageHeader()); + } + + @Override + public ByteBuffer getContent() + { + ByteBuffer content = message.getContent(0, (int) getSize()); + + return content.asReadOnlyBuffer(); + } + + @Override + public boolean isPersistent() + { + return message.isPersistent(); + } + + @Override + public long getSize() + { + return message.getSize(); + } + + @Override + public long getExpiration() + { + return message.getExpiration(); + } + + @Override + public long getMessageNumber() + { + return message.getMessageNumber(); + } + + @Override + public long getArrivalTime() + { + return message.getArrivalTime(); + } + }; + } + + private static ReportableMessageHeader convertMessageHeader(final AMQMessageHeader messageHeader) + { + return new ReportableMessageHeader() + { + @Override + public String getCorrelationId() + { + return messageHeader.getCorrelationId(); + } + + @Override + public long getExpiration() + { + return messageHeader.getExpiration(); + } + + @Override + public String getUserId() + { + return messageHeader.getUserId(); + } + + @Override + public String getAppId() + { + return messageHeader.getAppId(); + } + + @Override + public String getMessageId() + { + return messageHeader.getMessageId(); + } + + @Override + public String getMimeType() + { + return messageHeader.getMimeType(); + } + + @Override + public String getEncoding() + { + return messageHeader.getEncoding(); + } + + @Override + public byte getPriority() + { + return messageHeader.getPriority(); + } + + @Override + public long getTimestamp() + { + return messageHeader.getTimestamp(); + } + + @Override + public String getType() + { + return messageHeader.getType(); + } + + @Override + public String getReplyTo() + { + return messageHeader.getReplyTo(); + } + + @Override + public Object getHeader(final String name) + { + return makeImmutable(messageHeader.getHeader(name)); + } + + @Override + public boolean containsHeaders(final Set<String> names) + { + return messageHeader.containsHeaders(names); + } + + @Override + public boolean containsHeader(final String name) + { + return messageHeader.containsHeader(name); + } + + @Override + public Collection<String> getHeaderNames() + { + return Collections.unmodifiableCollection(messageHeader.getHeaderNames()); + } + }; + } + + private static Object makeImmutable(final Object value) + { + if(value == null || IMMUTABLE_CLASSES.contains(value.getClass())) + { + return value; + } + else if(value instanceof byte[]) + { + return ByteBuffer.wrap((byte[])value).asReadOnlyBuffer(); + } + else if(value instanceof List) + { + List orig = (List) value; + List<Object> copy = new ArrayList<>(orig.size()); + for(Object element : orig) + { + copy.add(makeImmutable(element)); + } + return copy; + } + else if(value instanceof Map) + { + Map<?,?> orig = (Map<?,?>) value; + LinkedHashMap<Object,Object> copy = new LinkedHashMap<>(); + for(Map.Entry<?,?> entry : orig.entrySet()) + { + copy.put(makeImmutable(entry.getKey()),makeImmutable(entry.getValue())); + } + return copy; + } + else return null; + } + + private final QueueReport<T> _report; + + public final T runReport(Queue<?> queue) + { + _report.setQueue(queue); + ReportVisitor visitor = new ReportVisitor(_report); + queue.visit(visitor); + return _report.getReport(); + } +} diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportableMessage.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportableMessage.java new file mode 100644 index 0000000000..00b6c4abeb --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportableMessage.java @@ -0,0 +1,42 @@ +/* + * + * 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.server.management.plugin.report; + +import java.nio.ByteBuffer; + +public interface ReportableMessage +{ + String getInitialRoutingAddress(); + + ReportableMessageHeader getMessageHeader(); + + public ByteBuffer getContent(); + + boolean isPersistent(); + + long getSize(); + + long getExpiration(); + + long getMessageNumber(); + + long getArrivalTime(); +} diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportableMessageHeader.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportableMessageHeader.java new file mode 100644 index 0000000000..e78415f8d0 --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportableMessageHeader.java @@ -0,0 +1,58 @@ +/* + * + * 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.server.management.plugin.report; + +import java.util.Collection; +import java.util.Set; + +public interface ReportableMessageHeader +{ + String getCorrelationId(); + + long getExpiration(); + + String getUserId(); + + String getAppId(); + + String getMessageId(); + + String getMimeType(); + + String getEncoding(); + + byte getPriority(); + + long getTimestamp(); + + String getType(); + + String getReplyTo(); + + Object getHeader(String name); + + boolean containsHeaders(Set<String> names); + + boolean containsHeader(String name); + + Collection<String> getHeaderNames(); + +} diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverter.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverter.java index 331b50ea7c..0f1b7d03e9 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverter.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverter.java @@ -162,14 +162,14 @@ public class ConfiguredObjectToMapConverter .getAttributeTypes(confObject.getClass()) .get(name); - if (attribute.isSecure() && !(isSecureTransport && extractAsConfig)) + if (attribute.isSecureValue(value) && !(isSecureTransport && extractAsConfig)) { // do not expose actual secure attribute value // getAttribute() returns encoded value value = confObject.getAttribute(name); } - if(attribute.isOversized() && !extractAsConfig) + if(attribute.isOversized() && !extractAsConfig && !useActualValues) { String valueString = String.valueOf(value); if(valueString.length() > oversizeThreshold) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueReportServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueReportServlet.java new file mode 100644 index 0000000000..2b3def2dab --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueReportServlet.java @@ -0,0 +1,103 @@ +/* + * + * 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.server.management.plugin.servlet.rest; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.server.management.plugin.report.ReportRunner; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.VirtualHost; + +public class QueueReportServlet extends AbstractServlet +{ + @Override + protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws + IOException, + ServletException + { + String[] pathInfoElements = getPathInfoElements(request); + if(pathInfoElements != null && pathInfoElements.length == 3) + { + Queue<?> queue = getQueueFromRequest(request); + ReportRunner<?> reportRunner = ReportRunner.createRunner(pathInfoElements[2],request.getParameterMap()); + Object output = reportRunner.runReport(queue); + response.setContentType(reportRunner.getContentType()); + if(reportRunner.isBinaryReport()) + { + response.getOutputStream().write((byte[])output); + } + else + { + response.getWriter().write((String)output); + } + } + else + { + throw new IllegalArgumentException("Invalid path is specified"); + } + + } + + private Queue<?> getQueueFromRequest(HttpServletRequest request) + { + String[] pathInfoElements = getPathInfoElements(request); + if(pathInfoElements == null || pathInfoElements.length < 2) + { + throw new IllegalArgumentException("Invalid path is specified"); + } + String vhostName = pathInfoElements[0]; + String queueName = pathInfoElements[1]; + + VirtualHost<?,?,?> vhost = getBroker().findVirtualHostByName(vhostName); + if (vhost == null) + { + throw new IllegalArgumentException("Could not find virtual host with name '" + vhostName + "'"); + } + + Queue queueFromVirtualHost = getQueueFromVirtualHost(queueName, vhost); + if (queueFromVirtualHost == null) + { + throw new IllegalArgumentException("Could not find queue with name '" + queueName + "' on virtual host '" + vhost.getName() + "'"); + } + return queueFromVirtualHost; + } + + private Queue getQueueFromVirtualHost(String queueName, VirtualHost<?,?,?> vhost) + { + Queue queue = null; + + for(Queue<?> q : vhost.getQueues()) + { + + if(q.getName().equals(queueName)) + { + queue = q; + break; + } + } + return queue; + } + +} diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html index b787e701ec..10b79987a5 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html @@ -159,6 +159,23 @@ </div> </div> + <div id="formAddPort:maxOpenConnections" > + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.transports">Maximum number of connections:</label> + </div> + <div class="formLabel-controlCell"> + <input id="formAddPort.maxOpenConnections" type="text" + data-dojo-type="dijit.form.ValidationTextBox" + data-dojo-props=" + name: 'maxOpenConnections', + placeHolder: 'maximum number of connections', + promptMessage: 'Maximum number of concurrent connections permitted by this port. The <code>-1</code> signifies no limit is imposed.', + title: 'Enter a maximum number of connections'"/> + </div> + </div> + </div> + <div id="formAddPort:fieldsTransportSSL"> <div class="clear"> <div class="formLabel-labelCell"> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/editVirtualHostNode.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/editVirtualHostNode.html index cee18f7185..59597845a2 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/editVirtualHostNode.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/editVirtualHostNode.html @@ -19,31 +19,34 @@ <div class="dijitHidden"> <div data-dojo-type="dijit/Dialog" data-dojo-props="title:'Edit Virtual Host'" id="editVirtualHostNodeDialog"> <form id="editVirtualHostNodeForm" method="post" data-dojo-type="dijit/form/Form"> - <div id="editVirtualHostNode.contentPane"> - <div class="editNoteBanner">NOTE: All changes will only take effect after Virtual Host Node restart.</div> - <div class="clear"> - <div class="formLabel-labelCell tableContainer-labelCell">Name*:</div> - <div class="formLabel-controlCell tableContainer-valueCell"> - <input type="text" id="editVirtualHostNode.name" - data-dojo-type="dijit/form/ValidationTextBox" - data-dojo-props=" + <div id="editVirtualHostNode.allFields"> + <div id="editVirtualHostNode.contentPane"> + <div class="editNoteBanner">NOTE: All changes will only take effect after Virtual Host Node restart.</div> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Name*:</div> + <div class="formLabel-controlCell tableContainer-valueCell"> + <input type="text" id="editVirtualHostNode.name" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" name: 'name', placeHolder: 'name', required: true, missingMessage: 'Name must be supplied', disabled: true, title: 'Enter virtual host name'" /> - </div> - </div> + </div> + </div> - <div id="editVirtualHostNode.typeFields"></div> + <div id="editVirtualHostNode.typeFields"></div> - <div class="clear"></div> + <div class="clear"></div> - <div data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'Context variables', open: false"> - <div id="editVirtualHostNode.context" ></div> + <div data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'Context variables', open: false"> + <div id="editVirtualHostNode.context" ></div> + </div> + </div> </div> - </div> + <div class="dijitDialogPaneActionBar qpidDialogPaneActionBar"> <button data-dojo-type="dijit/form/Button" id="editVirtualHostNode.saveButton" data-dojo-props="label: 'Save'">Save</button> <button data-dojo-type="dijit/form/Button" id="editVirtualHostNode.cancelButton" data-dojo-props="label: 'Cancel'" ></button> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ResourceWidget.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ResourceWidget.js index f603c96ff3..bee38149da 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ResourceWidget.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ResourceWidget.js @@ -44,6 +44,7 @@ function (declare, array, lang, util, _WidgetBase, _TemplatedMixin, _WidgetsInTe fileReaderSupported: window.FileReader ? true : false, displayWarningWhenFileReaderUnsupported: false, isDebug: false, + uploaded: false, buildRendering: function() { @@ -74,7 +75,7 @@ function (declare, array, lang, util, _WidgetBase, _TemplatedMixin, _WidgetsInTe { // Fall back for IE8/9 which do not support FileReader this.uploadFields.style.display = "none"; - if (displayWarningWhenFileReaderUnsupported) + if (this.displayWarningWhenFileReaderUnsupported) { this.unsupportedWarning.className = this.unsupportedWarning.className.replace("hidden", ""); } @@ -127,6 +128,7 @@ function (declare, array, lang, util, _WidgetBase, _TemplatedMixin, _WidgetsInTe }, _fileClearButtonClicked: function(event) { + this.uploaded = false; this.uploader.reset(); this.set("value", this._resetValue); }, @@ -134,20 +136,17 @@ function (declare, array, lang, util, _WidgetBase, _TemplatedMixin, _WidgetsInTe { var serverPathValue = this.resourceLocation.get("value") || this._resetValue; this.set("value", serverPathValue); + if (this.uploaded ) + { + this.uploaded = !serverPathValue; + } }, _setValueAttr: function(newValue, priorityChange) { - var isDataUrl = newValue && newValue.indexOf("data:") == 0; + var isDataUrl = this.uploaded || ( newValue && newValue.indexOf("data:") == 0 ); if (isDataUrl) { - this.uploadData.style.display = "block"; - this.selectedFileStatus.className = "loadedIcon"; - this.selectedFile.innerHTML = this.selectedFileName || "uploaded data"; - this.resourceLocation.set("value", ""); - this.resourceLocation.setDisabled(true); - this.resourceLocation.set("required", false); - this.clearButton.setDisabled(false); - this.selectedFileStatus.className = "loadedIcon"; + this._initUploaded(true); } else { @@ -172,6 +171,25 @@ function (declare, array, lang, util, _WidgetBase, _TemplatedMixin, _WidgetsInTe _setPlaceHolderAttr: function(newValue) { this.resourceLocation.set("placeHolder", newValue); + }, + _setUploadedAttr: function(uploaded) + { + this.uploaded = uploaded; + this._initUploaded(uploaded); + }, + _initUploaded: function(uploaded) + { + if (uploaded) + { + this.uploadData.style.display = "block"; + this.selectedFileStatus.className = "loadedIcon"; + this.selectedFile.innerHTML = this.selectedFileName || "uploaded data"; + this.resourceLocation.set("value", ""); + this.resourceLocation.setDisabled(true); + this.resourceLocation.set("required", false); + this.clearButton.setDisabled(false); + this.selectedFileStatus.className = "loadedIcon"; + } } } ); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/ColumnDefDialog.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/ColumnDefDialog.js index d285dfaad6..a0b62082cb 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/ColumnDefDialog.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/ColumnDefDialog.js @@ -45,10 +45,15 @@ return declare("qpid.common.grid.ColumnDefDialog", null, { constructor: function(args){ var grid = this.grid = args.grid; - + var that = this; this.containerNode = dom.create("div", {innerHTML: template}); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances) + { + that._postParse(); + }); + }, + _postParse: function() + { var submitButton = registry.byNode(query(".displayButton", this.containerNode)[0]); this.closeButton = registry.byNode(query(".cancelButton", this.containerNode)[0]); var columnsContainer = query(".columnList", this.containerNode)[0]; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/RowNumberLimitDialog.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/RowNumberLimitDialog.js index db3ae5a2ea..e78670bf57 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/RowNumberLimitDialog.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/grid/RowNumberLimitDialog.js @@ -41,11 +41,17 @@ return declare("qpid.management.logs.RowNumberLimitDialog", null, { grid: null, dialog: null, - constructor: function(domNode, limitChangedCallback){ - + constructor: function(domNode, limitChangedCallback) + { + var that = this; this.containerNode = dom.create("div", {innerHTML: template}); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances) + { + that._postParse(domNode, limitChangedCallback); + }); + }, + _postParse: function(domNode, limitChangedCallback) + { this.rowNumberLimit = registry.byNode(query(".rowNumberLimit", this.containerNode)[0]) this.submitButton = registry.byNode(query(".submitButton", this.containerNode)[0]); this.closeButton = registry.byNode(query(".cancelButton", this.containerNode)[0]); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js index 60be40b62b..746eb4bbbc 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js @@ -528,40 +528,41 @@ define(["dojo/_base/xhr", return object1 === object2; } - util.parseHtmlIntoDiv = function(containerNode, htmlTemplateLocation) + util.parseHtmlIntoDiv = function(containerNode, htmlTemplateLocation, postParseCallback) { xhr.get({url: htmlTemplateLocation, sync: true, load: function(template) { containerNode.innerHTML = template; - parser.parse(containerNode); + parser.parse(containerNode).then(function(instances) + { + if (postParseCallback && typeof postParseCallback == "function") + { + postParseCallback(); + } + }); }}); } - util.buildUI = function(containerNode, parent, htmlTemplateLocation, fieldNames, obj) + util.buildUI = function(containerNode, parent, htmlTemplateLocation, fieldNames, obj, postParseCallback) { - this.parseHtmlIntoDiv(containerNode, htmlTemplateLocation); - if (fieldNames && obj) - { - for(var i=0; i<fieldNames.length;i++) + this.parseHtmlIntoDiv(containerNode, htmlTemplateLocation, + function() + { + if (fieldNames && obj) { - var fieldName = fieldNames[i]; - obj[fieldName]= query("." + fieldName, containerNode)[0]; + for(var i=0; i<fieldNames.length;i++) + { + var fieldName = fieldNames[i]; + obj[fieldName]= query("." + fieldName, containerNode)[0]; + } } - } - } - util.buildEditUI = function(containerNode, htmlTemplateLocation, fieldNamePrefix, fieldNames, data) - { - this.parseHtmlIntoDiv(containerNode, htmlTemplateLocation); - if (fieldNames) - { - for(var i = 0; i < fieldNames.length; i++) - { - var fieldName = fieldNames[i]; - var widget = registry.byId(fieldNamePrefix + fieldName); - widget.set("value", data[fieldName]); - } - } + if (postParseCallback && typeof postParseCallback == "function") + { + postParseCallback(); + } + }); + } util.updateUI = function(data, fieldNames, obj) @@ -736,6 +737,11 @@ define(["dojo/_base/xhr", return "^(\\d+)|" + singleContextVarRegexp + "$"; } + util.signedOrContextVarRegexp = function(constraints) + { + return "^(-?\\d+)|" + singleContextVarRegexp + "$"; + } + util.nameOrContextVarRegexp = function(constraints) { return "^(\\w+)|" + singleContextVarRegexp + "$"; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AccessControlProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AccessControlProvider.js index 1d4cc1447b..cf95a23819 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AccessControlProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AccessControlProvider.js @@ -52,17 +52,19 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); + parser.parse(contentPane.containerNode).then(function(instances) + { - that.accessControlProviderUpdater = new AccessControlProviderUpdater(contentPane.containerNode, that.modelObj, that.controller); + that.accessControlProviderUpdater = new AccessControlProviderUpdater(contentPane.containerNode, that.modelObj, that.controller); - var deleteButton = query(".deleteAccessControlProviderButton", contentPane.containerNode)[0]; - var deleteWidget = registry.byNode(deleteButton); - connect.connect(deleteWidget, "onClick", + var deleteButton = query(".deleteAccessControlProviderButton", contentPane.containerNode)[0]; + var deleteWidget = registry.byNode(deleteButton); + connect.connect(deleteWidget, "onClick", function(evt){ event.stop(evt); that.deleteAccessControlProvider(); }); + }); }}); }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js index 8545d2da75..cf9c32496a 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/AuthenticationProvider.js @@ -56,7 +56,8 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); + parser.parse(contentPane.containerNode).then(function(instances) + { var authProviderUpdater = new AuthProviderUpdater(contentPane.containerNode, that.modelObj, that.controller, that); that.authProviderUpdater = authProviderUpdater; @@ -97,6 +98,7 @@ define(["dojo/_base/xhr", } updater.add( that.authProviderUpdater ); + }); }}); }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js index a0a2e8324f..9720bc988b 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js @@ -82,14 +82,10 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); - + parser.parse(contentPane.containerNode).then(function(instances) + { that.brokerUpdater = new BrokerUpdater(contentPane.containerNode, that.modelObj, that.controller); - updater.add( that.brokerUpdater ); - - that.brokerUpdater.update(); - var logViewerButton = query(".logViewer", contentPane.containerNode)[0]; registry.byNode(logViewerButton).on("click", function(evt){ that.controller.show("logViewer", ""); @@ -233,6 +229,7 @@ define(["dojo/_base/xhr", "Are you sure you want to delete access control provider"); } ); + }); }}); }; @@ -554,6 +551,9 @@ define(["dojo/_base/xhr", }); }, gridProperties, EnhancedGrid); that.displayACLWarnMessage(aclData); + + updater.add( that); + }); } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js index 34d9a9b2de..bbb4dc8322 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js @@ -50,14 +50,12 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); - - that.connectionUpdater = new ConnectionUpdater(contentPane.containerNode, that.modelObj, that.controller); - - updater.add( that.connectionUpdater ); - - that.connectionUpdater.update(); - + parser.parse(contentPane.containerNode).then(function(instances) + { + that.connectionUpdater = new ConnectionUpdater(contentPane.containerNode, that.modelObj, that.controller); + updater.add( that.connectionUpdater ); + that.connectionUpdater.update(); + }); }}); }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js index 2ac881abc1..1f1b8361a2 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js @@ -69,7 +69,8 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); + parser.parse(contentPane.containerNode).then(function(instances) + { that.exchangeUpdater = new ExchangeUpdater(contentPane.containerNode, that.modelObj, that.controller); @@ -106,7 +107,7 @@ define(["dojo/_base/xhr", that.deleteExchange(); }); } - + }); }}); }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js index f739e52665..9b32d0e6b2 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js @@ -56,8 +56,13 @@ define(["dojo/_base/xhr", var that = this; this.contentPane = contentPane; contentPane.containerNode.innerHTML = template; - parser.parse(contentPane.containerNode); + parser.parse(contentPane.containerNode).then(function(instances) { that.onOpen(); }); + }; + GroupProvider.prototype.onOpen = function() + { + var that = this; + var contentPane = this.contentPane; this.groupProviderUpdater = new GroupProviderUpdater(contentPane.containerNode, this.modelObj, this.controller); // load data diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js index 0f23053c2d..dfcb712740 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js @@ -51,7 +51,8 @@ define(["dojo/dom", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); + parser.parse(contentPane.containerNode).then(function(instances) + { that.keyStoreUpdater = new KeyStoreUpdater(contentPane.containerNode, that.modelObj, that.controller, that.url); that.keyStoreUpdater.update(); @@ -75,6 +76,7 @@ define(["dojo/dom", addStore.show(data[0], that.url); }); }); + }); }}); }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Plugin.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Plugin.js index 47f6cffe5a..300754ed8c 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Plugin.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Plugin.js @@ -48,9 +48,10 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); - - that.pluginUpdater = new PluginUpdater(contentPane.containerNode, that.modelObj, that.controller); + parser.parse(contentPane.containerNode).then(function(instances) + { + that.pluginUpdater = new PluginUpdater(contentPane.containerNode, that.modelObj, that.controller); + }); }}); }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js index 1bf41ec730..91407c0e83 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js @@ -51,8 +51,8 @@ define(["dojo/dom", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); - + parser.parse(contentPane.containerNode).then(function(instances) + { that.portUpdater = new PortUpdater(contentPane.containerNode, that.modelObj, that.controller, "api/latest/port/" + encodeURIComponent(that.name)); updater.add( that.portUpdater ); @@ -72,6 +72,7 @@ define(["dojo/dom", function(evt){ that.showEditDialog(); }); + }); }}); }; @@ -137,12 +138,15 @@ define(["dojo/dom", "needClientAuthValue", "wantClientAuthValue", "trustStoresValue", + "connectionCountValue", + "maxOpenConnectionsValue", "authenticationProvider", "bindingAddress", "keyStore", "needClientAuth", "wantClientAuth", - "trustStores" + "trustStores", + "maxOpenConnections" ]); this.query = url; @@ -150,6 +154,7 @@ define(["dojo/dom", xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) { that.portData = data[0]; + util.flattenStatistics( that.portData ); that.updateHeader(); }); @@ -177,6 +182,9 @@ define(["dojo/dom", this.protocolsValue.innerHTML = printArray( "protocols", this.portData); this.transportsValue.innerHTML = printArray( "transports", this.portData); this.bindingAddressValue.innerHTML = this.portData[ "bindingAddress" ] ? entities.encode(String(this.portData[ "bindingAddress" ])) : "" ; + this.connectionCountValue.innerHTML = this.portData[ "connectionCount" ] ? entities.encode(String(this.portData[ "connectionCount" ])) : "0" ; + this.maxOpenConnectionsValue.innerHTML = (this.portData[ "maxOpenConnections" ] && this.portData[ "maxOpenConnections" ] >= 0) ? entities.encode(String(this.portData[ "maxOpenConnections" ])) : "(no limit)" ; + this.keyStoreValue.innerHTML = this.portData[ "keyStore" ] ? entities.encode(String(this.portData[ "keyStore" ])) : ""; this.needClientAuthValue.innerHTML = "<input type='checkbox' disabled='disabled' "+(this.portData[ "needClientAuth" ] ? "checked='checked'": "")+" />" ; this.wantClientAuthValue.innerHTML = "<input type='checkbox' disabled='disabled' "+(this.portData[ "wantClientAuth" ] ? "checked='checked'": "")+" />" ; @@ -190,6 +198,9 @@ define(["dojo/dom", this.needClientAuth.style.display = "needClientAuth" in typeMetaData.attributes ? "block" : "none"; this.wantClientAuth.style.display = "wantClientAuth" in typeMetaData.attributes ? "block" : "none"; this.trustStores.style.display = "trustStores" in typeMetaData.attributes ? "block" : "none"; + + this.maxOpenConnections.style.display = "maxOpenConnections" in typeMetaData.attributes ? "block" : "none"; + }; PortUpdater.prototype.update = function() @@ -200,6 +211,7 @@ define(["dojo/dom", xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) { thisObj.portData = data[0]; + util.flattenStatistics( thisObj.portData ); thisObj.updateHeader(); }); }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Preferences.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Preferences.js index f9982a1699..c8e1d17e06 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Preferences.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Preferences.js @@ -65,8 +65,15 @@ function (declare, xhr, event, connect, dom, domConstruct, parser, json, Memory, this.userPreferences = {}; this.domNode = domConstruct.create("div", {innerHTML: markup}); - this.preferencesDialog = parser.parse(this.domNode)[0]; - + parser.parse(this.domNode).then(function(instances) + { + that._postParse(); + }); + }, + _postParse: function() + { + var that = this; + this.preferencesDialog = registry.byId("preferences.preferencesDialog"); for(var i=0; i<preferenceNames.length; i++) { var name = preferenceNames[i]; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/PreferencesProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/PreferencesProvider.js index 0d40669823..c145ba0d34 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/PreferencesProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/PreferencesProvider.js @@ -51,8 +51,8 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { node.innerHTML = data; - parser.parse(node); - + parser.parse(node).then(function(instances) + { that.containerNode = node; that.parentObject = parentObject; that.preferencesProviderType=query(".preferencesProviderType", node)[0]; @@ -65,6 +65,7 @@ define(["dojo/_base/xhr", editPreferencesProviderWidget.on("click", function(evt){ event.stop(evt); that.editPreferencesProvider();}); var deletePreferencesProviderWidget = registry.byNode(that.deletePreferencesProviderButton); deletePreferencesProviderWidget.on("click", function(evt){ event.stop(evt); that.deletePreferencesProvider();}); + }); }}); }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js index 5b441a7b2f..55d0df1241 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js @@ -79,7 +79,8 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); + parser.parse(contentPane.containerNode).then(function(instances) + { that.queueUpdater = new QueueUpdater(contentPane.containerNode, that, that.controller); @@ -180,6 +181,8 @@ define(["dojo/_base/xhr", editQueue.show({nodeName:that.modelObj.parent.parent.name, hostName:that.modelObj.parent.name,queueName:that.name}); }); UserPreferences.addListener(that); + + }); }}); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/TrustStore.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/TrustStore.js index 82e2b204f9..fa6b63212e 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/TrustStore.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/TrustStore.js @@ -51,7 +51,8 @@ define(["dojo/dom", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); + parser.parse(contentPane.containerNode).then(function(instances) + { that.keyStoreUpdater = new KeyStoreUpdater(contentPane.containerNode, that.modelObj, that.controller, that.url); that.keyStoreUpdater.update(); @@ -75,6 +76,7 @@ define(["dojo/dom", addStore.show(data[0], that.url); }); }); + }); }}); }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js index 434e119736..e4482cc39e 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js @@ -55,8 +55,8 @@ define(["dojo/_base/xhr", load: function(data) { var containerNode = contentPane.containerNode; containerNode.innerHTML = data; - parser.parse(containerNode); - + parser.parse(containerNode).then(function(instances) + { that.vhostUpdater = new Updater(containerNode, that.modelObj, that.controller, that); var addQueueButton = query(".addQueueButton", containerNode)[0]; @@ -149,6 +149,7 @@ define(["dojo/_base/xhr", that.vhostUpdater.update(); updater.add( that.vhostUpdater ); + }); }}); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHostNode.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHostNode.js index 76eaadad18..837ff04c78 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHostNode.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHostNode.js @@ -56,8 +56,10 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); - that.onOpen(contentPane.containerNode) + parser.parse(contentPane.containerNode).then(function(instances) + { + that.onOpen(contentPane.containerNode) + }); }}); }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/accesscontrolprovider/AclFile.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/accesscontrolprovider/AclFile.js index 12c8677c11..e8250217c6 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/accesscontrolprovider/AclFile.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/accesscontrolprovider/AclFile.js @@ -53,14 +53,14 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { node.innerHTML = data; - parser.parse(node); - + parser.parse(node).then(function(instances) + { that.groupDatabaseUpdater= new AclFileUpdater(node, aclProviderObj, controller); updater.add( that.groupDatabaseUpdater); that.groupDatabaseUpdater.update(); - + }); }}); } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/accesscontrolprovider/aclfile/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/accesscontrolprovider/aclfile/add.js index e42dafb3c3..2c25149091 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/accesscontrolprovider/aclfile/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/accesscontrolprovider/aclfile/add.js @@ -31,8 +31,11 @@ define(["dojo/dom","dojo/query","dijit/registry","qpid/common/util"], show: function(data) { var that=this; - util.parseHtmlIntoDiv(data.containerNode, "accesscontrolprovider/aclfile/add.html"); - + util.parseHtmlIntoDiv(data.containerNode, "accesscontrolprovider/aclfile/add.html", function(){that._postParse(data);}); + }, + _postParse: function(data) + { + var that=this; this.aclServerPath = registry.byId("addAccessControlProvider.serverPath"); this.aclUploadFields = dom.byId("addAccessControlProvider.uploadFields"); this.aclSelectedFileContainer = dom.byId("addAccessControlProvider.selectedFile"); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAccessControlProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAccessControlProvider.js index 38a6c8e841..83bf23f669 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAccessControlProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAccessControlProvider.js @@ -53,8 +53,11 @@ define(["dojo/_base/lang", { var that=this; this.containerNode = construct.create("div", {innerHTML: template}); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances){ that._postParse(); }); + }, + _postParse: function() + { + var that=this; this.accessControlProviderName = registry.byId("addAccessControlProvider.name"); this.accessControlProviderName.set("regExpGen", util.nameOrContextVarRegexp); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js index 17b7edcec9..ccae89d6c1 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js @@ -56,8 +56,11 @@ define(["dojo/_base/xhr", { var that=this; this.containerNode = construct.create("div", {innerHTML: template}); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances) { that._postParse(); }); + }, + _postParse: function() + { + var that = this; this.authenticationProviderName = registry.byId("addAuthenticationProvider.name"); this.authenticationProviderName.set("regExpGen", util.nameOrContextVarRegexp); this.authenticationProviderName.on("change", function(newValue){that.preferencesProviderForm.preferencesProviderNameWidget.set("value",newValue);}); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addGroupProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addGroupProvider.js index f158b8ceb6..81ce40ebe9 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addGroupProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addGroupProvider.js @@ -53,8 +53,11 @@ define([ { var that=this; this.containerNode = construct.create("div", {innerHTML: template}); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances) { that._postParse(); }); + }, + _postParse: function() + { + var that=this; this.groupProviderName = registry.byId("addGroupProvider.name"); this.groupProviderName.set("regExpGen", util.nameOrContextVarRegexp); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js index 43ccdfff70..befb5df9c1 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js @@ -79,6 +79,10 @@ define(["dojo/_base/xhr", registry.byId("formAddPort.bindingAddress").set("disabled", ! ("bindingAddress" in typeMetaData.attributes)); dom.byId("formAddPort:fieldsBindingAddress").style.display = "bindingAddress" in typeMetaData.attributes ? "block" : "none"; + //maxOpenConnections + registry.byId("formAddPort.maxOpenConnections").set("disabled", ! ("maxOpenConnections" in typeMetaData.attributes)); + dom.byId("formAddPort:maxOpenConnections").style.display = "maxOpenConnections" in typeMetaData.attributes ? "block" : "none"; + //transports var transportsMultiSelect = dom.byId("formAddPort.transports"); var transportsValidValues = typeMetaData.attributes.transports.validValues; @@ -314,6 +318,7 @@ define(["dojo/_base/xhr", var nameWidget = registry.byId("formAddPort.name"); var typeWidget = registry.byId("formAddPort.type"); var portWidget = registry.byId("formAddPort.port"); + var maxOpenConnectionsWidget = registry.byId("formAddPort.maxOpenConnections"); var editWarning = dojo.byId("portEditWarning"); var providerWidget = registry.byId("formAddPort.authenticationProvider"); @@ -418,6 +423,13 @@ define(["dojo/_base/xhr", bindAddressWidget.set("disabled", ! ("bindingAddress" in typeMetaData.attributes)); dom.byId("formAddPort:fieldsBindingAddress").style.display = "bindingAddress" in typeMetaData.attributes ? "block" : "none"; + //maxOpenConnections + var maxOpenConnectionsWidget = registry.byId("formAddPort.maxOpenConnections"); + maxOpenConnectionsWidget.set("regExpGen", util.signedOrContextVarRegexp); + maxOpenConnectionsWidget.set("value", port.maxOpenConnections ? port.maxOpenConnections : ""); + maxOpenConnectionsWidget.set("disabled", ! ("maxOpenConnections" in typeMetaData.attributes)); + dom.byId("formAddPort:maxOpenConnections").style.display = "maxOpenConnections" in typeMetaData.attributes ? "block" : "none"; + //ssl keystoreWidget.set("value", port.keyStore ? port.keyStore : ""); if (port.trustStores) @@ -447,6 +459,7 @@ define(["dojo/_base/xhr", truststoreWidget.initialValue = port.trustStores; transportWidget.initialValue = transportWidget.value; providerWidget.initialValue = providerWidget.value; + maxOpenConnectionsWidget.initialValue = maxOpenConnectionsWidget.value; registry.byId("addPort").show(); util.applyMetadataToWidgets(registry.byId("addPort").domNode, "Port", portType); @@ -465,8 +478,8 @@ define(["dojo/_base/xhr", nameWidget.set("disabled", false); nameWidget.set("regExpGen", util.nameOrContextVarRegexp); - portWidget.set("regExpGen", util.numericOrContextVarRegexp); + maxOpenConnectionsWidget.set("regExpGen", util.signedOrContextVarRegexp); editWarning.style.display = "none"; registry.byId("addPort").show(); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPreferencesProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPreferencesProvider.js index 072b202b23..2136318dfb 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPreferencesProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPreferencesProvider.js @@ -40,8 +40,11 @@ define([ { var that=this; this.containerNode = construct.create("div", {innerHTML: template}); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances) { that._postParse(); }); + }, + _postParse: function() + { + var that=this; this.preferencesProviderForm = registry.byId("addPreferencesProvider.preferencesProvider"); this.dialog = registry.byId("addPreferencesProvider"); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addStore.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addStore.js index 5a42f12870..caf14d0cc8 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addStore.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addStore.js @@ -53,8 +53,11 @@ define(["dojo/_base/lang", { var that=this; this.containerNode = construct.create("div", {innerHTML: template}); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances) { that._postParse(); }); + }, + _postParse: function() + { + var that=this; this.storeName = registry.byId("addStore.name"); this.storeName.set("regExpGen", util.nameOrContextVarRegexp); @@ -81,11 +84,11 @@ define(["dojo/_base/lang", show: function(effectiveData) { this.effectiveData = effectiveData; + this._destroyTypeFields(this.containerNode); this.storeForm.reset(); if (effectiveData) { - this._destroyTypeFields(this.containerNode); this._initFields(effectiveData); } this.storeName.set("disabled", effectiveData == null ? false : true); @@ -185,11 +188,6 @@ define(["dojo/_base/lang", { typeUI.show({containerNode:typeFieldsContainer, parent: that, data: that.initialData, effectiveData: that.effectiveData}); util.applyMetadataToWidgets(typeFieldsContainer, category, type); - if (that.effectiveData) - { - typeUI.update(that.effectiveData); - that.effectiveData = undefined; - } } catch(e) { diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js index f379361a09..21927ea0e5 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js @@ -57,8 +57,11 @@ define(["dojo/_base/xhr", { var that=this; this.containerNode = domConstruct.create("div", {innerHTML: template}); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances) { that._postParse(); }); + }, + _postParse: function() + { + var that=this; var virtualHostNodeName = registry.byId("addVirtualHostNode.nodeName"); virtualHostNodeName.set("regExpGen", util.nameOrContextVarRegexp); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js index 96083843fa..e6f2249f65 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js @@ -51,8 +51,10 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { node.innerHTML = data; - parser.parse(node); - that.init(node, authProviderObj, controller); + parser.parse(node).then(function(instances) + { + that.init(node, authProviderObj, controller); + }); }}); } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/base64md5passwordfile/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/base64md5passwordfile/add.js index a593b14fd6..cbc5ce356d 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/base64md5passwordfile/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/base64md5passwordfile/add.js @@ -24,12 +24,15 @@ define(["dojo/query","dijit/registry","qpid/common/util"], return { show: function(data) { - util.parseHtmlIntoDiv(data.containerNode, "authenticationprovider/filebased/add.html"); - if (data.data) + util.parseHtmlIntoDiv(data.containerNode, "authenticationprovider/filebased/add.html", + function() { - var path = registry.byNode(query(".path", data.containerNode)[0]); - path.set("value", data.data.path); - } + if (data.data) + { + var path = registry.byNode(query(".path", data.containerNode)[0]); + path.set("value", data.data.path); + } + }); } }; } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/external/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/external/add.js index 6147bf5249..979a10cae9 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/external/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/external/add.js @@ -24,12 +24,15 @@ define(["dojo/query","dijit/registry","qpid/common/util"], return { show: function(data) { - util.parseHtmlIntoDiv(data.containerNode, "authenticationprovider/external/add.html"); - if (data.data) + util.parseHtmlIntoDiv(data.containerNode, "authenticationprovider/external/add.html", + function() { - var useFullDN = registry.byNode(query(".useFullDN", data.containerNode)[0]); - useFullDN.set("value", data.data.useFullDN); - } + if (data.data) + { + var useFullDN = registry.byNode(query(".useFullDN", data.containerNode)[0]); + useFullDN.set("value", data.data.useFullDN); + } + }); } }; } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/plainpasswordfile/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/plainpasswordfile/add.js index a593b14fd6..cbc5ce356d 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/plainpasswordfile/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/plainpasswordfile/add.js @@ -24,12 +24,15 @@ define(["dojo/query","dijit/registry","qpid/common/util"], return { show: function(data) { - util.parseHtmlIntoDiv(data.containerNode, "authenticationprovider/filebased/add.html"); - if (data.data) + util.parseHtmlIntoDiv(data.containerNode, "authenticationprovider/filebased/add.html", + function() { - var path = registry.byNode(query(".path", data.containerNode)[0]); - path.set("value", data.data.path); - } + if (data.data) + { + var path = registry.byNode(query(".path", data.containerNode)[0]); + path.set("value", data.data.path); + } + }); } }; } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/add.js index 2c0dc688e9..4e04bfd6f0 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/authenticationprovider/simpleldap/add.js @@ -24,8 +24,11 @@ define(["dojo/_base/xhr","dojo/query","dijit/registry","qpid/common/util","qpid/ return { show: function(data) { - util.parseHtmlIntoDiv(data.containerNode, "authenticationprovider/simpleldap/add.html"); - + var that = this; + util.parseHtmlIntoDiv(data.containerNode, "authenticationprovider/simpleldap/add.html", function(){that._postParse(data);}); + }, + _postParse: function(data) + { var that = this; xhr.get({url: "api/latest/truststore", sync: true, handleAs: "json"}).then( function(trustStores) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editBroker.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editBroker.js index 07938fe8e7..08a4a84d47 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editBroker.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editBroker.js @@ -55,8 +55,11 @@ define(["dojo/_base/xhr", { var that=this; this.containerNode = domConstruct.create("div", {innerHTML: template}); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances){ that._postParse();}); + }, + _postParse: function() + { + var that=this; this.dialog = registry.byId("editBrokerDialog"); this.saveButton = registry.byId("editBroker.saveButton"); this.cancelButton = registry.byId("editBroker.cancelButton"); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editQueue.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editQueue.js index 06c9672efe..91fc9891cf 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editQueue.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editQueue.js @@ -79,7 +79,11 @@ define(["dojo/_base/xhr", { var that=this; this.containerNode = domConstruct.create("div", {innerHTML: template}); - parser.parse(this.containerNode); + parser.parse(this.containerNode).then(function(instances){ that._postParse();}); + }, + _postParse: function() + { + var that=this; this.allFieldsContainer = dom.byId("formEditQueue.allFields"); this.dialog = registry.byId("editQueue"); this.saveButton = registry.byId("formEditQueue.saveButton"); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHost.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHost.js index 849fd9378c..b47052b546 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHost.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHost.js @@ -56,7 +56,11 @@ define(["dojo/_base/xhr", { var that=this; this.containerNode = domConstruct.create("div", {innerHTML: template}); - parser.parse(this.containerNode); + parser.parse(this.containerNode).then(function(instances){ that._postParse();}); + }, + _postParse: function() + { + var that=this; this.allFieldsContainer = dom.byId("editVirtualHost.allFields"); this.typeFieldsContainer = dom.byId("editVirtualHost.typeFields"); this.dialog = registry.byId("editVirtualHostDialog"); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHostNode.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHostNode.js index 4f815f1f1d..b5a7edab2d 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHostNode.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHostNode.js @@ -52,7 +52,12 @@ define(["dojo/_base/xhr", { var that=this; this.containerNode = domConstruct.create("div", {innerHTML: template}); - parser.parse(this.containerNode); + parser.parse(this.containerNode).then(function(instances){ that._postParse();}); + }, + _postParse: function() + { + var that=this; + this.allFieldsContainer = dom.byId("editVirtualHostNode.allFields"); this.typeFieldsContainer = dom.byId("editVirtualHostNode.typeFields"); this.dialog = registry.byId("editVirtualHostNodeDialog"); this.saveButton = registry.byId("editVirtualHostNode.saveButton"); @@ -160,7 +165,7 @@ define(["dojo/_base/xhr", TypeUI.show({containerNode:that.typeFieldsContainer, parent: that, data: actualData, effectiveData: effectiveData}); that.form.connectChildren(); - util.applyMetadataToWidgets(that.allFieldsContainer, "VirtualHostNode", actualData.type); + util.applyToWidgets(that.allFieldsContainer, "VirtualHostNode", actualData.type, actualData); } catch(e) { diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/Group.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/Group.js index 8ac6be04cc..7832941e71 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/Group.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/Group.js @@ -76,8 +76,8 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { contentPane.containerNode.innerHTML = data; - parser.parse(contentPane.containerNode); - + parser.parse(contentPane.containerNode).then(function(instances) + { that.groupUpdater = new GroupUpdater(contentPane.containerNode, that, that.controller); that.groupUpdater.update(); updater.add( that.groupUpdater ); @@ -100,6 +100,7 @@ define(["dojo/_base/xhr", "Are you sure you want to remove group member"); } ); + }); }}); }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/GroupManagingGroupProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/GroupManagingGroupProvider.js index ea12280d0d..5788fad8af 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/GroupManagingGroupProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/GroupManagingGroupProvider.js @@ -54,9 +54,9 @@ define(["dojo/_base/xhr", var that = this; this.name = groupProviderObj.name; node.innerHTML = template; - parser.parse(node); this.controller = controller; - + parser.parse(node).then(function(instances) + { var groupDiv = query(".groups", node)[0]; var gridProperties = { @@ -75,7 +75,7 @@ define(["dojo/_base/xhr", indirectSelection: true }}; - this.groupsGrid = new UpdatableStore([], groupDiv, + that.groupsGrid = new UpdatableStore([], groupDiv, [ { name: "Group Name", field: "name", width: "100%" } ], function(obj) { connect.connect(obj.grid, "onRowDblClick", obj.grid, @@ -86,10 +86,11 @@ define(["dojo/_base/xhr", that.controller.show("group", name, groupProviderObj, theItem.id); }); }, gridProperties, EnhancedGrid); - var addGroupButton = query(".addGroupButton", node)[0]; - registry.byNode(addGroupButton).on("click", function(evt){ addGroup.show(groupProviderObj.name) }); - var deleteWidget = registry.byNode(query(".deleteGroupButton", node)[0]); - deleteWidget.on("click", function(evt){ event.stop(evt); that.deleteGroups(); }); + var addGroupButton = query(".addGroupButton", node)[0]; + registry.byNode(addGroupButton).on("click", function(evt){ addGroup.show(groupProviderObj.name) }); + var deleteWidget = registry.byNode(query(".deleteGroupButton", node)[0]); + deleteWidget.on("click", function(evt){ event.stop(evt); that.deleteGroups(); }); + }); } GroupManagingGroupProvider.prototype.deleteGroups = function() diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/groupfile/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/groupfile/add.js index f28f250134..6543d6a797 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/groupfile/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/groupfile/add.js @@ -25,12 +25,15 @@ define(["dojo/dom","dojo/query", "dojo/_base/array", "dijit/registry","qpid/comm return { show: function(data) { var that=this; - util.parseHtmlIntoDiv(data.containerNode, "groupprovider/groupfile/add.html"); - if (data.data) + util.parseHtmlIntoDiv(data.containerNode, "groupprovider/groupfile/add.html", + function() { - var pathWidget = registry.byNode(query(".addGroupProviderPath", data.containerNode)[0]); - pathWidget.set("value", data.data.path); - } + if (data.data) + { + var pathWidget = registry.byNode(query(".addGroupProviderPath", data.containerNode)[0]); + pathWidget.set("value", data.data.path); + } + }); } }; } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogFileDownloadDialog.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogFileDownloadDialog.js index 29054b5379..c013a88d0a 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogFileDownloadDialog.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogFileDownloadDialog.js @@ -51,9 +51,13 @@ return declare("qpid.management.logs.LogFileDownloadDialog", null, { closeButton: null, constructor: function(args){ + var that = this; this.containerNode = domConstruct.create("div", {innerHTML: template}); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances){that._postParse();}); + }, + _postParse: function() + { + var that = this; this.logFileTreeDiv = query(".logFilesGrid", this.containerNode)[0]; this.downloadLogsButton = registry.byNode(query(".downloadLogsButton", this.containerNode)[0]); this.closeButton = registry.byNode(query(".downloadLogsDialogCloseButton", this.containerNode)[0]); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogViewer.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogViewer.js index 470ad28cd2..4a76110a58 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogViewer.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/logs/LogViewer.js @@ -62,9 +62,13 @@ define(["dojo/_base/xhr", this.contentPane = contentPane; this.contentPane.containerNode.innerHTML = markup; - parser.parse(this.contentPane.containerNode); + parser.parse(this.contentPane.containerNode).then(function(instances){self._postParse();}); + }; + LogViewer.prototype._postParse = function() + { + var self = this; - this.downloadLogsButton = registry.byNode(query(".downloadLogs", contentPane.containerNode)[0]); + this.downloadLogsButton = registry.byNode(query(".downloadLogs", this.contentPane.containerNode)[0]); this.downloadLogDialog = new LogFileDownloadDialog(); this.downloadLogsButton.on("click", function(evt){ diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js index 69f520bf42..4c32cce7cd 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js @@ -47,14 +47,15 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { node.innerHTML = data; - parser.parse(node); - + parser.parse(node).then(function(instances) + { that.managementHttpUpdater= new ManagementHttpUpdater(node, pluginObject, controller); that.managementHttpUpdater.update(true); updater.add( that.managementHttpUpdater); var editButton = query(".editPluginButton", node)[0]; connect.connect(registry.byNode(editButton), "onClick", function(evt){ that.edit(); }); + }); }}); } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementjmx.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementjmx.js index 3579d258e9..4141b6b670 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementjmx.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementjmx.js @@ -43,14 +43,15 @@ define(["dojo/_base/xhr", sync: true, load: function(data) { node.innerHTML = data; - parser.parse(node); - + parser.parse(node).then(function(instances) + { that.managementJmxUpdater= new ManagementJmxUpdater(node, pluginObject, controller); that.managementJmxUpdater.update(true); updater.add( that.managementJmxUpdater); var editButton = query(".editPluginButton", node)[0]; connect.connect(registry.byNode(editButton), "onClick", function(evt){ that.edit(); }); + }); }}); } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/preferencesprovider/filesystempreferences/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/preferencesprovider/filesystempreferences/add.js index d030ea2832..929d318b4f 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/preferencesprovider/filesystempreferences/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/preferencesprovider/filesystempreferences/add.js @@ -23,12 +23,15 @@ define(["dojo/query", "dijit/registry", "qpid/common/util"], return { show: function (data) { - util.parseHtmlIntoDiv(data.containerNode, "preferencesprovider/filesystempreferences/add.html"); - if (data.data) + util.parseHtmlIntoDiv(data.containerNode, "preferencesprovider/filesystempreferences/add.html", + function() { - var pathWidget = registry.byNode(query(".addPreferencesProviderPath", data.containerNode)[0]); - pathWidget.set("value", data.data.path); - } + if (data.data) + { + var pathWidget = registry.byNode(query(".addPreferencesProviderPath", data.containerNode)[0]); + pathWidget.set("value", data.data.path); + } + }); } }; } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/preferencesprovider/filesystempreferences/show.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/preferencesprovider/filesystempreferences/show.js index 46dedcc9f5..660b6673f2 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/preferencesprovider/filesystempreferences/show.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/preferencesprovider/filesystempreferences/show.js @@ -32,8 +32,10 @@ define(["dojo/_base/xhr", sync: true, load: function(template) { containerNode.innerHTML = template; - parser.parse(containerNode); - that.preferencesProviderPath=query(".fileSystemPreferencesProviderPath", containerNode)[0]; + parser.parse(containerNode).then(function(instances) + { + that.preferencesProviderPath=query(".fileSystemPreferencesProviderPath", containerNode)[0]; + }); }}); } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filekeystore/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filekeystore/add.js index b4c45d8f99..dfe8e5059a 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filekeystore/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filekeystore/add.js @@ -18,30 +18,41 @@ * under the License. * */ -define(["dojo/dom","dojo/query", "dojo/_base/array", "dijit/registry","qpid/common/util", "qpid/common/metadata"], - function (dom, query, array, registry, util, metadata) +define(["dojo/dom", + "dojo/query", + "dojo/_base/array", + "dijit/registry", + "qpid/common/util", + "qpid/common/metadata", + "dojo/parser", + "dojo/text!store/filekeystore/add.html", + "dojo/domReady!"], + function (dom, query, array, registry, util, metadata, parser, template) { var addKeyStore = { - init: function() - { - }, show: function(data) { var that=this; - util.parseHtmlIntoDiv(data.containerNode, "store/filekeystore/add.html"); - this.containerNode = data.containerNode; + data.containerNode.innerHTML = template; + parser.parse(this.containerNode).then(function(instances) + { + that.keyStoreOldBrowserWarning = dom.byId("addStore.oldBrowserWarning"); - this.keyStoreOldBrowserWarning = dom.byId("addStore.oldBrowserWarning"); + if (!window.FileReader) + { + that.keyStoreOldBrowserWarning.innerHTML = "File upload requires a more recent browser with HTML5 support"; + that.keyStoreOldBrowserWarning.className = that.keyStoreOldBrowserWarning.className.replace("hidden", ""); + } - this.addButton = data.parent.addButton; + if (data.effectiveData) + { + that.update(data.effectiveData); + } - if (!window.FileReader) - { - this.keyStoreOldBrowserWarning.innerHTML = "File upload requires a more recent browser with HTML5 support"; - this.keyStoreOldBrowserWarning.className = this.keyStoreOldBrowserWarning.className.replace("hidden", ""); - } + util.applyMetadataToWidgets(data.containerNode, "KeyStore", "FileKeyStore"); + }); }, update: function(effectiveData) { @@ -53,28 +64,38 @@ define(["dojo/dom","dojo/query", "dojo/_base/array", "dijit/registry","qpid/comm if (name in attributes ) { var attribute = attributes[name]; - if (attribute.secure || attribute.oversize) - { - item.set("required", false); - item.set("placeHolder", effectiveData[name]); - } - else + var value = effectiveData[name]; + if (value) { - item.set("value", effectiveData[name]); + if (attribute.secure) + { + if (!/^\*+/.test(value) ) + { + item.set("value", value); + } + else + { + item.set("required", false); + if (name == "storeUrl") + { + item.set("uploaded", true) + } + else + { + item.set("placeHolder", value); + } + } + } + else + { + item.set("value", value); + } } } }); } }; - try - { - addKeyStore.init(); - } - catch(e) - { - console.warn(e); - } return addKeyStore; } ); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filetruststore/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filetruststore/add.js index e04ee1a835..5893ce0d2d 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filetruststore/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filetruststore/add.js @@ -18,31 +18,42 @@ * under the License. * */ -define(["dojo/dom","dojo/query", "dojo/_base/array", "dijit/registry","qpid/common/util", "qpid/common/metadata"], - function (dom, query, array, registry, util, metadata) +define(["dojo/dom", + "dojo/query", + "dojo/_base/array", + "dijit/registry", + "qpid/common/util", + "qpid/common/metadata", + "dojo/parser", + "dojo/text!store/filetruststore/add.html", + "dojo/domReady!"], + function (dom, query, array, registry, util, metadata, parser, template) { var addTrustStore = { - init: function() - { - }, show: function(data) { var that=this; - util.parseHtmlIntoDiv(data.containerNode, "store/filetruststore/add.html"); - this.containerNode = data.containerNode; + data.containerNode.innerHTML = template; + parser.parse(this.containerNode).then(function(instances) + { + that.keyStoreOldBrowserWarning = dom.byId("addStore.oldBrowserWarning"); - this.keyStoreOldBrowserWarning = dom.byId("addStore.oldBrowserWarning"); + if (!window.FileReader) + { + // Fall back for IE8/9 which do not support FileReader + that.keyStoreOldBrowserWarning.innerHTML = "File upload requires a more recent browser with HTML5 support"; + that.keyStoreOldBrowserWarning.className = that.keyStoreOldBrowserWarning.className.replace("hidden", ""); + } - this.addButton = data.parent.addButton; + if (data.effectiveData) + { + that.update(data.effectiveData); + } - if (!window.FileReader) - { - // Fall back for IE8/9 which do not support FileReader - this.keyStoreOldBrowserWarning.innerHTML = "File upload requires a more recent browser with HTML5 support"; - this.keyStoreOldBrowserWarning.className = this.keyStoreOldBrowserWarning.className.replace("hidden", ""); - } + util.applyMetadataToWidgets(data.containerNode, "TrustStore", "FileTrustStore"); + }); }, update: function(effectiveData) { @@ -54,14 +65,25 @@ define(["dojo/dom","dojo/query", "dojo/_base/array", "dijit/registry","qpid/comm if (name in attributes ) { var attribute = attributes[name]; - if (attribute.secure || attribute.oversize) - { - item.set("required", false); - item.set("placeHolder", effectiveData[name]); - } - else + var value = effectiveData[name]; + if (value) { - item.set("value", effectiveData[name]); + if (attribute.secure) + { + if (!/^\*+/.test(value) ) + { + item.set("value", value); + } + else + { + item.set("placeHolder", value); + item.set("required", false); + } + } + else + { + item.set("value", value); + } } } }); @@ -69,14 +91,6 @@ define(["dojo/dom","dojo/query", "dojo/_base/array", "dijit/registry","qpid/comm } }; - try - { - addTrustStore.init(); - } - catch(e) - { - console.warn(e); - } return addTrustStore; } ); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavakeystore/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavakeystore/add.js index 0d74699d79..5c25ae2cc6 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavakeystore/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavakeystore/add.js @@ -18,64 +18,85 @@ * under the License. * */ -define(["dojo/dom","dojo/query", "dojo/_base/array", "dijit/registry","qpid/common/util", "qpid/common/metadata", "qpid/common/ResourceWidget"], - function (dom, query, array, registry, util, metadata) +define(["dojo/dom", + "dojo/query", + "dojo/_base/array", + "dijit/registry", + "qpid/common/util", + "qpid/common/metadata", + "dojo/parser", + "dojo/text!store/nonjavakeystore/add.html", + "qpid/common/ResourceWidget", + "dojo/domReady!"], + function (dom, query, array, registry, util, metadata, parser, template) { var addKeyStore = { - init: function() - { - }, show: function(data) { var that=this; - util.parseHtmlIntoDiv(data.containerNode, "store/nonjavakeystore/add.html"); - - this.keyStoreOldBrowserWarning = dom.byId("addStore.oldBrowserWarning"); - this.addButton = data.parent.addButton; this.containerNode = data.containerNode; - - if (!window.FileReader) + data.containerNode.innerHTML = template; + parser.parse(this.containerNode).then(function(instances) { - this.keyStoreOldBrowserWarning.innerHTML = "File upload requires a more recent browser with HTML5 support"; - this.keyStoreOldBrowserWarning.className = this.keyStoreOldBrowserWarning.className.replace("hidden", ""); - } + that.keyStoreOldBrowserWarning = dom.byId("addStore.oldBrowserWarning"); + + if (!window.FileReader) + { + that.keyStoreOldBrowserWarning.innerHTML = "File upload requires a more recent browser with HTML5 support"; + that.keyStoreOldBrowserWarning.className = that.keyStoreOldBrowserWarning.className.replace("hidden", ""); + } + + if (data.effectiveData) + { + that.update(data.effectiveData); + } + + util.applyMetadataToWidgets(data.containerNode, "KeyStore", "NonJavaKeyStore"); + }); }, update: function(effectiveData) { - if (effectiveData) - { - var attributes = metadata.getMetaData("KeyStore", "NonJavaKeyStore").attributes; - var widgets = registry.findWidgets(this.containerNode); - array.forEach(widgets, function(item) + var attributes = metadata.getMetaData("KeyStore", "NonJavaKeyStore").attributes; + var widgets = registry.findWidgets(this.containerNode); + array.forEach(widgets, function(item) + { + var name = item.id.replace("addStore.",""); + if (name in attributes ) { - var name = item.id.replace("addStore.",""); - if (name in attributes ) + var attribute = attributes[name]; + var value = effectiveData[name]; + if (value) { - var attribute = attributes[name]; - if (attribute.oversize || attribute.secure) + if (attribute.secure) { - item.set("required", false); - item.set("placeHolder", effectiveData[name]); + if (!/^\*+/.test(value) ) + { + item.set("value", value); + } + else + { + item.set("required", false); + if (name == "privateKeyUrl") + { + item.set("uploaded", true) + } + else + { + item.set("placeHolder", value); + } + } } else { - item.set("value", effectiveData[name]); + item.set("value", value); } } - }); - } + } + }); } }; - try - { - addKeyStore.init(); - } - catch(e) - { - console.warn(e); - } return addKeyStore; } ); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavatruststore/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavatruststore/add.js index 53e3b43082..550c388910 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavatruststore/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavatruststore/add.js @@ -18,64 +18,77 @@ * under the License. * */ -define(["dojo/dom","dojo/query", "dojo/_base/array", "dijit/registry","qpid/common/util", "qpid/common/metadata"], - function (dom, query, array, registry, util, metadata) +define(["dojo/dom", + "dojo/query", + "dojo/_base/array", + "dijit/registry", + "qpid/common/util", + "qpid/common/metadata", + "dojo/parser", + "dojo/text!store/nonjavatruststore/add.html", + "dojo/domReady!"], + function (dom, query, array, registry, util, metadata, parser, template) { var addKeyStore = { - init: function() - { - }, show: function(data) { var that=this; - util.parseHtmlIntoDiv(data.containerNode, "store/nonjavatruststore/add.html"); - - this.keyStoreOldBrowserWarning = dom.byId("addStore.oldBrowserWarning"); - this.addButton = data.parent.addButton; this.containerNode = data.containerNode; - - if (!window.FileReader) + data.containerNode.innerHTML = template; + parser.parse(this.containerNode).then(function(instances) { - this.keyStoreOldBrowserWarning.innerHTML = "File upload requires a more recent browser with HTML5 support"; - this.keyStoreOldBrowserWarning.className = this.keyStoreOldBrowserWarning.className.replace("hidden", ""); - } + that.keyStoreOldBrowserWarning = dom.byId("addStore.oldBrowserWarning"); + + if (!window.FileReader) + { + that.keyStoreOldBrowserWarning.innerHTML = "File upload requires a more recent browser with HTML5 support"; + that.keyStoreOldBrowserWarning.className = that.keyStoreOldBrowserWarning.className.replace("hidden", ""); + } + + if (data.effectiveData) + { + that.update(data.effectiveData); + } + + util.applyMetadataToWidgets(data.containerNode, "TrustStore", "NonJavaTrustStore"); + }); }, update: function(effectiveData) { - if (effectiveData) - { - var attributes = metadata.getMetaData("TrustStore", "NonJavaTrustStore").attributes; - var widgets = registry.findWidgets(this.containerNode); - array.forEach(widgets, function(item) + var attributes = metadata.getMetaData("TrustStore", "NonJavaTrustStore").attributes; + var widgets = registry.findWidgets(this.containerNode); + array.forEach(widgets, function(item) + { + var name = item.id.replace("addStore.",""); + if (name in attributes ) { - var name = item.id.replace("addStore.",""); - if (name in attributes ) + var attribute = attributes[name]; + var value = effectiveData[name]; + if (value) { - var attribute = attributes[name]; - if (attribute.oversize || attribute.secure) + if (attribute.secure) { - item.set("required", false); - item.set("placeHolder", effectiveData[name]); + if (!/^\*+/.test(value) ) + { + item.set("value", value); + } + else + { + item.set("placeHolder", value); + item.set("required", false); + } } else { - item.set("value", effectiveData[name]); + item.set("value", value); } } - }); - } + } + }); } }; - try - { - addKeyStore.init(); - } - catch(e) - { - console.warn(e); - } return addKeyStore; } ); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavatruststore/show.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavatruststore/show.js index 89b0b5d88f..7d78026d05 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavatruststore/show.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/nonjavatruststore/show.js @@ -36,10 +36,12 @@ define(["dojo/query", { this.fields.push(name); } - util.buildUI(data.containerNode, data.parent, "store/nonjavatruststore/show.html", this.fields, this); - var gridNode = query(".details", data.containerNode)[0]; - var dateTimeFormatter = function(value){ return value ? UserPreferences.formatDateTime(value, {addOffset: true, appendTimeZone: true}) : "";}; - this.detailsGrid = new UpdatableStore([], + var that = this; + util.buildUI(data.containerNode, data.parent, "store/nonjavatruststore/show.html", this.fields, this, function() + { + var gridNode = query(".details", data.containerNode)[0]; + var dateTimeFormatter = function(value){ return value ? UserPreferences.formatDateTime(value, {addOffset: true, appendTimeZone: true}) : "";}; + that.detailsGrid = new UpdatableStore([], gridNode, [ { name: 'Subject', field: 'SUBJECT_NAME', width: '25%' }, @@ -47,6 +49,7 @@ define(["dojo/query", { name: 'Valid from', field: 'VALID_START', width: '25%', formatter: dateTimeFormatter }, { name: 'Valid to', field: 'VALID_END', width: '25%', formatter: dateTimeFormatter} ]); + }); } NonJavaTrustStore.prototype.update = function(data) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhost/providedstore/add.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhost/providedstore/add.js index 7d14c6450f..c4e44f5027 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhost/providedstore/add.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhost/providedstore/add.js @@ -32,9 +32,12 @@ define(["dojo/_base/xhr", return { show: function (data) { + var that= this; this.containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode); - parser.parse(this.containerNode); - + parser.parse(this.containerNode).then(function(instances) {that._postParse(data);}); + }, + _postParse: function(data) + { registry.byId("addVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); registry.byId("addVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); @@ -42,6 +45,7 @@ define(["dojo/_base/xhr", { dom.byId("addVirtualHost.diskFlowControls").style.display = "none"; } + } }; } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhost/providedstore/edit.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhost/providedstore/edit.js index 6264d81335..3a305fb016 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhost/providedstore/edit.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhost/providedstore/edit.js @@ -20,14 +20,15 @@ define(["dijit/registry", "qpid/common/util", "dojo/domReady!"], function (registry, util) { - var fieldNames = ["storeUnderfullSize", "storeOverfullSize"]; return { show: function(data) { - util.buildEditUI(data.containerNode, "virtualhost/providedstore/edit.html", "editVirtualHost.", fieldNames, data.data); - - registry.byId("editVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); - registry.byId("editVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + util.parseHtmlIntoDiv(data.containerNode, "virtualhost/providedstore/edit.html", + function() + { + registry.byId("editVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); + registry.byId("editVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); + }); } }; } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhostnode/json/edit.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhostnode/json/edit.js index 35ecbec315..4c70b4a22d 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhostnode/json/edit.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/virtualhostnode/json/edit.js @@ -22,8 +22,11 @@ define(["qpid/common/util", "dijit/registry", "dojo/domReady!"], return { show: function(data) { - util.buildEditUI(data.containerNode, "virtualhostnode/filebased/edit.html", "editVirtualHostNode.", ["storePath"], data.data); - registry.byId("editVirtualHostNode.storePath").set("disabled", !(data.data.state == "STOPPED" || data.data.state == "ERRORED")); + util.parseHtmlIntoDiv(data.containerNode, "virtualhostnode/filebased/edit.html", + function() + { + registry.byId("editVirtualHostNode.storePath").set("disabled", !(data.data.state == "STOPPED" || data.data.state == "ERRORED")); + }); } }; } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showPort.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showPort.html index 32071e262d..5e324bd219 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showPort.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showPort.html @@ -25,61 +25,72 @@ <div class="formLabel-labelCell">Name:</div> <div class="nameValue"></div> </div> - - <div class="clear type"> - <div class="formLabel-labelCell">Port Type:</div> - <div class="typeValue"></div> + <div class="clear"></div> + <div class="alignLeft"> + <div class="clear type"> + <div class="formLabel-labelCell">Port Type:</div> + <div class="formValue-valueCell typeValue"></div> + </div> </div> + <div class="alignRight"> + <div class="clear maxOpenConnections"> + <div class="formLabel-labelCell">Open connections (current/maximum):</div> + <div class="formValue-valueCell"> + <span class="connectionCountValue"></span><span>/</span><span class="maxOpenConnectionsValue"></span> + </div> + </div> + </div> - <div class="clear state"> + <div class="clear state"> <div class="formLabel-labelCell">State:</div> - <div class="stateValue"></div> - </div> + <div class="formValue-valueCell stateValue"></div> + </div> - <div class="clear port"> + <div class="clear port"> <div class="formLabel-labelCell">Port Number:</div> - <div class="portValue"></div> - </div> + <div class="formValue-valueCell portValue"></div> + </div> - <div class="clear protocols"> + <div class="clear protocols"> <div class="formLabel-labelCell">Protocols:</div> - <div class="protocolsValue multiLineValue"></div> - </div> + <div class="formValue-valueCell protocolsValue multiLineValue"></div> + </div> <div class="clear authenticationProvider"> - <div class="formLabel-labelCell">Authentication Provider:</div> - <div class="authenticationProviderValue"></div> + <div class="formLabel-labelCell">Authentication Provider:</div> + <div class="formValue-valueCell authenticationProviderValue"></div> </div> <div class="clear bindingAddress"> - <div class="formLabel-labelCell">Binding address:</div> - <div class="bindingAddressValue"></div> + <div class="formLabel-labelCell">Binding address:</div> + <div class="formValue-valueCell bindingAddressValue"></div> </div> <div class="clear transports"> <div class="formLabel-labelCell">Transports:</div> - <div class="transportsValue multiLineValue"></div> - </div> + <div class="formValue-valueCell transportsValue multiLineValue"></div> + </div> - <div class="clear keyStore"> - <div class="formLabel-labelCell">Key Store:</div> - <div class="keyStoreValue"></div> - </div> + <div class="clear keyStore"> + <div class="formLabel-labelCell">Key Store:</div> + <div class="formValue-valueCell keyStoreValue"></div> + </div> - <div class="clear needClientAuth"> - <div class="formLabel-labelCell">Need SSL Client Certificate:</div> - <div class="needClientAuthValue"></div> - </div> + <div class="clear needClientAuth"> + <div class="formLabel-labelCell">Need SSL Client Certificate:</div> + <div class="formValue-valueCell needClientAuthValue"></div> + </div> - <div class="clear wantClientAuth"> - <div class="formLabel-labelCell">Want SSL Client Certificate:</div> - <div class="wantClientAuthValue"></div> - </div> + <div class="clear wantClientAuth"> + <div class="formLabel-labelCell">Want SSL Client Certificate:</div> + <div class="formValue-valueCell wantClientAuthValue"></div> + </div> + + <div class="clear trustStores"> + <div class="formLabel-labelCell">Trust Stores:</div> + <div class="formValue-valueCell trustStoresValue multiLineValue"></div> + </div> - <div class="clear trustStores"> - <div class="formLabel-labelCell">Trust Stores:</div> - <div class="trustStoresValue multiLineValue"></div> - </div> <div class="clear"></div> </div> <br/> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html index a068868e7f..7132dd8105 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showQueue.html @@ -25,7 +25,7 @@ <div class="formLabel-labelCell">Name:</div> <div class="name formValue-valueCell"></div> </div> - <div class="clear"> + <div class="clear"></div> <div class="alignLeft"> <div class="clear"> <div class="formLabel-labelCell">Type:</div> diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/ReportRunnerTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/ReportRunnerTest.java new file mode 100644 index 0000000000..38432a26f4 --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/ReportRunnerTest.java @@ -0,0 +1,186 @@ +/* + * + * 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.server.management.plugin.report; + +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.mockito.ArgumentCaptor; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.QueueEntryVisitor; +import org.apache.qpid.test.utils.QpidTestCase; + +public class ReportRunnerTest extends QpidTestCase +{ + public void testTextReportCountsMessages() + { + ReportRunner<String> runner = (ReportRunner<String>) ReportRunner.createRunner(TestTextReport.NAME, + Collections.<String, String[]>emptyMap()); + Queue queue = createMockQueue(); + assertEquals("There are 0 messages on the queue.", runner.runReport(queue)); + + runner = (ReportRunner<String>) ReportRunner.createRunner(TestTextReport.NAME, + Collections.<String, String[]>emptyMap()); + Queue queue1 = createMockQueue(mock(ServerMessage.class)); + assertEquals("There are 1 messages on the queue.", runner.runReport(queue1)); + + runner = (ReportRunner<String>) ReportRunner.createRunner(TestTextReport.NAME, + Collections.<String, String[]>emptyMap()); + Queue queue2 = createMockQueue(mock(ServerMessage.class), mock(ServerMessage.class)); + assertEquals("There are 2 messages on the queue.", runner.runReport(queue2)); + } + + public void testTextReportSingleStringParam() + { + Queue queue2 = createMockQueue(mock(ServerMessage.class), mock(ServerMessage.class)); + + Map<String, String[]> parameterMap = new HashMap<>(); + parameterMap.put("stringParam", new String[]{"hello world"}); + ReportRunner<String> runner = + (ReportRunner<String>) ReportRunner.createRunner(TestTextReport.NAME, parameterMap); + assertEquals("There are 2 messages on the queue. stringParam = hello world.", runner.runReport(queue2)); + } + + public void testTextReportSingleStringArrayParam() + { + Queue queue = createMockQueue(); + + Map<String, String[]> parameterMap = new HashMap<>(); + parameterMap.put("stringArrayParam", new String[] { "hello world", "goodbye"}); + ReportRunner<String> runner = (ReportRunner<String>) ReportRunner.createRunner(TestTextReport.NAME, parameterMap); + assertEquals("There are 0 messages on the queue. stringArrayParam = [hello world, goodbye].", runner.runReport(queue)); + + } + + + public void testTextReportBothParams() + { + Queue queue = createMockQueue(); + + Map<String, String[]> parameterMap = new HashMap<>(); + parameterMap.put("stringParam", new String[]{"hello world"}); + parameterMap.put("stringArrayParam", new String[] { "hello world", "goodbye"}); + ReportRunner<String> runner = (ReportRunner<String>) ReportRunner.createRunner(TestTextReport.NAME, parameterMap); + assertEquals("There are 0 messages on the queue. stringParam = hello world. stringArrayParam = [hello world, goodbye].", runner.runReport(queue)); + + } + + public void testInvalidReportName() + { + try + { + ReportRunner.createRunner("unknown", Collections.<String, String[]>emptyMap()); + fail("Unknown report name should throw exception"); + } + catch(IllegalArgumentException e) + { + assertEquals("Unknown report: unknown", e.getMessage()); + } + } + + public void testBinaryReportWithLimit() throws Exception + { + Queue queue = createMockQueue(createMessageWithAppProperties(Collections.<String,Object>singletonMap("key",1)), + createMessageWithAppProperties(Collections.<String,Object>singletonMap("key",2)), + createMessageWithAppProperties(Collections.<String, Object>singletonMap("key", 3)), + createMessageWithAppProperties(Collections.<String, Object>singletonMap("key", 4))); + Map<String, String[]> parameterMap = new HashMap<>(); + parameterMap.put("propertyName", new String[]{"key"}); + parameterMap.put("limit", new String[] { "3" }); + + ReportRunner<byte[]> runner = (ReportRunner<byte[]>) ReportRunner.createRunner(TestBinaryReport.NAME, parameterMap); + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + ObjectOutputStream objects = new ObjectOutputStream(bytes); + objects.writeObject(Integer.valueOf(1)); + objects.writeObject(Integer.valueOf(2)); + objects.writeObject(Integer.valueOf(3)); + objects.flush(); + byte[] expected = bytes.toByteArray(); + byte[] actual = runner.runReport(queue); + assertTrue("Output not as expected", Arrays.equals(expected, actual)); + } + + private ServerMessage<?> createMessageWithAppProperties(final Map<String,Object> props) + { + ServerMessage<?> message = mock(ServerMessage.class); + final AMQMessageHeader header = mock(AMQMessageHeader.class); + when(message.getMessageHeader()).thenReturn(header); + final ArgumentCaptor<String> headerNameCaptor = ArgumentCaptor.forClass(String.class); + when(header.getHeader(headerNameCaptor.capture())).thenAnswer(new Answer<Object>() + { + @Override + public Object answer(final InvocationOnMock invocation) throws Throwable + { + String header = headerNameCaptor.getValue(); + return props.get(header); + } + }); + when(header.getHeaderNames()).thenReturn(props.keySet()); + return message; + } + + private Queue createMockQueue(final ServerMessage<?>... messages) + { + final AMQQueue queue = mock(AMQQueue.class); + final ArgumentCaptor<QueueEntryVisitor> captor = ArgumentCaptor.forClass(QueueEntryVisitor.class); + doAnswer(new Answer() + { + @Override + public Object answer(final InvocationOnMock invocation) throws Throwable + { + QueueEntryVisitor visitor = captor.getValue(); + for(ServerMessage<?> message : messages) + { + if(visitor.visit(makeEntry(queue, message))) + { + break; + } + } + return null; + } + }).when(queue).visit(captor.capture()); + return queue; + } + + private QueueEntry makeEntry(final AMQQueue queue, final ServerMessage<?> message) + { + QueueEntry entry = mock(QueueEntry.class); + when(entry.getQueue()).thenReturn(queue); + when(entry.getMessage()).thenReturn(message); + return entry; + } +} diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/TestBinaryReport.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/TestBinaryReport.java new file mode 100644 index 0000000000..fc5e93631e --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/TestBinaryReport.java @@ -0,0 +1,114 @@ +/* + * + * 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.server.management.plugin.report; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; + +public class TestBinaryReport extends QueueBinaryReport +{ + + + private int _limit; + private String _propertyName; + private int _count; + private final ByteArrayOutputStream _bytesOutputStream = new ByteArrayOutputStream(); + private final ObjectOutputStream _objectOutputStream; + public static final String NAME = "testBinary"; + + public TestBinaryReport() + { + try + { + _objectOutputStream = new ObjectOutputStream(_bytesOutputStream); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + ; + } + + @Override + public String getName() + { + return NAME; + } + + @Override + public String getContentType() + { + return "application/octet-stream"; + } + + @Override + public void addMessage(final ReportableMessage reportableMessage) + { + if(_propertyName != null) + { + Object value = reportableMessage.getMessageHeader().getHeader(_propertyName); + if(value != null) + { + try + { + _objectOutputStream.writeObject(value); + } + catch (IOException e) + { + // ignore + } + } + } + _count++; + } + + @Override + public boolean isComplete() + { + return _limit != 0 && _count >= _limit; + } + + @Override + public byte[] getReport() + { + try + { + _objectOutputStream.flush(); + + return _bytesOutputStream.toByteArray(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public void setLimit(final String limit) + { + _limit = Integer.parseInt(limit); + } + + public void setPropertyName(final String propertyName) + { + this._propertyName = propertyName; + } +} diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/TestTextReport.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/TestTextReport.java new file mode 100644 index 0000000000..7f9e1e2962 --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/TestTextReport.java @@ -0,0 +1,84 @@ +/* + * + * 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.server.management.plugin.report; + +import java.util.Arrays; + +public class TestTextReport extends QueueTextReport +{ + public static final String NAME = "testText"; + private int _count; + private String _stringParam; + private String[] _stringArrayParam; + + @Override + public String getName() + { + return NAME; + } + + @Override + public String getContentType() + { + return "text/plain"; + } + + @Override + public void addMessage(final ReportableMessage reportableMessage) + { + _count++; + } + + @Override + public boolean isComplete() + { + return false; + } + + @Override + public String getReport() + { + StringBuilder result = new StringBuilder("There are " + _count + " messages on the queue."); + if(_stringParam != null) + { + result.append(" stringParam = " + _stringParam + "."); + } + if(_stringArrayParam != null) + { + result.append(" stringArrayParam = " + Arrays.asList(_stringArrayParam) + "."); + } + return result.toString(); + } + + @SuppressWarnings("unused") + public void setStringParam(final String value) + { + _stringParam = value; + } + + @SuppressWarnings("unused") + public void setStringArrayParam(final String[] value) + { + _stringArrayParam = value; + } + + +} diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverterTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverterTest.java index b3c9bd911f..5fb73c8ee4 100644 --- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverterTest.java +++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConfiguredObjectToMapConverterTest.java @@ -313,6 +313,7 @@ public class ConfiguredObjectToMapConverterTest extends TestCase Map<String, ConfiguredObjectAttribute<?, ?>> attributeTypes = typeRegistry.getAttributeTypes(TestChild.class); ConfiguredObjectAttribute secureAttribute = mock(ConfiguredObjectAttribute.class); when(secureAttribute.isSecure()).thenReturn(true); + when(secureAttribute.isSecureValue(any())).thenReturn(true); when(attributeTypes.get(eq("secureAttribute"))).thenReturn(secureAttribute); TestChild mockChild = mock(TestChild.class); diff --git a/qpid/java/broker-plugins/management-http/src/test/resources/META-INF/services/org.apache.qpid.server.management.plugin.report.QueueReport b/qpid/java/broker-plugins/management-http/src/test/resources/META-INF/services/org.apache.qpid.server.management.plugin.report.QueueReport new file mode 100644 index 0000000000..7d25ec4378 --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/test/resources/META-INF/services/org.apache.qpid.server.management.plugin.report.QueueReport @@ -0,0 +1,2 @@ +org.apache.qpid.server.management.plugin.report.TestTextReport +org.apache.qpid.server.management.plugin.report.TestBinaryReport diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBean.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBean.java index a016ff9d9d..0787e404fa 100644 --- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBean.java +++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBean.java @@ -100,7 +100,7 @@ public class ConnectionMBean extends AbstractStatisticsGatheringMBean<Connection public String getObjectInstanceName() { - return ObjectName.quote(getRemoteAddress()); + return ObjectName.quote(getConfiguredObject().getName()); } @Override diff --git a/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBeanTest.java b/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBeanTest.java index 8754f9a465..232094ce9e 100644 --- a/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBeanTest.java +++ b/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBeanTest.java @@ -159,9 +159,9 @@ public class ConnectionMBeanTest extends TestCase public void testGetObjectInstanceName() { - String remoteAddress = "testRemoteAddress"; - String quotedRemoteAddress = "\"testRemoteAddress\""; - when(_mockConnection.getAttribute(Connection.REMOTE_ADDRESS)).thenReturn(remoteAddress); + String name = "[1] 127.0.0.1:5555"; + String quotedRemoteAddress = "\"" + name +"\""; + when(_mockConnection.getName()).thenReturn(name); String objectInstanceName = _connectionMBean.getObjectInstanceName(); assertEquals(quotedRemoteAddress, objectInstanceName); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 85fe7af0fb..be2252abbd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -25,9 +25,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.util.HashSet; -import java.util.Properties; -import java.util.Set; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; @@ -179,11 +176,14 @@ public class Main protected void execute() throws Exception { - String initialProperties = _commandLine.getOptionValue(OPTION_INITIAL_SYSTEM_PROPERTIES.getOpt()); - populateSystemPropertiesFromDefaults(initialProperties); - BrokerOptions options = new BrokerOptions(); + String initialProperties = _commandLine.getOptionValue(OPTION_INITIAL_SYSTEM_PROPERTIES.getOpt()); + if (initialProperties != null) + { + options.setInitialSystemProperties(initialProperties); + } + String initialConfigLocation = _commandLine.getOptionValue(OPTION_INITIAL_CONFIGURATION_PATH.getOpt()); if (initialConfigLocation != null) { @@ -320,33 +320,6 @@ public class Main } } - private void populateSystemPropertiesFromDefaults(final String initialProperties) throws IOException - { - URL initialPropertiesLocation; - if(initialProperties == null) - { - initialPropertiesLocation = getClass().getClassLoader().getResource("system.properties"); - } - else - { - initialPropertiesLocation = (new File(initialProperties)).toURI().toURL(); - } - - Properties props = new Properties(QpidProperties.asProperties()); - if(initialPropertiesLocation != null) - { - props.load(initialPropertiesLocation.openStream()); - } - - Set<String> propertyNames = new HashSet<>(props.stringPropertyNames()); - propertyNames.removeAll(System.getProperties().stringPropertyNames()); - for (String propName : propertyNames) - { - System.setProperty(propName, props.getProperty(propName)); - } - - } - private void copyInitialConfigFile(final BrokerOptions options, final File destinationFile) { String initialConfigLocation = options.getInitialConfigurationLocation(); diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java index bde20d0550..9d9278b74d 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQBrokerDetails.java @@ -20,18 +20,18 @@ */ package org.apache.qpid.client; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.jms.BrokerDetails; -import org.apache.qpid.transport.ConnectionSettings; -import org.apache.qpid.url.URLHelper; -import org.apache.qpid.url.URLSyntaxException; - import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.jms.BrokerDetails; +import org.apache.qpid.transport.ConnectionSettings; +import org.apache.qpid.url.URLHelper; +import org.apache.qpid.url.URLSyntaxException; + public class AMQBrokerDetails implements BrokerDetails, Serializable { private static final long serialVersionUID = 8450786374975932890L; @@ -42,6 +42,14 @@ public class AMQBrokerDetails implements BrokerDetails, Serializable private Map<String, String> _options = new HashMap<String, String>(); + public AMQBrokerDetails(BrokerDetails details) + { + _host = details.getHost(); + _port = details.getPort(); + _transport = details.getTransport(); + _options = new HashMap<>(details.getProperties()); + } + public AMQBrokerDetails(){} public AMQBrokerDetails(String url) throws URLSyntaxException diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java index 8e7b5b90d8..ec60bd2914 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java @@ -62,6 +62,7 @@ import org.apache.qpid.AMQDisconnectedException; import org.apache.qpid.AMQException; import org.apache.qpid.AMQProtocolException; import org.apache.qpid.AMQUnresolvedAddressException; +import org.apache.qpid.client.failover.ConnectionRedirectException; import org.apache.qpid.client.failover.FailoverException; import org.apache.qpid.client.failover.FailoverProtectedOperation; import org.apache.qpid.client.protocol.AMQProtocolHandler; @@ -462,9 +463,22 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } else if (!isConnected()) { - retryAllowed = _failoverPolicy.failoverAllowed(); - brokerDetails = _failoverPolicy.getNextBrokerDetails(); - _protocolHandler.setStateManager(new AMQStateManager(_protocolHandler.getProtocolSession())); + if(connectionException instanceof ConnectionRedirectException) + { + ConnectionRedirectException redirect = (ConnectionRedirectException) connectionException; + retryAllowed = true; + brokerDetails = new AMQBrokerDetails(brokerDetails); + brokerDetails.setHost(redirect.getHost()); + brokerDetails.setPort(redirect.getPort()); + _protocolHandler.setStateManager(new AMQStateManager(_protocolHandler.getProtocolSession())); + + } + else + { + retryAllowed = _failoverPolicy.failoverAllowed(); + brokerDetails = _failoverPolicy.getNextBrokerDetails(); + _protocolHandler.setStateManager(new AMQStateManager(_protocolHandler.getProtocolSession())); + } } } @@ -599,9 +613,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect _virtualHost = virtualHost; } - public boolean attemptReconnection(String host, int port) + public boolean attemptReconnection(String host, int port, final boolean useFailoverConfigOnFailure) { - BrokerDetails bd = new AMQBrokerDetails(host, port); + BrokerDetails bd = new AMQBrokerDetails(_failoverPolicy.getCurrentBrokerDetails()); + bd.setHost(host); + bd.setPort(port); _failoverPolicy.setBroker(bd); @@ -618,10 +634,9 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect _logger.info("Unable to connect to broker at " + bd); } - attemptReconnection(); + return useFailoverConfigOnFailure && attemptReconnection(); } - return false; } public boolean attemptReconnection() @@ -629,32 +644,41 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect BrokerDetails broker = null; while (_failoverPolicy.failoverAllowed() && (broker = _failoverPolicy.getNextBrokerDetails()) != null) { - try + if (attemptConnection(broker)) { - makeBrokerConnection(broker); return true; } - catch (Exception e) + } + + // connection unsuccessful + return false; + } + + private boolean attemptConnection(final BrokerDetails broker) + { + try + { + makeBrokerConnection(broker); + return true; + } + catch (Exception e) + { + if (!(e instanceof AMQException)) { - if (!(e instanceof AMQException)) + if (_logger.isInfoEnabled()) { - if (_logger.isInfoEnabled()) - { - _logger.info("Unable to connect to broker at " + _failoverPolicy.getCurrentBrokerDetails(), e); - } + _logger.info("Unable to connect to broker at " + _failoverPolicy.getCurrentBrokerDetails(), e); } - else + } + else + { + if (_logger.isInfoEnabled()) { - if (_logger.isInfoEnabled()) - { - _logger.info(e.getMessage() + ":Unable to connect to broker at " - + _failoverPolicy.getCurrentBrokerDetails()); - } + _logger.info(e.getMessage() + ":Unable to connect to broker at " + + _failoverPolicy.getCurrentBrokerDetails()); } } } - - // connection unsuccessful return false; } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java index e22a341205..2c10c585fc 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java @@ -61,6 +61,8 @@ import org.apache.qpid.transport.TransportException; public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, ConnectionListener { + private static final int DEFAULT_PORT = 5672; + /** * This class logger. */ @@ -238,7 +240,7 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec { code = AMQConstant.getConstant(ce.getClose().getReplyCode().getValue()); } - String msg = "Cannot connect to broker: " + ce.getMessage(); + String msg = "Cannot connect to broker ("+brokerDetail+"): " + ce.getMessage(); throw new AMQException(code, msg, ce); } @@ -314,25 +316,39 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec @Override public void run() { - try - { - if (_conn.firePreFailover(false) && _conn.attemptReconnection()) + try { - failoverPrep(); - _conn.resubscribeSessions(); - _conn.fireFailoverComplete(); - failoverDone.set(true); + boolean preFailover = _conn.firePreFailover(false); + if (preFailover) + { + boolean reconnected; + if(exc instanceof RedirectConnectionException) + { + RedirectConnectionException redirect = (RedirectConnectionException)exc; + reconnected = attemptRedirection(redirect.getHost(), redirect.getKnownHosts()); + } + else + { + reconnected = _conn.attemptReconnection(); + } + if(reconnected) + { + failoverPrep(); + _conn.resubscribeSessions(); + _conn.fireFailoverComplete(); + failoverDone.set(true); + } + } + } + catch (Exception e) + { + _logger.error("error during failover", e); + } + finally + { + _conn.getProtocolHandler().getFailoverLatch().countDown(); + _conn.getProtocolHandler().setFailoverLatch(null); } - } - catch (Exception e) - { - _logger.error("error during failover", e); - } - finally - { - _conn.getProtocolHandler().getFailoverLatch().countDown(); - _conn.getProtocolHandler().setFailoverLatch(null); - } } }); @@ -376,6 +392,58 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec } } + @Override + public boolean redirect(final String host, final List<Object> knownHosts) + { + exception = new RedirectConnectionException(host,knownHosts); + + return false; + } + + private boolean attemptRedirection(String host, List<Object> knownHosts) + { + + boolean redirected = host != null && attemptRedirection(host); + if(knownHosts != null) + { + for(Object knownHost : knownHosts) + { + redirected = attemptRedirection(String.valueOf(knownHost)); + if(redirected) + { + break; + } + } + } + return redirected; + } + + private boolean attemptRedirection(String host) + { + int portIndex = host.indexOf(':'); + + int port; + if (portIndex == -1) + { + port = DEFAULT_PORT; + } + else + { + try + { + port = Integer.parseInt(host.substring(portIndex + 1)); + } + catch(NumberFormatException e) + { + _logger.info("Unable to redirect to " + host + " - does not look like a valid address"); + return false; + } + host = host.substring(0, portIndex); + + } + return _conn.attemptReconnection(host,port,false); + } + public <T, E extends Exception> T executeRetrySupport(FailoverProtectedOperation<T,E> operation) throws E { if (_conn.isFailingOver()) @@ -538,4 +606,28 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec { return _qpidConnection.isMessageCompressionSupported(); } + + private class RedirectConnectionException extends ConnectionException + { + private final String _host; + private final List<Object> _knownHosts; + + public RedirectConnectionException(final String host, + final List<Object> knownHosts) + { + super("Connection redirected to " + host + " alternates " + knownHosts); + _host = host; + _knownHosts = knownHosts; + } + + public String getHost() + { + return _host; + } + + public List<Object> getKnownHosts() + { + return _knownHosts; + } + } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java index a71555480f..2eeea4c967 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java @@ -89,6 +89,8 @@ public abstract class AMQDestination implements Destination, Referenceable, Exte private RejectBehaviour _rejectBehaviour; + private Map<String,Object> _consumerArguments; + public static final int QUEUE_TYPE = 1; public static final int TOPIC_TYPE = 2; public static final int UNKNOWN_TYPE = 3; @@ -299,6 +301,7 @@ public abstract class AMQDestination implements Destination, Referenceable, Exte _bindingKeys = binding.getBindingKeys() == null || binding.getBindingKeys().length == 0 ? new AMQShortString[0] : binding.getBindingKeys(); final String rejectBehaviourValue = binding.getOption(BindingURL.OPTION_REJECT_BEHAVIOUR); _rejectBehaviour = rejectBehaviourValue == null ? null : RejectBehaviour.valueOf(rejectBehaviourValue.toUpperCase()); + _consumerArguments = binding.getConsumerOptions(); } protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, AMQShortString queueName) @@ -718,6 +721,11 @@ public abstract class AMQDestination implements Destination, Referenceable, Exte return result; } + public Map<String, Object> getConsumerArguments() + { + return _consumerArguments; + } + public Reference getReference() throws NamingException { return new Reference( diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java index 9cef1f8dce..3c947043c6 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java @@ -187,6 +187,10 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa } final FieldTable ft = FieldTableFactory.newFieldTable(); + if(destination.getConsumerArguments() != null) + { + ft.addAll(FieldTable.convertToFieldTable(destination.getConsumerArguments())); + } // rawSelector is used by HeadersExchange and is not a JMS Selector if (rawSelector != null) { @@ -203,6 +207,7 @@ public abstract class BasicMessageConsumer<U> extends Closeable implements Messa ft.put(AMQPFilterTypes.NO_LOCAL.getValue(), noLocal); } + _arguments = ft; _addressType = _destination.getAddressType(); } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java index 1d7bb6087a..4f2715bd7b 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java @@ -69,6 +69,7 @@ public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMe consumerArguments.put(AMQPFilterTypes.NO_CONSUME.getValue(), Boolean.TRUE); } + _topicDestinationCache = session.getTopicDestinationCache(); _queueDestinationCache = session.getQueueDestinationCache(); diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/failover/ConnectionRedirectException.java b/qpid/java/client/src/main/java/org/apache/qpid/client/failover/ConnectionRedirectException.java new file mode 100644 index 0000000000..78efdb4317 --- /dev/null +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/failover/ConnectionRedirectException.java @@ -0,0 +1,46 @@ +/* + * + * 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.client.failover; + +import org.apache.qpid.AMQException; + +public class ConnectionRedirectException extends AMQException +{ + private final String _host; + private final int _port; + + public ConnectionRedirectException(final String host, final int port) + { + super("Redirecting to " + host + ":" + port); + _host = host; + _port = port; + } + + public String getHost() + { + return _host; + } + + public int getPort() + { + return _port; + } +} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java index 315e3c4a3f..c9566db68c 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/failover/FailoverHandler.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.client.failover; +import java.util.concurrent.CountDownLatch; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,8 +30,6 @@ import org.apache.qpid.client.protocol.AMQProtocolHandler; import org.apache.qpid.client.state.AMQState; import org.apache.qpid.client.state.AMQStateManager; -import java.util.concurrent.CountDownLatch; - /** * FailoverHandler is a continuation that performs the failover procedure on a protocol session. As described in the * class level comment for {@link AMQProtocolHandler}, a protocol connection can span many physical transport @@ -168,7 +168,7 @@ public class FailoverHandler implements Runnable // if _host has value then we are performing a redirect. if (_host != null) { - failoverSucceeded = _amqProtocolHandler.getConnection().attemptReconnection(_host, _port); + failoverSucceeded = _amqProtocolHandler.getConnection().attemptReconnection(_host, _port, true); } else { diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionRedirectMethodHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionRedirectMethodHandler.java index 0ccb9b72b1..6440f3e290 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionRedirectMethodHandler.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionRedirectMethodHandler.java @@ -20,13 +20,18 @@ */ package org.apache.qpid.client.handler; +import java.nio.ByteBuffer; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.qpid.AMQException; +import org.apache.qpid.client.failover.ConnectionRedirectException; import org.apache.qpid.client.protocol.AMQProtocolSession; import org.apache.qpid.client.state.StateAwareMethodListener; import org.apache.qpid.framing.ConnectionRedirectBody; +import org.apache.qpid.transport.ByteBufferSender; +import org.apache.qpid.transport.TransportException; public class ConnectionRedirectMethodHandler implements StateAwareMethodListener<ConnectionRedirectBody> { @@ -65,7 +70,21 @@ public class ConnectionRedirectMethodHandler implements StateAwareMethodListener } - session.failover(host, port); + session.notifyError(new ConnectionRedirectException(host,port)); + + ByteBufferSender sender = session.getSender(); + + // Close the open TCP connection + try + { + sender.close(); + } + catch(TransportException e) + { + //Ignore, they are already logged by the Sender and this + //is a connection-close being processed by the IoReceiver + //which will as it closes initiate failover if necessary. + } } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java index f50447b930..200b1d72a4 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java @@ -799,14 +799,6 @@ public class AMQProtocolHandler implements ProtocolEngine return _writtenBytes; } - public void failover(String host, int port) - { - _failoverHandler.setHost(host); - _failoverHandler.setPort(port); - // see javadoc for FailoverHandler to see rationale for separate thread - startFailoverThread(); - } - public void blockUntilNotFailingOver() throws InterruptedException { synchronized(_failoverLatchChange) diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java index 9b0b21f06e..15cb908807 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolSession.java @@ -386,11 +386,6 @@ public class AMQProtocolSession implements AMQVersionAwareProtocolSession return _protocolHandler.getSender(); } - public void failover(String host, int port) - { - _protocolHandler.failover(host, port); - } - protected AMQShortString generateQueueName() { int id; diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java b/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java index fab0bcd71f..a44b6a1ff3 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/state/AMQStateManager.java @@ -20,6 +20,10 @@ */ package org.apache.qpid.client.state; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,10 +33,6 @@ import org.apache.qpid.framing.AMQMethodBody; import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.protocol.AMQMethodListener; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; - /** * The state manager is responsible for managing the state of the protocol session. * <p> diff --git a/qpid/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java b/qpid/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java index 808b2781c4..9faa58f11d 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/jms/BrokerDetails.java @@ -98,7 +98,7 @@ public interface BrokerDetails /** * Sets the properties associated with this connection * - * @param props the new p[roperties. + * @param props the new properties. */ public void setProperties(Map<String,String> props); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/common/AMQPFilterTypes.java b/qpid/java/common/src/main/java/org/apache/qpid/common/AMQPFilterTypes.java index 483fbaea50..d033bf86c2 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/common/AMQPFilterTypes.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/common/AMQPFilterTypes.java @@ -30,7 +30,8 @@ public enum AMQPFilterTypes JMS_SELECTOR("x-filter-jms-selector"), NO_CONSUME("x-filter-no-consume"), AUTO_CLOSE("x-filter-auto-close"), - NO_LOCAL("x-qpid-no-local"); + NO_LOCAL("x-qpid-no-local"), + REPLAY_PERIOD("x-qpid-replay-period"); /** The identifying string for the filter type. */ private final AMQShortString _value; diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java index c2a0911bc3..7c4e264ade 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java @@ -181,7 +181,15 @@ public class ClientDelegate extends ConnectionDelegate @Override public void connectionRedirect(Connection conn, ConnectionRedirect redir) { - throw new UnsupportedOperationException(); + conn.setRedirecting(true); + conn.getSender().close(); + for(ConnectionListener listener : conn.getListeners()) + { + if(listener.redirect(redir.getHost(), redir.getKnownHosts())) + { + break; + } + } } @Override diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java index 7007948980..4ae7e8d47a 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java @@ -80,6 +80,7 @@ public class Connection extends ConnectionInvoker private NetworkConnection _networkConnection; private FrameSizeObserver _frameSizeObserver; private boolean _messageCompressionSupported; + private final AtomicBoolean _redirecting = new AtomicBoolean(); public enum State { NEW, CLOSED, OPENING, OPEN, CLOSING, CLOSE_RCVD, RESUMING } @@ -91,6 +92,12 @@ public class Connection extends ConnectionInvoker log.error(exception, "connection exception"); } public void closed(Connection conn) {} + + @Override + public boolean redirect(final String host, final List<Object> knownHosts) + { + return false; + } } public static interface SessionFactory @@ -150,6 +157,11 @@ public class Connection extends ConnectionInvoker listeners.add(listener); } + public List<ConnectionListener> getListeners() + { + return Collections.unmodifiableList(listeners); + } + public ProtocolEventSender getSender() { return sender; @@ -224,6 +236,7 @@ public class Connection extends ConnectionInvoker synchronized (lock) { conSettings = settings; + _redirecting.set(false); state = OPENING; userID = settings.getUsername(); connectionLost.set(false); @@ -257,7 +270,7 @@ public class Connection extends ConnectionInvoker send(new ProtocolHeader(1, 0, 10)); Waiter w = new Waiter(lock, timeout); - while (w.hasTime() && state == OPENING && error == null) + while (w.hasTime() && ((state == OPENING && error == null) || isRedirecting())) { w.await(); } @@ -853,4 +866,15 @@ public class Connection extends ConnectionInvoker { return _messageCompressionSupported; } + + public boolean isRedirecting() + { + return _redirecting.get(); + } + + public void setRedirecting(final boolean redirecting) + { + _redirecting.set(redirecting); + } + } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java index 616e76825a..b055b9f5e1 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java @@ -21,6 +21,8 @@ package org.apache.qpid.transport; +import java.util.List; + /** * ConnectionListener * @@ -35,4 +37,5 @@ public interface ConnectionListener void closed(Connection connection); + boolean redirect(String host, List<Object> knownHosts); } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/sasl/SASLEncryptor.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/sasl/SASLEncryptor.java index 2a70087c10..5ef94b7d13 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/sasl/SASLEncryptor.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/security/sasl/SASLEncryptor.java @@ -21,6 +21,8 @@ package org.apache.qpid.transport.network.security.sasl; +import java.util.List; + import javax.security.sasl.Sasl; import javax.security.sasl.SaslClient; @@ -56,7 +58,13 @@ public abstract class SASLEncryptor implements ConnectionListener } } } - + + @Override + public boolean redirect(final String host, final List<Object> knownHosts) + { + return false; + } + public void exception(Connection conn, ConnectionException exception){} public void closed(Connection conn) {} diff --git a/qpid/java/common/src/main/java/org/apache/qpid/url/AMQBindingURL.java b/qpid/java/common/src/main/java/org/apache/qpid/url/AMQBindingURL.java index 77902c3531..3ea99ce4ab 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/url/AMQBindingURL.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/url/AMQBindingURL.java @@ -20,15 +20,16 @@ */ package org.apache.qpid.url; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import java.net.URISyntaxException; -import java.util.HashMap; - public class AMQBindingURL implements BindingURL { private static final Logger _logger = LoggerFactory.getLogger(AMQBindingURL.class); @@ -135,6 +136,20 @@ public class AMQBindingURL implements BindingURL return _options.get(key); } + @Override + public Map<String,Object> getConsumerOptions() + { + Map<String,Object> options = new HashMap<>(); + for(Map.Entry<String,String> option : _options.entrySet()) + { + if(!NON_CONSUMER_OPTIONS.contains(option.getKey())) + { + options.put(option.getKey(), option.getValue()); + } + } + return options; + } + public void setOption(String key, String value) { _options.put(key, value); diff --git a/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java b/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java index 80a1ae540b..91f80ff88c 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/url/BindingURL.java @@ -20,6 +20,12 @@ */ package org.apache.qpid.url; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + import org.apache.qpid.framing.AMQShortString; /* @@ -47,6 +53,18 @@ public interface BindingURL */ public static final String OPTION_REJECT_BEHAVIOUR = "rejectbehaviour"; + public static final Set<String> NON_CONSUMER_OPTIONS = + Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(OPTION_EXCLUSIVE, + OPTION_AUTODELETE, + OPTION_DURABLE, + OPTION_BROWSE, + OPTION_ROUTING_KEY, + OPTION_BINDING_KEY, + OPTION_EXCHANGE_AUTODELETE, + OPTION_EXCHANGE_DURABLE, + OPTION_EXCHANGE_DURABLE, + OPTION_REJECT_BEHAVIOUR))); + String getURL(); @@ -60,6 +78,9 @@ public interface BindingURL String getOption(String key); + Map<String,Object> getConsumerOptions(); + + boolean containsOption(String key); AMQShortString getRoutingKey(); diff --git a/qpid/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java b/qpid/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java index 46d1887496..afc2b968f4 100644 --- a/qpid/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java +++ b/qpid/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java @@ -20,12 +20,6 @@ */ package org.apache.qpid.transport; -import org.apache.log4j.Logger; -import org.apache.qpid.test.utils.QpidTestCase; -import org.apache.qpid.transport.network.ConnectionBinding; -import org.apache.qpid.transport.network.io.IoAcceptor; -import org.apache.qpid.transport.util.Waiter; - import static org.apache.qpid.transport.Option.EXPECTED; import static org.apache.qpid.transport.Option.NONE; import static org.apache.qpid.transport.Option.SYNC; @@ -37,6 +31,13 @@ import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.apache.log4j.Logger; + +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.transport.network.ConnectionBinding; +import org.apache.qpid.transport.network.io.IoAcceptor; +import org.apache.qpid.transport.util.Waiter; + /** * ConnectionTest */ @@ -171,6 +172,12 @@ public class ConnectionTest extends QpidTestCase implements SessionListener closed.countDown(); } } + + @Override + public boolean redirect(final String host, final List<Object> knownHosts) + { + return false; + } }); conn.connect("localhost", port, null, "guest", "guest", false, null); return conn; @@ -437,6 +444,12 @@ public class ConnectionTest extends QpidTestCase implements SessionListener conn.connect("localhost", port, null, "guest", "guest", false, null); conn.resume(); } + + @Override + public boolean redirect(final String host, final List<Object> knownHosts) + { + return false; + } } class TestSessionListener implements SessionListener diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java index e609d73268..19708353aa 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java @@ -76,6 +76,9 @@ public class Asserts ConfiguredObject.DESCRIPTION, ConfiguredObject.CONTEXT, ConfiguredObject.DESIRED_STATE, + VirtualHost.ENABLED_CONNECTION_VALIDATORS, + VirtualHost.DISABLED_CONNECTION_VALIDATORS, + VirtualHost.GLOBAL_ADDRESS_DOMAINS, VirtualHost.TYPE); assertEquals("Unexpected value of attribute " + VirtualHost.NAME, @@ -126,7 +129,9 @@ public class Asserts Queue.MESSAGE_GROUP_SHARED_GROUPS, PriorityQueue.PRIORITIES, ConfiguredObject.CONTEXT, - ConfiguredObject.DESIRED_STATE); + ConfiguredObject.DESIRED_STATE, + Queue.DEFAULT_FILTERS, + Queue.ENSURE_NONDESTRUCTIVE_CONSUMERS); assertEquals("Unexpected value of queue attribute " + Queue.NAME, queueName, queueData.get(Queue.NAME)); assertNotNull("Unexpected value of queue attribute " + Queue.ID, queueData.get(Queue.ID)); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java index df87432344..91447677a5 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java @@ -36,7 +36,6 @@ import org.apache.qpid.test.utils.TestBrokerConfiguration; public class QpidRestTestCase extends QpidBrokerTestCase { - public static final String ANONYMOUS_AUTHENTICATION_PROVIDER = "testAnonymous"; public static final String EXTERNAL_AUTHENTICATION_PROVIDER = "testExternal"; public static final String TEST1_VIRTUALHOST = "test"; @@ -88,11 +87,6 @@ public class QpidRestTestCase extends QpidBrokerTestCase config.removeObjectConfiguration(Port.class, TestBrokerConfiguration.ENTRY_NAME_JMX_PORT); config.removeObjectConfiguration(Port.class, TestBrokerConfiguration.ENTRY_NAME_RMI_PORT); - Map<String, Object> anonymousProviderAttributes = new HashMap<String, Object>(); - anonymousProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - anonymousProviderAttributes.put(AuthenticationProvider.NAME, ANONYMOUS_AUTHENTICATION_PROVIDER); - config.addObjectConfiguration(AuthenticationProvider.class, anonymousProviderAttributes); - config.setObjectAttribute(AuthenticationProvider.class, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, "secureOnlyMechanisms", "{}"); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java index 469e6ce52b..67978a264e 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java @@ -31,10 +31,11 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; -import java.net.URLDecoder; +import java.net.URLEncoder; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.util.Collections; @@ -303,7 +304,7 @@ public class RestTestHelper public void createNewGroupMember(String groupProviderName, String groupName, String memberName, int responseCode) throws IOException { HttpURLConnection connection = openManagementConnection( - "groupmember/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8") + "/" + URLDecoder.decode(memberName, "UTF-8"), + "groupmember/" + encodeAsUTF(groupProviderName) + "/"+ encodeAsUTF(groupName) + "/" + encodeAsUTF(memberName), "PUT"); Map<String, Object> groupMemberData = new HashMap<String, Object>(); @@ -323,7 +324,7 @@ public class RestTestHelper public void removeMemberFromGroup(String groupProviderName, String groupName, String memberName, int responseCode) throws IOException { HttpURLConnection connection = openManagementConnection( - "groupmember/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8") + "/" + URLDecoder.decode(memberName, "UTF-8"), + "groupmember/" + encodeAsUTF(groupProviderName) + "/"+ encodeAsUTF(groupName) + "/" + encodeAsUTF(memberName), "DELETE"); Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode()); @@ -356,7 +357,7 @@ public class RestTestHelper public void createGroup(String groupName, String groupProviderName, int responseCode) throws IOException { HttpURLConnection connection = openManagementConnection( - "group/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8"), + "group/" + encodeAsUTF(groupProviderName) + "/"+ encodeAsUTF(groupName), "PUT"); Map<String, Object> groupData = new HashMap<String, Object>(); @@ -389,7 +390,7 @@ public class RestTestHelper public void removeGroup(String groupName, String groupProviderName, int responseCode) throws IOException { HttpURLConnection connection = openManagementConnection( - "group/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8"), + "group/" + encodeAsUTF(groupProviderName) + "/"+ encodeAsUTF(groupName), "DELETE"); Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode()); @@ -575,4 +576,20 @@ public class RestTestHelper } } + public String encode(String value, String encoding) throws UnsupportedEncodingException + { + return URLEncoder.encode(value, encoding).replace("+", "%20"); + } + + public String encodeAsUTF(String value) + { + try + { + return encode(value, "UTF8"); + } + catch(UnsupportedEncodingException e) + { + throw new RuntimeException("Unsupported encoding UTF8", e); + } + } } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java index 9a3308603b..9bcc2cb3ae 100755 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java @@ -59,6 +59,7 @@ import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.jms.BrokerDetails; import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.server.Broker; import org.apache.qpid.server.BrokerOptions; import org.apache.qpid.server.configuration.BrokerProperties; import org.apache.qpid.server.configuration.updater.TaskExecutor; @@ -189,6 +190,19 @@ public class QpidBrokerTestCase extends QpidTestCase _brokerConfigurations = new HashMap<Integer, TestBrokerConfiguration>(); initialiseSpawnedBrokerLogConfigFile(); _brokerCommandTemplate = BROKER_COMMAND_TEMPLATE; + + + if (JAVA.equals(_brokerLanguage)) + { + try + { + Broker.populateSystemPropertiesFromDefaults(null); + } + catch (IOException ioe) + { + throw new RuntimeException("Failed to load Java broker system properties", ioe); + } + } } public TestBrokerConfiguration getBrokerConfiguration(int port) diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ArrivalTimeFilterTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ArrivalTimeFilterTest.java new file mode 100644 index 0000000000..9a5982e65d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ArrivalTimeFilterTest.java @@ -0,0 +1,107 @@ +/* + * + * 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.server.queue; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class ArrivalTimeFilterTest extends QpidBrokerTestCase +{ + + private String _queueName; + private Connection _connection; + private Session _session; + private Queue _queue; + + protected void setUp() throws Exception + { + super.setUp(); + + _queueName = getTestQueueName(); + _connection = getConnection(); + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _connection.start(); + } + + + public void testArrivalTime0() throws AMQException, JMSException, InterruptedException + { + createDestinationWithFilter(0); + final MessageProducer prod = _session.createProducer(_queue); + TextMessage textMessage = _session.createTextMessage("hello"); + prod.send(textMessage); + + Thread.sleep(100); + + MessageConsumer cons = _session.createConsumer(_queue); + + assertNull("Message should not be received", cons.receive(500)); + + textMessage = _session.createTextMessage("hello"); + prod.send( textMessage); + + Message receivedMsg = cons.receive(500); + assertNotNull("Message should be received", receivedMsg); + } + + + public void testArrivalTime1000() throws AMQException, JMSException, InterruptedException + { + createDestinationWithFilter(1000); + final MessageProducer prod = _session.createProducer(_queue); + TextMessage textMessage = _session.createTextMessage("hello"); + prod.send(textMessage); + + Thread.sleep(100); + + MessageConsumer cons = _session.createConsumer(_queue); + + assertNotNull("Message should be received", cons.receive(500)); + + textMessage = _session.createTextMessage("hello"); + prod.send( textMessage); + + Message receivedMsg = cons.receive(500); + assertNotNull("Message should be received", receivedMsg); + } + + private void createDestinationWithFilter(final int period) throws AMQException, JMSException + { + ((AMQSession<?,?>) _session).createQueue(new AMQShortString(_queueName), false, true, false, null); + Queue queue = new org.apache.qpid.client.AMQQueue("amq.direct", _queueName); + ((AMQSession<?,?>) _session).declareAndBind((AMQDestination)queue); + _queue = _session.createQueue("direct://amq.direct/"+_queueName+"/"+_queueName+"?x-qpid-replay-period='"+period+"0'"); + } + + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/DefaultFiltersTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/DefaultFiltersTest.java new file mode 100644 index 0000000000..b676e653ac --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/DefaultFiltersTest.java @@ -0,0 +1,116 @@ +/* + * + * 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.server.queue; + +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class DefaultFiltersTest extends QpidBrokerTestCase +{ + + private String _queueName; + private Connection _connection; + private Session _session; + private Queue _queue; + + protected void setUp() throws Exception + { + super.setUp(); + + _queueName = getTestQueueName(); + _connection = getConnection(); + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _connection.start(); + } + + private void createQueueWithDefaultFilter(String selector) throws AMQException + { + final Map<String,Object> arguments = new HashMap<>(); + selector = selector.replace("\\", "\\\\"); + selector = selector.replace("\"", "\\\""); + + arguments.put("qpid.default_filters","{ \"x-filter-jms-selector\" : { \"x-filter-jms-selector\" : [ \""+selector+"\" ] } }"); + ((AMQSession<?,?>) _session).createQueue(new AMQShortString(_queueName), false, true, false, arguments); + _queue = new org.apache.qpid.client.AMQQueue("amq.direct", _queueName); + ((AMQSession<?,?>) _session).declareAndBind((AMQDestination)_queue); + } + + public void testDefaultFilterIsApplied() throws AMQException, JMSException + { + createQueueWithDefaultFilter("foo = 1"); + final MessageProducer prod = _session.createProducer(_queue); + TextMessage textMessage = _session.createTextMessage("hello"); + textMessage.setIntProperty("foo", 0); + prod.send(textMessage); + + MessageConsumer cons = _session.createConsumer(_queue); + + assertNull("Message with foo=0 should not be received", cons.receive(500)); + + textMessage = _session.createTextMessage("hello"); + textMessage.setIntProperty("foo", 1); + prod.send( textMessage); + + Message receivedMsg = cons.receive(500); + assertNotNull("Message with foo=1 should be received", receivedMsg); + assertEquals("Property foo not as expected", 1, receivedMsg.getIntProperty("foo")); + } + + + public void testDefaultFilterIsOverridden() throws AMQException, JMSException + { + createQueueWithDefaultFilter("foo = 1"); + final MessageProducer prod = _session.createProducer(_queue); + TextMessage textMessage = _session.createTextMessage("hello"); + textMessage.setIntProperty("foo", 0); + prod.send(textMessage); + + MessageConsumer cons = _session.createConsumer(_queue, "foo = 0"); + + Message receivedMsg = cons.receive(500); + assertNotNull("Message with foo=0 should be received", receivedMsg); + assertEquals("Property foo not as expected", 0, receivedMsg.getIntProperty("foo")); + + + textMessage = _session.createTextMessage("hello"); + textMessage.setIntProperty("foo", 1); + prod.send(textMessage); + + assertNull("Message with foo=1 should not be received", cons.receive(500)); + + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/EnsureNondestructiveConsumersTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/EnsureNondestructiveConsumersTest.java new file mode 100644 index 0000000000..59f267cfbd --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/EnsureNondestructiveConsumersTest.java @@ -0,0 +1,116 @@ +/* + * + * 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.server.queue; + +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class EnsureNondestructiveConsumersTest extends QpidBrokerTestCase +{ + + private String _queueName; + private Connection _connection; + private Session _session; + private Queue _queue; + + protected void setUp() throws Exception + { + super.setUp(); + + _queueName = getTestQueueName(); + _connection = getConnection(); + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _connection.start(); + } + + private void createQueueEnsureNondestructiveConsumerOption(boolean ensureNonDestructiveConsumer) throws AMQException + { + final Map<String,Object> arguments = new HashMap<>(); + + arguments.put("qpid.ensure_nondestructive_consumers", String.valueOf(ensureNonDestructiveConsumer)); + ((AMQSession<?,?>) _session).createQueue(new AMQShortString(_queueName), false, true, false, arguments); + _queue = new org.apache.qpid.client.AMQQueue("amq.direct", _queueName); + ((AMQSession<?,?>) _session).declareAndBind((AMQDestination)_queue); + } + + public void testEnsureNondestructiveConsumers() throws AMQException, JMSException + { + createQueueEnsureNondestructiveConsumerOption(true); + final MessageProducer prod = _session.createProducer(_queue); + TextMessage textMessage; + + for(int i = 0; i < 5; i++) + { + textMessage = _session.createTextMessage("hello"); + textMessage.setIntProperty("msgID", i); + prod.send(textMessage); + } + + MessageConsumer cons1 = _session.createConsumer(_queue); + + for(int i = 0; i < 5 ; i++) + { + Message receivedMsg = cons1.receive(500); + assertNotNull("Message "+i+" not received", receivedMsg); + assertEquals("Unexpected message", i, receivedMsg.getIntProperty("msgID")); + } + + assertNull("Unexpected message arrived", cons1.receive(500)); + + MessageConsumer cons2 = _session.createConsumer(_queue); + + for(int i = 0; i < 5 ; i++) + { + Message receivedMsg = cons2.receive(500); + assertNotNull("Message "+i+" not received", receivedMsg); + assertEquals("Unexpected message", i, receivedMsg.getIntProperty("msgID")); + } + + assertNull("Unexpected message arrived", cons2.receive(500)); + + textMessage = _session.createTextMessage("hello"); + textMessage.setIntProperty("msgID", 6); + prod.send(textMessage); + + assertNotNull("Message not received on first consumer", cons1.receive(500)); + assertNotNull("Message not received on second consumer", cons2.receive(500)); + + assertNull("Unexpected message arrived", cons1.receive(500)); + assertNull("Unexpected message arrived", cons2.receive(500)); + + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java index 71f911627e..761ef74ad0 100644 --- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java @@ -35,7 +35,6 @@ import org.apache.qpid.server.model.Port; import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; import org.apache.qpid.server.virtualhost.ProvidedStoreVirtualHostImpl; import org.apache.qpid.server.virtualhostnode.memory.MemoryVirtualHostNode; import org.apache.qpid.systest.rest.QpidRestTestCase; @@ -63,11 +62,6 @@ public class MBeanLifeCycleTest extends QpidRestTestCase config.addHttpManagementConfiguration(); config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.PORT, getRestTestHelper().getHttpPort()); - Map<String, Object> anonymousProviderAttributes = new HashMap<String, Object>(); - anonymousProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - anonymousProviderAttributes.put(AuthenticationProvider.NAME, ANONYMOUS_AUTHENTICATION_PROVIDER); - config.addObjectConfiguration(AuthenticationProvider.class, anonymousProviderAttributes); - // set password authentication provider on http port for the tests config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java index 2467705903..dd93a917c0 100644 --- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java @@ -46,16 +46,11 @@ public class AuthenticationProviderRestTest extends QpidRestTestCase { List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider"); assertNotNull("Providers details cannot be null", providerDetails); - assertEquals("Unexpected number of providers", 2, providerDetails.size()); + assertEquals("Unexpected number of providers", 1, providerDetails.size()); for (Map<String, Object> provider : providerDetails) { boolean managesPrincipals = true; String type = PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE; - if (ANONYMOUS_AUTHENTICATION_PROVIDER.equals(provider.get(AuthenticationProvider.NAME))) - { - type = AnonymousAuthenticationManager.PROVIDER_TYPE; - managesPrincipals = false; - } assertProvider(managesPrincipals, type , provider); Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + provider.get(AuthenticationProvider.NAME)); @@ -258,53 +253,6 @@ public class AuthenticationProviderRestTest extends QpidRestTestCase } } - public void testCreateAndDeletePasswordAuthenticationProviderWithNonExistingFile() throws Exception - { - stopBroker(); - getBrokerConfiguration().setSaved(false); - getBrokerConfiguration().removeObjectConfiguration(AuthenticationProvider.class, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT, Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); - getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); - - startBroker(); - - File file = new File(TMP_FOLDER + File.separator + getTestName()); - if (file.exists()) - { - file.delete(); - } - assertFalse("File " + file.getAbsolutePath() + " should not exist", file.exists()); - - // create provider - String providerName = "test-provider"; - Map<String, Object> attributes = new HashMap<String, Object>(); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); - attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); - assertEquals("Password provider was not created", 201, responseCode); - - - Map<String, Object> providerDetails = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); - assertNotNull("Providers details cannot be null", providerDetails); - assertEquals("Unexpected name", providerName, providerDetails.get(AuthenticationProvider.NAME)); - assertEquals("Unexpected type", PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE, providerDetails.get(AuthenticationProvider.TYPE)); - assertEquals("Unexpected path", file.getAbsolutePath(), providerDetails.get( - ExternalFileBasedAuthenticationManager.PATH)); - - assertTrue("User file should be created", file.exists()); - - responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName , "DELETE"); - assertEquals("Unexpected response code for provider deletion", 200, responseCode); - - List<Map<String, Object>> providers = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName); - assertNotNull("Providers details cannot be null", providers); - assertEquals("Unexpected number of providers", 0, providers.size()); - - assertFalse("File " + file.getAbsolutePath() + " should be deleted", file.exists()); - } - private void assertProvider(boolean managesPrincipals, String type, Map<String, Object> provider) { Asserts.assertAttributesPresent(provider, BrokerModel.getInstance().getTypeRegistry().getAttributeNames( diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java index 439e592a7e..2142004411 100644 --- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java @@ -21,7 +21,6 @@ package org.apache.qpid.systest.rest; import java.io.IOException; -import java.net.URLDecoder; import java.util.List; import java.util.Map; @@ -112,7 +111,7 @@ public class ConnectionRestTest extends QpidRestTestCase String connectionName = getConnectionName(); Map<String, Object> connectionDetails = getRestTestHelper().getJsonAsSingletonList("connection/test/test/" - + URLDecoder.decode(connectionName, "UTF-8")); + + getRestTestHelper().encodeAsUTF(connectionName)); assertConnection(connectionDetails); } @@ -124,7 +123,7 @@ public class ConnectionRestTest extends QpidRestTestCase List<Map<String, Object>> connections = getRestTestHelper().getJsonAsList("connection/test/test"); assertEquals("Unexpected number of connections before deletion", 1, connections.size()); - String connectionUrl = "connection/test/test/" + URLDecoder.decode(connectionName, "UTF-8"); + String connectionUrl = "connection/test/test/" + getRestTestHelper().encodeAsUTF(connectionName); getRestTestHelper().submitRequest(connectionUrl, "DELETE", HttpServletResponse.SC_OK); connections = getRestTestHelper().getJsonAsList("connection/test/test"); @@ -161,7 +160,7 @@ public class ConnectionRestTest extends QpidRestTestCase String connectionName = getConnectionName(); List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("session/test/test/" - + URLDecoder.decode(connectionName, "UTF-8")); + + getRestTestHelper().encodeAsUTF(connectionName)); assertEquals("Unexpected number of sessions", 1, sessions.size()); assertSession(sessions.get(0), (AMQSession<?, ?>) _session); } @@ -172,7 +171,7 @@ public class ConnectionRestTest extends QpidRestTestCase String connectionName = getConnectionName(); List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("session/test/test/" - + URLDecoder.decode(connectionName, "UTF-8") + "/" + ((AMQSession<?, ?>) _session).getChannelId()); + + getRestTestHelper().encodeAsUTF(connectionName) + "/" + ((AMQSession<?, ?>) _session).getChannelId()); assertEquals("Unexpected number of sessions", 1, sessions.size()); assertSession(sessions.get(0), (AMQSession<?, ?>) _session); } @@ -187,7 +186,8 @@ public class ConnectionRestTest extends QpidRestTestCase String connectionName = getConnectionName(); List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("session/test/test/" - + URLDecoder.decode(connectionName, "UTF-8") + "/" + ((AMQSession<?, ?>) _session).getChannelId()); + + getRestTestHelper().encodeAsUTF(connectionName) + + "/" + ((AMQSession<?, ?>) _session).getChannelId()); assertEquals("Unexpected number of sessions", 1, sessions.size()); final Map<String, Object> sessionData = sessions.get(0); diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java index 51cb6dde1a..39e3c5c7c3 100644 --- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.systest.rest; -import java.net.URLDecoder; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -65,7 +64,7 @@ public class ExchangeRestTest extends QpidRestTestCase for (String exchangeName : EXPECTED_EXCHANGES) { Map<String, Object> exchange = getRestTestHelper().getJsonAsSingletonList("exchange/test/test/" - + URLDecoder.decode(exchangeName, "UTF-8")); + + getRestTestHelper().encodeAsUTF(exchangeName)); assertExchange(exchangeName, exchange); } } diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java index a3bf1ab3cb..fbf00339ce 100644 --- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java @@ -55,7 +55,7 @@ public class KeyStoreRestTest extends QpidRestTestCase Map<String, Object> keystore = keyStores.get(0); assertEquals("Unexpected name", TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, keystore.get(KeyStore.NAME)); - assertEquals("unexpected path to key store", AbstractConfiguredObject.SECURED_STRING_VALUE, keystore.get(FileKeyStore.STORE_URL)); + assertEquals("unexpected path to key store", ConfiguredObject.OVER_SIZED_ATTRIBUTE_ALTERNATIVE_TEXT, keystore.get(FileKeyStore.STORE_URL)); assertEquals("unexpected (dummy) password of default systests key store", AbstractConfiguredObject.SECURED_STRING_VALUE, keystore.get(FileKeyStore.PASSWORD)); assertEquals("unexpected type of default systests key store", java.security.KeyStore.getDefaultType(), keystore.get(FileKeyStore.KEY_STORE_TYPE)); assertFalse("should not be a certificateAlias attribute", keystore.containsKey(FileKeyStore.CERTIFICATE_ALIAS)); @@ -77,7 +77,7 @@ public class KeyStoreRestTest extends QpidRestTestCase Map<String, Object> keystore = keyStores.get(0); assertEquals("Unexpected name", name, keystore.get(KeyStore.NAME)); - assertEquals("unexpected path to key store", AbstractConfiguredObject.SECURED_STRING_VALUE, keystore.get(FileKeyStore.STORE_URL)); + assertEquals("unexpected path to key store", TestSSLConstants.KEYSTORE, keystore.get(FileKeyStore.STORE_URL)); assertEquals("unexpected password", AbstractConfiguredObject.SECURED_STRING_VALUE, keystore.get(FileKeyStore.PASSWORD)); assertEquals("unexpected alias", certAlias, keystore.get(FileKeyStore.CERTIFICATE_ALIAS)); } @@ -125,7 +125,7 @@ public class KeyStoreRestTest extends QpidRestTestCase List<Map<String, Object>> keyStores = assertNumberOfKeyStores(1); Map<String, Object> keystore = keyStores.get(0); assertEquals("Unexpected name", TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, keystore.get(KeyStore.NAME)); - assertEquals("unexpected path to key store", AbstractConfiguredObject.SECURED_STRING_VALUE, keystore.get(FileKeyStore.STORE_URL)); + assertEquals("unexpected path to key store", ConfiguredObject.OVER_SIZED_ATTRIBUTE_ALTERNATIVE_TEXT, keystore.get(FileKeyStore.STORE_URL)); assertEquals("unexpected (dummy) password of default systests key store", AbstractConfiguredObject.SECURED_STRING_VALUE, keystore.get(FileKeyStore.PASSWORD)); assertFalse("should not be a certificateAlias attribute", keystore.containsKey(FileKeyStore.CERTIFICATE_ALIAS)); } @@ -151,7 +151,7 @@ public class KeyStoreRestTest extends QpidRestTestCase Map<String, Object> keystore = keyStores.get(0); assertEquals("Unexpected name", name, keystore.get(KeyStore.NAME)); - assertEquals("unexpected data", AbstractConfiguredObject.SECURED_STRING_VALUE, keystore.get(FileKeyStore.STORE_URL)); + assertEquals("unexpected data", TestSSLConstants.UNTRUSTED_KEYSTORE, keystore.get(FileKeyStore.STORE_URL)); assertEquals("unexpected password", AbstractConfiguredObject.SECURED_STRING_VALUE, keystore.get(FileKeyStore.PASSWORD)); assertEquals("unexpected alias", null, keystore.get(FileKeyStore.CERTIFICATE_ALIAS)); } diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java index 538bd3b32a..4394d55294 100644 --- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java @@ -21,7 +21,6 @@ package org.apache.qpid.systest.rest; import java.net.ServerSocket; -import java.net.URLDecoder; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -71,7 +70,7 @@ public class PortRestTest extends QpidRestTestCase { String portName = (String) portMap.get(Port.NAME); assertNotNull("Port name attribute is not found", portName); - Map<String, Object> portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(portName, "UTF-8")); + Map<String, Object> portData = getRestTestHelper().getJsonAsSingletonList("port/" + getRestTestHelper().encodeAsUTF(portName)); assertNotNull("Port " + portName + " is not found", portData); Asserts.assertPortAttributes(portData); } @@ -319,12 +318,12 @@ public class PortRestTest extends QpidRestTestCase attributes = new HashMap<String, Object>(); attributes.put(Port.NAME, portName); - attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); + attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); assertEquals("Unexpected response when trying to change auth provider to existing one", 200, responseCode); Map<String, Object> port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); - assertEquals("Unexpected auth provider", ANONYMOUS_AUTHENTICATION_PROVIDER, port.get(Port.AUTHENTICATION_PROVIDER)); + assertEquals("Unexpected auth provider", TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, port.get(Port.AUTHENTICATION_PROVIDER)); } public void testDefaultAmqpPortIsQuiescedWhenInManagementMode() throws Exception @@ -335,14 +334,14 @@ public class PortRestTest extends QpidRestTestCase getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); String ampqPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - Map<String, Object> portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(ampqPortName, "UTF-8")); + Map<String, Object> portData = getRestTestHelper().getJsonAsSingletonList("port/" + getRestTestHelper().encodeAsUTF(ampqPortName)); Asserts.assertPortAttributes(portData, State.QUIESCED); } public void testNewPortErroredIfPortNumberInUse() throws Exception { String ampqPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - Map<String, Object> portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(ampqPortName, "UTF-8")); + Map<String, Object> portData = getRestTestHelper().getJsonAsSingletonList("port/" + getRestTestHelper().encodeAsUTF(ampqPortName)); int amqpPort = (Integer)portData.get(Port.PORT); ServerSocket socket = new ServerSocket(0); @@ -360,7 +359,7 @@ public class PortRestTest extends QpidRestTestCase int responseCode = getRestTestHelper().submitRequest("port/" + newPortName, "PUT", attributes); assertEquals("Unexpected response code for port creation", 409, responseCode); - List<Map<String,Object>> ports = getRestTestHelper().getJsonAsList("port/" + URLDecoder.decode(newPortName, "UTF-8")); + List<Map<String,Object>> ports = getRestTestHelper().getJsonAsList("port/" + getRestTestHelper().encodeAsUTF(newPortName)); assertTrue("Port should not be created", ports.isEmpty()); } } diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java index baebc9a28e..70450d57bf 100644 --- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java @@ -21,7 +21,6 @@ package org.apache.qpid.systest.rest; import java.io.IOException; -import java.net.URLDecoder; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -197,7 +196,7 @@ public class QueueRestTest extends QpidRestTestCase bindingData.put(Binding.EXCHANGE, exchangeName); bindingData.put(Binding.QUEUE, queueName); - String url = "binding/test/test/" + URLDecoder.decode(exchangeName, "UTF-8") + "/" + queueName + "/" + bindingName; + String url = "binding/test/test/" + getRestTestHelper().encodeAsUTF(exchangeName) + "/" + queueName + "/" + bindingName; int responseCode = getRestTestHelper().submitRequest(url, "PUT", bindingData); assertEquals("Unexpected response code", 201, responseCode); } diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.java index daefc05e2a..b6973359a3 100644 --- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.java +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.java @@ -53,7 +53,7 @@ public class StructureRestTest extends QpidRestTestCase @SuppressWarnings("unchecked") List<Map<String, Object>> providers = (List<Map<String, Object>>) structure.get("authenticationproviders"); - assertEquals("Unexpected number of authentication providers", 2, providers.size()); + assertEquals("Unexpected number of authentication providers", 1, providers.size()); for (String nodeName : EXPECTED_VIRTUALHOSTS) { diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java index c05e95c4d4..1b958f728f 100644 --- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java @@ -244,29 +244,6 @@ public class BrokerACLTest extends QpidRestTestCase assertPortDoesNotExist(portName); } - // TODO: test disabled until allowing the updating of active ports outside management mode - public void DISABLED_testSetPortAttributesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String portName = getTestName(); - - int responseCode = createPort(portName); - assertEquals("Port creation should be allowed", 201, responseCode); - - assertPortExists(portName); - - - Map<String, Object> attributes = new HashMap<String, Object>(); - attributes.put(Port.NAME, portName); - attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); - responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Setting of port attribites should be allowed", 200, responseCode); - - Map<String, Object> port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); - assertEquals("Unexpected authentication provider attribute value", ANONYMOUS_AUTHENTICATION_PROVIDER, - port.get(Port.AUTHENTICATION_PROVIDER)); - } public void testSetPortAttributesDenied() throws Exception { @@ -284,7 +261,7 @@ public class BrokerACLTest extends QpidRestTestCase Map<String, Object> attributes = new HashMap<String, Object>(); attributes.put(Port.NAME, portName); attributes.put(Port.PROTOCOLS, Arrays.asList(Protocol.AMQP_0_9)); - attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); + attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); assertEquals("Setting of port attribites should be denied", 403, responseCode); diff --git a/qpid/java/test-profiles/CPPExcludes b/qpid/java/test-profiles/CPPExcludes index f01e245560..4ad3087229 100755 --- a/qpid/java/test-profiles/CPPExcludes +++ b/qpid/java/test-profiles/CPPExcludes @@ -209,3 +209,8 @@ org.apache.qpid.test.unit.client.AMQSessionTest#testQueueDepthForQueueThatDoesNo org.apache.qpid.client.prefetch.PrefetchBehaviourTest#testPrefetchWindowExpandsOnReceiveTransaction org.apache.qpid.client.SyncPublishTest#* + +org.apache.qpid.server.queue.ArrivalTimeFilterTest#* +org.apache.qpid.server.queue.DefaultFiltersTest#* +org.apache.qpid.server.queue.EnsureNondestructiveConsumersTest#* + |