From 9dc57fe738f366d875c2319dafdfa2c50ce2f20b Mon Sep 17 00:00:00 2001 From: Keith Wall Date: Tue, 3 Mar 2015 14:56:40 +0000 Subject: merge from trunk git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/QPID-6262-JavaBrokerNIO@1663717 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/java/README.txt | 2 +- .../qpid/amqp_1_0/jms/impl/AmqpMessageImpl.java | 5 +- .../amqp_1_0/jms/impl/ConnectionFactoryImpl.java | 10 + .../qpid/amqp_1_0/jms/impl/MessageFactory.java | 7 + .../org/apache/qpid/amqp_1_0/client/Message.java | 185 +++++++- .../org/apache/qpid/amqp_1_0/client/Receiver.java | 38 +- .../amqp_1_0/transport/ConnectionEndpoint.java | 2 +- .../type/messaging/codec/AmqpValueConstructor.java | 15 +- .../berkeleydb/BDBHAReplicaVirtualHostImpl.java | 59 +++ .../berkeleydb/BDBHARemoteReplicationNode.java | 2 +- .../js/qpid/management/virtualhost/bdb/add.js | 9 +- .../js/qpid/management/virtualhost/bdb/edit.js | 10 +- .../js/qpid/management/virtualhost/bdb_ha/edit.js | 10 +- .../js/qpid/management/virtualhost/bdb_ha/show.js | 11 +- .../js/qpid/management/virtualhostnode/bdb/edit.js | 7 +- .../qpid/management/virtualhostnode/bdb_ha/add.js | 22 +- .../bdb_ha/add/existinggroup/add.js | 16 +- .../virtualhostnode/bdb_ha/add/newgroup/add.js | 10 +- .../qpid/management/virtualhostnode/bdb_ha/edit.js | 10 +- .../qpid/management/virtualhostnode/bdb_ha/show.js | 9 +- .../resources/virtualhostnode/bdb_ha/edit.html | 8 +- .../validation/AttributeAnnotationValidator.java | 7 + .../main/java/org/apache/qpid/server/Broker.java | 37 ++ .../java/org/apache/qpid/server/BrokerOptions.java | 21 + .../apache/qpid/server/binding/BindingImpl.java | 31 +- .../server/configuration/BrokerProperties.java | 1 + .../store/StoreConfigurationChangeListener.java | 39 +- .../qpid/server/exchange/AbstractExchange.java | 30 -- .../qpid/server/exchange/DefaultDestination.java | 5 +- .../qpid/server/exchange/HeadersBinding.java | 6 + .../qpid/server/filter/ArrivalTimeFilter.java | 46 ++ .../server/filter/ArrivalTimeFilterFactory.java | 52 +++ .../apache/qpid/server/filter/FilterManager.java | 58 ++- .../qpid/server/filter/FilterManagerFactory.java | 19 +- .../apache/qpid/server/filter/FilterSupport.java | 29 +- .../org/apache/qpid/server/filter/Filterable.java | 17 + .../qpid/server/filter/JMSSelectorFilter.java | 10 + .../server/filter/JMSSelectorFilterFactory.java | 57 +++ .../apache/qpid/server/filter/MessageFilter.java | 1 + .../qpid/server/filter/SimpleFilterManager.java | 105 ----- .../server/model/AbstractConfiguredObject.java | 32 +- .../qpid/server/model/AttributeValueConverter.java | 91 +++- .../server/model/ConfiguredAutomatedAttribute.java | 17 + .../server/model/ConfiguredDerivedAttribute.java | 18 + .../apache/qpid/server/model/ConfiguredObject.java | 3 + .../server/model/ConfiguredObjectAttribute.java | 20 + .../server/model/ConfiguredObjectFactoryImpl.java | 2 +- .../server/model/ConfiguredObjectTypeRegistry.java | 2 +- .../apache/qpid/server/model/DerivedAttribute.java | 1 + .../apache/qpid/server/model/ManagedAttribute.java | 1 + .../java/org/apache/qpid/server/model/Queue.java | 10 + .../qpid/server/model/RemoteReplicationNode.java | 3 - .../org/apache/qpid/server/model/SystemConfig.java | 4 + .../org/apache/qpid/server/model/VirtualHost.java | 24 +- .../apache/qpid/server/model/VirtualHostNode.java | 2 +- .../server/model/adapter/ConnectionAdapter.java | 2 +- .../model/adapter/FileBasedGroupProvider.java | 2 +- .../model/adapter/FileBasedGroupProviderImpl.java | 6 +- .../adapter/FileSystemPreferencesProviderImpl.java | 128 +++-- .../qpid/server/plugin/ConnectionValidator.java | 28 ++ .../qpid/server/plugin/MessageFilterFactory.java | 30 ++ .../qpid/server/plugin/QpidServiceLoader.java | 13 + .../apache/qpid/server/queue/AbstractQueue.java | 95 +++- .../qpid/server/queue/QueueArgumentsConverter.java | 7 + .../apache/qpid/server/queue/QueueEntryImpl.java | 22 +- .../apache/qpid/server/security/FileKeyStore.java | 2 +- .../qpid/server/security/NonJavaKeyStore.java | 2 +- .../AbstractPasswordFilePrincipalDatabase.java | 105 +---- ...64MD5PasswordDatabaseAuthenticationManager.java | 2 +- ...PlainPasswordDatabaseAuthenticationManager.java | 2 +- .../PrincipalDatabaseAuthenticationManager.java | 10 +- .../server/security/group/FileGroupDatabase.java | 26 +- .../qpid/server/store/JsonFileConfigStore.java | 83 ++-- .../VirtualHostStoreUpgraderAndRecoverer.java | 97 +++- .../qpid/server/transport/SelectorThread.java | 8 +- .../java/org/apache/qpid/server/util/Action.java | 2 +- .../org/apache/qpid/server/util/BaseAction.java | 26 ++ .../org/apache/qpid/server/util/FileHelper.java | 133 ++++++ .../server/virtualhost/AbstractVirtualHost.java | 206 +++++--- .../qpid/server/virtualhost/VirtualHostImpl.java | 4 + .../virtualhostnode/RedirectingVirtualHost.java | 32 ++ .../RedirectingVirtualHostImpl.java | 517 +++++++++++++++++++++ .../RedirectingVirtualHostNode.java | 36 ++ .../RedirectingVirtualHostNodeImpl.java | 124 +++++ .../src/main/resources/system.properties | 20 - .../org/apache/qpid/server/BrokerOptionsTest.java | 10 + .../java/org/apache/qpid/server/BrokerTest.java | 101 ++++ .../qpid/server/binding/BindingImplTest.java | 6 + .../StoreConfigurationChangeListenerTest.java | 7 +- .../apache/qpid/server/consumer/MockConsumer.java | 14 +- .../apache/qpid/server/model/VirtualHostTest.java | 15 +- .../singleton/AbstractConfiguredObjectTest.java | 84 ++++ .../qpid/server/queue/LastValueQueueListTest.java | 5 + .../qpid/server/queue/QueueEntryImplTestBase.java | 1 + .../qpid/server/queue/QueueEntryListTestBase.java | 2 + .../server/queue/SimpleQueueEntryImplTest.java | 1 + .../qpid/server/queue/SortedQueueEntryTest.java | 1 + .../server/queue/StandardQueueEntryListTest.java | 3 +- .../apache/qpid/server/util/FileHelperTest.java | 138 ++++++ .../protocol/v0_10/ServerConnectionDelegate.java | 24 +- .../protocol/v0_10/ServerSessionDelegate.java | 41 ++ .../qpid/server/protocol/v0_8/AMQChannel.java | 65 ++- .../server/protocol/v0_8/AMQProtocolEngine.java | 42 +- .../qpid/server/protocol/v1_0/SendingLink_1_0.java | 22 +- .../js/qpid/management/virtualhost/derby/add.js | 9 +- .../js/qpid/management/virtualhost/derby/edit.js | 10 +- .../qpid/management/virtualhostnode/derby/edit.js | 7 +- .../js/qpid/management/store/pool/bonecp/show.js | 14 +- .../js/qpid/management/virtualhost/jdbc/add.js | 12 +- .../js/qpid/management/virtualhost/jdbc/edit.js | 9 +- .../js/qpid/management/virtualhost/jdbc/show.js | 9 +- .../js/qpid/management/virtualhostnode/jdbc/add.js | 11 +- .../qpid/management/virtualhostnode/jdbc/edit.js | 8 +- .../qpid/management/virtualhostnode/jdbc/show.js | 11 +- .../server/management/plugin/HttpManagement.java | 3 + .../plugin/report/QueueBinaryReport.java | 28 ++ .../management/plugin/report/QueueReport.java | 161 +++++++ .../management/plugin/report/QueueTextReport.java | 28 ++ .../management/plugin/report/ReportRunner.java | 408 ++++++++++++++++ .../plugin/report/ReportableMessage.java | 42 ++ .../plugin/report/ReportableMessageHeader.java | 58 +++ .../rest/ConfiguredObjectToMapConverter.java | 4 +- .../plugin/servlet/rest/QueueReportServlet.java | 103 ++++ .../src/main/java/resources/addPort.html | 17 + .../main/java/resources/editVirtualHostNode.html | 33 +- .../resources/js/qpid/common/ResourceWidget.js | 38 +- .../js/qpid/common/grid/ColumnDefDialog.js | 11 +- .../js/qpid/common/grid/RowNumberLimitDialog.js | 14 +- .../src/main/java/resources/js/qpid/common/util.js | 52 ++- .../js/qpid/management/AccessControlProvider.js | 12 +- .../js/qpid/management/AuthenticationProvider.js | 4 +- .../java/resources/js/qpid/management/Broker.js | 12 +- .../resources/js/qpid/management/Connection.js | 14 +- .../java/resources/js/qpid/management/Exchange.js | 5 +- .../resources/js/qpid/management/GroupProvider.js | 7 +- .../java/resources/js/qpid/management/KeyStore.js | 4 +- .../java/resources/js/qpid/management/Plugin.js | 7 +- .../main/java/resources/js/qpid/management/Port.js | 18 +- .../resources/js/qpid/management/Preferences.js | 11 +- .../js/qpid/management/PreferencesProvider.js | 5 +- .../java/resources/js/qpid/management/Queue.js | 5 +- .../resources/js/qpid/management/TrustStore.js | 4 +- .../resources/js/qpid/management/VirtualHost.js | 5 +- .../js/qpid/management/VirtualHostNode.js | 6 +- .../management/accesscontrolprovider/AclFile.js | 6 +- .../accesscontrolprovider/aclfile/add.js | 7 +- .../js/qpid/management/addAccessControlProvider.js | 7 +- .../qpid/management/addAuthenticationProvider.js | 7 +- .../js/qpid/management/addGroupProvider.js | 7 +- .../java/resources/js/qpid/management/addPort.js | 15 +- .../js/qpid/management/addPreferencesProvider.js | 7 +- .../java/resources/js/qpid/management/addStore.js | 14 +- .../management/addVirtualHostNodeAndVirtualHost.js | 7 +- .../PrincipalDatabaseAuthenticationManager.js | 6 +- .../base64md5passwordfile/add.js | 13 +- .../authenticationprovider/external/add.js | 13 +- .../plainpasswordfile/add.js | 13 +- .../authenticationprovider/simpleldap/add.js | 7 +- .../resources/js/qpid/management/editBroker.js | 7 +- .../java/resources/js/qpid/management/editQueue.js | 6 +- .../js/qpid/management/editVirtualHost.js | 6 +- .../js/qpid/management/editVirtualHostNode.js | 9 +- .../resources/js/qpid/management/group/Group.js | 5 +- .../groupprovider/GroupManagingGroupProvider.js | 15 +- .../qpid/management/groupprovider/groupfile/add.js | 13 +- .../qpid/management/logs/LogFileDownloadDialog.js | 8 +- .../resources/js/qpid/management/logs/LogViewer.js | 8 +- .../js/qpid/management/plugin/managementhttp.js | 5 +- .../js/qpid/management/plugin/managementjmx.js | 5 +- .../filesystempreferences/add.js | 13 +- .../filesystempreferences/show.js | 6 +- .../js/qpid/management/store/filekeystore/add.js | 79 ++-- .../js/qpid/management/store/filetruststore/add.js | 74 +-- .../qpid/management/store/nonjavakeystore/add.js | 93 ++-- .../qpid/management/store/nonjavatruststore/add.js | 85 ++-- .../management/store/nonjavatruststore/show.js | 11 +- .../management/virtualhost/providedstore/add.js | 8 +- .../management/virtualhost/providedstore/edit.js | 11 +- .../qpid/management/virtualhostnode/json/edit.js | 7 +- .../src/main/java/resources/showPort.html | 81 ++-- .../src/main/java/resources/showQueue.html | 2 +- .../management/plugin/report/ReportRunnerTest.java | 186 ++++++++ .../management/plugin/report/TestBinaryReport.java | 114 +++++ .../management/plugin/report/TestTextReport.java | 84 ++++ .../rest/ConfiguredObjectToMapConverterTest.java | 1 + ...pid.server.management.plugin.report.QueueReport | 2 + .../qpid/server/jmx/mbeans/ConnectionMBean.java | 2 +- .../server/jmx/mbeans/ConnectionMBeanTest.java | 6 +- .../src/main/java/org/apache/qpid/server/Main.java | 39 +- .../org/apache/qpid/client/AMQBrokerDetails.java | 20 +- .../java/org/apache/qpid/client/AMQConnection.java | 70 ++- .../qpid/client/AMQConnectionDelegate_0_10.java | 128 ++++- .../org/apache/qpid/client/AMQDestination.java | 8 + .../apache/qpid/client/BasicMessageConsumer.java | 5 + .../qpid/client/BasicMessageConsumer_0_8.java | 1 + .../failover/ConnectionRedirectException.java | 46 ++ .../qpid/client/failover/FailoverHandler.java | 6 +- .../handler/ConnectionRedirectMethodHandler.java | 21 +- .../qpid/client/protocol/AMQProtocolHandler.java | 8 - .../qpid/client/protocol/AMQProtocolSession.java | 5 - .../apache/qpid/client/state/AMQStateManager.java | 8 +- .../java/org/apache/qpid/jms/BrokerDetails.java | 2 +- .../org/apache/qpid/common/AMQPFilterTypes.java | 3 +- .../org/apache/qpid/transport/ClientDelegate.java | 10 +- .../java/org/apache/qpid/transport/Connection.java | 26 +- .../apache/qpid/transport/ConnectionListener.java | 3 + .../network/security/sasl/SASLEncryptor.java | 10 +- .../java/org/apache/qpid/url/AMQBindingURL.java | 21 +- .../main/java/org/apache/qpid/url/BindingURL.java | 21 + .../org/apache/qpid/transport/ConnectionTest.java | 25 +- .../java/org/apache/qpid/systest/rest/Asserts.java | 7 +- .../apache/qpid/systest/rest/QpidRestTestCase.java | 6 - .../apache/qpid/systest/rest/RestTestHelper.java | 27 +- .../apache/qpid/test/utils/QpidBrokerTestCase.java | 14 + .../qpid/server/queue/ArrivalTimeFilterTest.java | 107 +++++ .../qpid/server/queue/DefaultFiltersTest.java | 116 +++++ .../queue/EnsureNondestructiveConsumersTest.java | 116 +++++ .../systest/management/jmx/MBeanLifeCycleTest.java | 6 - .../rest/AuthenticationProviderRestTest.java | 54 +-- .../qpid/systest/rest/ConnectionRestTest.java | 12 +- .../apache/qpid/systest/rest/ExchangeRestTest.java | 3 +- .../apache/qpid/systest/rest/KeyStoreRestTest.java | 8 +- .../org/apache/qpid/systest/rest/PortRestTest.java | 13 +- .../apache/qpid/systest/rest/QueueRestTest.java | 3 +- .../qpid/systest/rest/StructureRestTest.java | 2 +- .../qpid/systest/rest/acl/BrokerACLTest.java | 25 +- qpid/java/test-profiles/CPPExcludes | 5 + 227 files changed, 5619 insertions(+), 1291 deletions(-) create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/ArrivalTimeFilter.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/ArrivalTimeFilterFactory.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/JMSSelectorFilterFactory.java delete mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/filter/SimpleFilterManager.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/ConnectionValidator.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/MessageFilterFactory.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/BaseAction.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/FileHelper.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHost.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNode.java create mode 100644 qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeImpl.java delete mode 100644 qpid/java/broker-core/src/main/resources/system.properties create mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/BrokerTest.java create mode 100644 qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/FileHelperTest.java create mode 100644 qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueBinaryReport.java create mode 100644 qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueReport.java create mode 100644 qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/QueueTextReport.java create mode 100644 qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportRunner.java create mode 100644 qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportableMessage.java create mode 100644 qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/report/ReportableMessageHeader.java create mode 100644 qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueReportServlet.java create mode 100644 qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/ReportRunnerTest.java create mode 100644 qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/TestBinaryReport.java create mode 100644 qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/report/TestTextReport.java create mode 100644 qpid/java/broker-plugins/management-http/src/test/resources/META-INF/services/org.apache.qpid.server.management.plugin.report.QueueReport create mode 100644 qpid/java/client/src/main/java/org/apache/qpid/client/failover/ConnectionRedirectException.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ArrivalTimeFilterTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/DefaultFiltersTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/EnsureNondestructiveConsumersTest.java 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
EMPTY_MESSAGE = + Collections.
singletonList(new AmqpValue(null)); private List
_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
(); + _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.
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, Collection>> 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.>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.>singletonList(null)); + + + } + + private Binary _deliveryTag; private List
_payload = new ArrayList
(); private Boolean _resume; @@ -49,7 +117,12 @@ public class Message public Message(Collection
sections) { - _payload.addAll(sections); + this(sections, true); + } + + public Message(Collection
sections, boolean validate) + { + _payload.addAll(validate ? validateOrReorder(sections) : sections); } public Message(Section section) @@ -63,6 +136,106 @@ public class Message } + private static Collection
validateOrReorder(final Collection
providedSections) + { + Collection
validatedSections; + if(providedSections == null) + { + validatedSections = Collections.emptyList(); + } + else if(isValidOrder(providedSections)) + { + validatedSections = providedSections; + } + else + { + validatedSections = reorderSections(providedSections); + } + return validatedSections; + } + + private static Collection
reorderSections(final Collection
providedSections) + { + Collection
validSections = new ArrayList<>(); + List
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 valueSections = getAndRemoveSections(AmqpValue.class, originalSection, false); + final List sequenceSections = getAndRemoveSections(AmqpSequence.class, originalSection, true); + final List 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 List getAndRemoveSections(Class clazz, + List
sections, + boolean allowMultiple) + { + List desiredSections = new ArrayList<>(); + ListIterator
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
providedSections) + { + Class previousSection = null; + final Iterator it = providedSections.iterator(); + while(it.hasNext()) + { + Collection> validSections = VALID_NEXT_SECTIONS.get(previousSection); + Section next = it.next(); + Class sectionClass = next.getClass(); + if(validSections == null || !validSections.contains(sectionClass)) + { + return false; + } + else + { + previousSection = sectionClass; + } + } + Collection> 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 @@ -49,16 +49,7 @@ public class AmqpValueConstructor extends DescribedTypeConstructor 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 _enabledConnectionValidators; + + @ManagedAttributeField + private List _disabledConnectionValidators; + + @ManagedAttributeField + private List _globalAddressDomains; + @ManagedObjectFactoryConstructor public BDBHAReplicaVirtualHostImpl(final Map attributes, VirtualHostNode virtualHostNode) { @@ -161,6 +173,12 @@ public class BDBHAReplicaVirtualHostImpl extends AbstractConfiguredObject port) + { + return null; + } + @Override public boolean isQueue_deadLetterQueueEnabled() { @@ -448,6 +466,47 @@ public class BDBHAReplicaVirtualHostImpl extends AbstractConfiguredObject connection) + { + return false; + } + + @Override + public List getEnabledConnectionValidators() + { + return _enabledConnectionValidators; + } + + @Override + public List getDisabledConnectionValidators() + { + return _disabledConnectionValidators; + } + + @Override + public List 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> extends RemoteReplicationNode { 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 @@
- Required minimum number of nodes:
+ data-dojo-props="data: [{id: '0', name: 'Majority'}]">
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 _configProperties = new HashMap(); private boolean _startupLoggedToSystemOut = true; + private String _initialSystemProperties; public Map 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 @@ -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 enhanceWithDurable(Map 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 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 categoryClass = child.getCategoryClass(); - Collection> childTypes = child.getModel().getChildTypes(categoryClass); + Class categoryClass = child.getCategoryClass(); + Collection> childTypes = + child.getModel().getChildTypes(categoryClass); - for(Class childClass : childTypes) - { - for (ConfiguredObject grandchild : child.getChildren(childClass)) + for (Class 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 @@ -176,17 +176,6 @@ public abstract class AbstractExchange> getEventLogger().message(ExchangeMessages.CREATED(getType(), getName(), isDurable())); } - @Override - protected void onCreate() - { - super.onCreate(); - if(isDurable()) - { - getVirtualHost().getDurableConfigurationStore().create(asObjectRecord()); - } - - } - @Override public EventLogger getEventLogger() { @@ -213,12 +202,6 @@ public abstract class AbstractExchange> throw new RequiredExchangeException(getName()); } - if (isDurable() && !isAutoDelete()) - { - getVirtualHost().getDurableConfigurationStore().remove(asObjectRecord()); - - } - if(_closed.compareAndSet(false,true)) { List bindings = new ArrayList(_bindings); @@ -241,11 +224,6 @@ public abstract class AbstractExchange> } _closeTaskList.clear(); - if (isDurable() && !isAutoDelete()) - { - getVirtualHost().getDurableConfigurationStore().remove(asObjectRecord()); - - } } deleted(); } @@ -665,10 +643,6 @@ public abstract class AbstractExchange> doRemoveBinding(b); queue.removeBinding(b); - if (b.isDurable()) - { - _virtualHost.getDurableConfigurationStore().remove(b.asObjectRecord()); - } b.delete(); } @@ -905,10 +879,6 @@ public abstract class AbstractExchange> protected void changeAttributes(final Map 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 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 -// 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 _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 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 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 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 _filters; - private String _toString = ""; - - public SimpleFilterManager() - { - _logger.debug("Creating SimpleFilterManager"); - _filters = new ConcurrentLinkedQueue(); - } - - 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 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> im private final TaskExecutor _taskExecutor; private final Class _category; + private final Class _typeClass; private final Class _bestFitInterface; private final Model _model; + private final boolean _managesChildStorage; + @ManagedAttributeField private long _createdTime; @@ -206,6 +209,8 @@ public abstract class AbstractConfiguredObject> im _model = model; _category = ConfiguredObjectTypeRegistry.getCategory(getClass()); + Class 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> 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> im } } + private boolean managesChildren(final Class clazz) + { + return clazz.getAnnotation(ManagedObject.class).managesChildren(); + } + private Class calculateBestFitInterface() { Set> candidates = new HashSet>(); @@ -1056,11 +1067,24 @@ public abstract class AbstractConfiguredObject> im return _model; } + @Override public Class getCategoryClass() { return _category; } + @Override + public Class getTypeClass() + { + return _typeClass; + } + + @Override + public boolean managesChildStorage() + { + return _managesChildStorage; + } + public Map getContext() { return _context == null ? Collections.emptyMap() : Collections.unmodifiableMap(_context); @@ -1219,8 +1243,7 @@ public abstract class AbstractConfiguredObject> 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> 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 } }; + static final AttributeValueConverter OBJECT_CONVERTER = new AttributeValueConverter() + { + @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_CONVERTER = new AttributeValueConverter() { @Override @@ -398,7 +417,17 @@ abstract class AttributeValueConverter } else if(Map.class.isAssignableFrom(type)) { - return (AttributeValueConverter) MAP_CONVERTER; + if(returnType instanceof ParameterizedType) + { + Type keyType = ((ParameterizedType) returnType).getActualTypeArguments()[0]; + Type valueType = ((ParameterizedType) returnType).getActualTypeArguments()[1]; + + return (AttributeValueConverter) new GenericMapConverter(keyType,valueType); + } + else + { + return (AttributeValueConverter) MAP_CONVERTER; + } } else if(Collection.class.isAssignableFrom(type)) { @@ -416,6 +445,10 @@ abstract class AttributeValueConverter { return (AttributeValueConverter) new ConfiguredObjectConverter(type); } + else if(Object.class == type) + { + return (AttributeValueConverter) OBJECT_CONVERTER; + } throw new IllegalArgumentException("Cannot create attribute converter of type " + type.getName()); } @@ -575,6 +608,62 @@ abstract class AttributeValueConverter } } + public static class GenericMapConverter extends AttributeValueConverter + { + + 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> extends AttributeValueConverter { private final Class _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 extend private final ManagedAttribute _annotation; private final Method _validValuesMethod; + private final Pattern _secureValuePattern; ConfiguredAutomatedAttribute(final Class clazz, final Method getter, @@ -53,6 +55,16 @@ public class ConfiguredAutomatedAttribute 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 clazz) @@ -140,6 +152,11 @@ public class ConfiguredAutomatedAttribute extend return _annotation.description(); } + public Pattern getSecureValueFilter() + { + return _secureValuePattern; + } + public Collection 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 extends ConfiguredObjectAttribute { private final DerivedAttribute _annotation; + private final Pattern _secureValuePattern; ConfiguredDerivedAttribute(final Class clazz, final Method getter, @@ -32,6 +34,16 @@ public class ConfiguredDerivedAttribute 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 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> void setAttributes(Map attributes) throws IllegalStateException, AccessControlException, IllegalArgumentException; Class getCategoryClass(); + Class getTypeClass(); + + boolean managesChildStorage(); > C findConfiguredObject(Class 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 extends ConfiguredObjectAttributeOrStatistic { @@ -49,6 +50,25 @@ public abstract class ConfiguredObjectAttribute 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 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 getTypeClass(final Class clazz) + public Class getTypeClass(final Class clazz) { String typeName = getType(clazz); Class 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> extends ConfiguredObject 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> extends ConfiguredObject @ManagedAttribute( defaultValue = "NONE" ) ExclusivityPolicy getExclusive(); + @ManagedAttribute( defaultValue = "false" ) + boolean isEnsureNondestructiveConsumers(); + @DerivedAttribute( persist = true ) String getOwner(); @@ -155,6 +162,9 @@ public interface Queue> extends ConfiguredObject @ManagedAttribute long getMaximumMessageTtl(); + @ManagedAttribute + Map>> getDefaultFilters(); + //children Collection 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> extends ConfiguredObject { 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> 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, Q extends Queue, E extends Exchange > extends ConfiguredObject { @@ -42,6 +44,9 @@ public interface VirtualHost, 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, Q extends Queue, @DerivedAttribute( persist = true ) String getModelVersion(); + @ManagedContextDefault( name = "virtualhost.enabledConnectionValidators") + String DEFAULT_ENABLED_VALIDATORS = "[]"; + + @ManagedAttribute( defaultValue = "${virtualhost.enabledConnectionValidators}") + List getEnabledConnectionValidators(); + + @ManagedContextDefault( name = "virtualhost.disabledConnectionValidators") + String DEFAULT_DISABLED_VALIDATORS = "[]"; + + @ManagedAttribute( defaultValue = "${virtualhost.disabledConnectionValidators}") + List getDisabledConnectionValidators(); + + @ManagedAttribute( defaultValue = "[]") + List getGlobalAddressDomains(); + @ManagedStatistic long getQueueCount(); @@ -129,6 +149,8 @@ public interface VirtualHost, 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> extends ConfiguredObject { 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 attributes = new HashMap(); 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> extends GroupProvider, 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 implements FileBasedGroupProvider @@ -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> _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>(); + _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> preferencesMap = _objectMapper.readValue(data, - new TypeReference>>() - { - }); - _preferences.putAll(preferencesMap); - } - catch (JsonProcessingException e) - { - throw new IllegalConfigurationException("Cannot parse preferences json in " + _storeFile.getName(), e); - } + Map> preferencesMap = _objectMapper.readValue(_storeFile, + new TypeReference>>() + { + }); + _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() { - 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 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 Map getInstancesByType(Class clazz) + { + Map instances = new HashMap<>(); + for(C instance : instancesOf(clazz)) + { + instances.put(instance.getType(), instance); + } + return Collections.unmodifiableMap(instances); + } + private Iterable instancesOf(Class 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> @ManagedAttributeField private MessageDurability _messageDurability; + @ManagedAttributeField + private Map>> _defaultFilters; + private Object _exclusiveOwner; // could be connection, session, Principal or a String for the container name private final Set _notificationChecks = @@ -241,12 +249,15 @@ public abstract class AbstractQueue> private long _minimumMessageTtl; @ManagedAttributeField private long _maximumMessageTtl; + @ManagedAttributeField + private boolean _ensureNondestructiveConsumers; private final AtomicBoolean _recovering = new AtomicBoolean(true); private final ConcurrentLinkedQueue _postRecoveryQueue = new ConcurrentLinkedQueue<>(); private final QueueRunner _queueRunner = new QueueRunner(this); private boolean _closing; + private final ConcurrentMap _defaultFiltersMap = new ConcurrentHashMap<>(); protected AbstractQueue(Map attributes, VirtualHostImpl virtualHost) { @@ -283,11 +294,7 @@ public abstract class AbstractQueue> }); } - if (isDurable()) - { - _virtualHost.getDurableConfigurationStore().create(asObjectRecord()); - } - else if(getMessageDurability() != MessageDurability.NEVER) + if(!isDurable() && getMessageDurability() != MessageDurability.NEVER) { Subject.doAs(SecurityManager.getSubjectWithAddedSystemRights(), new PrivilegedAction() @@ -351,17 +358,9 @@ public abstract class AbstractQueue> 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> } _maxAsyncDeliveries = getContextValue(Integer.class, Queue.MAX_ASYNCHRONOUS_DELIVERIES); + + if(_defaultFilters != null) + { + QpidServiceLoader qpidServiceLoader = new QpidServiceLoader(); + final Map messageFilterFactories = + qpidServiceLoader.getInstancesByType(MessageFilterFactory.class); + + for (Map.Entry>> entry : _defaultFilters.entrySet()) + { + String name = String.valueOf(entry.getKey()); + Map> filterValue = entry.getValue(); + if(filterValue.size() == 1) + { + String filterTypeName = String.valueOf(filterValue.keySet().iterator().next()); + MessageFilterFactory filterFactory = messageFilterFactories.get(filterTypeName); + if(filterFactory != null) + { + List 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(); } @@ -554,6 +587,12 @@ public abstract class AbstractQueue> } } + @Override + public Map>> getDefaultFilters() + { + return _defaultFilters; + } + @Override public final MessageDurability getMessageDurability() { @@ -572,6 +611,14 @@ public abstract class AbstractQueue> return _maximumMessageTtl; } + @Override + public boolean isEnsureNondestructiveConsumers() + { + return _ensureNondestructiveConsumers; + } + + + @Override public Collection getAvailableAttributes() { @@ -603,7 +650,7 @@ public abstract class AbstractQueue> @Override public synchronized QueueConsumerImpl addConsumer(final ConsumerTarget target, - final FilterManager filters, + FilterManager filters, final Class messageClass, final String consumerName, EnumSet optionSet) @@ -699,6 +746,26 @@ public abstract class AbstractQueue> { throw new ExistingConsumerPreventsExclusive(); } + if(!_defaultFiltersMap.isEmpty()) + { + if(filters == null) + { + filters = new FilterManager(); + } + for (Map.Entry 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 ATTRIBUTE_MAPPINGS = new LinkedHashMap(); + 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 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> extends KeyStore @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> 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 _userMap = new HashMap(); + private final Map _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 newUserMap = new HashMap(); + final Map newUserMap = new HashMap<>(); BufferedReader reader = null; try @@ -224,71 +225,33 @@ public abstract class AbstractPasswordFilePrincipalDatabase() + { + @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 { 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 { 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> extends AbstractAuthenticationManager @@ -96,7 +100,11 @@ public abstract class PrincipalDatabaseAuthenticationManager() { - 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> _idsByType = new HashMap>(); private final ObjectMapper _objectMapper = new ObjectMapper(); private final Class _rootClass; + private final FileHelper _fileHelper; private Map> _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 data = null; + final Map 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() + { + @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>() + { + @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>() + { + @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> action) + { + applyRecursively(object, action, new HashSet>()); + } + + private void applyRecursively(final ConfiguredObject object, + final Action> action, + final HashSet> visited) + { + if(!visited.contains(object)) + { + visited.add(object); + action.performAction(object); + for(Class childClass : object.getModel().getChildTypes(object.getCategoryClass())) + { + Collection 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 _tasks = new ConcurrentLinkedQueue<>(); private final Queue _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 +public interface Action extends BaseAction { 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 +{ + 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 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 write) throws IOException + { + Files.deleteIfExists(tmpFile); + Files.deleteIfExists(backupFile); + + Set 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 permissions = posixFileAttributes == null ? null : PosixFilePermissions.fromString(posixFileAttributes); + return createNewFile(newFile, permissions ); + } + + public Path createNewFile(Path newFile, Set 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> extends AbstractConfiguredObject implements VirtualHostImpl, ExchangeImpl>, IConnectionRegistry.RegistryChangeListener, EventListener { + private final Collection _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> exte @ManagedAttributeField private int _housekeepingThreadCount; + @ManagedAttributeField + private List _enabledConnectionValidators; + + @ManagedAttributeField + private List _disabledConnectionValidators; + + @ManagedAttributeField + private List _globalAddressDomains; private boolean _useAsyncRecoverer; @@ -212,6 +223,13 @@ public abstract class AbstractVirtualHost> 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> 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> 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> 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> 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. @@ -525,10 +596,43 @@ public abstract class AbstractVirtualHost> exte return _houseKeepingTasks.getActiveCount(); } + @Override + public List getEnabledConnectionValidators() + { + return _enabledConnectionValidators; + } + + @Override + public List getDisabledConnectionValidators() + { + return _disabledConnectionValidators; + } + + @Override + public List 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> 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> 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> 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> 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> 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> 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, 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> + extends VirtualHostImpl, ExchangeImpl>, + NonStandardVirtualHost,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 + implements RedirectingVirtualHost +{ + 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 _enabledConnectionValidators; + + @ManagedAttributeField + private List _disabledConnectionValidators; + + @ManagedAttributeField + private List _globalAddressDomains; + + @ManagedObjectFactoryConstructor + public RedirectingVirtualHostImpl(final Map 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 changedAttributes) + { + super.validateChange(proxyForValidation, changedAttributes); + + throwUnsupportedForRedirector(); + } + + @Override + public String getModelVersion() + { + return BrokerModel.MODEL_VERSION; + } + + @Override + protected C addChild(final Class childClass, + final Map attributes, + final ConfiguredObject... otherParents) + { + throwUnsupportedForRedirector(); + return null; + } + + @Override + public ExchangeImpl createExchange(final Map 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 attributes) + { + throwUnsupportedForRedirector(); + return null; + } + + @Override + public void executeTransaction(final TransactionalOperation op) + { + throwUnsupportedForRedirector(); + } + + @Override + public Collection 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 getAliases() + { + return Collections.emptyList(); + } + + @Override + public Collection 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> getQueues() + { + return Collections.emptyList(); + } + + @Override + public int removeQueue(final AMQQueue queue) + { + throwUnsupportedForRedirector(); + return 0; + } + + @Override + public Collection> 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 getEnabledConnectionValidators() + { + return _enabledConnectionValidators; + } + + @Override + public List getDisabledConnectionValidators() + { + return _disabledConnectionValidators; + } + + @Override + public List 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> extends VirtualHostNode +{ + + @ManagedAttribute( defaultValue = "{}") + Map, 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 implements RedirectingVirtualHostNode +{ + 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,String> _redirects; + + private RedirectingVirtualHostImpl _virtualHost; + + @ManagedObjectFactoryConstructor + public RedirectingVirtualHostNodeImpl(Map attributes, Broker parent) + { + super(Collections.,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.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 getRemoteReplicationNodes() + { + return Collections.emptySet(); + } + + @Override + public Map, String> getRedirects() + { + return _redirects; + } + + public static Map> getSupportedChildTypes() + { + Collection 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 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.>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 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 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 entriesMap = new ConcurrentHashMap(); @@ -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() + { + @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 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())); + } 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 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 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 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 +{ + 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; + +/** + *

+ * The QueueReport class provides an extension point for installations to provide custom management reporting on + * queues through the REST API. + *

+ * + *

+ * 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}). + *

+ * + *

Running reports

+ *

+ * The report can be run using the URL: + * {@code http:///service/queuereport///[?param1=x¶m2=y...]} + *

+ * + *

Report Parameters

+ * + *

+ * 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. + *

+ *

+ * Setters for the parameters are guaranteed to be called before the first message is added to the report. + *

+ * + *

+ * 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. + *

+ * @param + */ +public abstract class QueueReport +{ + private Queue _queue; + + QueueReport() + { + + } + + /** + * Gets the name of the report. + *

+ * 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. + *

+ * @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. + * + *

+ * The method is called by the system for every message on the queue, or until {@link #isComplete()} returns true. + *

+ * @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). + * + *

+ * 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. + *

+ *

+ * If this method always returns false, then all messages from the queue will be added to the report. + *

+ *

+ * 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. + *

+ * + * @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. + *

+ * The system guarantees to only call this method once + *

+ * @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 +{ + 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 +{ + private static final Logger LOGGER = LoggerFactory.getLogger(ReportRunner.class); + + private static final Set IMMUTABLE_CLASSES = new HashSet<>(Arrays.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 report) + { + _report = report; + } + + public boolean isBinaryReport() + { + return _report instanceof QueueBinaryReport; + } + + public static ReportRunner createRunner(final String reportName, final Map parameterMap) + { + QueueReport report = getReport(reportName); + setReportParameters(report, parameterMap); + return new ReportRunner<>(report); + } + + private static void setReportParameters(final QueueReport report, final Map parameterMap) + { + if(parameterMap != null && !parameterMap.isEmpty()) + { + Class clazz = report.getClass(); + for(Map.Entry 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 names) + { + return messageHeader.containsHeaders(names); + } + + @Override + public boolean containsHeader(final String name) + { + return messageHeader.containsHeader(name); + } + + @Override + public Collection 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 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 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 _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 names); + + boolean containsHeader(String name); + + Collection 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 @@ +
+
+
+ +
+
+ +
+
+
+
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 @@
-
-
NOTE: All changes will only take effect after Virtual Host Node restart.
-
-
Name*:
-
- +
+
NOTE: All changes will only take effect after Virtual Host Node restart.
+
+
Name*:
+
+ -
-
+
+
-
+
-
+
-
-
+
+
+
+
-
+
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= 0) ? entities.encode(String(this.portData[ "maxOpenConnections" ])) : "(no limit)" ; + this.keyStoreValue.innerHTML = this.portData[ "keyStore" ] ? entities.encode(String(this.portData[ "keyStore" ])) : ""; this.needClientAuthValue.innerHTML = "" ; this.wantClientAuthValue.innerHTML = "" ; @@ -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; iName:
- -
-
Port Type:
-
+
+
+
+
Port Type:
+
+
+
+
+
Open connections (current/maximum):
+
+ / +
+
+
-
+
State:
-
-
+
+
-
+
Port Number:
-
-
+
+
-
+
Protocols:
-
-
+
+
-
Authentication Provider:
-
+
Authentication Provider:
+
-
Binding address:
-
+
Binding address:
+
Transports:
-
-
+
+
-
-
Key Store:
-
-
+
+
Key Store:
+
+
-
-
Need SSL Client Certificate:
-
-
+
+
Need SSL Client Certificate:
+
+
-
-
Want SSL Client Certificate:
-
-
+
+
Want SSL Client Certificate:
+
+
+ +
+
Trust Stores:
+
+
-
-
Trust Stores:
-
-

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 @@
Name:
-
+
Type:
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 runner = (ReportRunner) ReportRunner.createRunner(TestTextReport.NAME, + Collections.emptyMap()); + Queue queue = createMockQueue(); + assertEquals("There are 0 messages on the queue.", runner.runReport(queue)); + + runner = (ReportRunner) ReportRunner.createRunner(TestTextReport.NAME, + Collections.emptyMap()); + Queue queue1 = createMockQueue(mock(ServerMessage.class)); + assertEquals("There are 1 messages on the queue.", runner.runReport(queue1)); + + runner = (ReportRunner) ReportRunner.createRunner(TestTextReport.NAME, + Collections.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 parameterMap = new HashMap<>(); + parameterMap.put("stringParam", new String[]{"hello world"}); + ReportRunner runner = + (ReportRunner) 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 parameterMap = new HashMap<>(); + parameterMap.put("stringArrayParam", new String[] { "hello world", "goodbye"}); + ReportRunner runner = (ReportRunner) 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 parameterMap = new HashMap<>(); + parameterMap.put("stringParam", new String[]{"hello world"}); + parameterMap.put("stringArrayParam", new String[] { "hello world", "goodbye"}); + ReportRunner runner = (ReportRunner) 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.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.singletonMap("key",1)), + createMessageWithAppProperties(Collections.singletonMap("key",2)), + createMessageWithAppProperties(Collections.singletonMap("key", 3)), + createMessageWithAppProperties(Collections.singletonMap("key", 4))); + Map parameterMap = new HashMap<>(); + parameterMap.put("propertyName", new String[]{"key"}); + parameterMap.put("limit", new String[] { "3" }); + + ReportRunner runner = (ReportRunner) 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 props) + { + ServerMessage message = mock(ServerMessage.class); + final AMQMessageHeader header = mock(AMQMessageHeader.class); + when(message.getMessageHeader()).thenReturn(header); + final ArgumentCaptor headerNameCaptor = ArgumentCaptor.forClass(String.class); + when(header.getHeader(headerNameCaptor.capture())).thenAnswer(new Answer() + { + @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 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> 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 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 _options = new HashMap(); + 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 knownHosts) + { + exception = new RedirectConnectionException(host,knownHosts); + + return false; + } + + private boolean attemptRedirection(String host, List 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 executeRetrySupport(FailoverProtectedOperation 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 _knownHosts; + + public RedirectConnectionException(final String host, + final List knownHosts) + { + super("Connection redirected to " + host + " alternates " + knownHosts); + _host = host; + _knownHosts = knownHosts; + } + + public String getHost() + { + return _host; + } + + public List 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 _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 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 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 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 { @@ -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. *

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 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 knownHosts) + { + return false; + } } public static interface SessionFactory @@ -150,6 +157,11 @@ public class Connection extends ConnectionInvoker listeners.add(listener); } + public List 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 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 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 getConsumerOptions() + { + Map options = new HashMap<>(); + for(Map.Entry 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 NON_CONSUMER_OPTIONS = + Collections.unmodifiableSet(new HashSet(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 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 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 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 anonymousProviderAttributes = new HashMap(); - 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 groupMemberData = new HashMap(); @@ -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 groupData = new HashMap(); @@ -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(); 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 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 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 anonymousProviderAttributes = new HashMap(); - 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> 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 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 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 attributes = new HashMap(); - 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 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> 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 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 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> 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> 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> 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> 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 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 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 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 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> keyStores = assertNumberOfKeyStores(1); Map 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 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 portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(portName, "UTF-8")); + Map 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(); 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 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 portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(ampqPortName, "UTF-8")); + Map 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 portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(ampqPortName, "UTF-8")); + Map 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> ports = getRestTestHelper().getJsonAsList("port/" + URLDecoder.decode(newPortName, "UTF-8")); + List> 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> providers = (List>) 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 attributes = new HashMap(); - 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 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 attributes = new HashMap(); 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#* + -- cgit v1.2.1