diff options
Diffstat (limited to 'java')
110 files changed, 7121 insertions, 2980 deletions
diff --git a/java/bdbstore/jmx/src/main/java/org/apache/qpid/server/store/berkeleydb/jmx/BDBHAMessageStoreManagerMBeanProvider.java b/java/bdbstore/jmx/src/main/java/org/apache/qpid/server/store/berkeleydb/jmx/BDBHAMessageStoreManagerMBeanProvider.java index 45e0c39274..76e4415d7c 100644 --- a/java/bdbstore/jmx/src/main/java/org/apache/qpid/server/store/berkeleydb/jmx/BDBHAMessageStoreManagerMBeanProvider.java +++ b/java/bdbstore/jmx/src/main/java/org/apache/qpid/server/store/berkeleydb/jmx/BDBHAMessageStoreManagerMBeanProvider.java @@ -27,6 +27,7 @@ import org.apache.qpid.server.jmx.MBeanProvider; import org.apache.qpid.server.jmx.ManagedObject; import org.apache.qpid.server.jmx.ManagedObjectRegistry; import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.State; import org.apache.qpid.server.store.berkeleydb.replication.ReplicatedEnvironmentFacade; import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; @@ -46,7 +47,7 @@ public class BDBHAMessageStoreManagerMBeanProvider implements MBeanProvider @Override public boolean isChildManageableByMBean(ConfiguredObject child) { - return child instanceof BDBHAVirtualHostNode; + return child instanceof BDBHAVirtualHostNode && ((BDBHAVirtualHostNode)child).getState() != State.ERRORED; } @Override diff --git a/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBSystemConfigImpl.java b/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBSystemConfigImpl.java index 0fc44605fe..5d65d6e16d 100644 --- a/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBSystemConfigImpl.java +++ b/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBSystemConfigImpl.java @@ -26,6 +26,7 @@ import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.LogRecorder; import org.apache.qpid.server.model.AbstractSystemConfig; import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerShutdownProvider; import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.SystemConfigFactoryConstructor; @@ -48,9 +49,10 @@ public class BDBSystemConfigImpl extends AbstractSystemConfig<BDBSystemConfigImp public BDBSystemConfigImpl(final TaskExecutor taskExecutor, final EventLogger eventLogger, final LogRecorder logRecorder, - final BrokerOptions brokerOptions) + final BrokerOptions brokerOptions, + final BrokerShutdownProvider brokerShutdownProvider) { - super(taskExecutor, eventLogger, logRecorder, brokerOptions); + super(taskExecutor, eventLogger, logRecorder, brokerOptions, brokerShutdownProvider); } @Override diff --git a/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java b/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java index 20dbdc703a..532cffdac8 100644 --- a/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java +++ b/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java @@ -1253,7 +1253,7 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan { if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Setting permitted nodes to " + permittedNodes); + LOGGER.debug(_prettyGroupNodeName + " permitted nodes set to " + permittedNodes); } _permittedNodes.clear(); @@ -1263,12 +1263,18 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan registerAppStateMonitorIfPermittedNodesSpecified(); ReplicationGroupListener listener = _replicationGroupListener.get(); + int count = 0; for(ReplicationNode node: _remoteReplicationNodes.values()) { if (!isNodePermitted(node)) { onIntruder(listener, node); } + count++; + } + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug(_prettyGroupNodeName + " checked " + count + " node(s)"); } } } @@ -1329,7 +1335,7 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan } catch (IOException e) { - throw new IllegalConfigurationException(String.format("Cannot connect to '%s'", helperHostPort), e); + throw new IllegalConfigurationException(String.format("Cannot connect to existing node '%s' at '%s'", helperNodeName, helperHostPort), e); } catch (ServiceConnectFailedException e) { @@ -1337,8 +1343,8 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan } catch (Exception e) { - throw new RuntimeException(String.format("Unexpected exception on attempt to retrieve state from '%s' at '%s'", - helperNodeName, helperHostPort), e); + throw new RuntimeException(String.format("Cannot retrieve state for node '%s' (%s) from group '%s'", + helperNodeName, helperHostPort, groupName), e); } if (LOGGER.isDebugEnabled()) diff --git a/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java b/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java index e6109954c0..0003e74dbc 100644 --- a/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java +++ b/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java @@ -20,7 +20,11 @@ */ package org.apache.qpid.server.virtualhostnode.berkeleydb; +import java.io.File; import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; import java.security.PrivilegedAction; import java.text.MessageFormat; import java.util.ArrayList; @@ -74,6 +78,7 @@ import org.apache.qpid.server.store.berkeleydb.BDBConfigurationStore; import org.apache.qpid.server.store.berkeleydb.replication.ReplicatedEnvironmentFacade; import org.apache.qpid.server.store.berkeleydb.replication.ReplicatedEnvironmentFacadeFactory; import org.apache.qpid.server.store.berkeleydb.replication.ReplicationGroupListener; +import org.apache.qpid.server.util.PortUtil; import org.apache.qpid.server.util.ServerScopedRuntimeException; import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHostImpl; import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; @@ -255,7 +260,7 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu public String toString() { return "BDBHAVirtualHostNodeImpl [id=" + getId() + ", name=" + getName() + ", storePath=" + _storePath + ", groupName=" + _groupName + ", address=" + _address - + ", state=" + getState() + ", priority=" + _priority + ", designatedPrimary=" + _designatedPrimary + ", quorumOverride=" + _quorumOverride + "]"; + + ", state=" + getState() + ", priority=" + _priority + ", designatedPrimary=" + _designatedPrimary + ", quorumOverride=" + _quorumOverride + ", role=" + getRole() + "]"; } @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -282,22 +287,18 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu super.onCreate(); if (!isFirstNodeInAGroup()) { - try - { - int dbPingSocketTimeout = getContextKeys(false).contains("qpid.bdb.ha.db_ping_socket_timeout") ? getContextValue(Integer.class, "qpid.bdb.ha.db_ping_socket_timeout") : 10000 /* JE's own default */; - Collection<String> permittedNodes = ReplicatedEnvironmentFacade.connectToHelperNodeAndCheckPermittedHosts(getName(), getAddress(), getGroupName(), getHelperNodeName(), getHelperAddress(), dbPingSocketTimeout); - setAttribute(PERMITTED_NODES, null, new ArrayList<String>(permittedNodes)); - } - catch(IllegalConfigurationException e) - { - deleted(); - throw e; - } + _permittedNodes = new ArrayList<>(getPermittedNodesFromHelper()); } - getEventLogger().message(getVirtualHostNodeLogSubject(), HighAvailabilityMessages.CREATED()); } + @Override + public void onOpen() + { + validatePermittedNodesFormat(_permittedNodes); + super.onOpen(); + } + protected ReplicatedEnvironmentFacade getReplicatedEnvironmentFacade() { return _environmentFacade.get(); @@ -334,6 +335,24 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu throw new IllegalStateException("Environment facade is not created"); } + try + { + Set<ReplicationNode> remoteNodes = environmentFacade.getEnvironment().getGroup().getNodes(); + for (ReplicationNode node : remoteNodes) + { + String nodeAddress = node.getHostName() + ":" + node.getPort(); + if (!_permittedNodes.contains(nodeAddress)) + { + shutdownOnIntruder(nodeAddress); + throw new IllegalStateException("Intruder node detected: " + nodeAddress); + } + } + } + catch (DatabaseException dbe) + { + environmentFacade.handleDatabaseException("DB exception while checking for intruder node", dbe); + } + if (_environmentFacade.compareAndSet(null, environmentFacade)) { environmentFacade.setStateChangeListener(new EnvironmentStateChangeListener()); @@ -372,9 +391,15 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu @StateTransition( currentState = { State.ACTIVE, State.STOPPED, State.ERRORED}, desiredState = State.DELETED ) protected void doDelete() { + // get helpers before close. on close all children are closed and not available anymore Set<InetSocketAddress> helpers = getRemoteNodeAddresses(); super.doDelete(); - getEventLogger().message(getVirtualHostNodeLogSubject(), HighAvailabilityMessages.DELETED()); + + if (getConfigurationStore() != null) + { + getEventLogger().message(getVirtualHostNodeLogSubject(), HighAvailabilityMessages.DELETED()); + } + if (getState() == State.DELETED && !helpers.isEmpty()) { try @@ -432,20 +457,87 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu } @Override - public void onValidate() + protected void postResolve() { - super.onValidate(); + super.postResolve(); _virtualHostNodeLogSubject = new BDBHAVirtualHostNodeLogSubject(getGroupName(), getName()); _groupLogSubject = new GroupLogSubject(getGroupName()); _virtualHostNodePrincipalName = MessageFormat.format(VIRTUAL_HOST_PRINCIPAL_NAME_FORMAT, getGroupName(), getName()); } @Override - public void onOpen() + public void validateOnCreate() { - super.onOpen(); + super.validateOnCreate(); + + validateAddress(); - validatePermittedNodes(_permittedNodes); + validateStorePath(); + + if (!isFirstNodeInAGroup()) + { + getPermittedNodesFromHelper(); + } + } + + private Collection<String> getPermittedNodesFromHelper() + { + int dbPingSocketTimeout = getContextKeys(false).contains("qpid.bdb.ha.db_ping_socket_timeout") ? getContextValue(Integer.class, "qpid.bdb.ha.db_ping_socket_timeout") : 10000 /* JE's own default */; + return ReplicatedEnvironmentFacade.connectToHelperNodeAndCheckPermittedHosts(getName(), getAddress(), getGroupName(), getHelperNodeName(), getHelperAddress(), dbPingSocketTimeout); + } + + private void validateStorePath() + { + File storePath = new File(getStorePath()); + while (!storePath.exists()) + { + storePath = storePath.getParentFile(); + if (storePath == null) + { + throw new IllegalConfigurationException(String.format("Store path '%s' is invalid", getStorePath())); + } + } + + if (!storePath.isDirectory()) + { + throw new IllegalConfigurationException(String.format("Store path '%s' is not a folder", getStorePath())); + } + + if (!Files.isWritable(storePath.toPath())) + { + throw new IllegalConfigurationException(String.format("Store path '%s' is not writable", getStorePath())); + } + } + + private void validateAddress() + { + String address = getAddress(); + + URI uri = addressToURI(address); + + if (!PortUtil.isPortAvailable(uri.getHost(), uri.getPort())) + { + throw new IllegalConfigurationException(String.format("Cannot bind to address '%s'. Address is already in use.", address)); + } + } + + private URI addressToURI(String address) + { + if (address == null || "".equals(address)) + { + throw new IllegalConfigurationException("Node address is not set"); + } + + URI uri = null; + try + { + uri = new URI( "tcp://" + address); + } + catch (URISyntaxException e) + { + throw new IllegalConfigurationException(String.format("Invalid address specified '%s'. ", address)); + } + return uri; } private void onMaster() @@ -538,7 +630,7 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu private void onDetached() { - createReplicaVirtualHost(); + closeVirtualHostIfExist(); } private void createReplicaVirtualHost() @@ -578,7 +670,7 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu if (LOGGER.isInfoEnabled()) { - LOGGER.info("Received BDB event indicating transition to state " + state); + LOGGER.info("Received BDB event indicating transition to state " + state + " for " + getName()); } NodeRole previousRole = getRole(); try @@ -728,7 +820,7 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu private boolean isFirstNodeInAGroup() { - return getAddress().equals(getHelperAddress()); + return getHelperNodeName() == null; } BDBHAVirtualHostNodeLogSubject getVirtualHostNodeLogSubject() @@ -761,7 +853,7 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu } } - private void validatePermittedNodes(List<String> proposedPermittedNodes) + private void validatePermittedNodes(Collection<String> proposedPermittedNodes) { if (getRemoteReplicationNodes().size() > 0 && getRole() != NodeRole.MASTER && !(getState() == State.STOPPED || getState() == State.ERRORED)) { @@ -772,47 +864,48 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu throw new IllegalArgumentException(String.format("Attribute '%s' is mandatory and must be set", PERMITTED_NODES)); } - String missingNodeAddress = null; - if (getPermittedNodes().contains(getAddress()) && !proposedPermittedNodes.contains(getAddress())) + if (_permittedNodes != null) { - missingNodeAddress = getAddress(); - } - else - { - for (final RemoteReplicationNode<?> node : getRemoteReplicationNodes()) + String missingNodeAddress = null; + + if (_permittedNodes.contains(getAddress()) && !proposedPermittedNodes.contains(getAddress())) { - final BDBHARemoteReplicationNode<?> bdbHaRemoteReplicationNode = (BDBHARemoteReplicationNode<?>) node; - final String remoteNodeAddress = bdbHaRemoteReplicationNode.getAddress(); - if (getPermittedNodes().contains(remoteNodeAddress) && !proposedPermittedNodes.contains(remoteNodeAddress)) + missingNodeAddress = getAddress(); + } + else + { + for (final RemoteReplicationNode<?> node : getRemoteReplicationNodes()) { - missingNodeAddress = remoteNodeAddress; - break; + final BDBHARemoteReplicationNode<?> bdbHaRemoteReplicationNode = (BDBHARemoteReplicationNode<?>) node; + final String remoteNodeAddress = bdbHaRemoteReplicationNode.getAddress(); + if (_permittedNodes.contains(remoteNodeAddress) && !proposedPermittedNodes.contains(remoteNodeAddress)) + { + missingNodeAddress = remoteNodeAddress; + break; + } } } + + if (missingNodeAddress != null) + { + throw new IllegalArgumentException(String.format("The current group node '%s' cannot be removed from '%s' as its already a group member", missingNodeAddress, PERMITTED_NODES)); + } } - if (missingNodeAddress != null) + validatePermittedNodesFormat(proposedPermittedNodes); + } + + private void validatePermittedNodesFormat(Collection<String> permittedNodes) + { + if (permittedNodes == null || permittedNodes.isEmpty()) { - throw new IllegalArgumentException(String.format("The current group node '%s' cannot be removed from '%s' as its already a group member", missingNodeAddress, PERMITTED_NODES)); + throw new IllegalConfigurationException("Permitted nodes are not set"); } - for (String permittedNode: proposedPermittedNodes) + for (String permittedNode: permittedNodes) { - String[] tokens = permittedNode.split(":"); - if (tokens.length != 2) - { - throw new IllegalArgumentException(String.format("Invalid permitted node specified '%s'. ", permittedNode)); - } - try - { - Integer.parseInt(tokens[1]); - } - catch(Exception e) - { - throw new IllegalArgumentException(String.format("Invalid port is specified in permitted node '%s'. ", permittedNode)); - } + addressToURI(permittedNode); } - } private class RemoteNodesDiscoverer implements ReplicationGroupListener @@ -931,7 +1024,7 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu { byte[] applicationState = nodeState.getAppState(); Set<String> permittedNodes = ReplicatedEnvironmentFacade.convertApplicationStateBytesToPermittedNodeList(applicationState); - if (!_permittedNodes.equals(permittedNodes)) + if (_permittedNodes.size() != permittedNodes.size() || !_permittedNodes.containsAll(permittedNodes)) { if (_permittedNodes.contains(remoteNode.getAddress())) { @@ -972,7 +1065,7 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu private boolean processIntruderNode(ReplicationNode node) { - String hostAndPort = node.getHostName() + ":" + node.getPort(); + final String hostAndPort = node.getHostName() + ":" + node.getPort(); getEventLogger().message(getGroupLogSubject(), HighAvailabilityMessages.INTRUDER_DETECTED(node.getName(), hostAndPort)); boolean inManagementMode = getParent(Broker.class).isManagementMode(); @@ -994,35 +1087,16 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu BDBHAVirtualHostNodeImpl.this.getName(), _lastRole.get(), String.valueOf(BDBHAVirtualHostNodeImpl.this.getPermittedNodes()) )); - getTaskExecutor().submit(new Task<Void>() { @Override public Void execute() { - State state = getState(); - if (state != State.ERRORED) - { - try - { - stopAndSetStateTo(State.ERRORED); - } - catch(Exception e) - { - LOGGER.error("Unexpected exception on closing the node when intruder is detected ", e); - } - finally - { - closeEnvironment(); - - _lastRole.set(NodeRole.DETACHED); - attributeSet(ROLE, _role, NodeRole.DETACHED); - } - notifyStateChanged(state, State.ERRORED); - } + shutdownOnIntruder(hostAndPort); return null; } }); + return false; } } @@ -1044,6 +1118,28 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu } } + protected void shutdownOnIntruder(String intruderHostAndPort) + { + LOGGER.info("Intruder detected (" + intruderHostAndPort + "), stopping and setting state to ERRORED"); + + State initialState = getState(); + try + { + stopAndSetStateTo(State.ERRORED); + } + catch (Exception e) + { + LOGGER.error("Unexpected exception on closing the node when intruder is detected ", e); + } + finally + { + closeEnvironment(); + _lastRole.set(NodeRole.DETACHED); + attributeSet(ROLE, _role, NodeRole.DETACHED); + } + notifyStateChanged(initialState, State.ERRORED); + } + private abstract class VirtualHostNodeGroupTask implements Task<Void> { @Override diff --git a/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js b/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js index 18853e63a7..464a01b5b0 100644 --- a/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js +++ b/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js @@ -106,6 +106,7 @@ define(["dojo/_base/xhr", _changeAddress: function(address, virtualHostNodeHelperAddress) { virtualHostNodeHelperAddress.set("value", address); + this._updatePermittedNodesJson(); }, _clickAddPermittedNodeButton: function(e) { diff --git a/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java b/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java index e9bcc5d754..ee990d3211 100644 --- a/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java +++ b/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java @@ -23,13 +23,17 @@ package org.apache.qpid.server.store.berkeleydb; import static org.mockito.Mockito.when; import java.io.File; +import java.net.InetSocketAddress; +import java.net.ServerSocket; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import com.sleepycat.je.Durability; @@ -38,12 +42,14 @@ import com.sleepycat.je.rep.ReplicatedEnvironment; import com.sleepycat.je.rep.ReplicationConfig; 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.RemoteReplicationNode; import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.store.berkeleydb.replication.DatabasePinger; import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost; import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHostImpl; import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHARemoteReplicationNode; @@ -53,6 +59,8 @@ import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNodeTes import org.apache.qpid.server.virtualhostnode.berkeleydb.NodeRole; import org.apache.qpid.test.utils.PortHelper; import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.test.utils.TestFileUtils; +import org.apache.qpid.util.FileUtils; public class BDBHAVirtualHostNodeTest extends QpidTestCase { @@ -289,6 +297,7 @@ public class BDBHAVirtualHostNodeTest extends QpidTestCase _helper.awaitRemoteNodes(master, 2); BDBHAVirtualHostNode<?> replica = _helper.awaitAndFindNodeInRole(NodeRole.REPLICA); + _helper.awaitRemoteNodes(replica, 2); assertNotNull("Remote node " + replica.getName() + " is not found", _helper.findRemoteNode(master, replica.getName())); replica.delete(); @@ -481,21 +490,70 @@ public class BDBHAVirtualHostNodeTest extends QpidTestCase nonMasterNode.setAttributes(Collections.<String, Object>singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, amendedPermittedNodes)); } + public void testIntruderProtection() throws Exception + { + int nodePortNumber = _portHelper.getNextAvailable(); + int intruderPortNumber = _portHelper.getNextAvailable(); + + String helperAddress = "localhost:" + nodePortNumber; + String groupName = "group"; + String nodeName = "node"; + + Map<String, Object> node1Attributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, nodePortNumber, intruderPortNumber); + BDBHAVirtualHostNode<?> node = _helper.createAndStartHaVHN(node1Attributes); + + Map<String, Object> intruderAttributes = _helper.createNodeAttributes("intruder", groupName, "localhost:" + intruderPortNumber, helperAddress, nodeName); + intruderAttributes.put(BDBHAVirtualHostNode.PRIORITY, 0); + BDBHAVirtualHostNode<?> intruder = _helper.createAndStartHaVHN(intruderAttributes); + + final CountDownLatch stopLatch = new CountDownLatch(1); + ConfigurationChangeListener listener = new NoopConfigurationChangeListener() + { + @Override + public void stateChanged(ConfiguredObject<?> object, State oldState, State newState) + { + if (newState == State.ERRORED) + { + stopLatch.countDown(); + } + } + }; + node.addChangeListener(listener); + + List<String> permittedNodes = new ArrayList<String>(); + permittedNodes.add(helperAddress); + node.setAttributes(Collections.<String, Object>singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, permittedNodes)); + + assertTrue("Intruder protection was not triggered during expected timeout", stopLatch.await(10, TimeUnit.SECONDS)); + + // Try top re start the ERRORED node and ensure exception is thrown + try + { + node.start(); + fail("Restart of node should have thrown exception"); + } + catch (IllegalStateException ise) + { + assertEquals("Unexpected exception when restarting node post intruder detection", "Intruder node detected: " + "localhost:" + intruderPortNumber, ise.getMessage()); + } + _helper.awaitForAttributeChange(node, AbstractConfiguredObject.STATE, State.ERRORED); + } + public void testIntruderProtectionInManagementMode() throws Exception { - int node1PortNumber = _portHelper.getNextAvailable(); - int node2PortNumber = _portHelper.getNextAvailable(); + int nodePortNumber = _portHelper.getNextAvailable(); + int intruderPortNumber = _portHelper.getNextAvailable(); - String helperAddress = "localhost:" + node1PortNumber; + String helperAddress = "localhost:" + nodePortNumber; String groupName = "group"; - String nodeName = "node1"; + String nodeName = "node"; - Map<String, Object> node1Attributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, node1PortNumber, node2PortNumber); - BDBHAVirtualHostNode<?> node1 = _helper.createAndStartHaVHN(node1Attributes); + Map<String, Object> nodeAttributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, nodePortNumber, intruderPortNumber); + BDBHAVirtualHostNode<?> node = _helper.createAndStartHaVHN(nodeAttributes); - Map<String, Object> node2Attributes = _helper.createNodeAttributes("node2", groupName, "localhost:" + node2PortNumber, helperAddress, nodeName); - node2Attributes.put(BDBHAVirtualHostNode.PRIORITY, 0); - BDBHAVirtualHostNode<?> node2 = _helper.createAndStartHaVHN(node2Attributes); + Map<String, Object> intruderAttributes = _helper.createNodeAttributes("intruder", groupName, "localhost:" + intruderPortNumber, helperAddress, nodeName); + intruderAttributes.put(BDBHAVirtualHostNode.PRIORITY, 0); + BDBHAVirtualHostNode<?> intruder = _helper.createAndStartHaVHN(intruderAttributes); final CountDownLatch stopLatch = new CountDownLatch(1); ConfigurationChangeListener listener = new NoopConfigurationChangeListener() @@ -509,21 +567,85 @@ public class BDBHAVirtualHostNodeTest extends QpidTestCase } } }; - node1.addChangeListener(listener); + node.addChangeListener(listener); List<String> permittedNodes = new ArrayList<String>(); permittedNodes.add(helperAddress); - node1.setAttributes(Collections.<String, Object>singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, permittedNodes)); + node.setAttributes(Collections.<String, Object>singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, permittedNodes)); assertTrue("Intruder protection was not triggered during expected timeout", stopLatch.await(10, TimeUnit.SECONDS)); + // test that if management mode is enabled then the node can start without exception when(_helper.getBroker().isManagementMode()).thenReturn(true); - node1.start(); + node.start(); + + _helper.awaitForAttributeChange(node, AbstractConfiguredObject.STATE, State.ERRORED); + } + + public void testPermittedNodesChangedOnReplicaNodeOnlyOnceAfterBeingChangedOnMaster() throws Exception + { + int node1PortNumber = _portHelper.getNextAvailable(); + int node2PortNumber = _portHelper.getNextAvailable(); + + String helperAddress = "localhost:" + node1PortNumber; + String groupName = "group"; + String nodeName = "node1"; + + Map<String, Object> node1Attributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, node1PortNumber, node2PortNumber); + BDBHAVirtualHostNode<?> node1 = _helper.createAndStartHaVHN(node1Attributes); + + Map<String, Object> node2Attributes = _helper.createNodeAttributes("node2", groupName, "localhost:" + node2PortNumber, helperAddress, nodeName); + node2Attributes.put(BDBHAVirtualHostNode.PRIORITY, 0); + BDBHAVirtualHostNode<?> node2 = _helper.createAndStartHaVHN(node2Attributes); + assertEquals("Unexpected role", NodeRole.REPLICA, node2.getRole()); + _helper.awaitRemoteNodes(node2, 1); + + BDBHARemoteReplicationNode<?> remote = _helper.findRemoteNode(node2, node1.getName()); + + final AtomicInteger permittedNodesChangeCounter = new AtomicInteger(); + final CountDownLatch _permittedNodesLatch = new CountDownLatch(1); + node2.addChangeListener(new NoopConfigurationChangeListener() + { + @Override + public void attributeSet(ConfiguredObject<?> object, String attributeName, Object oldAttributeValue, Object newAttributeValue) + { + if (attributeName.equals(BDBHAVirtualHostNode.PERMITTED_NODES)) + { + permittedNodesChangeCounter.incrementAndGet(); + _permittedNodesLatch.countDown(); + } + } + }); + List<String> permittedNodes = new ArrayList<>(node1.getPermittedNodes()); + permittedNodes.add("localhost:5000"); + node1.setAttributes(Collections.<String, Object>singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, permittedNodes)); + + assertTrue("Permitted nodes were not changed on Replica", _permittedNodesLatch.await(10, TimeUnit.SECONDS)); + assertEquals("Not the same permitted nodes", new HashSet<>(node1.getPermittedNodes()), new HashSet<>(node2.getPermittedNodes())); + assertEquals("Unexpected counter of changes permitted nodes", 1, permittedNodesChangeCounter.get()); + + // change the order of permitted nodes + Collections.swap(permittedNodes, 0, 2); + node1.setAttributes(Collections.<String, Object>singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, permittedNodes)); + + // make sure that node2 onNodeState was invoked by performing transaction on master and making sure that it was replicated + performTransactionAndAwaitForRemoteNodeToGetAware(node1, remote); + + // perform transaction second time because permitted nodes are changed after last transaction id + performTransactionAndAwaitForRemoteNodeToGetAware(node1, remote); + assertEquals("Unexpected counter of changes permitted nodes", 1, permittedNodesChangeCounter.get()); + } - _helper.awaitRemoteNodes(node1, 1); + private void performTransactionAndAwaitForRemoteNodeToGetAware(BDBHAVirtualHostNode<?> node1, BDBHARemoteReplicationNode<?> remote) throws InterruptedException + { + new DatabasePinger().pingDb(((BDBConfigurationStore)node1.getConfigurationStore()).getEnvironmentFacade()); - BDBHARemoteReplicationNode<?> remote = _helper.findRemoteNode(node1, node2.getName()); - remote.delete(); + int waitCounter = 100; + while ( remote.getLastKnownReplicationTransactionId() != node1.getLastKnownReplicationTransactionId() && (waitCounter--) != 0) + { + Thread.sleep(100l); + } + assertEquals("Last transaction was not replicated", new Long(remote.getLastKnownReplicationTransactionId()), node1.getLastKnownReplicationTransactionId() ); } public void testIntruderConnected() throws Exception @@ -587,4 +709,87 @@ public class BDBHAVirtualHostNodeTest extends QpidTestCase assertTrue("Intruder protection was not triggered during expected timeout", stopLatch.await(20, TimeUnit.SECONDS)); } + public void testValidateOnCreateForNonExistingHelperNode() throws Exception + { + int node1PortNumber = findFreePort(); + int node2PortNumber = getNextAvailable(node1PortNumber + 1); + + + Map<String, Object> attributes = _helper.createNodeAttributes("node1", "group", "localhost:" + node1PortNumber, + "localhost:" + node2PortNumber, "node2", node1PortNumber, node1PortNumber, node2PortNumber); + try + { + _helper.createAndStartHaVHN(attributes); + fail("Node creation should fail because of invalid helper address"); + } + catch(IllegalConfigurationException e) + { + assertEquals("Unexpected exception on connection to non-existing helper address", + String.format("Cannot connect to existing node '%s' at '%s'", "node2", "localhost:" + node2PortNumber), e.getMessage()); + } + } + + public void testValidateOnCreateForAlreadyBoundAddress() throws Exception + { + int node1PortNumber = findFreePort(); + + ServerSocket serverSocket = null; + try + { + serverSocket = new ServerSocket(); + serverSocket.setReuseAddress(true); + serverSocket.bind(new InetSocketAddress("localhost", node1PortNumber)); + + + Map<String, Object> attributes = _helper.createNodeAttributes("node1", "group", "localhost:" + node1PortNumber, + "localhost:" + node1PortNumber, "node2", node1PortNumber, node1PortNumber); + try + { + _helper.createAndStartHaVHN(attributes); + fail("Node creation should fail because of invalid address"); + } + catch(IllegalConfigurationException e) + { + assertEquals("Unexpected exception on attempt to create node with already bound address", + String.format("Cannot bind to address '%s'. Address is already in use.", "localhost:" + node1PortNumber), e.getMessage()); + } + } + finally + { + if (serverSocket != null) + { + serverSocket.close(); + } + } + } + + public void testValidateOnCreateForInvalidStorePath() throws Exception + { + int node1PortNumber = findFreePort(); + + File storeBaseFolder = TestFileUtils.createTestDirectory(); + File file = new File(storeBaseFolder, getTestName()); + file.createNewFile(); + File storePath = new File(file, "test"); + try + { + Map<String, Object> attributes = _helper.createNodeAttributes("node1", "group", "localhost:" + node1PortNumber, + "localhost:" + node1PortNumber, "node2", node1PortNumber, node1PortNumber); + attributes.put(BDBHAVirtualHostNode.STORE_PATH, storePath.getAbsoluteFile()); + try + { + _helper.createAndStartHaVHN(attributes); + fail("Node creation should fail because of invalid store path"); + } + catch (IllegalConfigurationException e) + { + assertEquals("Unexpected exception on attempt to create environment in invalid location", + String.format("Store path '%s' is not a folder", storePath.getAbsoluteFile()), e.getMessage()); + } + } + finally + { + FileUtils.delete(storeBaseFolder, true); + } + } } diff --git a/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBVirtualHostImplTest.java b/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBVirtualHostImplTest.java new file mode 100644 index 0000000000..92da465dbd --- /dev/null +++ b/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBVirtualHostImplTest.java @@ -0,0 +1,106 @@ +/* + * + * 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.virtualhost.berkeleydb; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.util.BrokerTestHelper; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.test.utils.TestFileUtils; +import org.apache.qpid.util.FileUtils; + +public class BDBVirtualHostImplTest extends QpidTestCase +{ + private File _storePath; + private VirtualHostNode<?> _node; + + @Override + public void setUp() throws Exception + { + super.setUp(); + Broker broker = BrokerTestHelper.createBrokerMock(); + + TaskExecutor taskExecutor = CurrentThreadTaskExecutor.newStartedInstance(); + when(broker.getTaskExecutor()).thenReturn(taskExecutor); + + _storePath = TestFileUtils.createTestDirectory(); + + _node = mock(VirtualHostNode.class); + when(_node.getParent(Broker.class)).thenReturn(broker); + when(_node.getModel()).thenReturn(BrokerModel.getInstance()); + when(_node.getTaskExecutor()).thenReturn(taskExecutor); + when(_node.getConfigurationStore()).thenReturn(mock(DurableConfigurationStore.class)); + when(_node.getId()).thenReturn(UUID.randomUUID()); + } + + @Override + public void tearDown() throws Exception + { + try + { + if (_storePath != null) + { + FileUtils.delete(_storePath, true); + } + } + finally + { + super.tearDown(); + } + } + + public void testValidateOnCreateForInvalidStorePath() throws Exception + { + String hostName = getTestName(); + File file = new File(_storePath + File.separator + hostName); + assertTrue("Empty file is not created", file.createNewFile()); + Map<String, Object> attributes = new HashMap<>(); + attributes.put(BDBVirtualHost.ID, UUID.randomUUID()); + attributes.put(BDBVirtualHost.TYPE, BDBVirtualHostImpl.VIRTUAL_HOST_TYPE); + attributes.put(BDBVirtualHost.NAME, hostName); + attributes.put(BDBVirtualHost.STORE_PATH, file.getAbsoluteFile()); + + BDBVirtualHostImpl host = new BDBVirtualHostImpl(attributes, _node); + try + { + host.create(); + fail("Cannot create DBD virtual host from existing empty file"); + } + catch (IllegalConfigurationException e) + { + assertTrue("Unexpected exception " + e.getMessage(), e.getMessage().startsWith("Cannot open virtual host message store")); + } + } + +} diff --git a/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java b/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java index d71fb8b474..6d740568ab 100644 --- a/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java +++ b/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java @@ -87,6 +87,9 @@ public class BDBHAVirtualHostNodeOperationalLoggingTest extends QpidTestCase _helper.assertNodeRole(node1, NodeRole.MASTER); + // stop node to avoid running into race when role change is reported after we performed the check + node1.stop(); + assertEquals("Unexpected VHN log subject", "[grp(/group)/vhn(/node1)] ", node1.getVirtualHostNodeLogSubject().getLogString()); assertEquals("Unexpected group log subject", "[grp(/group)] ", node1.getGroupLogSubject().getLogString()); diff --git a/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java b/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java index c12fecece3..0dc72acdb9 100644 --- a/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java +++ b/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java @@ -279,11 +279,14 @@ public class BDBHAVirtualHostNodeTestHelper node1Attributes.put(BDBHAVirtualHostNode.ADDRESS, address); node1Attributes.put(BDBHAVirtualHostNode.HELPER_ADDRESS, helperAddress); node1Attributes.put(BDBHAVirtualHostNode.STORE_PATH, getMessageStorePath() + File.separator + nodeName); - node1Attributes.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, helperNodeNode); if (address.equals(helperAddress)) { node1Attributes.put(BDBHAVirtualHostNode.PERMITTED_NODES, getPermittedNodes(ports)); } + else + { + node1Attributes.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, helperNodeNode); + } Map<String, String> context = new HashMap<String, String>(); context.put(ReplicationConfig.REPLICA_ACK_TIMEOUT, "2 s"); diff --git a/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBVirtualHostNodeTest.java b/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBVirtualHostNodeTest.java new file mode 100644 index 0000000000..6608312088 --- /dev/null +++ b/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBVirtualHostNodeTest.java @@ -0,0 +1,92 @@ +/* + * + * 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.berkeleydb; + +import static org.mockito.Mockito.when; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.util.BrokerTestHelper; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.test.utils.TestFileUtils; +import org.apache.qpid.util.FileUtils; + +public class BDBVirtualHostNodeTest extends QpidTestCase +{ + private Broker<?> _broker; + private File _storePath; + + @Override + public void setUp() throws Exception + { + super.setUp(); + _broker = BrokerTestHelper.createBrokerMock(); + when(_broker.getTaskExecutor()).thenReturn(CurrentThreadTaskExecutor.newStartedInstance()); + + _storePath = TestFileUtils.createTestDirectory(); + } + + @Override + public void tearDown() throws Exception + { + try + { + if (_storePath != null) + { + FileUtils.delete(_storePath, true); + } + } + finally + { + super.tearDown(); + } + } + + public void testValidateOnCreateForInvalidStorePath() throws Exception + { + String nodeName = getTestName(); + File file = new File(_storePath + File.separator + nodeName); + assertTrue("Empty file is not created", file.createNewFile()); + Map<String, Object> attributes = new HashMap<>(); + attributes.put(BDBVirtualHostNode.ID, UUID.randomUUID()); + attributes.put(BDBVirtualHostNode.TYPE, BDBVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE); + attributes.put(BDBVirtualHostNode.NAME, nodeName); + attributes.put(BDBVirtualHostNode.STORE_PATH, file.getAbsolutePath()); + + BDBVirtualHostNodeImpl node = new BDBVirtualHostNodeImpl(attributes, _broker); + try + { + node.create(); + fail("Cannot create DBD node from existing empty file"); + } + catch (IllegalConfigurationException e) + { + assertTrue("Unexpected exception " + e.getMessage(), e.getMessage().startsWith("Cannot open node configuration store")); + } + } + +} diff --git a/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java b/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java index c0c1b23a34..cfbd030474 100644 --- a/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java +++ b/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java @@ -326,7 +326,10 @@ public class BDBHAVirtualHostNodeRestTest extends QpidRestTestCase nodeData.put(BDBHAVirtualHostNode.GROUP_NAME, _hostName); nodeData.put(BDBHAVirtualHostNode.ADDRESS, "localhost:" + nodePort); nodeData.put(BDBHAVirtualHostNode.HELPER_ADDRESS, "localhost:" + helperPort); - nodeData.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, NODE1); + if (nodePort != helperPort) + { + nodeData.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, NODE1); + } Map<String,String> context = new HashMap<>(); nodeData.put(BDBHAVirtualHostNode.CONTEXT, context); diff --git a/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java b/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java index 9e850714b0..38484b546f 100644 --- a/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java +++ b/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java @@ -166,8 +166,8 @@ public class MultiNodeTest extends QpidBrokerTestCase // New connections should now fail as vhost will be unavailable try { - getConnection(_negativeFailoverUrl); - fail("Exception not thrown"); + Connection unexpectedConnection = getConnection(_negativeFailoverUrl); + fail("Got unexpected connection to node in group without quorum " + unexpectedConnection); } catch (JMSException je) { diff --git a/java/broker-codegen/src/main/java/org/apache/qpid/server/model/SystemConfigFactoryGenerator.java b/java/broker-codegen/src/main/java/org/apache/qpid/server/model/SystemConfigFactoryGenerator.java index c569bc4641..317e0f7c74 100644 --- a/java/broker-codegen/src/main/java/org/apache/qpid/server/model/SystemConfigFactoryGenerator.java +++ b/java/broker-codegen/src/main/java/org/apache/qpid/server/model/SystemConfigFactoryGenerator.java @@ -117,9 +117,9 @@ public class SystemConfigFactoryGenerator extends AbstractProcessor pw.println("import org.apache.qpid.server.configuration.updater.TaskExecutor;"); pw.println("import org.apache.qpid.server.logging.EventLogger;"); pw.println("import org.apache.qpid.server.logging.LogRecorder;"); - pw.println("import org.apache.qpid.server.model.SystemConfig;"); + pw.println("import org.apache.qpid.server.model.BrokerShutdownProvider;"); pw.println("import org.apache.qpid.server.model.ConfiguredObjectTypeRegistry;"); - pw.println(); + pw.println("import org.apache.qpid.server.model.SystemConfig;"); pw.println("import org.apache.qpid.server.plugin.PluggableService;"); pw.println("import org.apache.qpid.server.plugin.SystemConfigFactory;"); pw.println(); @@ -140,9 +140,10 @@ public class SystemConfigFactoryGenerator extends AbstractProcessor pw.println(" public "+objectSimpleName+" newInstance(final TaskExecutor taskExecutor,"); pw.println(" final EventLogger eventLogger,"); pw.println(" final LogRecorder logRecorder,"); - pw.println(" final BrokerOptions brokerOptions)"); + pw.println(" final BrokerOptions brokerOptions,"); + pw.println(" final BrokerShutdownProvider brokerShutdownProvider)"); pw.println(" {"); - pw.println(" return new "+objectSimpleName+"(taskExecutor, eventLogger, logRecorder, brokerOptions);"); + pw.println(" return new "+objectSimpleName+"(taskExecutor, eventLogger, logRecorder, brokerOptions, brokerShutdownProvider);"); pw.println(" }"); pw.println("}"); diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java b/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java index 0a1979128f..0b925d130c 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java @@ -40,6 +40,7 @@ import org.apache.qpid.server.logging.LogRecorder; import org.apache.qpid.server.logging.SystemOutMessageLogger; import org.apache.qpid.server.logging.log4j.LoggingManagementFacade; import org.apache.qpid.server.logging.messages.BrokerMessages; +import org.apache.qpid.server.model.BrokerShutdownProvider; import org.apache.qpid.server.model.SystemConfig; import org.apache.qpid.server.plugin.PluggableFactoryLoader; import org.apache.qpid.server.plugin.SystemConfigFactory; @@ -48,7 +49,7 @@ import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.store.DurableConfigurationStore; -public class Broker +public class Broker implements BrokerShutdownProvider { private static final Logger LOGGER = Logger.getLogger(Broker.class); @@ -143,7 +144,7 @@ public class Broker LogRecorder logRecorder = new LogRecorder(); _taskExecutor.start(); - SystemConfig systemConfig = configFactory.newInstance(_taskExecutor, _eventLogger, logRecorder, options); + SystemConfig systemConfig = configFactory.newInstance(_taskExecutor, _eventLogger, logRecorder, options, this); systemConfig.open(); DurableConfigurationStore store = systemConfig.getConfigurationStore(); diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java b/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java index b71d667fe0..6c67a44bb0 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java @@ -29,9 +29,12 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.configuration.updater.VoidTask; import org.apache.qpid.server.exchange.AbstractExchange; import org.apache.qpid.server.exchange.ExchangeImpl; +import org.apache.qpid.server.filter.AMQInvalidArgumentException; +import org.apache.qpid.server.filter.FilterSupport; import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.messages.BindingMessages; import org.apache.qpid.server.logging.subjects.BindingLogSubject; @@ -269,4 +272,23 @@ public class BindingImpl ); } + + @Override + public void validateOnCreate() + { + AMQQueue queue = getAMQQueue(); + Map<String, Object> arguments = getArguments(); + if (arguments!=null && !arguments.isEmpty() && FilterSupport.argumentsContainFilter(arguments)) + { + try + { + FilterSupport.createMessageFilter(arguments, queue); + } + catch (AMQInvalidArgumentException e) + { + throw new IllegalConfigurationException(e.getMessage(), e); + } + } + } + } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index fd0333f6e7..989a4abea5 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -118,16 +118,6 @@ public abstract class AbstractExchange<T extends AbstractExchange<T>> throw new IllegalArgumentException("Unknown attributes provided: " + providedAttributeNames); } _virtualHost = vhost; - // check ACL - try - { - _virtualHost.getSecurityManager().authoriseCreateExchange(this); - } - catch (AccessControlException e) - { - deleted(); - throw e; - } _logSubject = new ExchangeLogSubject(this, this.getVirtualHost()); @@ -145,6 +135,12 @@ public abstract class AbstractExchange<T extends AbstractExchange<T>> } @Override + public void validateOnCreate() + { + _virtualHost.getSecurityManager().authoriseCreateExchange(this); + } + + @Override public void onValidate() { super.onValidate(); @@ -756,7 +752,7 @@ public abstract class AbstractExchange<T extends AbstractExchange<T>> final Map<String, Object> oldArguments); - @StateTransition(currentState = State.UNINITIALIZED, desiredState = State.ACTIVE) + @StateTransition(currentState = {State.UNINITIALIZED,State.ERRORED}, desiredState = State.ACTIVE) private void activate() { setState(State.ACTIVE); diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java b/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java index d3741cd846..e6f79fef16 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java @@ -47,6 +47,7 @@ import java.util.concurrent.atomic.AtomicReference; import javax.security.auth.Subject; +import org.apache.log4j.Logger; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.Version; @@ -72,6 +73,8 @@ import org.apache.qpid.util.Strings; public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> implements ConfiguredObject<X> { + private static final Logger LOGGER = Logger.getLogger(AbstractConfiguredObject.class); + private static final Map<Class, Object> SECURE_VALUES; public static final String SECURED_STRING_VALUE = "********"; @@ -156,9 +159,10 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im private final OwnAttributeResolver _attributeResolver = new OwnAttributeResolver(this); - @ManagedAttributeField( afterSet = "attainStateIfResolved" ) + @ManagedAttributeField( afterSet = "attainStateIfOpenedOrReopenFailed" ) private State _desiredState; private boolean _openComplete; + private boolean _openFailed; private volatile State _state = State.UNINITIALIZED; protected static Map<Class<? extends ConfiguredObject>, ConfiguredObject<?>> parentsMap(ConfiguredObject<?>... parents) @@ -404,10 +408,19 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { if(_dynamicState.compareAndSet(DynamicState.UNINIT, DynamicState.OPENED)) { - doResolution(true); - doValidation(true); - doOpening(true); - doAttainState(); + _openFailed = false; + OpenExceptionHandler exceptionHandler = new OpenExceptionHandler(); + try + { + doResolution(true, exceptionHandler); + doValidation(true, exceptionHandler); + doOpening(true, exceptionHandler); + doAttainState(exceptionHandler); + } + catch(RuntimeException e) + { + exceptionHandler.handleException(e, this); + } } } @@ -485,18 +498,76 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im _lastUpdatedTime = currentTime; _createdTime = currentTime; - doResolution(true); - doValidation(true); + CreateExceptionHandler createExceptionHandler = new CreateExceptionHandler(); + try + { + doResolution(true, createExceptionHandler); + doValidation(true, createExceptionHandler); + validateOnCreate(); + registerWithParents(); + } + catch(RuntimeException e) + { + createExceptionHandler.handleException(e, this); + } + + AbstractConfiguredObjectExceptionHandler unregisteringExceptionHandler = new CreateExceptionHandler(true); + try + { + doCreation(true, unregisteringExceptionHandler); + doOpening(true, unregisteringExceptionHandler); + doAttainState(unregisteringExceptionHandler); + } + catch(RuntimeException e) + { + unregisteringExceptionHandler.handleException(e, this); + } + } + } + + protected void validateOnCreate() + { + } + + protected final void handleExceptionOnOpen(RuntimeException e) + { + if (e instanceof ServerScopedRuntimeException) + { + throw e; + } + + LOGGER.error("Failed to open object with name '" + getName() + "'. Object will be put into ERROR state.", e); - registerWithParents(); + try + { + onExceptionInOpen(e); + } + catch (RuntimeException re) + { + LOGGER.error("Unexpected exception while handling exception on open for " + getName(), e); + } - doCreation(true); - doOpening(true); - doAttainState(); + if (!_openComplete) + { + _openFailed = true; + _dynamicState.compareAndSet(DynamicState.OPENED, DynamicState.UNINIT); } + + //TODO: children of ERRORED CO will continue to remain in ACTIVE state + setState(State.ERRORED); + } + + /** + * Callback method to perform ConfiguredObject specific exception handling on exception in open. + * <p/> + * The method is not expected to throw any runtime exception. + * @param e open exception + */ + protected void onExceptionInOpen(RuntimeException e) + { } - private void doAttainState() + private void doAttainState(final AbstractConfiguredObjectExceptionHandler exceptionHandler) { applyToChildren(new Action<ConfiguredObject<?>>() { @@ -505,14 +576,25 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { if (child instanceof AbstractConfiguredObject) { - ((AbstractConfiguredObject) child).doAttainState(); + AbstractConfiguredObject configuredObject = (AbstractConfiguredObject) child; + if (configuredObject._dynamicState.get() == DynamicState.OPENED) + { + try + { + configuredObject.doAttainState(exceptionHandler); + } + catch (RuntimeException e) + { + exceptionHandler.handleException(e, configuredObject); + } + } } } }); attainState(); } - protected void doOpening(final boolean skipCheck) + protected void doOpening(boolean skipCheck, final AbstractConfiguredObjectExceptionHandler exceptionHandler) { if(skipCheck || _dynamicState.compareAndSet(DynamicState.UNINIT,DynamicState.OPENED)) { @@ -523,9 +605,17 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im @Override public void performAction(final ConfiguredObject<?> child) { - if (child instanceof AbstractConfiguredObject) + if (child.getState() != State.ERRORED && child instanceof AbstractConfiguredObject) { - ((AbstractConfiguredObject) child).doOpening(false); + AbstractConfiguredObject configuredObject = (AbstractConfiguredObject) child; + try + { + configuredObject.doOpening(false, exceptionHandler); + } + catch (RuntimeException e) + { + exceptionHandler.handleException(e, configuredObject); + } } } }); @@ -533,7 +623,7 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im } } - protected final void doValidation(final boolean skipCheck) + protected final void doValidation(final boolean skipCheck, final AbstractConfiguredObjectExceptionHandler exceptionHandler) { if(skipCheck || _dynamicState.get() != DynamicState.OPENED) { @@ -542,9 +632,17 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im @Override public void performAction(final ConfiguredObject<?> child) { - if (child instanceof AbstractConfiguredObject) + if (child.getState() != State.ERRORED && child instanceof AbstractConfiguredObject) { - ((AbstractConfiguredObject) child).doValidation(false); + AbstractConfiguredObject configuredObject = (AbstractConfiguredObject) child; + try + { + configuredObject.doValidation(false, exceptionHandler); + } + catch (RuntimeException e) + { + exceptionHandler.handleException(e, configuredObject); + } } } }); @@ -552,20 +650,28 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im } } - protected final void doResolution(final boolean skipCheck) + protected final void doResolution(boolean skipCheck, final AbstractConfiguredObjectExceptionHandler exceptionHandler) { if(skipCheck || _dynamicState.get() != DynamicState.OPENED) { onResolve(); postResolve(); - applyToChildren(new Action<ConfiguredObject<?>>() + applyToChildren(new Action() { @Override - public void performAction(final ConfiguredObject<?> child) + public void performAction(Object child) { if (child instanceof AbstractConfiguredObject) { - ((AbstractConfiguredObject) child).doResolution(false); + AbstractConfiguredObject configuredObject = (AbstractConfiguredObject) child; + try + { + configuredObject.doResolution(false, exceptionHandler); + } + catch (RuntimeException e) + { + exceptionHandler.handleException(e, configuredObject); + } } } }); @@ -576,7 +682,7 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { } - protected final void doCreation(final boolean skipCheck) + protected final void doCreation(final boolean skipCheck, final AbstractConfiguredObjectExceptionHandler exceptionHandler) { if(skipCheck || _dynamicState.get() != DynamicState.OPENED) { @@ -588,7 +694,15 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { if (child instanceof AbstractConfiguredObject) { - ((AbstractConfiguredObject) child).doCreation(false); + AbstractConfiguredObject configuredObject =(AbstractConfiguredObject) child; + try + { + configuredObject.doCreation(false, exceptionHandler); + } + catch (RuntimeException e) + { + exceptionHandler.handleException(e, configuredObject); + } } } }); @@ -711,12 +825,16 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im } } - private void attainStateIfResolved() + private void attainStateIfOpenedOrReopenFailed() { - if(_openComplete) + if (_openComplete || getDesiredState() == State.DELETED) { attainState(); } + else if (_openFailed) + { + open(); + } } protected void onOpen() @@ -830,8 +948,13 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im State state = getState(); if(desiredState == getDesiredState() && desiredState != state) { - attainState(); - return getState(); + attainStateIfOpenedOrReopenFailed(); + final State currentState = getState(); + if (currentState != state) + { + notifyStateChanged(state, currentState); + } + return currentState; } else { @@ -1217,7 +1340,6 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { if (_childrenByName.get(categoryClass).containsKey(name)) { - child.delete(); throw new DuplicateNameException(child); } _childrenByName.get(categoryClass).put(name, child); @@ -1756,4 +1878,54 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im return _name; } } + + interface AbstractConfiguredObjectExceptionHandler + { + void handleException(RuntimeException exception, AbstractConfiguredObject<?> source); + } + + private static class OpenExceptionHandler implements AbstractConfiguredObjectExceptionHandler + { + @Override + public void handleException(RuntimeException exception, AbstractConfiguredObject<?> source) + { + source.handleExceptionOnOpen(exception); + } + } + + private static class CreateExceptionHandler implements AbstractConfiguredObjectExceptionHandler + { + private final boolean _unregister; + + private CreateExceptionHandler() + { + this(false); + } + + private CreateExceptionHandler(boolean unregister) + { + _unregister = unregister; + } + + @Override + + public void handleException(RuntimeException exception, AbstractConfiguredObject<?> source) + { + try + { + if (source.getState() != State.DELETED) + { + source.delete(); + } + } + finally + { + if (_unregister) + { + source.unregister(false); + } + throw exception; + } + } + } } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractSystemConfig.java b/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractSystemConfig.java index 19f6139387..f8dac7cbe9 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractSystemConfig.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractSystemConfig.java @@ -49,13 +49,15 @@ public abstract class AbstractSystemConfig<X extends SystemConfig<X>> private final EventLogger _eventLogger; private final LogRecorder _logRecorder; private final BrokerOptions _brokerOptions; + private final BrokerShutdownProvider _brokerShutdownProvider; private DurableConfigurationStore _configurationStore; public AbstractSystemConfig(final TaskExecutor taskExecutor, final EventLogger eventLogger, final LogRecorder logRecorder, - final BrokerOptions brokerOptions) + final BrokerOptions brokerOptions, + final BrokerShutdownProvider brokerShutdownProvider) { super(parentsMap(), updateAttributes(brokerOptions.convertToSystemAttributes()), @@ -64,6 +66,7 @@ public abstract class AbstractSystemConfig<X extends SystemConfig<X>> getTaskExecutor().start(); _logRecorder = logRecorder; _brokerOptions = brokerOptions; + _brokerShutdownProvider = brokerShutdownProvider; } private static Map<String, Object> updateAttributes(Map<String, Object> attributes) @@ -212,4 +215,9 @@ public abstract class AbstractSystemConfig<X extends SystemConfig<X>> } + @Override + public BrokerShutdownProvider getBrokerShutdownProvider() + { + return _brokerShutdownProvider; + } } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/model/BrokerShutdownProvider.java b/java/broker-core/src/main/java/org/apache/qpid/server/model/BrokerShutdownProvider.java new file mode 100644 index 0000000000..5c8ab3e850 --- /dev/null +++ b/java/broker-core/src/main/java/org/apache/qpid/server/model/BrokerShutdownProvider.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.model; + +public interface BrokerShutdownProvider +{ + void shutdown(); +} diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/model/JsonSystemConfigImpl.java b/java/broker-core/src/main/java/org/apache/qpid/server/model/JsonSystemConfigImpl.java index 1763aca524..c9a828e7e4 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/model/JsonSystemConfigImpl.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/model/JsonSystemConfigImpl.java @@ -38,9 +38,10 @@ public class JsonSystemConfigImpl extends AbstractSystemConfig<JsonSystemConfigI public JsonSystemConfigImpl(final TaskExecutor taskExecutor, final EventLogger eventLogger, final LogRecorder logRecorder, - final BrokerOptions brokerOptions) + final BrokerOptions brokerOptions, + final BrokerShutdownProvider brokerShutdownProvider) { - super(taskExecutor, eventLogger, logRecorder, brokerOptions); + super(taskExecutor, eventLogger, logRecorder, brokerOptions, brokerShutdownProvider); } public String getStorePath() diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java b/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java index 7943c32c42..ec063142b4 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java @@ -37,4 +37,6 @@ public interface SystemConfig<X extends SystemConfig<X>> extends ConfiguredObjec LogRecorder getLogRecorder(); DurableConfigurationStore getConfigurationStore(); + + BrokerShutdownProvider getBrokerShutdownProvider(); } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java b/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java index 92ac43e629..109aaff5bd 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java @@ -943,6 +943,28 @@ public class BrokerAdapter extends AbstractConfiguredObject<BrokerAdapter> imple _eventLogger = eventLogger; } + @Override + protected void onExceptionInOpen(RuntimeException e) + { + SystemConfig systemConfig = getParent(SystemConfig.class); + if (systemConfig != null) + { + BrokerShutdownProvider shutdownProvider = systemConfig.getBrokerShutdownProvider(); + if (shutdownProvider != null) + { + shutdownProvider.shutdown(); + } + else + { + throw new IllegalStateException("Shutdown provider is not found in system config"); + } + } + else + { + throw new IllegalStateException("SystemConfig is not found among broker parents"); + } + } + public void registerMessageDelivered(long messageSize) { _messagesDelivered.registerEvent(1L); diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java b/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java index c96f4c0849..1b3d0591c0 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java @@ -114,22 +114,27 @@ public class FileBasedGroupProviderImpl throw new IllegalArgumentException("Cannot change the path"); } } + + @Override protected void onOpen() { super.onOpen(); - if(_groupDatabase == null) + FileGroupDatabase groupDatabase = new FileGroupDatabase(); + try { - _groupDatabase = new FileGroupDatabase(); - try - { - _groupDatabase.setGroupFile(getPath()); - } - catch (IOException e) + groupDatabase.setGroupFile(getPath()); + } + catch(IOException | RuntimeException e) + { + if (e instanceof IllegalConfigurationException) { - setState(State.ERRORED); - LOGGER.warn(("Unable to open preferences file at " + _path)); + throw (IllegalConfigurationException) e; } + throw new IllegalConfigurationException(String.format("Cannot load groups from '%s'", getPath()), e); } + + _groupDatabase = groupDatabase; + Set<Principal> groups = getGroupPrincipals(); Collection<Group> principals = new ArrayList<Group>(groups.size()); for (Principal group : groups) @@ -150,43 +155,47 @@ public class FileBasedGroupProviderImpl protected void onCreate() { super.onCreate(); - _groupDatabase = new FileGroupDatabase(); - File file = new File(_path); if (!file.exists()) { File parent = file.getParentFile(); - if (!parent.exists()) + if (!parent.exists() && !file.getParentFile().mkdirs()) { - parent.mkdirs(); + throw new IllegalConfigurationException(String.format("Cannot create groups file at '%s'",_path)); } - if (parent.exists()) + try { - try - { - file.createNewFile(); - } - catch (IOException e) - { - throw new IllegalConfigurationException("Cannot create group file"); - } + file.createNewFile(); } - else + catch (IOException e) { - throw new IllegalConfigurationException("Cannot create group file"); + throw new IllegalConfigurationException(String.format("Cannot create groups file at '%s'", _path), e); } } - try - { - _groupDatabase.setGroupFile(getPath()); - } - catch (IOException e) - { - setState(State.ERRORED); - LOGGER.warn(("Unable to open preferences file at " + _path)); - } + } + @Override + protected void validateOnCreate() + { + super.validateOnCreate(); + File groupsFile = new File(_path); + if (groupsFile.exists()) + { + if (!groupsFile.canRead()) + { + throw new IllegalConfigurationException(String.format("Cannot read groups file '%s'. Please check permissions.", _path)); + } + FileGroupDatabase groupDatabase = new FileGroupDatabase(); + try + { + groupDatabase.setGroupFile(_path); + } + catch (Exception e) + { + throw new IllegalConfigurationException(String.format("Cannot load groups from '%s'", _path), e); + } + } } @Override @@ -205,6 +214,11 @@ public class FileBasedGroupProviderImpl getSecurityManager().authoriseGroupOperation(Operation.CREATE, groupName); + if (getState() != State.ACTIVE) + { + throw new IllegalConfigurationException(String.format("Group provider '%s' is not activated. Cannot create a group.", getName())); + } + _groupDatabase.createGroup(groupName); Map<String,Object> attrMap = new HashMap<String, Object>(); @@ -247,20 +261,22 @@ public class FileBasedGroupProviderImpl return _broker.getSecurityManager(); } - @StateTransition( currentState = { State.UNINITIALIZED, State.QUIESCED }, desiredState = State.ACTIVE ) + @StateTransition( currentState = { State.UNINITIALIZED, State.QUIESCED, State.ERRORED }, desiredState = State.ACTIVE ) private void activate() { - try + if (_groupDatabase != null) { - _groupDatabase.setGroupFile(getPath()); setState(State.ACTIVE); } - catch(IOException | RuntimeException e) + else { - setState(State.ERRORED); if (_broker.isManagementMode()) { - LOGGER.warn("Failed to activate group provider: " + getName(), e); + LOGGER.warn("Failed to activate group provider: " + getName()); + } + else + { + throw new IllegalConfigurationException(String.format("Cannot load groups from '%s'", getPath())); } } } @@ -268,6 +284,7 @@ public class FileBasedGroupProviderImpl @StateTransition( currentState = { State.QUIESCED, State.ACTIVE, State.ERRORED}, desiredState = State.DELETED ) private void doDelete() { + close(); File file = new File(getPath()); if (file.exists()) { @@ -289,7 +306,7 @@ public class FileBasedGroupProviderImpl public Set<Principal> getGroupPrincipalsForUser(String username) { - Set<String> groups = _groupDatabase.getGroupsForUser(username); + Set<String> groups = _groupDatabase == null ? Collections.<String>emptySet(): _groupDatabase.getGroupsForUser(username); if (groups.isEmpty()) { return Collections.emptySet(); diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java b/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java index f2be4fd861..e3ded3006d 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java @@ -76,20 +76,64 @@ public class FileSystemPreferencesProviderImpl _authenticationProvider = authenticationProvider; } - @StateTransition( currentState = State.UNINITIALIZED, desiredState = State.ACTIVE ) + @Override + protected void validateOnCreate() + { + super.validateOnCreate(); + File storeFile = new File(_path); + if (storeFile.exists() ) + { + if (!storeFile.canRead()) + { + throw new IllegalConfigurationException(String.format("Cannot read preferences file '%s'. Please check permissions.", _path)); + } + + FileSystemPreferencesStore store = null; + try + { + store = new FileSystemPreferencesStore(storeFile); + store.open(); + } + catch (RuntimeException e) + { + if (e instanceof IllegalConfigurationException) + { + throw e; + } + throw new IllegalConfigurationException(String.format("Cannot open preferences store at '%s'", _path), e); + } + finally + { + if (store != null) + { + store.close(); + } + } + } + } + + @Override + protected void onOpen() + { + 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.open(); + _store = store; + _open = true; + } + + @StateTransition( currentState = {State.UNINITIALIZED, State.ERRORED}, desiredState = State.ACTIVE ) private void activate() { - try + if (_store != null) { - _store = new FileSystemPreferencesStore(new File(_path)); - createStoreIfNotExist(); - _store.open(); - _open = true; setState(State.ACTIVE); } - catch( RuntimeException e ) + else { - setState(State.ERRORED); + throw new IllegalStateException("Cannot open preferences provider " + getName() + " in state " + getState() ); } } @@ -148,9 +192,14 @@ public class FileSystemPreferencesProviderImpl setState(State.DELETED); } - @StateTransition(currentState = { State.QUIESCED, State.ERRORED }, desiredState = State.ACTIVE ) + @StateTransition(currentState = State.QUIESCED, desiredState = State.ACTIVE ) private void restart() { + if (_store == null) + { + throw new IllegalStateException("Cannot open preferences provider " + getName() + " in state " + getState() ); + } + _store.open(); setState(State.ACTIVE); } @@ -158,24 +207,39 @@ public class FileSystemPreferencesProviderImpl @Override public Map<String, Object> getPreferences(String userId) { - return _store.getPreferences(userId); + return _store == null? Collections.<String, Object>emptyMap() : _store.getPreferences(userId); } @Override public Map<String, Object> setPreferences(String userId, Map<String, Object> preferences) { + if (_store == null) + { + throw new IllegalStateException("Cannot set preferences with preferences provider " + getName() + " in state " + getState() ); + } + return _store.setPreferences(userId, preferences); } @Override public String[] deletePreferences(String... userIDs) { + if (_store == null) + { + throw new IllegalStateException("Cannot delete preferences with preferences provider " + getName() + " in state " + getState() ); + } + return _store.deletePreferences(userIDs); } @Override public Set<String> listUserIDs() { + if (_store == null) + { + return Collections.emptySet(); + } + return _store.listUserIDs(); } @@ -215,9 +279,10 @@ public class FileSystemPreferencesProviderImpl } else { - _store = new FileSystemPreferencesStore(new File(_path)); - createStoreIfNotExist(); - _store.open(); + FileSystemPreferencesStore store = new FileSystemPreferencesStore(new File(_path)); + store.createIfNotExist(); + store.open(); + _store = store; } } } @@ -265,11 +330,6 @@ public class FileSystemPreferencesProviderImpl } - private void createStoreIfNotExist() - { - _store.createIfNotExist(); - } - public static class FileSystemPreferencesStore { private final ObjectMapper _objectMapper; @@ -294,18 +354,18 @@ public class FileSystemPreferencesProviderImpl File parent = _storeFile.getParentFile(); if (!parent.exists() && !parent.mkdirs()) { - throw new IllegalConfigurationException("Cannot create preferences store folders"); + throw new IllegalConfigurationException(String.format("Cannot create preferences store folder at '%s'", _storeFile.getAbsolutePath())); } try { if (_storeFile.createNewFile() && !_storeFile.exists()) { - throw new IllegalConfigurationException("Preferences store file was not created:" + _storeFile.getAbsolutePath()); + throw new IllegalConfigurationException(String.format("Cannot create preferences store file at '%s'", _storeFile.getAbsolutePath())); } } catch (IOException e) { - throw new IllegalConfigurationException("Cannot create preferences store file"); + throw new IllegalConfigurationException(String.format("Cannot create preferences store file at '%s'", _storeFile.getAbsolutePath()), e); } } } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java b/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java index c0aa99a7d6..e2e7eff322 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java @@ -317,7 +317,7 @@ abstract public class AbstractPort<X extends AbstractPort<X>> extends AbstractCo setState(State.DELETED); } - @StateTransition( currentState = {State.UNINITIALIZED, State.QUIESCED}, desiredState = State.ACTIVE ) + @StateTransition( currentState = {State.UNINITIALIZED, State.QUIESCED, State.ERRORED}, desiredState = State.ACTIVE ) protected void activate() { try @@ -327,8 +327,7 @@ abstract public class AbstractPort<X extends AbstractPort<X>> extends AbstractCo catch (RuntimeException e) { setState(State.ERRORED); - LOGGER.error("Unable to active port '" + getName() + "'of type " + getType() + " on port " + getPort(), - e); + throw new IllegalConfigurationException("Unable to active port '" + getName() + "'of type " + getType() + " on " + getPort(), e); } } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java b/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java index fe7d419c78..afe3c9a44e 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java @@ -34,6 +34,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import org.apache.qpid.server.util.PortUtil; import org.codehaus.jackson.map.ObjectMapper; import org.apache.qpid.server.configuration.BrokerProperties; @@ -187,6 +188,18 @@ public class AmqpPortImpl extends AbstractClientAuthCapablePortWithAuthProvider< } } + @Override + public void validateOnCreate() + { + super.validateOnCreate(); + String bindingAddress = getBindingAddress(); + if (!PortUtil.isPortAvailable(bindingAddress, getPort())) + { + throw new IllegalConfigurationException(String.format("Cannot bind to port %d and binding address '%s'. Port is already is use.", + getPort(), bindingAddress == null || "".equals(bindingAddress) ? "*" : bindingAddress)); + } + } + private SSLContext createSslContext() { KeyStore keyStore = getKeyStore(); diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java b/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java index 1774f16ab6..3be5854645 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java @@ -22,10 +22,12 @@ package org.apache.qpid.server.model.port; import java.util.Map; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; import org.apache.qpid.server.model.State; +import org.apache.qpid.server.util.PortUtil; public class HttpPortImpl extends AbstractClientAuthCapablePortWithAuthProvider<HttpPortImpl> implements HttpPort<HttpPortImpl> { @@ -65,4 +67,16 @@ public class HttpPortImpl extends AbstractClientAuthCapablePortWithAuthProvider< return State.QUIESCED; } } + + @Override + public void validateOnCreate() + { + super.validateOnCreate(); + String bindingAddress = getBindingAddress(); + if (!PortUtil.isPortAvailable(bindingAddress, getPort())) + { + throw new IllegalConfigurationException(String.format("Cannot bind to port %d and binding address '%s'. Port is already is use.", + getPort(), bindingAddress == null || "".equals(bindingAddress) ? "*" : bindingAddress)); + } + } } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/plugin/SystemConfigFactory.java b/java/broker-core/src/main/java/org/apache/qpid/server/plugin/SystemConfigFactory.java index 9162f9e095..885194d939 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/plugin/SystemConfigFactory.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/plugin/SystemConfigFactory.java @@ -24,6 +24,7 @@ import org.apache.qpid.server.BrokerOptions; import org.apache.qpid.server.configuration.updater.TaskExecutor; import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.LogRecorder; +import org.apache.qpid.server.model.BrokerShutdownProvider; import org.apache.qpid.server.model.SystemConfig; public interface SystemConfigFactory<X extends SystemConfig<X>> extends Pluggable @@ -31,5 +32,6 @@ public interface SystemConfigFactory<X extends SystemConfig<X>> extends Pluggabl public X newInstance(final TaskExecutor taskExecutor, final EventLogger eventLogger, final LogRecorder logRecorder, - final BrokerOptions brokerOptions); + final BrokerOptions brokerOptions, + final BrokerShutdownProvider brokerShutdownProvider); } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java b/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java index a5156c9073..53e446ba2d 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java @@ -254,6 +254,12 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> } @Override + protected void validateOnCreate() + { + _virtualHost.getSecurityManager().authoriseCreateQueue(this); + } + + @Override protected void onCreate() { super.onCreate(); @@ -304,6 +310,7 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> } } + @Override protected void onOpen() { super.onOpen(); @@ -319,17 +326,6 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> _logSubject = new QueueLogSubject(this); - try - { - - _virtualHost.getSecurityManager().authoriseCreateQueue(this); - } - catch(AccessControlException e) - { - deleted(); - throw e; - } - Subject activeSubject = Subject.getSubject(AccessController.getContext()); Set<SessionPrincipal> sessionPrincipals = activeSubject == null ? Collections.<SessionPrincipal>emptySet() : activeSubject.getPrincipals(SessionPrincipal.class); AMQSessionModel<?,?> sessionModel; @@ -2798,7 +2794,7 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> //============= - @StateTransition(currentState = State.UNINITIALIZED, desiredState = State.ACTIVE) + @StateTransition(currentState = {State.UNINITIALIZED,State.ERRORED}, desiredState = State.ACTIVE) private void activate() { setState(State.ACTIVE); @@ -2965,7 +2961,10 @@ public abstract class AbstractQueue<X extends AbstractQueue<X>> { throw new IllegalConfigurationException("Flow resume size can't be greater than flow control size"); } - + else if (changedAttributes.contains(DURABLE) && proxyForValidation.isDurable() != isDurable()) + { + throw new IllegalConfigurationException("Message durability cannot be modified after queue creation"); + } for (String attrName : NON_NEGATIVE_NUMBERS) { diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index a6a2ea8d34..192a096d12 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -76,25 +76,32 @@ public abstract class PrincipalDatabaseAuthenticationManager<T extends Principal } @Override + protected void validateOnCreate() + { + super.validateOnCreate(); + File passwordFile = new File(_path); + if (passwordFile.exists() && !passwordFile.canRead()) + { + throw new IllegalConfigurationException(String.format("Cannot read password file '%s'. Please check permissions.", _path)); + } + } + + @Override protected void onCreate() { super.onCreate(); - try + File passwordFile = new File(_path); + if (!passwordFile.exists()) { - File passwordFile = new File(_path); - if (!passwordFile.exists()) + try { passwordFile.createNewFile(); } - else if (!passwordFile.canRead()) + catch (IOException e) { - throw new IllegalConfigurationException("Cannot read password file" + _path + ". Check permissions."); + throw new IllegalConfigurationException(String.format("Cannot create password file at '%s'", _path), e); } } - catch (IOException e) - { - throw new IllegalConfigurationException("Cannot use password database at :" + _path, e); - } } @Override @@ -102,23 +109,14 @@ public abstract class PrincipalDatabaseAuthenticationManager<T extends Principal { super.onOpen(); _principalDatabase = createDatabase(); - try + initialise(); + List<Principal> users = _principalDatabase == null ? Collections.<Principal>emptyList() : _principalDatabase.getUsers(); + for (Principal user : users) { - initialise(); - List<Principal> users = - _principalDatabase == null ? Collections.<Principal>emptyList() : _principalDatabase.getUsers(); - for (Principal user : users) - { - PrincipalAdapter principalAdapter = new PrincipalAdapter(user); - principalAdapter.registerWithParents(); - principalAdapter.open(); - _userMap.put(user, principalAdapter); - } - } - catch(IllegalConfigurationException e) - { - setState(State.ERRORED); - + PrincipalAdapter principalAdapter = new PrincipalAdapter(user); + principalAdapter.registerWithParents(); + principalAdapter.open(); + _userMap.put(user, principalAdapter); } } @@ -457,7 +455,7 @@ public abstract class PrincipalDatabaseAuthenticationManager<T extends Principal return super.changeAttribute(name, expected, desired); } - @StateTransition(currentState = State.UNINITIALIZED, desiredState = State.ACTIVE) + @StateTransition(currentState = {State.UNINITIALIZED,State.ERRORED}, desiredState = State.ACTIVE) private void activate() { setState(State.ACTIVE); diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java index 4e285df384..260fdfd1c6 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.security.auth.manager; import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.ManagedAttribute; +import org.apache.qpid.server.model.ManagedContextDefault; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.TrustStore; @@ -29,24 +30,34 @@ import org.apache.qpid.server.model.TrustStore; public interface SimpleLDAPAuthenticationManager<X extends SimpleLDAPAuthenticationManager<X>> extends AuthenticationProvider<X> { String PROVIDER_TYPE = "SimpleLDAP"; + String PROVIDER_URL = "providerUrl"; + String PROVIDER_AUTH_URL = "providerAuthUrl"; + String SEARCH_CONTEXT = "searchContext"; + String LDAP_CONTEXT_FACTORY = "ldapContextFactory"; + String SEARCH_USERNAME = "getSearchUsername"; + String SEARCH_PASSWORD = "getSearchPassword"; String TRUST_STORE = "trustStore"; - @ManagedAttribute( description = "LDAP server URL" ) + + @ManagedAttribute( description = "LDAP server URL", mandatory = true) String getProviderUrl(); @ManagedAttribute( description = "LDAP authentication URL") String getProviderAuthUrl(); - @ManagedAttribute( description = "Search context") + @ManagedAttribute( description = "Search context", mandatory = true) String getSearchContext(); - @ManagedAttribute( description = "Search filter") + @ManagedAttribute( description = "Search filter", mandatory = true) String getSearchFilter(); @ManagedAttribute( description = "Bind without search") boolean isBindWithoutSearch(); - @ManagedAttribute( description = "LDAP context factory") + @ManagedContextDefault( name = "ldap.context.factory") + String DEFAULT_LDAP_CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory"; + + @ManagedAttribute( description = "LDAP context factory", defaultValue = "${ldap.context.factory}") String getLdapContextFactory(); @ManagedAttribute( description = "Trust store name") diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerImpl.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerImpl.java index a0ba4518c8..6a0b83eb94 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerImpl.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerImpl.java @@ -19,15 +19,18 @@ package org.apache.qpid.server.security.auth.manager; +import static java.util.Collections.disjoint; +import static java.util.Collections.unmodifiableList; +import static java.util.Collections.singletonList; + import java.io.IOException; import java.security.GeneralSecurityException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; import java.security.Principal; -import java.util.Collections; +import java.util.Arrays; import java.util.Hashtable; import java.util.List; import java.util.Map; +import java.util.Set; import javax.naming.AuthenticationException; import javax.naming.Context; @@ -48,7 +51,9 @@ import javax.security.sasl.SaslServer; import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.IllegalConfigurationException; 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.TrustStore; @@ -59,7 +64,6 @@ import org.apache.qpid.server.security.auth.manager.ldap.AbstractLDAPSSLSocketFa import org.apache.qpid.server.security.auth.manager.ldap.LDAPSSLSocketFactoryGenerator; import org.apache.qpid.server.security.auth.sasl.plain.PlainPasswordCallback; import org.apache.qpid.server.security.auth.sasl.plain.PlainSaslServer; -import org.apache.qpid.server.util.ServerScopedRuntimeException; import org.apache.qpid.server.util.StringUtil; import org.apache.qpid.ssl.SSLContextFactory; @@ -68,6 +72,14 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM { private static final Logger _logger = Logger.getLogger(SimpleLDAPAuthenticationManagerImpl.class); + private static final List<String> CONNECTIVITY_ATTRS = unmodifiableList(Arrays.asList(PROVIDER_URL, + PROVIDER_AUTH_URL, + SEARCH_CONTEXT, + LDAP_CONTEXT_FACTORY, + SEARCH_USERNAME, + SEARCH_PASSWORD, + TRUST_STORE)); + /** * Environment key to instruct {@link InitialDirContext} to override the socket factory. */ @@ -111,15 +123,37 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM super(attributes, broker); } + @Override + protected void validateOnCreate() + { + super.validateOnCreate(); + + Class<? extends SocketFactory> sslSocketFactoryOverrideClass = _trustStore == null ? null : createSslSocketFactoryOverrideClass(_trustStore); + validateInitialDirContext(sslSocketFactoryOverrideClass, _providerUrl, _searchUsername, _searchPassword); + } + + @Override + protected void validateChange(final ConfiguredObject<?> proxyForValidation, final Set<String> changedAttributes) + { + super.validateChange(proxyForValidation, changedAttributes); + + if (!disjoint(changedAttributes, CONNECTIVITY_ATTRS)) + { + SimpleLDAPAuthenticationManager changed = (SimpleLDAPAuthenticationManager)proxyForValidation; + TrustStore changedTruststore = changed.getTrustStore(); + Class<? extends SocketFactory> sslSocketFactoryOverrideClass = changedTruststore == null ? null : createSslSocketFactoryOverrideClass( + changedTruststore); + validateInitialDirContext(sslSocketFactoryOverrideClass, changed.getProviderUrl(), changed.getSearchUsername(), + changed.getSearchPassword()); + } + } @Override protected void onOpen() { super.onOpen(); - _sslSocketFactoryOverrideClass = createSslSocketFactoryOverrideClass(); - - // validateInitialDirContext(); + _sslSocketFactoryOverrideClass = _trustStore == null ? null : createSslSocketFactoryOverrideClass(_trustStore); } @Override @@ -174,7 +208,7 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM @Override public List<String> getMechanisms() { - return Collections.singletonList(PlainSaslServer.MECHANISM); + return singletonList(PlainSaslServer.MECHANISM); } @Override @@ -259,7 +293,7 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM InitialDirContext ctx = null; try { - ctx = createInitialDirContext(env); + ctx = createInitialDirContext(env, _sslSocketFactoryOverrideClass); //Authentication succeeded return new AuthenticationResult(new UsernamePrincipal(name)); @@ -291,7 +325,8 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM return env; } - private InitialDirContext createInitialDirContext(Hashtable<String, Object> env) throws NamingException + private InitialDirContext createInitialDirContext(Hashtable<String, Object> env, + Class<? extends SocketFactory> sslSocketFactoryOverrideClass) throws NamingException { ClassLoader existingContextClassLoader = null; @@ -300,11 +335,11 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM boolean revertContentClassLoader = false; try { - if (isLdaps && _sslSocketFactoryOverrideClass != null) + if (isLdaps && sslSocketFactoryOverrideClass != null) { existingContextClassLoader = Thread.currentThread().getContextClassLoader(); - env.put(JAVA_NAMING_LDAP_FACTORY_SOCKET, _sslSocketFactoryOverrideClass.getName()); - Thread.currentThread().setContextClassLoader(_sslSocketFactoryOverrideClass.getClassLoader()); + env.put(JAVA_NAMING_LDAP_FACTORY_SOCKET, sslSocketFactoryOverrideClass.getName()); + Thread.currentThread().setContextClassLoader(sslSocketFactoryOverrideClass.getClassLoader()); revertContentClassLoader = true; } return new InitialDirContext(env); @@ -323,59 +358,59 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM * associated with the {@link SSLContext} generated from that trust store. * * @return generated socket factory class + * @param trustStore */ - private Class<? extends SocketFactory> createSslSocketFactoryOverrideClass() + private Class<? extends SocketFactory> createSslSocketFactoryOverrideClass(final TrustStore trustStore) { - if (_trustStore != null) + String clazzName = new StringUtil().createUniqueJavaName(getName() + "_" + trustStore.getName()); + SSLContext sslContext = null; + try { - String clazzName = new StringUtil().createUniqueJavaName(getName()); - SSLContext sslContext = null; - try - { - sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, _trustStore.getTrustManagers(), null); - } - catch (NoSuchAlgorithmException e) - { - _logger.error("Exception creating SSLContext", e); - throw new ServerScopedRuntimeException("Error creating SSLContext for trust store : " + _trustStore.getName() , e); - } - catch (KeyManagementException e) - { - _logger.error("Exception creating SSLContext", e); - throw new ServerScopedRuntimeException("Error creating SSLContext for trust store : " + _trustStore.getName() , e); - } - catch (GeneralSecurityException e) - { - _logger.error("Exception creating SSLContext", e); - throw new ServerScopedRuntimeException("Error creating SSLContext for trust store : " + _trustStore.getName() , e); - } + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, trustStore.getTrustManagers(), null); + } + catch (GeneralSecurityException e) + { + _logger.error("Exception creating SSLContext", e); + throw new IllegalConfigurationException("Error creating SSLContext with trust store : " + trustStore.getName() , e); + } - Class<? extends AbstractLDAPSSLSocketFactory> clazz = LDAPSSLSocketFactoryGenerator.createSubClass(clazzName, sslContext.getSocketFactory()); - if (_logger.isDebugEnabled()) - { - _logger.debug("Connection to Directory will use custom SSL socket factory : " + clazz); - } - return clazz; + Class<? extends AbstractLDAPSSLSocketFactory> clazz = LDAPSSLSocketFactoryGenerator.createSubClass(clazzName, sslContext.getSocketFactory()); + if (_logger.isDebugEnabled()) + { + _logger.debug("Connection to Directory will use custom SSL socket factory : " + clazz); } + return clazz; + } - return null; + @Override + public String toString() + { + return "SimpleLDAPAuthenticationManagerImpl [id=" + getId() + ", name=" + getName() + + ", providerUrl=" + _providerUrl + ", providerAuthUrl=" + _providerAuthUrl + + ", searchContext=" + _searchContext + ", state=" + getState() + + ", searchFilter=" + _searchFilter + ", ldapContextFactory=" + _ldapContextFactory + + ", bindWithoutSearch=" + _bindWithoutSearch + ", trustStore=" + _trustStore + + ", searchUsername=" + _searchUsername + "]"; } - private void validateInitialDirContext() + private void validateInitialDirContext(Class<? extends SocketFactory> sslSocketFactoryOverrideClass, + final String providerUrl, + final String searchUsername, final String searchPassword) { - Hashtable<String,Object> env = createInitialDirContextEnvironment(_providerUrl); + Hashtable<String,Object> env = createInitialDirContextEnvironment(providerUrl); - setupSearchContext(env); + setupSearchContext(env, searchUsername, searchPassword); InitialDirContext ctx = null; try { - ctx = createInitialDirContext(env); + ctx = createInitialDirContext(env, sslSocketFactoryOverrideClass); } catch (NamingException e) { - throw new ServerScopedRuntimeException("Unable to establish connection to the ldap server at " + _providerUrl, e); + _logger.error("Failed to establish connectivity to the ldap server for " + providerUrl, e); + throw new IllegalConfigurationException("Failed to establish connectivity to the ldap server." , e); } finally { @@ -383,13 +418,14 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM } } - private void setupSearchContext(final Hashtable<String, Object> env) + private void setupSearchContext(final Hashtable<String, Object> env, + final String searchUsername, final String searchPassword) { if(_searchUsername != null && _searchUsername.trim().length()>0) { env.put(Context.SECURITY_AUTHENTICATION, "simple"); - env.put(Context.SECURITY_PRINCIPAL, _searchUsername); - env.put(Context.SECURITY_CREDENTIALS, _searchPassword); + env.put(Context.SECURITY_PRINCIPAL, searchUsername); + env.put(Context.SECURITY_CREDENTIALS, searchPassword); } else { @@ -454,9 +490,9 @@ public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationM { Hashtable<String, Object> env = createInitialDirContextEnvironment(_providerUrl); - setupSearchContext(env); + setupSearchContext(env, _searchUsername, _searchPassword); - InitialDirContext ctx = createInitialDirContext(env); + InitialDirContext ctx = createInitialDirContext(env, _sslSocketFactoryOverrideClass); try { diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractJDBCConfigurationStore.java b/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractJDBCConfigurationStore.java index 52072678e8..4fbfdfdd2d 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractJDBCConfigurationStore.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractJDBCConfigurationStore.java @@ -572,7 +572,7 @@ public abstract class AbstractJDBCConfigurationStore implements MessageStoreProv } catch (SQLException e) { - throw new StoreException("Error creating ConfiguredObject " + object); + throw new StoreException("Error creating ConfiguredObject " + object, e); } } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractJDBCMessageStore.java b/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractJDBCMessageStore.java index 9633e32408..4dfaa716cf 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractJDBCMessageStore.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/store/AbstractJDBCMessageStore.java @@ -133,7 +133,7 @@ public abstract class AbstractJDBCMessageStore implements MessageStore } catch (SQLException e) { - throw new StoreException(e); + throw new StoreException("Failed to determine maximum ids", e); } } @@ -816,7 +816,6 @@ public abstract class AbstractJDBCMessageStore implements MessageStore private void commitTran(ConnectionWrapper connWrapper) throws StoreException { - try { Connection conn = connWrapper.getConnection(); @@ -833,10 +832,6 @@ public abstract class AbstractJDBCMessageStore implements MessageStore { throw new StoreException("Error commit tx: " + e.getMessage(), e); } - finally - { - - } } private StoreFuture commitTranAsync(ConnectionWrapper connWrapper) throws StoreException @@ -1448,7 +1443,7 @@ public abstract class AbstractJDBCMessageStore implements MessageStore } catch (SQLException e) { - throw new StoreException(e); + throw new StoreException("Failed to get metadata for message id: " + _messageId, e); } } @@ -1507,7 +1502,7 @@ public abstract class AbstractJDBCMessageStore implements MessageStore } catch (SQLException e) { - throw new StoreException(e); + throw new StoreException("Failed to get content for message id " + _messageId, e); } } else @@ -1551,7 +1546,7 @@ public abstract class AbstractJDBCMessageStore implements MessageStore } catch (SQLException e) { - throw new StoreException(e); + throw new StoreException("Failed to get content for message id: " + _messageId, e); } } else @@ -1598,11 +1593,7 @@ public abstract class AbstractJDBCMessageStore implements MessageStore } catch (SQLException e) { - throw new StoreException(e); - } - finally - { - + throw new StoreException("Failed to flow to disk", e); } return true; } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/util/PortUtil.java b/java/broker-core/src/main/java/org/apache/qpid/server/util/PortUtil.java new file mode 100644 index 0000000000..5d093bd3d5 --- /dev/null +++ b/java/broker-core/src/main/java/org/apache/qpid/server/util/PortUtil.java @@ -0,0 +1,69 @@ +/* + * + * 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.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; + +public class PortUtil +{ + public static boolean isPortAvailable(String hostName, int port) + { + InetSocketAddress socketAddress = null; + if ( hostName == null || "".equals(hostName) || "*".equals(hostName) ) + { + socketAddress = new InetSocketAddress(port); + } + else + { + socketAddress = new InetSocketAddress(hostName, port); + } + + ServerSocket serverSocket = null; + try + { + serverSocket = new ServerSocket(); + serverSocket.setReuseAddress(true); + serverSocket.bind(socketAddress); + return true; + } + catch (IOException e) + { + return false; + } + finally + { + if (serverSocket != null) + { + try + { + serverSocket.close(); + } + catch (IOException e) + { + throw new RuntimeException("Couldn't close port " + port + " that was created to check its availability", e); + } + } + } + } +} diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java b/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java index f52c1967f8..48077ba503 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java @@ -37,7 +37,6 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; import javax.security.auth.Subject; @@ -231,6 +230,47 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte } @Override + public void validateOnCreate() + { + super.validateOnCreate(); + validateMessageStoreCreation(); + } + + private void validateMessageStoreCreation() + { + MessageStore store = createMessageStore(); + if (store != null) + { + try + { + store.openMessageStore(this); + } + catch (Exception e) + { + throw new IllegalConfigurationException("Cannot open virtual host message store:" + e.getMessage(), e); + } + finally + { + try + { + store.closeMessageStore(); + } + catch(Exception e) + { + _logger.warn("Failed to close database", e); + } + } + } + } + + @Override + protected void onExceptionInOpen(RuntimeException e) + { + super.onExceptionInOpen(e); + closeMessageStore(); + } + + @Override protected void onOpen() { super.onOpen(); @@ -638,6 +678,7 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte protected void onClose() { + setState(State.UNAVAILABLE); //Stop Connections _connectionRegistry.close(); _dtxRegistry.close(); @@ -659,11 +700,11 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte { _logger.error("Failed to close message store", e); } - } - if (!(_virtualHostNode.getConfigurationStore() instanceof MessageStoreProvider)) - { - getEventLogger().message(getMessageStoreLogSubject(), MessageStoreMessages.CLOSED()); + if (!(_virtualHostNode.getConfigurationStore() instanceof MessageStoreProvider)) + { + getEventLogger().message(getMessageStoreLogSubject(), MessageStoreMessages.CLOSED()); + } } } @@ -1355,7 +1396,7 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte getDurableConfigurationStore().create(new ConfiguredObjectRecordImpl(record.getId(), record.getType(), record.getAttributes())); } - @StateTransition( currentState = { State.UNINITIALIZED }, desiredState = State.ACTIVE ) + @StateTransition( currentState = { State.UNINITIALIZED,State.ERRORED }, desiredState = State.ACTIVE ) private void onActivate() { _houseKeepingTasks = new ScheduledThreadPoolExecutor(getHousekeepingThreadCount()); diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNode.java b/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNode.java index ce97502124..03c30a9cd4 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNode.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNode.java @@ -41,6 +41,7 @@ import org.apache.qpid.server.model.VirtualHostNode; import org.apache.qpid.server.security.SecurityManager; 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.VirtualHostStoreUpgraderAndRecoverer; public abstract class AbstractStandardVirtualHostNode<X extends AbstractStandardVirtualHostNode<X>> extends AbstractVirtualHostNode<X> @@ -169,4 +170,33 @@ public abstract class AbstractStandardVirtualHostNode<X extends AbstractStandard { return Collections.emptyList(); } + + @Override + public void validateOnCreate() + { + super.validateOnCreate(); + DurableConfigurationStore store = createConfigurationStore(); + if (store != null) + { + try + { + store.openConfigurationStore(this, false); + } + catch (Exception e) + { + throw new IllegalConfigurationException("Cannot open node configuration store:" + e.getMessage(), e); + } + finally + { + try + { + store.closeConfigurationStore(); + } + catch(Exception e) + { + LOGGER.warn("Failed to close database", e); + } + } + } + } } diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java b/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java index 5cbfb0942a..aea07e3ed3 100644 --- a/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java +++ b/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java @@ -36,7 +36,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; -import java.util.concurrent.atomic.AtomicReference; import org.apache.log4j.Logger; @@ -100,8 +99,6 @@ public abstract class AbstractVirtualHostNode<X extends AbstractVirtualHostNode< { super.onOpen(); _durableConfigurationStore = createConfigurationStore(); - _configurationStoreLogSubject = new MessageStoreLogSubject(getName(), _durableConfigurationStore.getClass().getSimpleName()); - } @Override @@ -167,11 +164,6 @@ public abstract class AbstractVirtualHostNode<X extends AbstractVirtualHostNode< return _eventLogger; } - protected DurableConfigurationStore getDurableConfigurationStore() - { - return _durableConfigurationStore; - } - protected MessageStoreLogSubject getConfigurationStoreLogSubject() { return _configurationStoreLogSubject; @@ -184,7 +176,11 @@ public abstract class AbstractVirtualHostNode<X extends AbstractVirtualHostNode< deleteVirtualHostIfExists(); close(); deleted(); - getConfigurationStore().onDelete(this); + DurableConfigurationStore configurationStore = getConfigurationStore(); + if (configurationStore != null) + { + configurationStore.onDelete(this); + } } protected void deleteVirtualHostIfExists() @@ -205,11 +201,30 @@ public abstract class AbstractVirtualHostNode<X extends AbstractVirtualHostNode< protected void stopAndSetStateTo(State stoppedState) { closeChildren(); - closeConfigurationStore(); + closeConfigurationStoreSafely(); setState(stoppedState); } @Override + protected void onExceptionInOpen(RuntimeException e) + { + super.onExceptionInOpen(e); + closeConfigurationStoreSafely(); + } + + @Override + protected void postResolve() + { + super.postResolve(); + DurableConfigurationStore store = getConfigurationStore(); + if (store == null) + { + store = createConfigurationStore(); + } + _configurationStoreLogSubject = new MessageStoreLogSubject(getName(), store.getClass().getSimpleName()); + } + + @Override protected void onClose() { closeConfigurationStore(); @@ -262,6 +277,18 @@ public abstract class AbstractVirtualHostNode<X extends AbstractVirtualHostNode< } } + private void closeConfigurationStoreSafely() + { + try + { + closeConfigurationStore(); + } + catch(Exception e) + { + LOGGER.warn("Unexpected exception on close of configuration store", e); + } + } + @Override public String getVirtualHostInitialConfiguration() { diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/binding/BindingImplTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/binding/BindingImplTest.java new file mode 100644 index 0000000000..93fa9114fb --- /dev/null +++ b/java/broker-core/src/test/java/org/apache/qpid/server/binding/BindingImplTest.java @@ -0,0 +1,76 @@ +/* + * + * 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.binding; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.exchange.ExchangeImpl; +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.test.utils.QpidTestCase; + +public class BindingImplTest extends QpidTestCase +{ + private TaskExecutor _taskExecutor; + private Model _model; + + public void setUp() throws Exception + { + super.setUp(); + _taskExecutor = CurrentThreadTaskExecutor.newStartedInstance(); + _model = BrokerModel.getInstance(); + } + + public void testBindingValidationOnCreateWithInvalidSelector() + { + Map<String, String> arguments = new HashMap<>(); + arguments.put(AMQPFilterTypes.JMS_SELECTOR.toString(), "test in ("); + Map<String,Object> attributes = new HashMap<>(); + attributes.put(Binding.ARGUMENTS, arguments); + attributes.put(Binding.NAME, getTestName()); + AMQQueue queue = mock(AMQQueue.class); + when(queue.getTaskExecutor()).thenReturn(_taskExecutor); + when(queue.getModel()).thenReturn(_model); + ExchangeImpl exchange = mock(ExchangeImpl.class); + when(exchange.getTaskExecutor()).thenReturn(_taskExecutor); + when(exchange.getModel()).thenReturn(_model); + BindingImpl binding = new BindingImpl(attributes, queue, exchange); + try + { + binding.create(); + fail("Exception is expected on validation with invalid selector"); + } + catch (IllegalConfigurationException e) + { + assertTrue("Unexpected exception message " + e.getMessage(), e.getMessage().startsWith("Cannot parse JMS selector")); + } + } +} diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/FileKeyStoreCreationTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/FileKeyStoreCreationTest.java index 4b4891d838..b4f92990eb 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/FileKeyStoreCreationTest.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/FileKeyStoreCreationTest.java @@ -63,7 +63,7 @@ public class FileKeyStoreCreationTest extends TestCase Map<String, Object> attributesCopy = new HashMap<String, Object>(attributes); Broker broker = mock(Broker.class); - TaskExecutor executor = new CurrentThreadTaskExecutor(); + TaskExecutor executor = CurrentThreadTaskExecutor.newStartedInstance(); when(broker.getObjectFactory()).thenReturn(_factory); when(broker.getModel()).thenReturn(_factory.getModel()); when(broker.getTaskExecutor()).thenReturn(executor); diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandlerTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandlerTest.java index 36353f0dba..fbb08cdd2a 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandlerTest.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandlerTest.java @@ -34,6 +34,7 @@ import java.util.HashSet; import java.util.Map; import java.util.UUID; +import org.apache.qpid.server.model.BrokerShutdownProvider; import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -78,7 +79,8 @@ public class ManagementModeStoreHandlerTest extends QpidTestCase _taskExecutor.start(); _systemConfig = new JsonSystemConfigImpl(_taskExecutor, mock(EventLogger.class), - mock(LogRecorder.class), new BrokerOptions()); + mock(LogRecorder.class), new BrokerOptions(), + mock(BrokerShutdownProvider.class)); ConfiguredObjectRecord systemContextRecord = _systemConfig.asObjectRecord(); diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/model/AbstractConfiguredObjectTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/model/AbstractConfiguredObjectTest.java index e5c5a89c10..a1a363d5fe 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/model/AbstractConfiguredObjectTest.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/model/AbstractConfiguredObjectTest.java @@ -26,7 +26,9 @@ import java.util.Map; import junit.framework.TestCase; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.model.testmodel.TestChildCategory; +import org.apache.qpid.server.model.testmodel.TestConfiguredObject; import org.apache.qpid.server.model.testmodel.TestModel; import org.apache.qpid.server.model.testmodel.TestRootCategory; import org.apache.qpid.server.store.ConfiguredObjectRecord; @@ -257,4 +259,189 @@ public class AbstractConfiguredObjectTest extends TestCase parent.getChildren(TestChildCategory.class).isEmpty()); } + public void testOpeningResultsInErroredStateWhenResolutionFails() throws Exception + { + TestConfiguredObject object = new TestConfiguredObject(getName()); + object.setThrowExceptionOnPostResolve(true); + object.open(); + assertFalse("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.ERRORED, object.getState()); + + object.setThrowExceptionOnPostResolve(false); + object.setAttributes(Collections.<String, Object>singletonMap(Port.DESIRED_STATE, State.ACTIVE)); + assertTrue("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.ACTIVE, object.getState()); + } + + public void testOpeningInERROREDStateAfterFailedOpenOnDesiredStateChangeToActive() throws Exception + { + TestConfiguredObject object = new TestConfiguredObject(getName()); + object.setThrowExceptionOnOpen(true); + object.open(); + assertFalse("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.ERRORED, object.getState()); + + object.setThrowExceptionOnOpen(false); + object.setAttributes(Collections.<String, Object>singletonMap(Port.DESIRED_STATE, State.ACTIVE)); + assertTrue("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.ACTIVE, object.getState()); + } + + public void testOpeningInERROREDStateAfterFailedOpenOnStart() throws Exception + { + TestConfiguredObject object = new TestConfiguredObject(getName()); + object.setThrowExceptionOnOpen(true); + object.open(); + assertFalse("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.ERRORED, object.getState()); + + object.setThrowExceptionOnOpen(false); + object.start(); + assertTrue("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.ACTIVE, object.getState()); + } + + public void testDeletionERROREDStateAfterFailedOpenOnDelete() throws Exception + { + TestConfiguredObject object = new TestConfiguredObject(getName()); + object.setThrowExceptionOnOpen(true); + object.open(); + assertFalse("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.ERRORED, object.getState()); + + object.delete(); + assertFalse("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.DELETED, object.getState()); + } + + public void testDeletionInERROREDStateAfterFailedOpenOnDesiredStateChangeToDelete() throws Exception + { + TestConfiguredObject object = new TestConfiguredObject(getName()); + object.setThrowExceptionOnOpen(true); + object.open(); + assertFalse("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.ERRORED, object.getState()); + + object.setAttributes(Collections.<String, Object>singletonMap(Port.DESIRED_STATE, State.DELETED)); + assertFalse("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.DELETED, object.getState()); + } + + + public void testCreationWithExceptionThrownFromValidationOnCreate() throws Exception + { + TestConfiguredObject object = new TestConfiguredObject(getName()); + object.setThrowExceptionOnValidationOnCreate(true); + try + { + object.create(); + fail("IllegalConfigurationException is expected to be thrown"); + } + catch(IllegalConfigurationException e) + { + //pass + } + assertFalse("Unexpected opened", object.isOpened()); + } + + public void testCreationWithoutExceptionThrownFromValidationOnCreate() throws Exception + { + TestConfiguredObject object = new TestConfiguredObject(getName()); + object.setThrowExceptionOnValidationOnCreate(false); + object.create(); + assertTrue("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.ACTIVE, object.getState()); + } + + public void testCreationWithExceptionThrownFromOnOpen() throws Exception + { + TestConfiguredObject object = new TestConfiguredObject(getName()); + object.setThrowExceptionOnOpen(true); + try + { + object.create(); + fail("Exception should have been re-thrown"); + } + catch (RuntimeException re) + { + // pass + } + + assertFalse("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.DELETED, object.getState()); + } + + public void testCreationWithExceptionThrownFromOnCreate() throws Exception + { + TestConfiguredObject object = new TestConfiguredObject(getName()); + object.setThrowExceptionOnCreate(true); + try + { + object.create(); + fail("Exception should have been re-thrown"); + } + catch (RuntimeException re) + { + // pass + } + + assertFalse("Unexpected opened", object.isOpened()); + assertEquals("Unexpected state", State.DELETED, object.getState()); + } + + public void testUnresolvedChildInERROREDStateIsNotValidatedOrOpenedOrAttainedDesiredStateOnParentOpen() throws Exception + { + TestConfiguredObject parent = new TestConfiguredObject("parent"); + TestConfiguredObject child1 = new TestConfiguredObject("child1", parent, parent.getTaskExecutor()); + child1.registerWithParents(); + TestConfiguredObject child2 = new TestConfiguredObject("child2", parent, parent.getTaskExecutor()); + child2.registerWithParents(); + + child1.setThrowExceptionOnPostResolve(true); + + parent.open(); + + assertTrue("Parent should be resolved", parent.isResolved()); + assertTrue("Parent should be validated", parent.isValidated()); + assertTrue("Parent should be opened", parent.isOpened()); + assertEquals("Unexpected parent state", State.ACTIVE, parent.getState()); + + assertTrue("Child2 should be resolved", child2.isResolved()); + assertTrue("Child2 should be validated", child2.isValidated()); + assertTrue("Child2 should be opened", child2.isOpened()); + assertEquals("Unexpected child2 state", State.ACTIVE, child2.getState()); + + assertFalse("Child2 should not be resolved", child1.isResolved()); + assertFalse("Child1 should not be validated", child1.isValidated()); + assertFalse("Child1 should not be opened", child1.isOpened()); + assertEquals("Unexpected child1 state", State.ERRORED, child1.getState()); + } + + public void testUnvalidatedChildInERROREDStateIsNotOpenedOrAttainedDesiredStateOnParentOpen() throws Exception + { + TestConfiguredObject parent = new TestConfiguredObject("parent"); + TestConfiguredObject child1 = new TestConfiguredObject("child1", parent, parent.getTaskExecutor()); + child1.registerWithParents(); + TestConfiguredObject child2 = new TestConfiguredObject("child2", parent, parent.getTaskExecutor()); + child2.registerWithParents(); + + child1.setThrowExceptionOnValidate(true); + + parent.open(); + + assertTrue("Parent should be resolved", parent.isResolved()); + assertTrue("Parent should be validated", parent.isValidated()); + assertTrue("Parent should be opened", parent.isOpened()); + assertEquals("Unexpected parent state", State.ACTIVE, parent.getState()); + + assertTrue("Child2 should be resolved", child2.isResolved()); + assertTrue("Child2 should be validated", child2.isValidated()); + assertTrue("Child2 should be opened", child2.isOpened()); + assertEquals("Unexpected child2 state", State.ACTIVE, child2.getState()); + + assertTrue("Child1 should be resolved", child1.isResolved()); + assertFalse("Child1 should not be validated", child1.isValidated()); + assertFalse("Child1 should not be opened", child1.isOpened()); + assertEquals("Unexpected child1 state", State.ERRORED, child1.getState()); + } } diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java index db5cf1a7ba..ba6b0d95f3 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/model/VirtualHostTest.java @@ -65,6 +65,7 @@ public class VirtualHostTest extends QpidTestCase private TaskExecutor _taskExecutor; private VirtualHostNode<?> _virtualHostNode; private DurableConfigurationStore _configStore; + private VirtualHost<?, ?, ?> _virtualHost; @Override protected void setUp() throws Exception @@ -94,7 +95,17 @@ public class VirtualHostTest extends QpidTestCase { try { - _taskExecutor.stopImmediately(); + try + { + _taskExecutor.stopImmediately(); + } + finally + { + if (_virtualHost != null) + { + _virtualHost.close(); + } + } } finally { @@ -386,6 +397,7 @@ public class VirtualHostTest extends QpidTestCase TestMemoryVirtualHost host = new TestMemoryVirtualHost(attributes, _virtualHostNode); host.create(); + _virtualHost = host; return host; } diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImplTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImplTest.java new file mode 100644 index 0000000000..50a4e5a86e --- /dev/null +++ b/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImplTest.java @@ -0,0 +1,117 @@ +/* + * + * 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.model.adapter; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.test.utils.TestFileUtils; + +public class FileBasedGroupProviderImplTest extends QpidTestCase +{ + private TaskExecutor _taskExecutor; + private Broker _broker; + private File _groupFile; + + @Override + public void setUp() throws Exception + { + super.setUp(); + _taskExecutor = CurrentThreadTaskExecutor.newStartedInstance(); + + _broker = mock(Broker.class); + when(_broker.getTaskExecutor()).thenReturn(_taskExecutor); + when(_broker.getModel()).thenReturn(BrokerModel.getInstance()); + when(_broker.getId()).thenReturn(UUID.randomUUID()); + when(_broker.getSecurityManager()).thenReturn(new SecurityManager(_broker, false)); + } + + @Override + public void tearDown() throws Exception + { + try + { + if (_groupFile.exists()) + { + _groupFile.delete(); + } + _taskExecutor.stop(); + } + finally + { + super.tearDown(); + } + } + + public void testValidationOnCreateWithInvalidPath() + { + Map<String,Object> attributes = new HashMap<>(); + _groupFile = TestFileUtils.createTempFile(this, "groups"); + + String groupsFile = _groupFile.getAbsolutePath() + File.separator + "groups"; + assertFalse("File should not exist", new File(groupsFile).exists()); + attributes.put(FileBasedGroupProvider.PATH, groupsFile); + attributes.put(FileBasedGroupProvider.NAME, getTestName()); + + FileBasedGroupProviderImpl groupsProvider = new FileBasedGroupProviderImpl(attributes, _broker); + try + { + groupsProvider.create(); + fail("Exception is expected on validation of groups provider with invalid path"); + } catch (IllegalConfigurationException e) + { + assertEquals("Unexpected exception message:" + e.getMessage(), String.format("Cannot create groups file at '%s'", groupsFile), e.getMessage()); + } + } + + public void testValidationOnCreateWithInvalidGroups() + { + _groupFile = TestFileUtils.createTempFile(this, "groups", "=blah"); + Map<String, Object> attributes = new HashMap<>(); + String groupsFile = _groupFile.getAbsolutePath(); + attributes.put(FileBasedGroupProvider.PATH, groupsFile); + attributes.put(FileBasedGroupProvider.NAME, getTestName()); + + FileBasedGroupProviderImpl groupsProvider = new FileBasedGroupProviderImpl(attributes, _broker); + try + { + groupsProvider.create(); + fail("Exception is expected on validation of groups provider with invalid group file"); + } + catch (IllegalConfigurationException e) + { + assertEquals("Unexpected exception message:" + e.getMessage(), String.format("Cannot load groups from '%s'", groupsFile), e.getMessage()); + } + } + +} diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderTest.java index 9bb004e4c2..f532a9325b 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderTest.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderTest.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; import org.apache.qpid.server.configuration.updater.TaskExecutor; import org.apache.qpid.server.model.AuthenticationProvider; @@ -109,7 +110,7 @@ public class FileSystemPreferencesProviderTest extends QpidTestCase attributes.put(ConfiguredObject.ID, UUID.randomUUID()); attributes.put(ConfiguredObject.NAME, getTestName()); _preferencesProvider = new FileSystemPreferencesProviderImpl(attributes, _authenticationProvider); - _preferencesProvider.open(); + _preferencesProvider.create(); assertEquals(State.ACTIVE, _preferencesProvider.getState()); assertTrue("Preferences file was not created", nonExistingFile.exists()); @@ -120,6 +121,57 @@ public class FileSystemPreferencesProviderTest extends QpidTestCase } } + public void testValidationOnCreateForInvalidPath() throws Exception + { + File file = new File(TMP_FOLDER + File.separator + getTestName() + System.nanoTime() ); + file.createNewFile(); + String path = file.getAbsolutePath() + File.separator + "users"; + + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(FileSystemPreferencesProvider.PATH, path); + attributes.put(ConfiguredObject.ID, UUID.randomUUID()); + attributes.put(ConfiguredObject.NAME, getTestName()); + _preferencesProvider = new FileSystemPreferencesProviderImpl(attributes, _authenticationProvider); + + try + { + + _preferencesProvider.create(); + + fail("Creation of preferences provider with invalid path should have failed"); + } + catch(IllegalConfigurationException e) + { + assertEquals("Unexpected exception message:" + e.getMessage(), String.format("Cannot create preferences store file at '%s'", path), e.getMessage()); + } + } + + public void testValidationOnCreateWithInvalidPreferences() + { + File tmp = TestFileUtils.createTempFile(this, "preferences", "{blah:=boo}"); + try + { + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(FileSystemPreferencesProvider.PATH, tmp.getAbsolutePath()); + attributes.put(ConfiguredObject.ID, UUID.randomUUID()); + attributes.put(ConfiguredObject.NAME, getTestName()); + _preferencesProvider = new FileSystemPreferencesProviderImpl(attributes, _authenticationProvider); + try + { + _preferencesProvider.create(); + fail("Exception is expected on validation of groups provider with invalid preferences format"); + } + catch (IllegalConfigurationException e) + { + assertEquals("Unexpected exception message:" + e.getMessage(), "Cannot parse preferences json in " + tmp.getName(), e.getMessage()); + } + } + finally + { + tmp.delete(); + } + } + public void testConstructionWithEmptyFile() throws Exception { File emptyPrefsFile = new File(TMP_FOLDER, "preferences-" + getTestName() + ".json"); diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java index 523203c756..642ea06ede 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java @@ -54,7 +54,7 @@ import org.apache.qpid.test.utils.QpidTestCase; public class PortFactoryTest extends QpidTestCase { private UUID _portId = UUID.randomUUID(); - private int _portNumber = 123; + private int _portNumber; private Set<String> _tcpStringSet = Collections.singleton(Transport.TCP.name()); private Set<Transport> _tcpTransports = Collections.singleton(Transport.TCP); private Set<String> _sslStringSet = Collections.singleton(Transport.SSL.name()); @@ -68,11 +68,13 @@ public class PortFactoryTest extends QpidTestCase private String _authProviderName = "authProvider"; private AuthenticationProvider _authProvider = mock(AuthenticationProvider.class); private ConfiguredObjectFactoryImpl _factory; + private Port<?> _port; @Override protected void setUp() throws Exception { + _portNumber = findFreePort(); TaskExecutor executor = CurrentThreadTaskExecutor.newStartedInstance(); when(_authProvider.getName()).thenReturn(_authProviderName); when(_broker.getChildren(eq(AuthenticationProvider.class))).thenReturn(Collections.singleton(_authProvider)); @@ -109,30 +111,45 @@ public class PortFactoryTest extends QpidTestCase _attributes.put(Port.BINDING_ADDRESS, "127.0.0.1"); } + public void tearDown() throws Exception + { + try + { + if (_port != null) + { + _port.close(); + } + } + finally + { + super.tearDown(); + } + } + public void testCreatePortWithMinimumAttributes() { Map<String, Object> attributes = new HashMap<String, Object>(); - attributes.put(Port.PORT, 1); + attributes.put(Port.PORT, _portNumber); attributes.put(Port.NAME, getName()); attributes.put(Port.AUTHENTICATION_PROVIDER, _authProviderName); attributes.put(Port.DESIRED_STATE, State.QUIESCED); - Port<?> port = _factory.create(Port.class, attributes, _broker); + _port = _factory.create(Port.class, attributes, _broker); - assertNotNull(port); - assertTrue(port instanceof AmqpPort); - assertEquals("Unexpected port", 1, port.getPort()); - assertEquals("Unexpected transports", Collections.singleton(PortFactory.DEFAULT_TRANSPORT), port.getTransports()); + assertNotNull(_port); + assertTrue(_port instanceof AmqpPort); + assertEquals("Unexpected _port", _portNumber, _port.getPort()); + assertEquals("Unexpected transports", Collections.singleton(PortFactory.DEFAULT_TRANSPORT), _port.getTransports()); assertEquals("Unexpected send buffer size", PortFactory.DEFAULT_AMQP_SEND_BUFFER_SIZE, - port.getAttribute(AmqpPort.SEND_BUFFER_SIZE)); + _port.getAttribute(AmqpPort.SEND_BUFFER_SIZE)); assertEquals("Unexpected receive buffer size", PortFactory.DEFAULT_AMQP_RECEIVE_BUFFER_SIZE, - port.getAttribute(AmqpPort.RECEIVE_BUFFER_SIZE)); + _port.getAttribute(AmqpPort.RECEIVE_BUFFER_SIZE)); assertEquals("Unexpected need client auth", PortFactory.DEFAULT_AMQP_NEED_CLIENT_AUTH, - port.getAttribute(Port.NEED_CLIENT_AUTH)); + _port.getAttribute(Port.NEED_CLIENT_AUTH)); assertEquals("Unexpected want client auth", PortFactory.DEFAULT_AMQP_WANT_CLIENT_AUTH, - port.getAttribute(Port.WANT_CLIENT_AUTH)); - assertEquals("Unexpected tcp no delay", PortFactory.DEFAULT_AMQP_TCP_NO_DELAY, port.getAttribute(Port.TCP_NO_DELAY)); - assertEquals("Unexpected binding", PortFactory.DEFAULT_AMQP_BINDING, port.getAttribute(Port.BINDING_ADDRESS)); + _port.getAttribute(Port.WANT_CLIENT_AUTH)); + assertEquals("Unexpected tcp no delay", PortFactory.DEFAULT_AMQP_TCP_NO_DELAY, _port.getAttribute(Port.TCP_NO_DELAY)); + assertEquals("Unexpected binding", PortFactory.DEFAULT_AMQP_BINDING, _port.getAttribute(Port.BINDING_ADDRESS)); } public void testCreateAmqpPort() @@ -256,27 +273,27 @@ public class PortFactoryTest extends QpidTestCase _attributes.put(Port.DESIRED_STATE, State.QUIESCED); - Port<?> port = _factory.create(Port.class, _attributes, _broker); + _port = _factory.create(Port.class, _attributes, _broker); - assertNotNull(port); - assertTrue(port instanceof AmqpPort); - assertEquals(_portId, port.getId()); - assertEquals(_portNumber, port.getPort()); + assertNotNull(_port); + assertTrue(_port instanceof AmqpPort); + assertEquals(_portId, _port.getId()); + assertEquals(_portNumber, _port.getPort()); if(useSslTransport) { - assertEquals(_sslTransports, port.getTransports()); + assertEquals(_sslTransports, _port.getTransports()); } else { - assertEquals(_tcpTransports, port.getTransports()); + assertEquals(_tcpTransports, _port.getTransports()); } - assertEquals(amqp010ProtocolSet, port.getProtocols()); - assertEquals("Unexpected send buffer size", 2, port.getAttribute(AmqpPort.SEND_BUFFER_SIZE)); - assertEquals("Unexpected receive buffer size", 1, port.getAttribute(AmqpPort.RECEIVE_BUFFER_SIZE)); - assertEquals("Unexpected need client auth", needClientAuth, port.getAttribute(Port.NEED_CLIENT_AUTH)); - assertEquals("Unexpected want client auth", wantClientAuth, port.getAttribute(Port.WANT_CLIENT_AUTH)); - assertEquals("Unexpected tcp no delay", true, port.getAttribute(Port.TCP_NO_DELAY)); - assertEquals("Unexpected binding", "127.0.0.1", port.getAttribute(Port.BINDING_ADDRESS)); + assertEquals(amqp010ProtocolSet, _port.getProtocols()); + assertEquals("Unexpected send buffer size", 2, _port.getAttribute(AmqpPort.SEND_BUFFER_SIZE)); + assertEquals("Unexpected receive buffer size", 1, _port.getAttribute(AmqpPort.RECEIVE_BUFFER_SIZE)); + assertEquals("Unexpected need client auth", needClientAuth, _port.getAttribute(Port.NEED_CLIENT_AUTH)); + assertEquals("Unexpected want client auth", wantClientAuth, _port.getAttribute(Port.WANT_CLIENT_AUTH)); + assertEquals("Unexpected tcp no delay", true, _port.getAttribute(Port.TCP_NO_DELAY)); + assertEquals("Unexpected binding", "127.0.0.1", _port.getAttribute(Port.BINDING_ADDRESS)); } public void testCreateNonAmqpPort() @@ -291,14 +308,14 @@ public class PortFactoryTest extends QpidTestCase _attributes.put(Port.NAME, getName()); _attributes.put(Port.ID, _portId); - Port<?> port = _factory.create(Port.class, _attributes, _broker); + _port = _factory.create(Port.class, _attributes, _broker); - assertNotNull(port); - assertFalse("Port should not be an AMQP-specific subclass", port instanceof AmqpPort); - assertEquals(_portId, port.getId()); - assertEquals(_portNumber, port.getPort()); - assertEquals(_tcpTransports, port.getTransports()); - assertEquals(nonAmqpProtocolSet, port.getProtocols()); + assertNotNull(_port); + assertFalse("Port should not be an AMQP-specific subclass", _port instanceof AmqpPort); + assertEquals(_portId, _port.getId()); + assertEquals(_portNumber, _port.getPort()); + assertEquals(_tcpTransports, _port.getTransports()); + assertEquals(nonAmqpProtocolSet, _port.getProtocols()); } public void testCreateNonAmqpPortWithPartiallySetAttributes() @@ -312,14 +329,14 @@ public class PortFactoryTest extends QpidTestCase _attributes.put(Port.NAME, getName()); _attributes.put(Port.ID, _portId); - Port<?> port = _factory.create(Port.class, _attributes, _broker); + _port = _factory.create(Port.class, _attributes, _broker); - assertNotNull(port); - assertFalse("Port not be an AMQP-specific port subclass", port instanceof AmqpPort); - assertEquals(_portId, port.getId()); - assertEquals(_portNumber, port.getPort()); - assertEquals(Collections.singleton(PortFactory.DEFAULT_TRANSPORT), port.getTransports()); - assertEquals(nonAmqpProtocolSet, port.getProtocols()); + assertNotNull(_port); + assertFalse("Port not be an AMQP-specific _port subclass", _port instanceof AmqpPort); + assertEquals(_portId, _port.getId()); + assertEquals(_portNumber, _port.getPort()); + assertEquals(Collections.singleton(PortFactory.DEFAULT_TRANSPORT), _port.getTransports()); + assertEquals(nonAmqpProtocolSet, _port.getProtocols()); } @@ -330,7 +347,7 @@ public class PortFactoryTest extends QpidTestCase try { - Port<?> port = _factory.create(Port.class, _attributes, _broker); + _port = _factory.create(Port.class, _attributes, _broker); fail("Exception not thrown"); } catch (IllegalConfigurationException e) @@ -353,7 +370,7 @@ public class PortFactoryTest extends QpidTestCase try { - Port<?> port = _factory.create(Port.class, attributes, _broker); + _port = _factory.create(Port.class, attributes, _broker); fail("RMI port creation should fail as another one already exist"); } catch(IllegalConfigurationException e) @@ -377,7 +394,7 @@ public class PortFactoryTest extends QpidTestCase try { - Port<?> port = _factory.create(Port.class, attributes, _broker); + _port = _factory.create(Port.class, attributes, _broker); fail("RMI port creation should fail due to requesting SSL"); } catch(IllegalConfigurationException e) diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/model/port/AmqpPortImplTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/model/port/AmqpPortImplTest.java new file mode 100644 index 0000000000..1a993f8967 --- /dev/null +++ b/java/broker-core/src/test/java/org/apache/qpid/server/model/port/AmqpPortImplTest.java @@ -0,0 +1,123 @@ +/* + * 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.model.port; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.logging.EventLogger; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.Model; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.test.utils.QpidTestCase; + +public class AmqpPortImplTest extends QpidTestCase +{ + private static final String AUTHENTICATION_PROVIDER_NAME = "test"; + private TaskExecutor _taskExecutor; + private Broker _broker; + private ServerSocket _socket; + private AmqpPortImpl _port; + + @Override + public void setUp() throws Exception + { + super.setUp(); + _taskExecutor = CurrentThreadTaskExecutor.newStartedInstance(); + Model model = BrokerModel.getInstance(); + + _broker = mock(Broker.class); + when(_broker.getTaskExecutor()).thenReturn(_taskExecutor); + when(_broker.getModel()).thenReturn(model); + when(_broker.getId()).thenReturn(UUID.randomUUID()); + when(_broker.getSecurityManager()).thenReturn(new SecurityManager(_broker, false)); + when(_broker.getCategoryClass()).thenReturn(Broker.class); + when(_broker.getEventLogger()).thenReturn(new EventLogger()); + AuthenticationProvider<?> provider = mock(AuthenticationProvider.class); + when(provider.getName()).thenReturn(AUTHENTICATION_PROVIDER_NAME); + when(provider.getParent(Broker.class)).thenReturn(_broker); + when(_broker.getChildren(AuthenticationProvider.class)).thenReturn(Collections.<AuthenticationProvider>singleton(provider)); + when(_broker.getChildByName(AuthenticationProvider.class, AUTHENTICATION_PROVIDER_NAME)).thenReturn(provider); + } + + @Override + public void tearDown() throws Exception + { + try + { + if (_socket != null) + { + _socket.close(); + } + _taskExecutor.stop(); + } + finally + { + if (_port != null) + { + _port.close(); + } + super.tearDown(); + } + } + + public void testValidateOnCreate() throws Exception + { + _socket = openSocket(); + + Map<String, Object> attributes = new HashMap<>(); + attributes.put(AmqpPort.PORT, _socket.getLocalPort()); + attributes.put(AmqpPort.NAME, getTestName()); + attributes.put(AmqpPort.AUTHENTICATION_PROVIDER, AUTHENTICATION_PROVIDER_NAME); + _port = new AmqpPortImpl(attributes, _broker); + try + { + _port.create(); + fail("Creation should fail due to validation check"); + } + catch (IllegalConfigurationException e) + { + assertEquals("Unexpected exception message", + String.format("Cannot bind to port %d and binding address '%s'. Port is already is use.", + _socket.getLocalPort(), "*"), e.getMessage()); + } + } + + private ServerSocket openSocket() throws IOException + { + ServerSocket serverSocket = new ServerSocket(); + serverSocket.setReuseAddress(true); + serverSocket.bind(new InetSocketAddress(findFreePort())); + return serverSocket; + } +} diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestConfiguredObject.java b/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestConfiguredObject.java new file mode 100644 index 0000000000..5c04db0cd6 --- /dev/null +++ b/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestConfiguredObject.java @@ -0,0 +1,256 @@ +/* + * 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.model.testmodel; + +import static org.mockito.Mockito.mock; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.ConfiguredObjectFactory; +import org.apache.qpid.server.model.ConfiguredObjectFactoryImpl; +import org.apache.qpid.server.model.ConfiguredObjectTypeRegistry; +import org.apache.qpid.server.model.ManagedObject; +import org.apache.qpid.server.model.Model; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.StateTransition; +import org.apache.qpid.server.plugin.ConfiguredObjectRegistration; + +@ManagedObject +public class TestConfiguredObject extends AbstractConfiguredObject +{ + private boolean _opened; + private boolean _validated; + private boolean _resolved; + private boolean _throwExceptionOnOpen; + private boolean _throwExceptionOnValidationOnCreate; + private boolean _throwExceptionOnPostResolve; + private boolean _throwExceptionOnCreate; + private boolean _throwExceptionOnValidate; + + public final static Map<Class<? extends ConfiguredObject>, ConfiguredObject<?>> createParents(ConfiguredObject<?> parent) + { + return Collections.<Class<? extends ConfiguredObject>, ConfiguredObject<?>>singletonMap(parent.getCategoryClass(), parent); + } + + public TestConfiguredObject(String name) + { + this(name, mock(ConfiguredObject.class), CurrentThreadTaskExecutor.newStartedInstance()); + } + + public TestConfiguredObject(String name, ConfiguredObject<?> parent, TaskExecutor taskExecutor) + { + this(createParents(parent), Collections.<String, Object>singletonMap(ConfiguredObject.NAME, name), taskExecutor, TestConfiguredObjectModel.INSTANCE); + } + + public TestConfiguredObject(Map parents, Map<String, Object> attributes, TaskExecutor taskExecutor, Model model) + { + super(parents, attributes, taskExecutor, model); + _opened = false; + } + + @Override + protected void postResolve() + { + if (_throwExceptionOnPostResolve) + { + throw new IllegalConfigurationException("Cannot resolve"); + } + _resolved = true; + } + + @Override + protected void onCreate() + { + if (_throwExceptionOnCreate) + { + throw new IllegalConfigurationException("Cannot create"); + } + } + + @Override + protected void onOpen() + { + if (_throwExceptionOnOpen) + { + throw new IllegalConfigurationException("Cannot open"); + } + _opened = true; + } + + @Override + protected void validateOnCreate() + { + if (_throwExceptionOnValidationOnCreate) + { + throw new IllegalConfigurationException("Cannot validate on create"); + } + } + + @Override + public void onValidate() + { + if (_throwExceptionOnValidate) + { + throw new IllegalConfigurationException("Cannot validate"); + } + _validated = true; + } + + @StateTransition( currentState = {State.ERRORED, State.UNINITIALIZED}, desiredState = State.ACTIVE ) + protected void activate() + { + setState(State.ACTIVE); + } + + @StateTransition( currentState = {State.ERRORED, State.UNINITIALIZED}, desiredState = State.DELETED ) + protected void doDelete() + { + setState(State.DELETED); + } + + public boolean isOpened() + { + return _opened; + } + + public void setThrowExceptionOnOpen(boolean throwException) + { + _throwExceptionOnOpen = throwException; + } + + public void setThrowExceptionOnValidationOnCreate(boolean throwException) + { + _throwExceptionOnValidationOnCreate = throwException; + } + + public void setThrowExceptionOnPostResolve(boolean throwException) + { + _throwExceptionOnPostResolve = throwException; + } + + public void setThrowExceptionOnCreate(boolean throwExceptionOnCreate) + { + _throwExceptionOnCreate = throwExceptionOnCreate; + } + + public void setThrowExceptionOnValidate(boolean throwException) + { + _throwExceptionOnValidate= throwException; + } + + public boolean isValidated() + { + return _validated; + } + + public boolean isResolved() + { + return _resolved; + } + + public static class TestConfiguredObjectModel extends Model + { + + private Collection<Class<? extends ConfiguredObject>> CATEGORIES = Collections.<Class<? extends ConfiguredObject>>singleton(TestConfiguredObject.class); + private ConfiguredObjectFactoryImpl _configuredObjectFactory; + + private static TestConfiguredObjectModel INSTANCE = new TestConfiguredObjectModel(); + private ConfiguredObjectTypeRegistry _configuredObjectTypeRegistry; + + private TestConfiguredObjectModel() + { + _configuredObjectFactory = new ConfiguredObjectFactoryImpl(this); + ConfiguredObjectRegistration configuredObjectRegistration = new ConfiguredObjectRegistration() + { + @Override + public Collection<Class<? extends ConfiguredObject>> getConfiguredObjectClasses() + { + return CATEGORIES; + } + + @Override + public String getType() + { + return TestConfiguredObjectModel.class.getSimpleName(); + } + }; + _configuredObjectTypeRegistry = new ConfiguredObjectTypeRegistry(Arrays.asList(configuredObjectRegistration), CATEGORIES); + } + + @Override + public Collection<Class<? extends ConfiguredObject>> getSupportedCategories() + { + return CATEGORIES; + } + + @Override + public Collection<Class<? extends ConfiguredObject>> getChildTypes(Class<? extends ConfiguredObject> parent) + { + return TestConfiguredObject.class.isAssignableFrom(parent) + ? CATEGORIES + : Collections.<Class<? extends ConfiguredObject>>emptySet(); + } + + @Override + public Class<? extends ConfiguredObject> getRootCategory() + { + return TestConfiguredObject.class; + } + + @Override + public Collection<Class<? extends ConfiguredObject>> getParentTypes(final Class<? extends ConfiguredObject> child) + { + return TestConfiguredObject.class.isAssignableFrom(child) + ? CATEGORIES + : Collections.<Class<? extends ConfiguredObject>>emptySet(); + } + + @Override + public int getMajorVersion() + { + return 99; + } + + @Override + public int getMinorVersion() + { + return 99; + } + + @Override + public ConfiguredObjectFactory getObjectFactory() + { + return _configuredObjectFactory; + } + + @Override + public ConfiguredObjectTypeRegistry getTypeRegistry() + { + return _configuredObjectTypeRegistry; + } + } +} diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java index 703a8d43c9..84ba7a3822 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java @@ -90,31 +90,28 @@ public class PrincipalDatabaseAuthenticationManagerTest extends QpidTestCase private void setupMocks() throws Exception { - _principalDatabase = mock(PrincipalDatabase.class); - - when(_principalDatabase.getMechanisms()).thenReturn(Collections.singletonList(MOCK_MECH_NAME)); - when(_principalDatabase.createSaslServer(MOCK_MECH_NAME, LOCALHOST, null)).thenReturn(new MySaslServer(false, true)); + setUpPrincipalDatabase(); setupManager(false); _manager.initialise(); } + private void setUpPrincipalDatabase() throws SaslException + { + _principalDatabase = mock(PrincipalDatabase.class); + + when(_principalDatabase.getMechanisms()).thenReturn(Collections.singletonList(MOCK_MECH_NAME)); + when(_principalDatabase.createSaslServer(MOCK_MECH_NAME, LOCALHOST, null)).thenReturn(new MySaslServer(false, true)); + } + private void setupManager(final boolean recovering) { Map<String,Object> attrs = new HashMap<String, Object>(); attrs.put(ConfiguredObject.ID, UUID.randomUUID()); attrs.put(ConfiguredObject.NAME, getTestName()); attrs.put("path", _passwordFileLocation); - _manager = new PrincipalDatabaseAuthenticationManager(attrs, BrokerTestHelper.createBrokerMock()) - { - @Override - protected PrincipalDatabase createDatabase() - { - return _principalDatabase; - } - - }; + _manager = getPrincipalDatabaseAuthenticationManager(attrs); if(recovering) { _manager.open(); @@ -273,6 +270,41 @@ public class PrincipalDatabaseAuthenticationManagerTest extends QpidTestCase assertFalse("Password file was not deleted", new File(_passwordFileLocation).exists()); } + public void testCreateForInvalidPath() throws Exception + { + setUpPrincipalDatabase(); + + Map<String,Object> attrs = new HashMap<>(); + attrs.put(ConfiguredObject.ID, UUID.randomUUID()); + attrs.put(ConfiguredObject.NAME, getTestName()); + String path = TMP_FOLDER + File.separator + getTestName() + System.nanoTime() + File.separator + "users"; + attrs.put("path", path); + + _manager = getPrincipalDatabaseAuthenticationManager(attrs); + try + { + _manager.create(); + fail("Creation with invalid path should have failed"); + } + catch(IllegalConfigurationException e) + { + assertEquals("Unexpected exception message:" + e.getMessage(), String.format("Cannot create password file at '%s'", path), e.getMessage()); + } + } + + PrincipalDatabaseAuthenticationManager getPrincipalDatabaseAuthenticationManager(final Map<String, Object> attrs) + { + return new PrincipalDatabaseAuthenticationManager(attrs, BrokerTestHelper.createBrokerMock()) + { + @Override + protected PrincipalDatabase createDatabase() + { + return _principalDatabase; + } + + }; + } + private void deletePasswordFileIfExists() { File passwordFile = new File(_passwordFileLocation); diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactoryTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactoryTest.java index 6001ed1750..9e580d3157 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactoryTest.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactoryTest.java @@ -57,40 +57,15 @@ public class SimpleLDAPAuthenticationManagerFactoryTest extends TestCase _configuration.put(AuthenticationProvider.NAME, getName()); } - public void testLdapInstanceCreated() throws Exception + public void testLdapCreated() throws Exception { _configuration.put(AuthenticationProvider.TYPE, SimpleLDAPAuthenticationManager.PROVIDER_TYPE); - _configuration.put("providerUrl", "ldap://example.com:389/"); - _configuration.put("searchContext", "dc=example"); - - AuthenticationProvider manager = _factory.create(AuthenticationProvider.class, _configuration, _broker); - assertNotNull(manager); - - } - - public void testLdapsInstanceCreated() throws Exception - { - _configuration.put(AuthenticationProvider.TYPE, SimpleLDAPAuthenticationManager.PROVIDER_TYPE); - _configuration.put("providerUrl", "ldaps://example.com:636/"); - _configuration.put("searchContext", "dc=example"); - - AuthenticationProvider manager = _factory.create(AuthenticationProvider.class, _configuration, _broker); - assertNotNull(manager); - - } - - public void testLdapsWithTrustStoreInstanceCreated() throws Exception - { - when(_broker.getChildren(eq(TrustStore.class))).thenReturn(Collections.singletonList(_trustStore)); - - - _configuration.put(AuthenticationProvider.TYPE, SimpleLDAPAuthenticationManager.PROVIDER_TYPE); _configuration.put("providerUrl", "ldaps://example.com:636/"); _configuration.put("searchContext", "dc=example"); - _configuration.put("trustStore", "mytruststore"); + _configuration.put("searchFilter", "(uid={0})"); + _configuration.put("ldapContextFactory", TestLdapDirectoryContext.class.getName()); - AuthenticationProvider manager = _factory.create(AuthenticationProvider.class, _configuration, _broker); - assertNotNull(manager); + _factory.create(AuthenticationProvider.class, _configuration, _broker); } public void testLdapsWhenTrustStoreNotFound() throws Exception @@ -100,6 +75,7 @@ public class SimpleLDAPAuthenticationManagerFactoryTest extends TestCase _configuration.put(AuthenticationProvider.TYPE, SimpleLDAPAuthenticationManager.PROVIDER_TYPE); _configuration.put("providerUrl", "ldaps://example.com:636/"); _configuration.put("searchContext", "dc=example"); + _configuration.put("searchFilter", "(uid={0})"); _configuration.put("trustStore", "notfound"); try @@ -110,7 +86,7 @@ public class SimpleLDAPAuthenticationManagerFactoryTest extends TestCase catch(IllegalArgumentException e) { // PASS - assertTrue("Message does not include underlying issue", e.getMessage().contains("name 'notfound'")); + assertTrue("Message does not include underlying issue ", e.getMessage().contains("name 'notfound'")); assertTrue("Message does not include the attribute name", e.getMessage().contains("trustStore")); assertTrue("Message does not include the expected type", e.getMessage().contains("TrustStore")); } diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/TestLdapDirectoryContext.java b/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/TestLdapDirectoryContext.java new file mode 100644 index 0000000000..87b73c8373 --- /dev/null +++ b/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/TestLdapDirectoryContext.java @@ -0,0 +1,38 @@ +/* + * 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.security.auth.manager; + +import static org.mockito.Mockito.mock; + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; + +public class TestLdapDirectoryContext implements javax.naming.spi.InitialContextFactory +{ + @Override + public Context getInitialContext(final Hashtable<?, ?> environment) throws NamingException + { + return (DirContext)mock(DirContext.class); + } + +} diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerRecovererTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerRecovererTest.java index 52f70e7fd6..c220876a23 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerRecovererTest.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerRecovererTest.java @@ -21,7 +21,9 @@ package org.apache.qpid.server.store; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; import java.util.Arrays; import java.util.Collections; @@ -40,6 +42,7 @@ import org.apache.qpid.server.logging.LogRecorder; import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.BrokerShutdownProvider; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.GroupProvider; import org.apache.qpid.server.model.JsonSystemConfigImpl; @@ -55,6 +58,7 @@ public class BrokerRecovererTest extends TestCase private UUID _authenticationProvider1Id = UUID.randomUUID(); private SystemConfig<?> _systemConfig; private TaskExecutor _taskExecutor; + private BrokerShutdownProvider _brokerShutdownProvider; @Override protected void setUp() throws Exception @@ -63,8 +67,11 @@ public class BrokerRecovererTest extends TestCase _taskExecutor = new CurrentThreadTaskExecutor(); _taskExecutor.start(); + _brokerShutdownProvider = mock(BrokerShutdownProvider.class); _systemConfig = new JsonSystemConfigImpl(_taskExecutor, - mock(EventLogger.class), mock(LogRecorder.class), new BrokerOptions()); + mock(EventLogger.class), mock(LogRecorder.class), + new BrokerOptions(), + _brokerShutdownProvider); when(_brokerEntry.getId()).thenReturn(_brokerId); when(_brokerEntry.getType()).thenReturn(Broker.class.getSimpleName()); @@ -251,18 +258,10 @@ public class BrokerRecovererTest extends TestCase brokerAttributes.put(Broker.NAME, getName()); when(_brokerEntry.getAttributes()).thenReturn(brokerAttributes); - try - { - resolveObjects(_brokerEntry); - Broker<?> broker = _systemConfig.getBroker(); - broker.open(); - fail("The broker creation should fail due to unsupported model version"); - } - catch (IllegalConfigurationException e) - { - assertEquals("The model version '" + incompatibleVersion - + "' in configuration is incompatible with the broker model version '" + BrokerModel.MODEL_VERSION + "'", e.getMessage()); - } + resolveObjects(_brokerEntry); + Broker<?> broker = _systemConfig.getBroker(); + broker.open(); + verify(_brokerShutdownProvider).shutdown(); } } @@ -276,20 +275,12 @@ public class BrokerRecovererTest extends TestCase when(_brokerEntry.getAttributes()).thenReturn(brokerAttributes); - try - { - UnresolvedConfiguredObject<? extends ConfiguredObject> recover = - _systemConfig.getObjectFactory().recover(_brokerEntry, _systemConfig); + UnresolvedConfiguredObject<? extends ConfiguredObject> recover = + _systemConfig.getObjectFactory().recover(_brokerEntry, _systemConfig); - Broker<?> broker = (Broker<?>) recover.resolve(); - broker.open(); - fail("The broker creation should fail due to unsupported model version"); - } - catch (IllegalConfigurationException e) - { - assertEquals("The model version '" + incompatibleVersion - + "' in configuration is incompatible with the broker model version '" + BrokerModel.MODEL_VERSION + "'", e.getMessage()); - } + Broker<?> broker = (Broker<?>) recover.resolve(); + broker.open(); + verify(_brokerShutdownProvider).shutdown(); } public void testIncorrectModelVersion() throws Exception @@ -303,18 +294,12 @@ public class BrokerRecovererTest extends TestCase brokerAttributes.put(Broker.MODEL_VERSION, modelVersion); when(_brokerEntry.getAttributes()).thenReturn(brokerAttributes); - try - { - UnresolvedConfiguredObject<? extends ConfiguredObject> recover = - _systemConfig.getObjectFactory().recover(_brokerEntry, _systemConfig); - Broker<?> broker = (Broker<?>) recover.resolve(); - broker.open(); - fail("The broker creation should fail due to unsupported model version"); - } - catch (IllegalConfigurationException e) - { - // pass - } + UnresolvedConfiguredObject<? extends ConfiguredObject> recover = + _systemConfig.getObjectFactory().recover(_brokerEntry, _systemConfig); + Broker<?> broker = (Broker<?>) recover.resolve(); + broker.open(); + verify(_brokerShutdownProvider).shutdown(); + reset(_brokerShutdownProvider); } } diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecovererTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecovererTest.java index c94a0ef9c4..45b595b62e 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecovererTest.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecovererTest.java @@ -32,6 +32,7 @@ import org.apache.qpid.server.BrokerOptions; import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.LogRecorder; +import org.apache.qpid.server.model.BrokerShutdownProvider; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.JsonSystemConfigImpl; import org.apache.qpid.server.model.SystemConfig; @@ -60,7 +61,8 @@ public class BrokerStoreUpgraderAndRecovererTest extends QpidTestCase _systemConfig = new JsonSystemConfigImpl(_taskExecutor, mock(EventLogger.class), mock(LogRecorder.class), - new BrokerOptions()); + new BrokerOptions(), + mock(BrokerShutdownProvider.class)); } public void testUpgradeVirtualHostWithJDBCStoreAndBoneCPPool() diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/virtualhost/AbstractVirtualHostTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/virtualhost/AbstractVirtualHostTest.java new file mode 100644 index 0000000000..889097f850 --- /dev/null +++ b/java/broker-core/src/test/java/org/apache/qpid/server/virtualhost/AbstractVirtualHostTest.java @@ -0,0 +1,247 @@ +/* + * + * 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.virtualhost; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.doThrow; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.configuration.updater.TaskExecutorImpl; +import org.apache.qpid.server.logging.EventLogger; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.SystemConfig; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.store.DurableConfigurationStore; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.test.utils.QpidTestCase; +import org.mockito.verification.VerificationMode; + +public class AbstractVirtualHostTest extends QpidTestCase +{ + private TaskExecutor _taskExecutor; + private VirtualHostNode<?> _node; + private MessageStore _failingStore; + + @Override + public void setUp() throws Exception + { + super.setUp(); + + SystemConfig systemConfig = mock(SystemConfig.class); + when(systemConfig.getEventLogger()).thenReturn(mock(EventLogger.class)); + Broker<?> broker = mock(Broker.class); + when(broker.getParent(SystemConfig.class)).thenReturn(systemConfig); + when(broker.getSecurityManager()).thenReturn(new SecurityManager(broker, false)); + + _taskExecutor = new TaskExecutorImpl(); + _taskExecutor.start(); + when(broker.getTaskExecutor()).thenReturn(_taskExecutor); + + _node = mock(VirtualHostNode.class); + when(_node.getParent(Broker.class)).thenReturn(broker); + when(_node.getModel()).thenReturn(BrokerModel.getInstance()); + when(_node.getTaskExecutor()).thenReturn(_taskExecutor); + when(_node.getConfigurationStore()).thenReturn(mock(DurableConfigurationStore.class)); + + _failingStore = mock(MessageStore.class); + doThrow(new RuntimeException("Cannot open store")).when(_failingStore).openMessageStore(any(ConfiguredObject.class)); + } + + @Override + public void tearDown() throws Exception + { + try + { + if (_taskExecutor != null) + { + _taskExecutor.stopImmediately(); + } + } + finally + { + super.tearDown(); + } + } + + public void testValidateOnCreateFails() + { + Map<String,Object> attributes = Collections.<String, Object>singletonMap(AbstractVirtualHost.NAME, getTestName()); + + AbstractVirtualHost host = new AbstractVirtualHost(attributes, _node) + { + @Override + protected MessageStore createMessageStore() + { + return _failingStore; + } + }; + + try + { + host.validateOnCreate(); + fail("Validation on creation should fail"); + } + catch(IllegalConfigurationException e) + { + assertTrue("Unexpected exception " + e.getMessage(), e.getMessage().startsWith("Cannot open virtual host message store")); + } + } + + public void testValidateOnCreateSucceeds() + { + Map<String,Object> attributes = Collections.<String, Object>singletonMap(AbstractVirtualHost.NAME, getTestName()); + final MessageStore store = mock(MessageStore.class); + AbstractVirtualHost host = new AbstractVirtualHost(attributes, _node) + { + @Override + protected MessageStore createMessageStore() + { + return store; + } + }; + + host.validateOnCreate(); + verify(store).openMessageStore(host); + verify(store).closeMessageStore(); + } + + public void testOpenFails() + { + Map<String,Object> attributes = Collections.<String, Object>singletonMap(AbstractVirtualHost.NAME, getTestName()); + + AbstractVirtualHost host = new AbstractVirtualHost(attributes, _node) + { + @Override + protected MessageStore createMessageStore() + { + return _failingStore; + } + }; + + host.open(); + assertEquals("Unexpected host state", State.ERRORED, host.getState()); + } + + public void testOpenSucceeds() + { + Map<String,Object> attributes = Collections.<String, Object>singletonMap(AbstractVirtualHost.NAME, getTestName()); + final MessageStore store = mock(MessageStore.class); + AbstractVirtualHost host = new AbstractVirtualHost(attributes, _node) + { + @Override + protected MessageStore createMessageStore() + { + return store; + } + }; + + host.open(); + assertEquals("Unexpected host state", State.ACTIVE, host.getState()); + verify(store).openMessageStore(host); + + // make sure that method AbstractVirtualHost.onExceptionInOpen was not called + verify(store, times(0)).closeMessageStore(); + } + + public void testDeleteInErrorStateAfterOpen() + { + Map<String,Object> attributes = Collections.<String, Object>singletonMap(AbstractVirtualHost.NAME, getTestName()); + AbstractVirtualHost host = new AbstractVirtualHost(attributes, _node) + { + @Override + protected MessageStore createMessageStore() + { + return _failingStore; + } + }; + + host.open(); + + assertEquals("Unexpected state", State.ERRORED, host.getState()); + + host.delete(); + assertEquals("Unexpected state", State.DELETED, host.getState()); + } + + public void testActivateInErrorStateAfterOpen() throws Exception + { + Map<String,Object> attributes = Collections.<String, Object>singletonMap(AbstractVirtualHost.NAME, getTestName()); + final MessageStore store = mock(MessageStore.class); + doThrow(new RuntimeException("Cannot open store")).when(store).openMessageStore(any(ConfiguredObject.class)); + AbstractVirtualHost host = new AbstractVirtualHost(attributes, _node) + { + @Override + protected MessageStore createMessageStore() + { + return store; + } + }; + + host.open(); + assertEquals("Unexpected state", State.ERRORED, host.getState()); + + doNothing().when(store).openMessageStore(any(ConfiguredObject.class)); + + host.setAttributes(Collections.<String, Object>singletonMap(VirtualHost.DESIRED_STATE, State.ACTIVE)); + assertEquals("Unexpected state", State.ACTIVE, host.getState()); + } + + public void testStartInErrorStateAfterOpen() throws Exception + { + Map<String,Object> attributes = Collections.<String, Object>singletonMap(AbstractVirtualHost.NAME, getTestName()); + final MessageStore store = mock(MessageStore.class); + doThrow(new RuntimeException("Cannot open store")).when(store).openMessageStore(any(ConfiguredObject.class)); + AbstractVirtualHost host = new AbstractVirtualHost(attributes, _node) + { + @Override + protected MessageStore createMessageStore() + { + return store; + } + }; + + host.open(); + assertEquals("Unexpected state", State.ERRORED, host.getState()); + + doNothing().when(store).openMessageStore(any(ConfiguredObject.class)); + + host.start(); + assertEquals("Unexpected state", State.ACTIVE, host.getState()); + } +} diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java b/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java index 971c96b2ff..b17f383217 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java @@ -20,22 +20,30 @@ */ package org.apache.qpid.server.virtualhostnode; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.security.AccessControlException; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; import org.apache.qpid.server.configuration.updater.TaskExecutor; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.ConfiguredObjectFactoryImpl; import org.apache.qpid.server.model.Model; +import org.apache.qpid.server.model.RemoteReplicationNode; import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.SystemConfig; import org.apache.qpid.server.model.VirtualHost; @@ -348,6 +356,132 @@ public class AbstractStandardVirtualHostNodeTest extends QpidTestCase assertEquals("Virtual host node state changed unexpectedly", State.ACTIVE, node.getState()); } + public void testValidateOnCreateFails() throws Exception + { + String nodeName = getTestName(); + Map<String, Object> attributes = Collections.<String, Object>singletonMap(TestVirtualHostNode.NAME, nodeName); + + final DurableConfigurationStore store = mock(DurableConfigurationStore.class); + doThrow(new RuntimeException("Cannot open store")).when(store).openConfigurationStore(any(ConfiguredObject.class), any(boolean.class)); + AbstractStandardVirtualHostNode node = createAbstractStandardVirtualHostNode(attributes, store); + + try + { + node.validateOnCreate(); + fail("Cannot create node"); + } + catch (IllegalConfigurationException e) + { + assertTrue("Unexpected exception " + e.getMessage(), e.getMessage().startsWith("Cannot open node configuration store")); + } + } + + public void testValidateOnCreateSucceeds() throws Exception + { + String nodeName = getTestName(); + Map<String, Object> attributes = Collections.<String, Object>singletonMap(TestVirtualHostNode.NAME, nodeName); + + final DurableConfigurationStore store = mock(DurableConfigurationStore.class); + AbstractStandardVirtualHostNode node = createAbstractStandardVirtualHostNode(attributes, store); + + node.validateOnCreate(); + verify(store).openConfigurationStore(node, false); + verify(store).closeConfigurationStore(); + } + + public void testOpenFails() throws Exception + { + String nodeName = getTestName(); + Map<String, Object> attributes = Collections.<String, Object>singletonMap(TestVirtualHostNode.NAME, nodeName); + + DurableConfigurationStore store = mock(DurableConfigurationStore.class); + AbstractVirtualHostNode node = new TestAbstractVirtualHostNode( _broker, attributes, store); + node.open(); + assertEquals("Unexpected node state", State.ERRORED, node.getState()); + } + + public void testOpenSucceeds() throws Exception + { + String nodeName = getTestName(); + Map<String, Object> attributes = Collections.<String, Object>singletonMap(TestVirtualHostNode.NAME, nodeName); + + final AtomicBoolean onFailureFlag = new AtomicBoolean(); + DurableConfigurationStore store = mock(DurableConfigurationStore.class); + AbstractVirtualHostNode node = new TestAbstractVirtualHostNode( _broker, attributes, store) + { + @Override + public void onValidate() + { + // no op + } + + @Override + protected void onExceptionInOpen(RuntimeException e) + { + try + { + super.onExceptionInOpen(e); + } + finally + { + onFailureFlag.set(true); + } + } + }; + + node.open(); + assertEquals("Unexpected node state", State.ACTIVE, node.getState()); + assertFalse("onExceptionInOpen was called", onFailureFlag.get()); + } + + + public void testDeleteInErrorStateAfterOpen() + { + String nodeName = getTestName(); + Map<String, Object> attributes = Collections.<String, Object>singletonMap(TestVirtualHostNode.NAME, nodeName); + + final DurableConfigurationStore store = mock(DurableConfigurationStore.class); + doThrow(new RuntimeException("Cannot open store")).when(store).openConfigurationStore(any(ConfiguredObject.class), any(boolean.class)); + AbstractStandardVirtualHostNode node = createAbstractStandardVirtualHostNode(attributes, store); + node.open(); + assertEquals("Unexpected node state", State.ERRORED, node.getState()); + + node.delete(); + assertEquals("Unexpected state", State.DELETED, node.getState()); + } + + public void testActivateInErrorStateAfterOpen() throws Exception + { + String nodeName = getTestName(); + Map<String, Object> attributes = Collections.<String, Object>singletonMap(TestVirtualHostNode.NAME, nodeName); + + DurableConfigurationStore store = mock(DurableConfigurationStore.class); + doThrow(new RuntimeException("Cannot open store")).when(store).openConfigurationStore(any(ConfiguredObject.class), any(boolean.class)); + AbstractVirtualHostNode node = createAbstractStandardVirtualHostNode(attributes, store); + node.open(); + assertEquals("Unexpected node state", State.ERRORED, node.getState()); + doNothing().when(store).openConfigurationStore(any(ConfiguredObject.class), any(boolean.class)); + + node.setAttributes(Collections.<String, Object>singletonMap(VirtualHostNode.DESIRED_STATE, State.ACTIVE)); + assertEquals("Unexpected state", State.ACTIVE, node.getState()); + } + + public void testStartInErrorStateAfterOpen() throws Exception + { + String nodeName = getTestName(); + Map<String, Object> attributes = Collections.<String, Object>singletonMap(TestVirtualHostNode.NAME, nodeName); + + DurableConfigurationStore store = mock(DurableConfigurationStore.class); + doThrow(new RuntimeException("Cannot open store")).when(store).openConfigurationStore(any(ConfiguredObject.class), any(boolean.class)); + AbstractVirtualHostNode node = createAbstractStandardVirtualHostNode(attributes, store); + node.open(); + assertEquals("Unexpected node state", State.ERRORED, node.getState()); + doNothing().when(store).openConfigurationStore(any(ConfiguredObject.class), any(boolean.class)); + + node.start(); + assertEquals("Unexpected state", State.ACTIVE, node.getState()); + } + private ConfiguredObjectRecord createVirtualHostConfiguredObjectRecord(UUID virtualHostId) { Map<String, Object> virtualHostAttributes = new HashMap<>(); @@ -384,4 +518,62 @@ public class AbstractStandardVirtualHostNodeTest extends QpidTestCase return configStoreThatProduces(null); } + + private AbstractStandardVirtualHostNode createAbstractStandardVirtualHostNode(final Map<String, Object> attributes, final DurableConfigurationStore store) + { + return new AbstractStandardVirtualHostNode(attributes, _broker){ + + @Override + protected void writeLocationEventLog() + { + + } + + @Override + protected DurableConfigurationStore createConfigurationStore() + { + return store; + } + }; + } + + private class TestAbstractVirtualHostNode extends AbstractVirtualHostNode + { + private DurableConfigurationStore _store; + + public TestAbstractVirtualHostNode(Broker parent, Map attributes, DurableConfigurationStore store) + { + super(parent, attributes); + _store = store; + } + + @Override + public void onValidate() + { + throw new RuntimeException("Cannot validate"); + } + + @Override + protected DurableConfigurationStore createConfigurationStore() + { + return _store; + } + + @Override + protected void activate() + { + } + + @Override + protected ConfiguredObjectRecord enrichInitialVirtualHostRootRecord(ConfiguredObjectRecord vhostRecord) + { + return null; + } + + @Override + public Collection<? extends RemoteReplicationNode> getRemoteReplicationNodes() + { + return null; + } + } } diff --git a/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/TestVirtualHostNode.java b/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/TestVirtualHostNode.java index 277ef8b400..4fe8136624 100644 --- a/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/TestVirtualHostNode.java +++ b/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/TestVirtualHostNode.java @@ -53,6 +53,12 @@ public class TestVirtualHostNode extends AbstractStandardVirtualHostNode<TestVir } @Override + public DurableConfigurationStore getConfigurationStore() + { + return _store; + } + + @Override protected void writeLocationEventLog() { } diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImpl.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImpl.java index f0edc59025..1adc6561c7 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImpl.java +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImpl.java @@ -25,10 +25,10 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.model.AbstractConfiguredObject; import org.apache.qpid.server.model.AccessControlProvider; import org.apache.qpid.server.model.Broker; @@ -83,6 +83,29 @@ public class ACLFileAccessControlProviderImpl } @Override + protected void validateOnCreate() + { + DefaultAccessControl accessControl = null; + try + { + accessControl = new DefaultAccessControl(getPath(), _broker); + accessControl.validate(); + accessControl.open(); + } + catch(RuntimeException e) + { + throw new IllegalConfigurationException(e.getMessage(), e); + } + finally + { + if (accessControl != null) + { + accessControl.close(); + } + } + } + + @Override protected void onOpen() { super.onOpen(); @@ -105,6 +128,7 @@ public class ACLFileAccessControlProviderImpl @StateTransition(currentState = {State.UNINITIALIZED, State.QUIESCED, State.ERRORED}, desiredState = State.ACTIVE) private void activate() { + if(_broker.isManagementMode()) { @@ -136,7 +160,10 @@ public class ACLFileAccessControlProviderImpl protected void onClose() { super.onClose(); - _accessControl.close(); + if (_accessControl != null) + { + _accessControl.close(); + } } @StateTransition(currentState = State.UNINITIALIZED, desiredState = State.QUIESCED) diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImplTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImplTest.java new file mode 100644 index 0000000000..005d2a95bc --- /dev/null +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImplTest.java @@ -0,0 +1,80 @@ +/* + * + * 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.security.access.plugins; + + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.Model; +import org.apache.qpid.test.utils.QpidTestCase; + +public class ACLFileAccessControlProviderImplTest extends QpidTestCase +{ + private TaskExecutor _taskExecutor; + private Model _model; + private Broker _broker; + + public void setUp() throws Exception + { + super.setUp(); + _taskExecutor = CurrentThreadTaskExecutor.newStartedInstance(); + _model = BrokerModel.getInstance(); + + _broker = mock(Broker.class); + when(_broker.getTaskExecutor()).thenReturn(_taskExecutor); + when(_broker.getModel()).thenReturn(_model); + when(_broker.getId()).thenReturn(UUID.randomUUID()); + } + + public void testValidationOnCreateWithNonExistingACLFile() + { + Map<String,Object> attributes = new HashMap<>(); + String aclFilePath = new File(TMP_FOLDER, "test_" + getTestName() + System.nanoTime() + ".acl").getAbsolutePath(); + + attributes.put("path", aclFilePath); + attributes.put(ACLFileAccessControlProvider.NAME, getTestName()); + + + ACLFileAccessControlProviderImpl aclProvider = new ACLFileAccessControlProviderImpl(attributes, _broker); + try + { + aclProvider.create(); + fail("Exception is expected on validation with non-existing ACL file"); + } + catch (IllegalConfigurationException e) + { + assertEquals("Unexpected exception message:" + e.getMessage(), String.format("ACL file '%s' is not found", aclFilePath ), e.getMessage()); + } + } + +} diff --git a/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java b/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java index 79f73b5ca9..7574cc3533 100644 --- a/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java +++ b/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java @@ -1322,6 +1322,12 @@ public class AMQChannel<T extends AMQProtocolSession<T>> return _subject; } + public ChannelMethodProcessor getMethodProcessor() + { + // TODO + return null; + } + private class ImmediateAction implements Action<MessageInstance> { diff --git a/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ChannelMethodProcessor.java b/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ChannelMethodProcessor.java new file mode 100644 index 0000000000..d8c7115316 --- /dev/null +++ b/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ChannelMethodProcessor.java @@ -0,0 +1,25 @@ +/* + * + * 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.protocol.v0_8; + +public interface ChannelMethodProcessor +{ +} diff --git a/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ServerMethodDispatcherImpl.java b/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ServerMethodDispatcherImpl.java index d8300709f2..6f4c1d91d5 100644 --- a/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ServerMethodDispatcherImpl.java +++ b/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ServerMethodDispatcherImpl.java @@ -1,2237 +1,2266 @@ -/*
- *
- * 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.protocol.v0_8;
-
-import java.security.AccessControlException;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.UUID;
-
-import javax.security.sasl.SaslException;
-import javax.security.sasl.SaslServer;
-
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.AMQConnectionException;
-import org.apache.qpid.AMQException;
-import org.apache.qpid.exchange.ExchangeDefaults;
-import org.apache.qpid.framing.*;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.consumer.ConsumerImpl;
-import org.apache.qpid.server.exchange.ExchangeImpl;
-import org.apache.qpid.server.filter.AMQInvalidArgumentException;
-import org.apache.qpid.server.flow.FlowCreditManager;
-import org.apache.qpid.server.flow.MessageOnlyCreditManager;
-import org.apache.qpid.server.message.InstanceProperties;
-import org.apache.qpid.server.message.MessageDestination;
-import org.apache.qpid.server.message.MessageInstance;
-import org.apache.qpid.server.message.MessageSource;
-import org.apache.qpid.server.message.ServerMessage;
-import org.apache.qpid.server.model.Broker;
-import org.apache.qpid.server.model.ExclusivityPolicy;
-import org.apache.qpid.server.model.LifetimePolicy;
-import org.apache.qpid.server.model.NoFactoryForTypeException;
-import org.apache.qpid.server.model.Queue;
-import org.apache.qpid.server.model.State;
-import org.apache.qpid.server.model.UnknownConfiguredObjectException;
-import org.apache.qpid.server.model.port.AmqpPort;
-import org.apache.qpid.server.protocol.AMQSessionModel;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.QueueArgumentsConverter;
-import org.apache.qpid.server.security.SubjectCreator;
-import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
-import org.apache.qpid.server.virtualhost.ExchangeExistsException;
-import org.apache.qpid.server.virtualhost.ExchangeIsAlternateException;
-import org.apache.qpid.server.virtualhost.QueueExistsException;
-import org.apache.qpid.server.virtualhost.RequiredExchangeException;
-import org.apache.qpid.server.virtualhost.ReservedExchangeNameException;
-import org.apache.qpid.server.virtualhost.VirtualHostImpl;
-
-public class ServerMethodDispatcherImpl implements MethodDispatcher
-{
- private static final Logger _logger = Logger.getLogger(ServerMethodDispatcherImpl.class);
-
- private final AMQProtocolSession<?> _connection;
-
-
- public static MethodDispatcher createMethodDispatcher(AMQProtocolSession<?> connection)
- {
- return new ServerMethodDispatcherImpl(connection);
- }
-
-
- public ServerMethodDispatcherImpl(AMQProtocolSession<?> connection)
- {
- _connection = connection;
- }
-
-
- protected final AMQProtocolSession<?> getConnection()
- {
- return _connection;
- }
-
- public boolean dispatchAccessRequest(AccessRequestBody body, int channelId) throws AMQException
- {
- final AMQChannel channel = _connection.getChannel(channelId);
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
-
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
-
- if(ProtocolVersion.v0_91.equals(_connection.getProtocolVersion()) )
- {
- throw new AMQException(AMQConstant.COMMAND_INVALID, "AccessRequest not present in AMQP versions other than 0-8, 0-9");
- }
-
- // We don't implement access control class, but to keep clients happy that expect it
- // always use the "0" ticket.
- AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0);
- channel.sync();
- _connection.writeFrame(response.generateFrame(channelId));
- return true;
- }
-
- public boolean dispatchBasicAck(BasicAckBody body, int channelId) throws AMQException
- {
-
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Ack(Tag:" + body.getDeliveryTag() + ":Mult:" + body.getMultiple() + ") received on channel " + channelId);
- }
-
- final AMQChannel channel = _connection.getChannel(channelId);
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
-
- // this method throws an AMQException if the delivery tag is not known
- channel.acknowledgeMessage(body.getDeliveryTag(), body.getMultiple());
- return true;
- }
-
- public boolean dispatchBasicCancel(BasicCancelBody body, int channelId) throws AMQException
- {
- final AMQChannel channel = _connection.getChannel(channelId);
-
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
-
- if (_logger.isDebugEnabled())
- {
- _logger.debug("BasicCancel: for:" + body.getConsumerTag() +
- " nowait:" + body.getNowait());
- }
-
- channel.unsubscribeConsumer(body.getConsumerTag());
- if (!body.getNowait())
- {
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- BasicCancelOkBody cancelOkBody = methodRegistry.createBasicCancelOkBody(body.getConsumerTag());
- channel.sync();
- _connection.writeFrame(cancelOkBody.generateFrame(channelId));
- }
- return true;
- }
-
- public boolean dispatchBasicConsume(BasicConsumeBody body, int channelId) throws AMQException
- {
- AMQChannel channel = _connection.getChannel(channelId);
- VirtualHostImpl<?,?,?> vHost = _connection.getVirtualHost();
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
- else
- {
- channel.sync();
- String queueName = body.getQueue() == null ? null : body.getQueue().asString();
- if (_logger.isDebugEnabled())
- {
- _logger.debug("BasicConsume: from '" + queueName +
- "' for:" + body.getConsumerTag() +
- " nowait:" + body.getNowait() +
- " args:" + body.getArguments());
- }
-
- MessageSource queue = queueName == null ? channel.getDefaultQueue() : vHost.getQueue(queueName);
- final Collection<MessageSource> sources = new HashSet<>();
- if(queue != null)
- {
- sources.add(queue);
- }
- else if(vHost.getContextValue(Boolean.class, "qpid.enableMultiQueueConsumers")
- && body.getArguments() != null
- && body.getArguments().get("x-multiqueue") instanceof Collection)
- {
- for(Object object : (Collection<Object>) body.getArguments().get("x-multiqueue"))
- {
- String sourceName = String.valueOf(object);
- sourceName = sourceName.trim();
- if(sourceName.length() != 0)
- {
- MessageSource source = vHost.getMessageSource(sourceName);
- if(source == null)
- {
- sources.clear();
- break;
- }
- else
- {
- sources.add(source);
- }
- }
- }
- queueName = body.getArguments().get("x-multiqueue").toString();
- }
-
- if (sources.isEmpty())
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("No queue for '" + queueName + "'");
- }
- if (queueName != null)
- {
- String msg = "No such queue, '" + queueName + "'";
- throw body.getChannelException(AMQConstant.NOT_FOUND, msg, _connection.getMethodRegistry());
- }
- else
- {
- String msg = "No queue name provided, no default queue defined.";
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED, msg, _connection.getMethodRegistry());
- }
- }
- else
- {
- final AMQShortString consumerTagName;
-
- if (body.getConsumerTag() != null)
- {
- consumerTagName = body.getConsumerTag().intern(false);
- }
- else
- {
- consumerTagName = null;
- }
-
- try
- {
- if(consumerTagName == null || channel.getSubscription(consumerTagName) == null)
- {
-
- AMQShortString consumerTag = channel.consumeFromSource(consumerTagName,
- sources,
- !body.getNoAck(),
- body.getArguments(),
- body.getExclusive(),
- body.getNoLocal());
- if (!body.getNowait())
- {
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createBasicConsumeOkBody(consumerTag);
- _connection.writeFrame(responseBody.generateFrame(channelId));
-
- }
- }
- else
- {
- AMQShortString msg = AMQShortString.validValueOf("Non-unique consumer tag, '" + body.getConsumerTag() + "'");
-
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode
- msg, // replytext
- body.getClazz(),
- body.getMethod());
- _connection.writeFrame(responseBody.generateFrame(0));
- }
-
- }
- catch (AMQInvalidArgumentException ise)
- {
- _logger.debug("Closing connection due to invalid selector");
-
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createChannelCloseBody(AMQConstant.ARGUMENT_INVALID.getCode(),
- AMQShortString.validValueOf(ise.getMessage()),
- body.getClazz(),
- body.getMethod());
- _connection.writeFrame(responseBody.generateFrame(channelId));
-
-
- }
- catch (AMQQueue.ExistingExclusiveConsumer e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- "Cannot subscribe to queue "
- + queue.getName()
- + " as it already has an existing exclusive consumer",
- _connection.getMethodRegistry());
- }
- catch (AMQQueue.ExistingConsumerPreventsExclusive e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- "Cannot subscribe to queue "
- + queue.getName()
- + " exclusively as it already has a consumer",
- _connection.getMethodRegistry());
- }
- catch (AccessControlException e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- "Cannot subscribe to queue "
- + queue.getName()
- + " permission denied", _connection.getMethodRegistry());
- }
- catch (MessageSource.ConsumerAccessRefused consumerAccessRefused)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- "Cannot subscribe to queue "
- + queue.getName()
- + " as it already has an incompatible exclusivity policy",
- _connection.getMethodRegistry());
- }
-
- }
- }
- return true;
- }
-
- public boolean dispatchBasicGet(BasicGetBody body, int channelId) throws AMQException
- {
-
- VirtualHostImpl vHost = _connection.getVirtualHost();
-
- AMQChannel channel = _connection.getChannel(channelId);
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
- else
- {
- channel.sync();
- AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueue(body.getQueue().toString());
- if (queue == null)
- {
- _logger.info("No queue for '" + body.getQueue() + "'");
- if(body.getQueue()!=null)
- {
- throw body.getConnectionException(AMQConstant.NOT_FOUND,
- "No such queue, '" + body.getQueue() + "'",
- _connection.getMethodRegistry());
- }
- else
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "No queue name provided, no default queue defined.",
- _connection.getMethodRegistry());
- }
- }
- else
- {
-
- try
- {
- if (!performGet(queue, _connection, channel, !body.getNoAck()))
- {
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
-
- BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null);
-
-
- _connection.writeFrame(responseBody.generateFrame(channelId));
- }
- }
- catch (AccessControlException e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- e.getMessage(), _connection.getMethodRegistry());
- }
- catch (MessageSource.ExistingExclusiveConsumer e)
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "Queue has an exclusive consumer",
- _connection.getMethodRegistry());
- }
- catch (MessageSource.ExistingConsumerPreventsExclusive e)
- {
- throw body.getConnectionException(AMQConstant.INTERNAL_ERROR,
- "The GET request has been evaluated as an exclusive consumer, " +
- "this is likely due to a programming error in the Qpid broker",
- _connection.getMethodRegistry());
- }
- catch (MessageSource.ConsumerAccessRefused consumerAccessRefused)
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "Queue has an incompatible exclusivit policy",
- _connection.getMethodRegistry());
- }
- }
- }
- return true;
- }
-
- public static boolean performGet(final AMQQueue queue,
- final AMQProtocolSession session,
- final AMQChannel channel,
- final boolean acks)
- throws AMQException, MessageSource.ExistingConsumerPreventsExclusive,
- MessageSource.ExistingExclusiveConsumer, MessageSource.ConsumerAccessRefused
- {
-
- final FlowCreditManager singleMessageCredit = new MessageOnlyCreditManager(1L);
-
- final GetDeliveryMethod getDeliveryMethod =
- new GetDeliveryMethod(singleMessageCredit, session, channel, queue);
- final RecordDeliveryMethod getRecordMethod = new RecordDeliveryMethod()
- {
-
- public void recordMessageDelivery(final ConsumerImpl sub, final MessageInstance entry, final long deliveryTag)
- {
- channel.addUnacknowledgedMessage(entry, deliveryTag, null);
- }
- };
-
- ConsumerTarget_0_8 target;
- EnumSet<ConsumerImpl.Option> options = EnumSet.of(ConsumerImpl.Option.TRANSIENT, ConsumerImpl.Option.ACQUIRES,
- ConsumerImpl.Option.SEES_REQUEUES);
- if(acks)
- {
-
- target = ConsumerTarget_0_8.createAckTarget(channel,
- AMQShortString.EMPTY_STRING, null,
- singleMessageCredit, getDeliveryMethod, getRecordMethod);
- }
- else
- {
- target = ConsumerTarget_0_8.createGetNoAckTarget(channel,
- AMQShortString.EMPTY_STRING, null,
- singleMessageCredit, getDeliveryMethod, getRecordMethod);
- }
-
- ConsumerImpl sub = queue.addConsumer(target, null, AMQMessage.class, "", options);
- sub.flush();
- sub.close();
- return(getDeliveryMethod.hasDeliveredMessage());
-
-
- }
-
-
- private static class GetDeliveryMethod implements ClientDeliveryMethod
- {
-
- private final FlowCreditManager _singleMessageCredit;
- private final AMQProtocolSession _session;
- private final AMQChannel _channel;
- private final AMQQueue _queue;
- private boolean _deliveredMessage;
-
- public GetDeliveryMethod(final FlowCreditManager singleMessageCredit,
- final AMQProtocolSession session,
- final AMQChannel channel, final AMQQueue queue)
- {
- _singleMessageCredit = singleMessageCredit;
- _session = session;
- _channel = channel;
- _queue = queue;
- }
-
- @Override
- public long deliverToClient(final ConsumerImpl sub, final ServerMessage message,
- final InstanceProperties props, final long deliveryTag)
- {
- _singleMessageCredit.useCreditForMessage(message.getSize());
- long size =_session.getProtocolOutputConverter().writeGetOk(message,
- props,
- _channel.getChannelId(),
- deliveryTag,
- _queue.getQueueDepthMessages());
-
- _deliveredMessage = true;
- return size;
- }
-
- public boolean hasDeliveredMessage()
- {
- return _deliveredMessage;
- }
- }
-
- public boolean dispatchBasicPublish(BasicPublishBody body, int channelId) throws AMQException
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Publish received on channel " + channelId);
- }
-
- AMQShortString exchangeName = body.getExchange();
- VirtualHostImpl vHost = _connection.getVirtualHost();
-
- // TODO: check the delivery tag field details - is it unique across the broker or per subscriber?
-
- MessageDestination destination;
-
- if (exchangeName == null || AMQShortString.EMPTY_STRING.equals(exchangeName))
- {
- destination = vHost.getDefaultDestination();
- }
- else
- {
- destination = vHost.getMessageDestination(exchangeName.toString());
- }
-
- // if the exchange does not exist we raise a channel exception
- if (destination == null)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange name",
- _connection.getMethodRegistry());
- }
- else
- {
- // The partially populated BasicDeliver frame plus the received route body
- // is stored in the channel. Once the final body frame has been received
- // it is routed to the exchange.
- AMQChannel channel = _connection.getChannel(channelId);
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
-
- MessagePublishInfo info = new MessagePublishInfo(body.getExchange(),
- body.getImmediate(),
- body.getMandatory(),
- body.getRoutingKey());
- info.setExchange(exchangeName);
- try
- {
- channel.setPublishFrame(info, destination);
- }
- catch (AccessControlException e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- e.getMessage(),
- _connection.getMethodRegistry());
- }
- }
- return true;
- }
-
- public boolean dispatchBasicQos(BasicQosBody body, int channelId) throws AMQException
- {
- AMQChannel channel = _connection.getChannel(channelId);
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
- channel.sync();
- channel.setCredit(body.getPrefetchSize(), body.getPrefetchCount());
-
-
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createBasicQosOkBody();
- _connection.writeFrame(responseBody.generateFrame(channelId));
-
- return true;
- }
-
- public boolean dispatchBasicRecover(BasicRecoverBody body, int channelId) throws AMQException
- {
- _logger.debug("Recover received on protocol session " + _connection
- + " and channel " + channelId);
- AMQChannel channel = _connection.getChannel(channelId);
-
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
-
- channel.resend();
-
- // Qpid 0-8 hacks a synchronous -ok onto recover.
- // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant
- if(_connection.getProtocolVersion().equals(ProtocolVersion.v8_0))
- {
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody();
- channel.sync();
- _connection.writeFrame(recoverOk.generateFrame(channelId));
-
- }
-
- return true;
- }
-
- public boolean dispatchBasicReject(BasicRejectBody body, int channelId) throws AMQException
- {
-
- AMQChannel channel = _connection.getChannel(channelId);
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
-
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Rejecting:" + body.getDeliveryTag() +
- ": Requeue:" + body.getRequeue() +
- " on channel:" + channel.debugIdentity());
- }
-
- long deliveryTag = body.getDeliveryTag();
-
- MessageInstance message = channel.getUnacknowledgedMessageMap().get(deliveryTag);
-
- if (message == null)
- {
- _logger.warn("Dropping reject request as message is null for tag:" + deliveryTag);
- }
- else
- {
-
- if (message.getMessage() == null)
- {
- _logger.warn("Message has already been purged, unable to Reject.");
- }
- else
- {
-
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Rejecting: DT:" + deliveryTag + "-" + message.getMessage() +
- ": Requeue:" + body.getRequeue() +
- " on channel:" + channel.debugIdentity());
- }
-
- if (body.getRequeue())
- {
- //this requeue represents a message rejected from the pre-dispatch queue
- //therefore we need to amend the delivery counter.
- message.decrementDeliveryCount();
-
- channel.requeue(deliveryTag);
- }
- else
- {
- // Since the Java client abuses the reject flag for requeing after rollback, we won't set reject here
- // as it would prevent redelivery
- // message.reject();
-
- final boolean maxDeliveryCountEnabled = channel.isMaxDeliveryCountEnabled(deliveryTag);
- _logger.debug("maxDeliveryCountEnabled: "
- + maxDeliveryCountEnabled
- + " deliveryTag "
- + deliveryTag);
- if (maxDeliveryCountEnabled)
- {
- final boolean deliveredTooManyTimes = channel.isDeliveredTooManyTimes(deliveryTag);
- _logger.debug("deliveredTooManyTimes: "
- + deliveredTooManyTimes
- + " deliveryTag "
- + deliveryTag);
- if (deliveredTooManyTimes)
- {
- channel.deadLetter(body.getDeliveryTag());
- }
- else
- {
- //this requeue represents a message rejected because of a recover/rollback that we
- //are not ready to DLQ. We rely on the reject command to resend from the unacked map
- //and therefore need to increment the delivery counter so we cancel out the effect
- //of the AMQChannel#resend() decrement.
- message.incrementDeliveryCount();
- }
- }
- else
- {
- channel.requeue(deliveryTag);
- }
- }
- }
- }
- return true;
- }
-
- public boolean dispatchChannelOpen(ChannelOpenBody body, int channelId) throws AMQException
- {
- VirtualHostImpl virtualHost = _connection.getVirtualHost();
-
- // Protect the broker against out of order frame request.
- if (virtualHost == null)
- {
- throw new AMQException(AMQConstant.COMMAND_INVALID, "Virtualhost has not yet been set. ConnectionOpen has not been called.", null);
- }
- _logger.info("Connecting to: " + virtualHost.getName());
-
- final AMQChannel channel = new AMQChannel(_connection, channelId, virtualHost.getMessageStore());
-
- _connection.addChannel(channel);
-
- ChannelOpenOkBody response;
-
-
- response = _connection.getMethodRegistry().createChannelOpenOkBody();
-
-
- _connection.writeFrame(response.generateFrame(channelId));
- return true;
- }
-
-
- public boolean dispatchAccessRequestOk(AccessRequestOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
-
- public boolean dispatchBasicCancelOk(BasicCancelOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicConsumeOk(BasicConsumeOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicDeliver(BasicDeliverBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicGetEmpty(BasicGetEmptyBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicGetOk(BasicGetOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicQosOk(BasicQosOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchBasicReturn(BasicReturnBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchChannelClose(ChannelCloseBody body, int channelId) throws AMQException
- {
-
- if (_logger.isInfoEnabled())
- {
- _logger.info("Received channel close for id " + channelId
- + " citing class " + body.getClassId() +
- " and method " + body.getMethodId());
- }
-
-
- AMQChannel channel = _connection.getChannel(channelId);
-
- if (channel == null)
- {
- throw body.getConnectionException(AMQConstant.CHANNEL_ERROR,
- "Trying to close unknown channel",
- _connection.getMethodRegistry());
- }
- channel.sync();
- _connection.closeChannel(channelId);
- // Client requested closure so we don't wait for ok we send it
- _connection.closeChannelOk(channelId);
-
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- ChannelCloseOkBody responseBody = methodRegistry.createChannelCloseOkBody();
- _connection.writeFrame(responseBody.generateFrame(channelId));
- return true;
- }
-
-
- public boolean dispatchChannelCloseOk(ChannelCloseOkBody body, int channelId) throws AMQException
- {
-
- _logger.info("Received channel-close-ok for channel-id " + channelId);
-
- // Let the Protocol Session know the channel is now closed.
- _connection.closeChannelOk(channelId);
- return true;
- }
-
-
- public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException
- {
- final AMQProtocolSession<?> connection = getConnection();
-
-
- AMQChannel channel = connection.getChannel(channelId);
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, connection.getMethodRegistry());
- }
- channel.sync();
- channel.setSuspended(!body.getActive());
- _logger.debug("Channel.Flow for channel " + channelId + ", active=" + body.getActive());
-
- MethodRegistry methodRegistry = connection.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createChannelFlowOkBody(body.getActive());
- connection.writeFrame(responseBody.generateFrame(channelId));
- return true;
- }
-
- public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchChannelOpenOk(ChannelOpenOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
-
- public boolean dispatchConnectionOpen(ConnectionOpenBody body, int channelId) throws AMQException
- {
-
- //ignore leading '/'
- String virtualHostName;
- if ((body.getVirtualHost() != null) && body.getVirtualHost().charAt(0) == '/')
- {
- virtualHostName = new StringBuilder(body.getVirtualHost().subSequence(1, body.getVirtualHost().length())).toString();
- }
- else
- {
- virtualHostName = body.getVirtualHost() == null ? null : String.valueOf(body.getVirtualHost());
- }
-
- VirtualHostImpl virtualHost = ((AmqpPort) _connection.getPort()).getVirtualHost(virtualHostName);
-
- if (virtualHost == null)
- {
- throw body.getConnectionException(AMQConstant.NOT_FOUND, "Unknown virtual host: '" + virtualHostName + "'",
- _connection.getMethodRegistry());
- }
- else
- {
- // Check virtualhost access
- if (virtualHost.getState() != State.ACTIVE)
- {
- throw body.getConnectionException(AMQConstant.CONNECTION_FORCED,
- "Virtual host '" + virtualHost.getName() + "' is not active",
- _connection.getMethodRegistry());
- }
-
- _connection.setVirtualHost(virtualHost);
- try
- {
- virtualHost.getSecurityManager().authoriseCreateConnection(_connection);
- }
- catch (AccessControlException e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- e.getMessage(),
- _connection.getMethodRegistry());
- }
-
- // See Spec (0.8.2). Section 3.1.2 Virtual Hosts
- if (_connection.getContextKey() == null)
- {
- _connection.setContextKey(new AMQShortString(Long.toString(System.currentTimeMillis())));
- }
-
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createConnectionOpenOkBody(body.getVirtualHost());
-
- _connection.writeFrame(responseBody.generateFrame(channelId));
- }
- return true;
- }
-
-
- public boolean dispatchConnectionClose(ConnectionCloseBody body, int channelId) throws AMQException
- {
- if (_logger.isInfoEnabled())
- {
- _logger.info("ConnectionClose received with reply code/reply text " + body.getReplyCode() + "/" +
- body.getReplyText() + " for " + _connection);
- }
- try
- {
- _connection.closeSession();
- }
- catch (Exception e)
- {
- _logger.error("Error closing protocol session: " + e, e);
- }
-
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- ConnectionCloseOkBody responseBody = methodRegistry.createConnectionCloseOkBody();
- _connection.writeFrame(responseBody.generateFrame(channelId));
-
- _connection.closeProtocolSession();
-
- return true;
- }
-
-
- public boolean dispatchConnectionCloseOk(ConnectionCloseOkBody body, int channelId) throws AMQException
- {
- _logger.info("Received Connection-close-ok");
-
- try
- {
- _connection.closeSession();
- }
- catch (Exception e)
- {
- _logger.error("Error closing protocol session: " + e, e);
- }
- return true;
- }
-
- public boolean dispatchConnectionOpenOk(ConnectionOpenOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchConnectionRedirect(ConnectionRedirectBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchConnectionSecure(ConnectionSecureBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchConnectionStart(ConnectionStartBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchConnectionTune(ConnectionTuneBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
-
- public boolean dispatchExchangeBoundOk(ExchangeBoundOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchExchangeDeclareOk(ExchangeDeclareOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchExchangeDeleteOk(ExchangeDeleteOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchQueueBindOk(QueueBindOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchQueueDeclareOk(QueueDeclareOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchQueueDeleteOk(QueueDeleteOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchQueuePurgeOk(QueuePurgeOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchTxCommitOk(TxCommitOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchTxRollbackOk(TxRollbackOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchTxSelectOk(TxSelectOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
-
- public boolean dispatchConnectionSecureOk(ConnectionSecureOkBody body, int channelId) throws AMQException
- {
- Broker<?> broker = _connection.getBroker();
-
- SubjectCreator subjectCreator = _connection.getSubjectCreator();
-
- SaslServer ss = _connection.getSaslServer();
- if (ss == null)
- {
- throw new AMQException("No SASL context set up in session");
- }
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- SubjectAuthenticationResult authResult = subjectCreator.authenticate(ss, body.getResponse());
- switch (authResult.getStatus())
- {
- case ERROR:
- Exception cause = authResult.getCause();
-
- _logger.info("Authentication failed:" + (cause == null ? "" : cause.getMessage()));
-
- ConnectionCloseBody connectionCloseBody =
- methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(),
- AMQConstant.NOT_ALLOWED.getName(),
- body.getClazz(),
- body.getMethod());
-
- _connection.writeFrame(connectionCloseBody.generateFrame(0));
- disposeSaslServer(_connection);
- break;
- case SUCCESS:
- if (_logger.isInfoEnabled())
- {
- _logger.info("Connected as: " + authResult.getSubject());
- }
-
- int frameMax = broker.getContextValue(Integer.class, Broker.BROKER_FRAME_SIZE);
-
- if(frameMax <= 0)
- {
- frameMax = Integer.MAX_VALUE;
- }
-
- ConnectionTuneBody tuneBody =
- methodRegistry.createConnectionTuneBody(broker.getConnection_sessionCountLimit(),
- frameMax,
- broker.getConnection_heartBeatDelay());
- _connection.writeFrame(tuneBody.generateFrame(0));
- _connection.setAuthorizedSubject(authResult.getSubject());
- disposeSaslServer(_connection);
- break;
- case CONTINUE:
-
- ConnectionSecureBody
- secureBody = methodRegistry.createConnectionSecureBody(authResult.getChallenge());
- _connection.writeFrame(secureBody.generateFrame(0));
- }
- return true;
- }
-
- private void disposeSaslServer(AMQProtocolSession ps)
- {
- SaslServer ss = ps.getSaslServer();
- if (ss != null)
- {
- ps.setSaslServer(null);
- try
- {
- ss.dispose();
- }
- catch (SaslException e)
- {
- _logger.error("Error disposing of Sasl server: " + e);
- }
- }
- }
-
- public boolean dispatchConnectionStartOk(ConnectionStartOkBody body, int channelId) throws AMQException
- {
- Broker<?> broker = _connection.getBroker();
-
- _logger.info("SASL Mechanism selected: " + body.getMechanism());
- _logger.info("Locale selected: " + body.getLocale());
-
- SubjectCreator subjectCreator = _connection.getSubjectCreator();
- SaslServer ss = null;
- try
- {
- ss = subjectCreator.createSaslServer(String.valueOf(body.getMechanism()),
- _connection.getLocalFQDN(),
- _connection.getPeerPrincipal());
-
- if (ss == null)
- {
- throw body.getConnectionException(AMQConstant.RESOURCE_ERROR,
- "Unable to create SASL Server:" + body.getMechanism(),
- _connection.getMethodRegistry());
- }
-
- _connection.setSaslServer(ss);
-
- final SubjectAuthenticationResult authResult = subjectCreator.authenticate(ss, body.getResponse());
- //save clientProperties
- _connection.setClientProperties(body.getClientProperties());
-
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
-
- switch (authResult.getStatus())
- {
- case ERROR:
- Exception cause = authResult.getCause();
-
- _logger.info("Authentication failed:" + (cause == null ? "" : cause.getMessage()));
-
- ConnectionCloseBody closeBody =
- methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode
- AMQConstant.NOT_ALLOWED.getName(),
- body.getClazz(),
- body.getMethod());
-
- _connection.writeFrame(closeBody.generateFrame(0));
- disposeSaslServer(_connection);
- break;
-
- case SUCCESS:
- if (_logger.isInfoEnabled())
- {
- _logger.info("Connected as: " + authResult.getSubject());
- }
- _connection.setAuthorizedSubject(authResult.getSubject());
-
- int frameMax = broker.getContextValue(Integer.class, Broker.BROKER_FRAME_SIZE);
-
- if(frameMax <= 0)
- {
- frameMax = Integer.MAX_VALUE;
- }
-
- ConnectionTuneBody
- tuneBody = methodRegistry.createConnectionTuneBody(broker.getConnection_sessionCountLimit(),
- frameMax,
- broker.getConnection_heartBeatDelay());
- _connection.writeFrame(tuneBody.generateFrame(0));
- break;
- case CONTINUE:
- ConnectionSecureBody
- secureBody = methodRegistry.createConnectionSecureBody(authResult.getChallenge());
- _connection.writeFrame(secureBody.generateFrame(0));
- }
- }
- catch (SaslException e)
- {
- disposeSaslServer(_connection);
- throw new AMQException("SASL error: " + e, e);
- }
- return true;
- }
-
- public boolean dispatchConnectionTuneOk(ConnectionTuneOkBody body, int channelId) throws AMQException
- {
- final AMQProtocolSession<?> connection = getConnection();
-
- if (_logger.isDebugEnabled())
- {
- _logger.debug(body);
- }
-
- connection.initHeartbeats(body.getHeartbeat());
-
- int brokerFrameMax = connection.getBroker().getContextValue(Integer.class, Broker.BROKER_FRAME_SIZE);
- if(brokerFrameMax <= 0)
- {
- brokerFrameMax = Integer.MAX_VALUE;
- }
-
- if(body.getFrameMax() > (long) brokerFrameMax)
- {
- throw new AMQConnectionException(AMQConstant.SYNTAX_ERROR,
- "Attempt to set max frame size to " + body.getFrameMax()
- + " greater than the broker will allow: "
- + brokerFrameMax,
- body.getClazz(), body.getMethod(),
- connection.getMethodRegistry(),null);
- }
- else if(body.getFrameMax() > 0 && body.getFrameMax() < AMQConstant.FRAME_MIN_SIZE.getCode())
- {
- throw new AMQConnectionException(AMQConstant.SYNTAX_ERROR,
- "Attempt to set max frame size to " + body.getFrameMax()
- + " which is smaller than the specification definined minimum: "
- + AMQConstant.FRAME_MIN_SIZE.getCode(),
- body.getClazz(), body.getMethod(),
- connection.getMethodRegistry(),null);
- }
- int frameMax = body.getFrameMax() == 0 ? brokerFrameMax : (int) body.getFrameMax();
- connection.setMaxFrameSize(frameMax);
-
- long maxChannelNumber = body.getChannelMax();
- //0 means no implied limit, except that forced by protocol limitations (0xFFFF)
- connection.setMaximumNumberOfChannels(maxChannelNumber == 0 ? 0xFFFFL : maxChannelNumber);
- return true;
- }
-
- public static final int OK = 0;
- public static final int EXCHANGE_NOT_FOUND = 1;
- public static final int QUEUE_NOT_FOUND = 2;
- public static final int NO_BINDINGS = 3;
- public static final int QUEUE_NOT_BOUND = 4;
- public static final int NO_QUEUE_BOUND_WITH_RK = 5;
- public static final int SPECIFIC_QUEUE_NOT_BOUND_WITH_RK = 6;
-
- public boolean dispatchExchangeBound(ExchangeBoundBody body, int channelId) throws AMQException
- {
- VirtualHostImpl virtualHost = _connection.getVirtualHost();
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
-
- final AMQChannel channel = _connection.getChannel(channelId);
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
- channel.sync();
-
-
- AMQShortString exchangeName = body.getExchange();
- AMQShortString queueName = body.getQueue();
- AMQShortString routingKey = body.getRoutingKey();
- ExchangeBoundOkBody response;
-
- if(isDefaultExchange(exchangeName))
- {
- if(routingKey == null)
- {
- if(queueName == null)
- {
- response = methodRegistry.createExchangeBoundOkBody(virtualHost.getQueues().isEmpty() ? NO_BINDINGS : OK, null);
- }
- else
- {
- AMQQueue queue = virtualHost.getQueue(queueName.toString());
- if (queue == null)
- {
-
- response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode
- AMQShortString.validValueOf("Queue '" + queueName + "' not found")); // replyText
- }
- else
- {
- response = methodRegistry.createExchangeBoundOkBody(OK, null);
- }
- }
- }
- else
- {
- if(queueName == null)
- {
- response = methodRegistry.createExchangeBoundOkBody(virtualHost.getQueue(routingKey.toString()) == null ? NO_QUEUE_BOUND_WITH_RK : OK, null);
- }
- else
- {
- AMQQueue queue = virtualHost.getQueue(queueName.toString());
- if (queue == null)
- {
-
- response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode
- AMQShortString.validValueOf("Queue '" + queueName + "' not found")); // replyText
- }
- else
- {
- response = methodRegistry.createExchangeBoundOkBody(queueName.equals(routingKey) ? OK : SPECIFIC_QUEUE_NOT_BOUND_WITH_RK, null);
- }
- }
- }
- }
- else
- {
- ExchangeImpl exchange = virtualHost.getExchange(exchangeName.toString());
- if (exchange == null)
- {
-
-
- response = methodRegistry.createExchangeBoundOkBody(EXCHANGE_NOT_FOUND,
- AMQShortString.validValueOf("Exchange '" + exchangeName + "' not found"));
- }
- else if (routingKey == null)
- {
- if (queueName == null)
- {
- if (exchange.hasBindings())
- {
- response = methodRegistry.createExchangeBoundOkBody(OK, null);
- }
- else
- {
-
- response = methodRegistry.createExchangeBoundOkBody(NO_BINDINGS, // replyCode
- null); // replyText
- }
- }
- else
- {
-
- AMQQueue queue = virtualHost.getQueue(queueName.toString());
- if (queue == null)
- {
-
- response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode
- AMQShortString.validValueOf("Queue '" + queueName + "' not found")); // replyText
- }
- else
- {
- if (exchange.isBound(queue))
- {
-
- response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode
- null); // replyText
- }
- else
- {
-
- response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_BOUND, // replyCode
- AMQShortString.validValueOf("Queue '" + queueName + "' not bound to exchange '" + exchangeName + "'")); // replyText
- }
- }
- }
- }
- else if (queueName != null)
- {
- AMQQueue queue = virtualHost.getQueue(queueName.toString());
- if (queue == null)
- {
-
- response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode
- AMQShortString.validValueOf("Queue '" + queueName + "' not found")); // replyText
- }
- else
- {
- String bindingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().asString();
- if (exchange.isBound(bindingKey, queue))
- {
-
- response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode
- null); // replyText
- }
- else
- {
-
- String message = "Queue '" + queueName + "' not bound with routing key '" +
- body.getRoutingKey() + "' to exchange '" + exchangeName + "'";
-
- response = methodRegistry.createExchangeBoundOkBody(SPECIFIC_QUEUE_NOT_BOUND_WITH_RK, // replyCode
- AMQShortString.validValueOf(message)); // replyText
- }
- }
- }
- else
- {
- if (exchange.isBound(body.getRoutingKey() == null ? "" : body.getRoutingKey().asString()))
- {
-
- response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode
- null); // replyText
- }
- else
- {
-
- response = methodRegistry.createExchangeBoundOkBody(NO_QUEUE_BOUND_WITH_RK, // replyCode
- AMQShortString.validValueOf("No queue bound with routing key '" + body.getRoutingKey() +
- "' to exchange '" + exchangeName + "'")); // replyText
- }
- }
- }
- _connection.writeFrame(response.generateFrame(channelId));
- return true;
- }
-
- public boolean dispatchExchangeDeclare(ExchangeDeclareBody body, int channelId) throws AMQException
- {
- VirtualHostImpl virtualHost = _connection.getVirtualHost();
- final AMQChannel channel = _connection.getChannel(channelId);
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
-
- final AMQShortString exchangeName = body.getExchange();
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Request to declare exchange of type " + body.getType() + " with name " + exchangeName);
- }
-
- ExchangeImpl exchange;
-
- if(isDefaultExchange(exchangeName))
- {
- if(!new AMQShortString(ExchangeDefaults.DIRECT_EXCHANGE_CLASS).equals(body.getType()))
- {
- throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare default exchange: "
- + " of type "
- + ExchangeDefaults.DIRECT_EXCHANGE_CLASS
- + " to " + body.getType() +".",
- body.getClazz(), body.getMethod(),
- _connection.getMethodRegistry(),null);
- }
- }
- else
- {
- if (body.getPassive())
- {
- exchange = virtualHost.getExchange(exchangeName.toString());
- if(exchange == null)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange: " + exchangeName,
- _connection.getMethodRegistry());
- }
- else if (!(body.getType() == null || body.getType().length() ==0) && !exchange.getType().equals(body.getType().asString()))
- {
-
- throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " +
- exchangeName + " of type " + exchange.getType()
- + " to " + body.getType() +".",
- body.getClazz(), body.getMethod(),
- _connection.getMethodRegistry(),null);
- }
-
- }
- else
- {
- try
- {
- String name = exchangeName == null ? null : exchangeName.intern().toString();
- String type = body.getType() == null ? null : body.getType().intern().toString();
-
- Map<String,Object> attributes = new HashMap<String, Object>();
- if(body.getArguments() != null)
- {
- attributes.putAll(FieldTable.convertToMap(body.getArguments()));
- }
- attributes.put(org.apache.qpid.server.model.Exchange.ID, null);
- attributes.put(org.apache.qpid.server.model.Exchange.NAME,name);
- attributes.put(org.apache.qpid.server.model.Exchange.TYPE,type);
- attributes.put(org.apache.qpid.server.model.Exchange.DURABLE, body.getDurable());
- attributes.put(org.apache.qpid.server.model.Exchange.LIFETIME_POLICY,
- body.getAutoDelete() ? LifetimePolicy.DELETE_ON_NO_LINKS : LifetimePolicy.PERMANENT);
- if(!attributes.containsKey(org.apache.qpid.server.model.Exchange.ALTERNATE_EXCHANGE))
- {
- attributes.put(org.apache.qpid.server.model.Exchange.ALTERNATE_EXCHANGE, null);
- }
- exchange = virtualHost.createExchange(attributes);
-
- }
- catch(ReservedExchangeNameException e)
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "Attempt to declare exchange: " + exchangeName +
- " which begins with reserved prefix.",
- _connection.getMethodRegistry());
-
- }
- catch(ExchangeExistsException e)
- {
- exchange = e.getExistingExchange();
- if(!new AMQShortString(exchange.getType()).equals(body.getType()))
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: "
- + exchangeName + " of type "
- + exchange.getType()
- + " to " + body.getType() + ".",
- _connection.getMethodRegistry());
- }
- }
- catch(NoFactoryForTypeException e)
- {
- throw body.getConnectionException(AMQConstant.COMMAND_INVALID,
- "Unknown exchange type '"
- + e.getType()
- + "' for exchange '"
- + exchangeName
- + "'",
- _connection.getMethodRegistry());
- }
- catch (AccessControlException e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- e.getMessage(),
- _connection.getMethodRegistry());
- }
- catch (UnknownConfiguredObjectException e)
- {
- // note - since 0-8/9/9-1 can't set the alt. exchange this exception should never occur
- throw body.getConnectionException(AMQConstant.NOT_FOUND,
- "Unknown alternate exchange "
- + (e.getName() != null
- ? "name: \"" + e.getName() + "\""
- : "id: " + e.getId()),
- _connection.getMethodRegistry());
- }
- catch (IllegalArgumentException e)
- {
- throw body.getConnectionException(AMQConstant.COMMAND_INVALID,
- "Error creating exchange '"
- + exchangeName
- + "': "
- + e.getMessage(),
- _connection.getMethodRegistry());
- }
- }
- }
-
- if(!body.getNowait())
- {
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createExchangeDeclareOkBody();
- channel.sync();
- _connection.writeFrame(responseBody.generateFrame(channelId));
- }
- return true;
- }
-
- public boolean dispatchExchangeDelete(ExchangeDeleteBody body, int channelId) throws AMQException
- {
- VirtualHostImpl virtualHost = _connection.getVirtualHost();
- final AMQChannel channel = _connection.getChannel(channelId);
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
- channel.sync();
- try
- {
-
- if(isDefaultExchange(body.getExchange()))
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "Default Exchange cannot be deleted",
- _connection.getMethodRegistry());
- }
-
- final String exchangeName = body.getExchange().toString();
-
- final ExchangeImpl exchange = virtualHost.getExchange(exchangeName);
- if(exchange == null)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND, "No such exchange: " + body.getExchange(),
- _connection.getMethodRegistry());
- }
-
- virtualHost.removeExchange(exchange, !body.getIfUnused());
-
- ExchangeDeleteOkBody responseBody = _connection.getMethodRegistry().createExchangeDeleteOkBody();
-
- _connection.writeFrame(responseBody.generateFrame(channelId));
- }
-
- catch (ExchangeIsAlternateException e)
- {
- throw body.getChannelException(AMQConstant.NOT_ALLOWED, "Exchange in use as an alternate exchange",
- _connection.getMethodRegistry());
-
- }
- catch (RequiredExchangeException e)
- {
- throw body.getChannelException(AMQConstant.NOT_ALLOWED,
- "Exchange '" + body.getExchange() + "' cannot be deleted",
- _connection.getMethodRegistry());
- }
- catch (AccessControlException e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- e.getMessage(),
- _connection.getMethodRegistry());
- }
- return true;
- }
-
- private boolean isDefaultExchange(final AMQShortString exchangeName)
- {
- return exchangeName == null || exchangeName.equals(AMQShortString.EMPTY_STRING);
- }
-
- public boolean dispatchQueueBind(QueueBindBody body, int channelId) throws AMQException
- {
- VirtualHostImpl virtualHost = _connection.getVirtualHost();
- AMQChannel channel = _connection.getChannel(channelId);
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
-
- final AMQQueue queue;
- final AMQShortString routingKey;
-
- final AMQShortString queueName = body.getQueue();
-
- if (queueName == null)
- {
-
- queue = channel.getDefaultQueue();
-
- if (queue == null)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND,
- "No default queue defined on channel and queue was null",
- _connection.getMethodRegistry());
- }
-
- if (body.getRoutingKey() == null)
- {
- routingKey = AMQShortString.valueOf(queue.getName());
- }
- else
- {
- routingKey = body.getRoutingKey().intern();
- }
- }
- else
- {
- queue = virtualHost.getQueue(queueName.toString());
- routingKey = body.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : body.getRoutingKey().intern();
- }
-
- if (queue == null)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + queueName + " does not exist.",
- _connection.getMethodRegistry());
- }
-
- if(isDefaultExchange(body.getExchange()))
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "Cannot bind the queue " + queueName + " to the default exchange",
- _connection.getMethodRegistry());
- }
-
- final String exchangeName = body.getExchange().toString();
-
- final ExchangeImpl exch = virtualHost.getExchange(exchangeName);
- if (exch == null)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + exchangeName + " does not exist.",
- _connection.getMethodRegistry());
- }
-
-
- try
- {
-
- Map<String,Object> arguments = FieldTable.convertToMap(body.getArguments());
- String bindingKey = String.valueOf(routingKey);
-
- if (!exch.isBound(bindingKey, arguments, queue))
- {
-
- if(!exch.addBinding(bindingKey, queue, arguments) && ExchangeDefaults.TOPIC_EXCHANGE_CLASS.equals(exch.getType()))
- {
- exch.replaceBinding(bindingKey, queue, arguments);
- }
- }
- }
- catch (AccessControlException e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- e.getMessage(),
- _connection.getMethodRegistry());
- }
-
- if (_logger.isInfoEnabled())
- {
- _logger.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey);
- }
- if (!body.getNowait())
- {
- channel.sync();
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createQueueBindOkBody();
- _connection.writeFrame(responseBody.generateFrame(channelId));
-
- }
- return true;
- }
-
- public boolean dispatchQueueDeclare(QueueDeclareBody body, int channelId) throws AMQException
- {
- final AMQSessionModel session = _connection.getChannel(channelId);
- VirtualHostImpl virtualHost = _connection.getVirtualHost();
-
- final AMQShortString queueName;
-
- // if we aren't given a queue name, we create one which we return to the client
- if ((body.getQueue() == null) || (body.getQueue().length() == 0))
- {
- queueName = new AMQShortString("tmp_" + UUID.randomUUID());
- }
- else
- {
- queueName = body.getQueue().intern();
- }
-
- AMQQueue queue;
-
- //TODO: do we need to check that the queue already exists with exactly the same "configuration"?
-
- AMQChannel channel = _connection.getChannel(channelId);
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
-
- if(body.getPassive())
- {
- queue = virtualHost.getQueue(queueName.toString());
- if (queue == null)
- {
- String msg = "Queue: " + queueName + " not found on VirtualHost(" + virtualHost + ").";
- throw body.getChannelException(AMQConstant.NOT_FOUND, msg, _connection.getMethodRegistry());
- }
- else
- {
- if (!queue.verifySessionAccess(channel))
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "Queue "
- + queue.getName()
- + " is exclusive, but not created on this Connection.",
- _connection.getMethodRegistry());
- }
-
- //set this as the default queue on the channel:
- channel.setDefaultQueue(queue);
- }
- }
- else
- {
-
- try
- {
-
- queue = createQueue(channel, queueName, body, virtualHost, _connection);
-
- }
- catch(QueueExistsException qe)
- {
-
- queue = qe.getExistingQueue();
-
- if (!queue.verifySessionAccess(channel))
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "Queue "
- + queue.getName()
- + " is exclusive, but not created on this Connection.",
- _connection.getMethodRegistry());
- }
- else if(queue.isExclusive() != body.getExclusive())
- {
-
- throw body.getChannelException(AMQConstant.ALREADY_EXISTS,
- "Cannot re-declare queue '"
- + queue.getName()
- + "' with different exclusivity (was: "
- + queue.isExclusive()
- + " requested "
- + body.getExclusive()
- + ")",
- _connection.getMethodRegistry());
- }
- else if((body.getAutoDelete() && queue.getLifetimePolicy() != LifetimePolicy.DELETE_ON_NO_OUTBOUND_LINKS)
- || (!body.getAutoDelete() && queue.getLifetimePolicy() != ((body.getExclusive() && !body.getDurable()) ? LifetimePolicy.DELETE_ON_CONNECTION_CLOSE : LifetimePolicy.PERMANENT)))
- {
- throw body.getChannelException(AMQConstant.ALREADY_EXISTS,
- "Cannot re-declare queue '"
- + queue.getName()
- + "' with different lifetime policy (was: "
- + queue.getLifetimePolicy()
- + " requested autodelete: "
- + body.getAutoDelete()
- + ")",
- _connection.getMethodRegistry());
- }
- else if(queue.isDurable() != body.getDurable())
- {
- throw body.getChannelException(AMQConstant.ALREADY_EXISTS,
- "Cannot re-declare queue '"
- + queue.getName()
- + "' with different durability (was: "
- + queue.isDurable()
- + " requested "
- + body.getDurable()
- + ")",
- _connection.getMethodRegistry());
- }
-
- }
- catch (AccessControlException e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- e.getMessage(),
- _connection.getMethodRegistry());
- }
-
- //set this as the default queue on the channel:
- channel.setDefaultQueue(queue);
- }
-
- if (!body.getNowait())
- {
- channel.sync();
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- QueueDeclareOkBody responseBody =
- methodRegistry.createQueueDeclareOkBody(queueName,
- queue.getQueueDepthMessages(),
- queue.getConsumerCount());
- _connection.writeFrame(responseBody.generateFrame(channelId));
-
- _logger.info("Queue " + queueName + " declared successfully");
- }
- return true;
- }
-
- protected AMQQueue createQueue(final AMQChannel channel, final AMQShortString queueName,
- QueueDeclareBody body,
- final VirtualHostImpl virtualHost,
- final AMQProtocolSession session)
- throws AMQException, QueueExistsException
- {
-
- final boolean durable = body.getDurable();
- final boolean autoDelete = body.getAutoDelete();
- final boolean exclusive = body.getExclusive();
-
-
- Map<String, Object> attributes =
- QueueArgumentsConverter.convertWireArgsToModel(FieldTable.convertToMap(body.getArguments()));
- final String queueNameString = AMQShortString.toString(queueName);
- attributes.put(Queue.NAME, queueNameString);
- attributes.put(Queue.ID, UUID.randomUUID());
- attributes.put(Queue.DURABLE, durable);
-
- LifetimePolicy lifetimePolicy;
- ExclusivityPolicy exclusivityPolicy;
-
- if(exclusive)
- {
- lifetimePolicy = autoDelete
- ? LifetimePolicy.DELETE_ON_NO_OUTBOUND_LINKS
- : durable ? LifetimePolicy.PERMANENT : LifetimePolicy.DELETE_ON_CONNECTION_CLOSE;
- exclusivityPolicy = durable ? ExclusivityPolicy.CONTAINER : ExclusivityPolicy.CONNECTION;
- }
- else
- {
- lifetimePolicy = autoDelete ? LifetimePolicy.DELETE_ON_NO_OUTBOUND_LINKS : LifetimePolicy.PERMANENT;
- exclusivityPolicy = ExclusivityPolicy.NONE;
- }
-
- attributes.put(Queue.EXCLUSIVE, exclusivityPolicy);
- attributes.put(Queue.LIFETIME_POLICY, lifetimePolicy);
-
-
- final AMQQueue queue = virtualHost.createQueue(attributes);
-
- return queue;
- }
-
- public boolean dispatchQueueDelete(QueueDeleteBody body, int channelId) throws AMQException
- {
- VirtualHostImpl virtualHost = _connection.getVirtualHost();
-
- AMQChannel channel = _connection.getChannel(channelId);
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
- channel.sync();
- AMQQueue queue;
- if (body.getQueue() == null)
- {
-
- //get the default queue on the channel:
- queue = channel.getDefaultQueue();
- }
- else
- {
- queue = virtualHost.getQueue(body.getQueue().toString());
- }
-
- if (queue == null)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist.",
- _connection.getMethodRegistry());
-
- }
- else
- {
- if (body.getIfEmpty() && !queue.isEmpty())
- {
- throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is not empty.",
- _connection.getMethodRegistry());
- }
- else if (body.getIfUnused() && !queue.isUnused())
- {
- // TODO - Error code
- throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is still used.",
- _connection.getMethodRegistry());
- }
- else
- {
- if (!queue.verifySessionAccess(channel))
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "Queue "
- + queue.getName()
- + " is exclusive, but not created on this Connection.",
- _connection.getMethodRegistry());
- }
-
- int purged = 0;
- try
- {
- purged = virtualHost.removeQueue(queue);
- }
- catch (AccessControlException e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- e.getMessage(),
- _connection.getMethodRegistry());
- }
-
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- QueueDeleteOkBody responseBody = methodRegistry.createQueueDeleteOkBody(purged);
- _connection.writeFrame(responseBody.generateFrame(channelId));
- }
- }
- return true;
- }
-
- public boolean dispatchQueuePurge(QueuePurgeBody body, int channelId) throws AMQException
- {
- VirtualHostImpl virtualHost = _connection.getVirtualHost();
-
- AMQChannel channel = _connection.getChannel(channelId);
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
- AMQQueue queue;
- if(body.getQueue() == null)
- {
-
- //get the default queue on the channel:
- queue = channel.getDefaultQueue();
-
- if(queue == null)
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "No queue specified.",
- _connection.getMethodRegistry());
- }
- }
- else
- {
- queue = virtualHost.getQueue(body.getQueue().toString());
- }
-
- if(queue == null)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist.",
- _connection.getMethodRegistry());
- }
- else
- {
- if (!queue.verifySessionAccess(channel))
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "Queue is exclusive, but not created on this Connection.",
- _connection.getMethodRegistry());
- }
-
- long purged = 0;
- try
- {
- purged = queue.clearQueue();
- }
- catch (AccessControlException e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- e.getMessage(),
- _connection.getMethodRegistry());
- }
-
-
- if(!body.getNowait())
- {
- channel.sync();
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged);
- _connection.writeFrame(responseBody.generateFrame(channelId));
-
- }
- }
- return true;
- }
-
-
- public boolean dispatchTxCommit(TxCommitBody body, final int channelId) throws AMQException
- {
- try
- {
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Commit received on channel " + channelId);
- }
- AMQChannel channel = _connection.getChannel(channelId);
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
- channel.commit(new Runnable()
- {
-
- @Override
- public void run()
- {
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- AMQMethodBody responseBody = methodRegistry.createTxCommitOkBody();
- _connection.writeFrame(responseBody.generateFrame(channelId));
- }
- }, true);
-
-
-
- }
- catch (AMQException e)
- {
- throw body.getChannelException(e.getErrorCode(), "Failed to commit: " + e.getMessage(),
- _connection.getMethodRegistry());
- }
- return true;
- }
-
- public boolean dispatchTxRollback(TxRollbackBody body, final int channelId) throws AMQException
- {
- try
- {
- AMQChannel channel = _connection.getChannel(channelId);
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
-
-
-
- final MethodRegistry methodRegistry = _connection.getMethodRegistry();
- final AMQMethodBody responseBody = methodRegistry.createTxRollbackOkBody();
-
- Runnable task = new Runnable()
- {
-
- public void run()
- {
- _connection.writeFrame(responseBody.generateFrame(channelId));
- }
- };
-
- channel.rollback(task);
-
- //Now resend all the unacknowledged messages back to the original subscribers.
- //(Must be done after the TxnRollback-ok response).
- // Why, are we not allowed to send messages back to client before the ok method?
- channel.resend();
-
- }
- catch (AMQException e)
- {
- throw body.getChannelException(e.getErrorCode(), "Failed to rollback: " + e.getMessage(),
- _connection.getMethodRegistry());
- }
- return true;
- }
-
- public boolean dispatchTxSelect(TxSelectBody body, int channelId) throws AMQException
- {
- AMQChannel channel = _connection.getChannel(channelId);
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry());
- }
-
- channel.setLocalTransactional();
-
- MethodRegistry methodRegistry = _connection.getMethodRegistry();
- TxSelectOkBody responseBody = methodRegistry.createTxSelectOkBody();
- _connection.writeFrame(responseBody.generateFrame(channelId));
- return true;
- }
-
- public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException
- {
- final AMQProtocolSession<?> connection = getConnection();
-
- _logger.debug("Recover received on protocol session " + connection + " and channel " + channelId);
- AMQChannel channel = connection.getChannel(channelId);
-
-
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, connection.getMethodRegistry());
- }
- channel.sync();
- channel.resend();
-
- MethodRegistry methodRegistry = connection.getMethodRegistry();
- AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody();
- connection.writeFrame(recoverOk.generateFrame(channelId));
-
- return true;
- }
-
- public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- @Override
- public boolean dispatchChannelAlert(final ChannelAlertBody body, final int channelId)
- throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException
- {
- throw new UnexpectedMethodException(body);
- }
-
- public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException
- {
- final AMQProtocolSession<?> connection = getConnection();
-
- if (ProtocolVersion.v8_0.equals(connection.getProtocolVersion()))
- {
- // 0-8 does not support QueueUnbind
- throw new AMQException(AMQConstant.COMMAND_INVALID, "QueueUnbind not present in AMQP version: " + connection.getProtocolVersion(), null);
- }
-
- VirtualHostImpl virtualHost = connection.getVirtualHost();
-
- final AMQQueue queue;
- final AMQShortString routingKey;
-
-
- AMQChannel channel = connection.getChannel(channelId);
- if (channel == null)
- {
- throw body.getChannelNotFoundException(channelId, connection.getMethodRegistry());
- }
-
- if (body.getQueue() == null)
- {
-
- queue = channel.getDefaultQueue();
-
- if (queue == null)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND,
- "No default queue defined on channel and queue was null",
- connection.getMethodRegistry());
- }
-
- routingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().intern(false);
-
- }
- else
- {
- queue = virtualHost.getQueue(body.getQueue().toString());
- routingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().intern(false);
- }
-
- if (queue == null)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist.",
- connection.getMethodRegistry());
- }
-
- if(isDefaultExchange(body.getExchange()))
- {
- throw body.getConnectionException(AMQConstant.NOT_ALLOWED,
- "Cannot unbind the queue "
- + queue.getName()
- + " from the default exchange", connection.getMethodRegistry());
- }
-
- final ExchangeImpl exch = virtualHost.getExchange(body.getExchange() == null ? null : body.getExchange().toString());
- if (exch == null)
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.getExchange() + " does not exist.",
- connection.getMethodRegistry());
- }
-
- if(!exch.hasBinding(String.valueOf(routingKey), queue))
- {
- throw body.getChannelException(AMQConstant.NOT_FOUND, "No such binding", connection.getMethodRegistry());
- }
- else
- {
- try
- {
- exch.deleteBinding(String.valueOf(routingKey), queue);
- }
- catch (AccessControlException e)
- {
- throw body.getConnectionException(AMQConstant.ACCESS_REFUSED,
- e.getMessage(),
- connection.getMethodRegistry());
- }
- }
-
-
- if (_logger.isInfoEnabled())
- {
- _logger.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey);
- }
-
-
- final AMQMethodBody responseBody = connection.getMethodRegistry().createQueueUnbindOkBody();
- channel.sync();
- connection.writeFrame(responseBody.generateFrame(channelId));
- return true;
- }
-
-}
+/* + * + * 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.protocol.v0_8; + +import java.security.AccessControlException; +import java.security.PrivilegedAction; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.UUID; + +import javax.security.auth.Subject; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQConnectionException; +import org.apache.qpid.AMQException; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.consumer.ConsumerImpl; +import org.apache.qpid.server.exchange.ExchangeImpl; +import org.apache.qpid.server.filter.AMQInvalidArgumentException; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.flow.MessageOnlyCreditManager; +import org.apache.qpid.server.message.InstanceProperties; +import org.apache.qpid.server.message.MessageDestination; +import org.apache.qpid.server.message.MessageInstance; +import org.apache.qpid.server.message.MessageSource; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ExclusivityPolicy; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.NoFactoryForTypeException; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.UnknownConfiguredObjectException; +import org.apache.qpid.server.model.port.AmqpPort; +import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.QueueArgumentsConverter; +import org.apache.qpid.server.security.SubjectCreator; +import org.apache.qpid.server.security.auth.SubjectAuthenticationResult; +import org.apache.qpid.server.virtualhost.ExchangeExistsException; +import org.apache.qpid.server.virtualhost.ExchangeIsAlternateException; +import org.apache.qpid.server.virtualhost.QueueExistsException; +import org.apache.qpid.server.virtualhost.RequiredExchangeException; +import org.apache.qpid.server.virtualhost.ReservedExchangeNameException; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; + +public class ServerMethodDispatcherImpl implements MethodDispatcher +{ + private static final Logger _logger = Logger.getLogger(ServerMethodDispatcherImpl.class); + + private final AMQProtocolSession<?> _connection; + + + private static interface ChannelAction + { + void onChannel(ChannelMethodProcessor channel); + } + + public static MethodDispatcher createMethodDispatcher(AMQProtocolSession<?> connection) + { + return new ServerMethodDispatcherImpl(connection); + } + + + public ServerMethodDispatcherImpl(AMQProtocolSession<?> connection) + { + _connection = connection; + } + + + protected final AMQProtocolSession<?> getConnection() + { + return _connection; + } + + private void processChannelMethod(int channelId, final ChannelAction action) + { + final AMQChannel channel = _connection.getChannel(channelId); + if (channel == null) + { + // TODO throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + else + { + Subject.doAs(channel.getSubject(), new PrivilegedAction<Void>() + { + @Override + public Void run() + { + action.onChannel(channel.getMethodProcessor()); + return null; + } + }); + } + + } + + public boolean dispatchAccessRequest(AccessRequestBody body, int channelId) throws AMQException + { + final AMQChannel channel = _connection.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + + if(ProtocolVersion.v0_91.equals(_connection.getProtocolVersion()) ) + { + throw new AMQException(AMQConstant.COMMAND_INVALID, "AccessRequest not present in AMQP versions other than 0-8, 0-9"); + } + + // We don't implement access control class, but to keep clients happy that expect it + // always use the "0" ticket. + AccessRequestOkBody response = methodRegistry.createAccessRequestOkBody(0); + channel.sync(); + _connection.writeFrame(response.generateFrame(channelId)); + return true; + } + + public boolean dispatchBasicAck(BasicAckBody body, int channelId) throws AMQException + { + + if (_logger.isDebugEnabled()) + { + _logger.debug("Ack(Tag:" + body.getDeliveryTag() + ":Mult:" + body.getMultiple() + ") received on channel " + channelId); + } + + final AMQChannel channel = _connection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + + // this method throws an AMQException if the delivery tag is not known + channel.acknowledgeMessage(body.getDeliveryTag(), body.getMultiple()); + return true; + } + + public boolean dispatchBasicCancel(BasicCancelBody body, int channelId) throws AMQException + { + final AMQChannel channel = _connection.getChannel(channelId); + + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("BasicCancel: for:" + body.getConsumerTag() + + " nowait:" + body.getNowait()); + } + + channel.unsubscribeConsumer(body.getConsumerTag()); + if (!body.getNowait()) + { + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + BasicCancelOkBody cancelOkBody = methodRegistry.createBasicCancelOkBody(body.getConsumerTag()); + channel.sync(); + _connection.writeFrame(cancelOkBody.generateFrame(channelId)); + } + return true; + } + + public boolean dispatchBasicConsume(BasicConsumeBody body, int channelId) throws AMQException + { + AMQChannel channel = _connection.getChannel(channelId); + VirtualHostImpl<?,?,?> vHost = _connection.getVirtualHost(); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + else + { + channel.sync(); + String queueName = body.getQueue() == null ? null : body.getQueue().asString(); + if (_logger.isDebugEnabled()) + { + _logger.debug("BasicConsume: from '" + queueName + + "' for:" + body.getConsumerTag() + + " nowait:" + body.getNowait() + + " args:" + body.getArguments()); + } + + MessageSource queue = queueName == null ? channel.getDefaultQueue() : vHost.getQueue(queueName); + final Collection<MessageSource> sources = new HashSet<>(); + if(queue != null) + { + sources.add(queue); + } + else if(vHost.getContextValue(Boolean.class, "qpid.enableMultiQueueConsumers") + && body.getArguments() != null + && body.getArguments().get("x-multiqueue") instanceof Collection) + { + for(Object object : (Collection<Object>) body.getArguments().get("x-multiqueue")) + { + String sourceName = String.valueOf(object); + sourceName = sourceName.trim(); + if(sourceName.length() != 0) + { + MessageSource source = vHost.getMessageSource(sourceName); + if(source == null) + { + sources.clear(); + break; + } + else + { + sources.add(source); + } + } + } + queueName = body.getArguments().get("x-multiqueue").toString(); + } + + if (sources.isEmpty()) + { + if (_logger.isDebugEnabled()) + { + _logger.debug("No queue for '" + queueName + "'"); + } + if (queueName != null) + { + String msg = "No such queue, '" + queueName + "'"; + throw body.getChannelException(AMQConstant.NOT_FOUND, msg, _connection.getMethodRegistry()); + } + else + { + String msg = "No queue name provided, no default queue defined."; + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, msg, _connection.getMethodRegistry()); + } + } + else + { + final AMQShortString consumerTagName; + + if (body.getConsumerTag() != null) + { + consumerTagName = body.getConsumerTag().intern(false); + } + else + { + consumerTagName = null; + } + + try + { + if(consumerTagName == null || channel.getSubscription(consumerTagName) == null) + { + + AMQShortString consumerTag = channel.consumeFromSource(consumerTagName, + sources, + !body.getNoAck(), + body.getArguments(), + body.getExclusive(), + body.getNoLocal()); + if (!body.getNowait()) + { + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createBasicConsumeOkBody(consumerTag); + _connection.writeFrame(responseBody.generateFrame(channelId)); + + } + } + else + { + AMQShortString msg = AMQShortString.validValueOf("Non-unique consumer tag, '" + body.getConsumerTag() + "'"); + + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode + msg, // replytext + body.getClazz(), + body.getMethod()); + _connection.writeFrame(responseBody.generateFrame(0)); + } + + } + catch (AMQInvalidArgumentException ise) + { + _logger.debug("Closing connection due to invalid selector"); + + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createChannelCloseBody(AMQConstant.ARGUMENT_INVALID.getCode(), + AMQShortString.validValueOf(ise.getMessage()), + body.getClazz(), + body.getMethod()); + _connection.writeFrame(responseBody.generateFrame(channelId)); + + + } + catch (AMQQueue.ExistingExclusiveConsumer e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + "Cannot subscribe to queue " + + queue.getName() + + " as it already has an existing exclusive consumer", + _connection.getMethodRegistry()); + } + catch (AMQQueue.ExistingConsumerPreventsExclusive e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + "Cannot subscribe to queue " + + queue.getName() + + " exclusively as it already has a consumer", + _connection.getMethodRegistry()); + } + catch (AccessControlException e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + "Cannot subscribe to queue " + + queue.getName() + + " permission denied", _connection.getMethodRegistry()); + } + catch (MessageSource.ConsumerAccessRefused consumerAccessRefused) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + "Cannot subscribe to queue " + + queue.getName() + + " as it already has an incompatible exclusivity policy", + _connection.getMethodRegistry()); + } + + } + } + return true; + } + + public boolean dispatchBasicGet(BasicGetBody body, int channelId) throws AMQException + { + + VirtualHostImpl vHost = _connection.getVirtualHost(); + + AMQChannel channel = _connection.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + else + { + channel.sync(); + AMQQueue queue = body.getQueue() == null ? channel.getDefaultQueue() : vHost.getQueue(body.getQueue().toString()); + if (queue == null) + { + _logger.info("No queue for '" + body.getQueue() + "'"); + if(body.getQueue()!=null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, + "No such queue, '" + body.getQueue() + "'", + _connection.getMethodRegistry()); + } + else + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "No queue name provided, no default queue defined.", + _connection.getMethodRegistry()); + } + } + else + { + + try + { + if (!performGet(queue, _connection, channel, !body.getNoAck())) + { + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + + BasicGetEmptyBody responseBody = methodRegistry.createBasicGetEmptyBody(null); + + + _connection.writeFrame(responseBody.generateFrame(channelId)); + } + } + catch (AccessControlException e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + e.getMessage(), _connection.getMethodRegistry()); + } + catch (MessageSource.ExistingExclusiveConsumer e) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Queue has an exclusive consumer", + _connection.getMethodRegistry()); + } + catch (MessageSource.ExistingConsumerPreventsExclusive e) + { + throw body.getConnectionException(AMQConstant.INTERNAL_ERROR, + "The GET request has been evaluated as an exclusive consumer, " + + "this is likely due to a programming error in the Qpid broker", + _connection.getMethodRegistry()); + } + catch (MessageSource.ConsumerAccessRefused consumerAccessRefused) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Queue has an incompatible exclusivit policy", + _connection.getMethodRegistry()); + } + } + } + return true; + } + + public static boolean performGet(final AMQQueue queue, + final AMQProtocolSession session, + final AMQChannel channel, + final boolean acks) + throws AMQException, MessageSource.ExistingConsumerPreventsExclusive, + MessageSource.ExistingExclusiveConsumer, MessageSource.ConsumerAccessRefused + { + + final FlowCreditManager singleMessageCredit = new MessageOnlyCreditManager(1L); + + final GetDeliveryMethod getDeliveryMethod = + new GetDeliveryMethod(singleMessageCredit, session, channel, queue); + final RecordDeliveryMethod getRecordMethod = new RecordDeliveryMethod() + { + + public void recordMessageDelivery(final ConsumerImpl sub, final MessageInstance entry, final long deliveryTag) + { + channel.addUnacknowledgedMessage(entry, deliveryTag, null); + } + }; + + ConsumerTarget_0_8 target; + EnumSet<ConsumerImpl.Option> options = EnumSet.of(ConsumerImpl.Option.TRANSIENT, ConsumerImpl.Option.ACQUIRES, + ConsumerImpl.Option.SEES_REQUEUES); + if(acks) + { + + target = ConsumerTarget_0_8.createAckTarget(channel, + AMQShortString.EMPTY_STRING, null, + singleMessageCredit, getDeliveryMethod, getRecordMethod); + } + else + { + target = ConsumerTarget_0_8.createGetNoAckTarget(channel, + AMQShortString.EMPTY_STRING, null, + singleMessageCredit, getDeliveryMethod, getRecordMethod); + } + + ConsumerImpl sub = queue.addConsumer(target, null, AMQMessage.class, "", options); + sub.flush(); + sub.close(); + return(getDeliveryMethod.hasDeliveredMessage()); + + + } + + + private static class GetDeliveryMethod implements ClientDeliveryMethod + { + + private final FlowCreditManager _singleMessageCredit; + private final AMQProtocolSession _session; + private final AMQChannel _channel; + private final AMQQueue _queue; + private boolean _deliveredMessage; + + public GetDeliveryMethod(final FlowCreditManager singleMessageCredit, + final AMQProtocolSession session, + final AMQChannel channel, final AMQQueue queue) + { + _singleMessageCredit = singleMessageCredit; + _session = session; + _channel = channel; + _queue = queue; + } + + @Override + public long deliverToClient(final ConsumerImpl sub, final ServerMessage message, + final InstanceProperties props, final long deliveryTag) + { + _singleMessageCredit.useCreditForMessage(message.getSize()); + long size =_session.getProtocolOutputConverter().writeGetOk(message, + props, + _channel.getChannelId(), + deliveryTag, + _queue.getQueueDepthMessages()); + + _deliveredMessage = true; + return size; + } + + public boolean hasDeliveredMessage() + { + return _deliveredMessage; + } + } + + public boolean dispatchBasicPublish(BasicPublishBody body, int channelId) throws AMQException + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Publish received on channel " + channelId); + } + + AMQShortString exchangeName = body.getExchange(); + VirtualHostImpl vHost = _connection.getVirtualHost(); + + // TODO: check the delivery tag field details - is it unique across the broker or per subscriber? + + MessageDestination destination; + + if (exchangeName == null || AMQShortString.EMPTY_STRING.equals(exchangeName)) + { + destination = vHost.getDefaultDestination(); + } + else + { + destination = vHost.getMessageDestination(exchangeName.toString()); + } + + // if the exchange does not exist we raise a channel exception + if (destination == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange name", + _connection.getMethodRegistry()); + } + else + { + // The partially populated BasicDeliver frame plus the received route body + // is stored in the channel. Once the final body frame has been received + // it is routed to the exchange. + AMQChannel channel = _connection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + + MessagePublishInfo info = new MessagePublishInfo(body.getExchange(), + body.getImmediate(), + body.getMandatory(), + body.getRoutingKey()); + info.setExchange(exchangeName); + try + { + channel.setPublishFrame(info, destination); + } + catch (AccessControlException e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + e.getMessage(), + _connection.getMethodRegistry()); + } + } + return true; + } + + public boolean dispatchBasicQos(BasicQosBody body, int channelId) throws AMQException + { + AMQChannel channel = _connection.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + channel.sync(); + channel.setCredit(body.getPrefetchSize(), body.getPrefetchCount()); + + + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createBasicQosOkBody(); + _connection.writeFrame(responseBody.generateFrame(channelId)); + + return true; + } + + public boolean dispatchBasicRecover(BasicRecoverBody body, int channelId) throws AMQException + { + _logger.debug("Recover received on protocol session " + _connection + + " and channel " + channelId); + AMQChannel channel = _connection.getChannel(channelId); + + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + + channel.resend(); + + // Qpid 0-8 hacks a synchronous -ok onto recover. + // In Qpid 0-9 we create a separate sync-recover, sync-recover-ok pair to be "more" compliant + if(_connection.getProtocolVersion().equals(ProtocolVersion.v8_0)) + { + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody(); + channel.sync(); + _connection.writeFrame(recoverOk.generateFrame(channelId)); + + } + + return true; + } + + public boolean dispatchBasicReject(BasicRejectBody body, int channelId) throws AMQException + { + + AMQChannel channel = _connection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("Rejecting:" + body.getDeliveryTag() + + ": Requeue:" + body.getRequeue() + + " on channel:" + channel.debugIdentity()); + } + + long deliveryTag = body.getDeliveryTag(); + + MessageInstance message = channel.getUnacknowledgedMessageMap().get(deliveryTag); + + if (message == null) + { + _logger.warn("Dropping reject request as message is null for tag:" + deliveryTag); + } + else + { + + if (message.getMessage() == null) + { + _logger.warn("Message has already been purged, unable to Reject."); + } + else + { + + if (_logger.isDebugEnabled()) + { + _logger.debug("Rejecting: DT:" + deliveryTag + "-" + message.getMessage() + + ": Requeue:" + body.getRequeue() + + " on channel:" + channel.debugIdentity()); + } + + if (body.getRequeue()) + { + //this requeue represents a message rejected from the pre-dispatch queue + //therefore we need to amend the delivery counter. + message.decrementDeliveryCount(); + + channel.requeue(deliveryTag); + } + else + { + // Since the Java client abuses the reject flag for requeing after rollback, we won't set reject here + // as it would prevent redelivery + // message.reject(); + + final boolean maxDeliveryCountEnabled = channel.isMaxDeliveryCountEnabled(deliveryTag); + _logger.debug("maxDeliveryCountEnabled: " + + maxDeliveryCountEnabled + + " deliveryTag " + + deliveryTag); + if (maxDeliveryCountEnabled) + { + final boolean deliveredTooManyTimes = channel.isDeliveredTooManyTimes(deliveryTag); + _logger.debug("deliveredTooManyTimes: " + + deliveredTooManyTimes + + " deliveryTag " + + deliveryTag); + if (deliveredTooManyTimes) + { + channel.deadLetter(body.getDeliveryTag()); + } + else + { + //this requeue represents a message rejected because of a recover/rollback that we + //are not ready to DLQ. We rely on the reject command to resend from the unacked map + //and therefore need to increment the delivery counter so we cancel out the effect + //of the AMQChannel#resend() decrement. + message.incrementDeliveryCount(); + } + } + else + { + channel.requeue(deliveryTag); + } + } + } + } + return true; + } + + public boolean dispatchChannelOpen(ChannelOpenBody body, int channelId) throws AMQException + { + VirtualHostImpl virtualHost = _connection.getVirtualHost(); + + // Protect the broker against out of order frame request. + if (virtualHost == null) + { + throw new AMQException(AMQConstant.COMMAND_INVALID, "Virtualhost has not yet been set. ConnectionOpen has not been called.", null); + } + _logger.info("Connecting to: " + virtualHost.getName()); + + final AMQChannel channel = new AMQChannel(_connection, channelId, virtualHost.getMessageStore()); + + _connection.addChannel(channel); + + ChannelOpenOkBody response; + + + response = _connection.getMethodRegistry().createChannelOpenOkBody(); + + + _connection.writeFrame(response.generateFrame(channelId)); + return true; + } + + + public boolean dispatchAccessRequestOk(AccessRequestOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchBasicCancelOk(BasicCancelOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicConsumeOk(BasicConsumeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicDeliver(BasicDeliverBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicGetEmpty(BasicGetEmptyBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicGetOk(BasicGetOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicQosOk(BasicQosOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchBasicReturn(BasicReturnBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelClose(ChannelCloseBody body, int channelId) throws AMQException + { + + if (_logger.isInfoEnabled()) + { + _logger.info("Received channel close for id " + channelId + + " citing class " + body.getClassId() + + " and method " + body.getMethodId()); + } + + + AMQChannel channel = _connection.getChannel(channelId); + + if (channel == null) + { + throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, + "Trying to close unknown channel", + _connection.getMethodRegistry()); + } + channel.sync(); + _connection.closeChannel(channelId); + // Client requested closure so we don't wait for ok we send it + _connection.closeChannelOk(channelId); + + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + ChannelCloseOkBody responseBody = methodRegistry.createChannelCloseOkBody(); + _connection.writeFrame(responseBody.generateFrame(channelId)); + return true; + } + + + public boolean dispatchChannelCloseOk(ChannelCloseOkBody body, int channelId) throws AMQException + { + + _logger.info("Received channel-close-ok for channel-id " + channelId); + + // Let the Protocol Session know the channel is now closed. + _connection.closeChannelOk(channelId); + return true; + } + + + public boolean dispatchChannelFlow(ChannelFlowBody body, int channelId) throws AMQException + { + final AMQProtocolSession<?> connection = getConnection(); + + + AMQChannel channel = connection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, connection.getMethodRegistry()); + } + channel.sync(); + channel.setSuspended(!body.getActive()); + _logger.debug("Channel.Flow for channel " + channelId + ", active=" + body.getActive()); + + MethodRegistry methodRegistry = connection.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createChannelFlowOkBody(body.getActive()); + connection.writeFrame(responseBody.generateFrame(channelId)); + return true; + } + + public boolean dispatchChannelFlowOk(ChannelFlowOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchChannelOpenOk(ChannelOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchConnectionOpen(ConnectionOpenBody body, int channelId) throws AMQException + { + + //ignore leading '/' + String virtualHostName; + if ((body.getVirtualHost() != null) && body.getVirtualHost().charAt(0) == '/') + { + virtualHostName = new StringBuilder(body.getVirtualHost().subSequence(1, body.getVirtualHost().length())).toString(); + } + else + { + virtualHostName = body.getVirtualHost() == null ? null : String.valueOf(body.getVirtualHost()); + } + + VirtualHostImpl virtualHost = ((AmqpPort) _connection.getPort()).getVirtualHost(virtualHostName); + + if (virtualHost == null) + { + throw body.getConnectionException(AMQConstant.NOT_FOUND, "Unknown virtual host: '" + virtualHostName + "'", + _connection.getMethodRegistry()); + } + else + { + // Check virtualhost access + if (virtualHost.getState() != State.ACTIVE) + { + throw body.getConnectionException(AMQConstant.CONNECTION_FORCED, + "Virtual host '" + virtualHost.getName() + "' is not active", + _connection.getMethodRegistry()); + } + + _connection.setVirtualHost(virtualHost); + try + { + virtualHost.getSecurityManager().authoriseCreateConnection(_connection); + } + catch (AccessControlException e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + e.getMessage(), + _connection.getMethodRegistry()); + } + + // See Spec (0.8.2). Section 3.1.2 Virtual Hosts + if (_connection.getContextKey() == null) + { + _connection.setContextKey(new AMQShortString(Long.toString(System.currentTimeMillis()))); + } + + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createConnectionOpenOkBody(body.getVirtualHost()); + + _connection.writeFrame(responseBody.generateFrame(channelId)); + } + return true; + } + + + public boolean dispatchConnectionClose(ConnectionCloseBody body, int channelId) throws AMQException + { + if (_logger.isInfoEnabled()) + { + _logger.info("ConnectionClose received with reply code/reply text " + body.getReplyCode() + "/" + + body.getReplyText() + " for " + _connection); + } + try + { + _connection.closeSession(); + } + catch (Exception e) + { + _logger.error("Error closing protocol session: " + e, e); + } + + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + ConnectionCloseOkBody responseBody = methodRegistry.createConnectionCloseOkBody(); + _connection.writeFrame(responseBody.generateFrame(channelId)); + + _connection.closeProtocolSession(); + + return true; + } + + + public boolean dispatchConnectionCloseOk(ConnectionCloseOkBody body, int channelId) throws AMQException + { + _logger.info("Received Connection-close-ok"); + + try + { + _connection.closeSession(); + } + catch (Exception e) + { + _logger.error("Error closing protocol session: " + e, e); + } + return true; + } + + public boolean dispatchConnectionOpenOk(ConnectionOpenOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionRedirect(ConnectionRedirectBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionSecure(ConnectionSecureBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionStart(ConnectionStartBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchConnectionTune(ConnectionTuneBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchExchangeBoundOk(ExchangeBoundOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeDeclareOk(ExchangeDeclareOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchExchangeDeleteOk(ExchangeDeleteOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueBindOk(QueueBindOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueDeclareOk(QueueDeclareOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueDeleteOk(QueueDeleteOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueuePurgeOk(QueuePurgeOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxCommitOk(TxCommitOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxRollbackOk(TxRollbackOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchTxSelectOk(TxSelectOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + + public boolean dispatchConnectionSecureOk(ConnectionSecureOkBody body, int channelId) throws AMQException + { + Broker<?> broker = _connection.getBroker(); + + SubjectCreator subjectCreator = _connection.getSubjectCreator(); + + SaslServer ss = _connection.getSaslServer(); + if (ss == null) + { + throw new AMQException("No SASL context set up in session"); + } + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + SubjectAuthenticationResult authResult = subjectCreator.authenticate(ss, body.getResponse()); + switch (authResult.getStatus()) + { + case ERROR: + Exception cause = authResult.getCause(); + + _logger.info("Authentication failed:" + (cause == null ? "" : cause.getMessage())); + + ConnectionCloseBody connectionCloseBody = + methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), + AMQConstant.NOT_ALLOWED.getName(), + body.getClazz(), + body.getMethod()); + + _connection.writeFrame(connectionCloseBody.generateFrame(0)); + disposeSaslServer(_connection); + break; + case SUCCESS: + if (_logger.isInfoEnabled()) + { + _logger.info("Connected as: " + authResult.getSubject()); + } + + int frameMax = broker.getContextValue(Integer.class, Broker.BROKER_FRAME_SIZE); + + if(frameMax <= 0) + { + frameMax = Integer.MAX_VALUE; + } + + ConnectionTuneBody tuneBody = + methodRegistry.createConnectionTuneBody(broker.getConnection_sessionCountLimit(), + frameMax, + broker.getConnection_heartBeatDelay()); + _connection.writeFrame(tuneBody.generateFrame(0)); + _connection.setAuthorizedSubject(authResult.getSubject()); + disposeSaslServer(_connection); + break; + case CONTINUE: + + ConnectionSecureBody + secureBody = methodRegistry.createConnectionSecureBody(authResult.getChallenge()); + _connection.writeFrame(secureBody.generateFrame(0)); + } + return true; + } + + private void disposeSaslServer(AMQProtocolSession ps) + { + SaslServer ss = ps.getSaslServer(); + if (ss != null) + { + ps.setSaslServer(null); + try + { + ss.dispose(); + } + catch (SaslException e) + { + _logger.error("Error disposing of Sasl server: " + e); + } + } + } + + public boolean dispatchConnectionStartOk(ConnectionStartOkBody body, int channelId) throws AMQException + { + Broker<?> broker = _connection.getBroker(); + + _logger.info("SASL Mechanism selected: " + body.getMechanism()); + _logger.info("Locale selected: " + body.getLocale()); + + SubjectCreator subjectCreator = _connection.getSubjectCreator(); + SaslServer ss = null; + try + { + ss = subjectCreator.createSaslServer(String.valueOf(body.getMechanism()), + _connection.getLocalFQDN(), + _connection.getPeerPrincipal()); + + if (ss == null) + { + throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, + "Unable to create SASL Server:" + body.getMechanism(), + _connection.getMethodRegistry()); + } + + _connection.setSaslServer(ss); + + final SubjectAuthenticationResult authResult = subjectCreator.authenticate(ss, body.getResponse()); + //save clientProperties + _connection.setClientProperties(body.getClientProperties()); + + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + + switch (authResult.getStatus()) + { + case ERROR: + Exception cause = authResult.getCause(); + + _logger.info("Authentication failed:" + (cause == null ? "" : cause.getMessage())); + + ConnectionCloseBody closeBody = + methodRegistry.createConnectionCloseBody(AMQConstant.NOT_ALLOWED.getCode(), // replyCode + AMQConstant.NOT_ALLOWED.getName(), + body.getClazz(), + body.getMethod()); + + _connection.writeFrame(closeBody.generateFrame(0)); + disposeSaslServer(_connection); + break; + + case SUCCESS: + if (_logger.isInfoEnabled()) + { + _logger.info("Connected as: " + authResult.getSubject()); + } + _connection.setAuthorizedSubject(authResult.getSubject()); + + int frameMax = broker.getContextValue(Integer.class, Broker.BROKER_FRAME_SIZE); + + if(frameMax <= 0) + { + frameMax = Integer.MAX_VALUE; + } + + ConnectionTuneBody + tuneBody = methodRegistry.createConnectionTuneBody(broker.getConnection_sessionCountLimit(), + frameMax, + broker.getConnection_heartBeatDelay()); + _connection.writeFrame(tuneBody.generateFrame(0)); + break; + case CONTINUE: + ConnectionSecureBody + secureBody = methodRegistry.createConnectionSecureBody(authResult.getChallenge()); + _connection.writeFrame(secureBody.generateFrame(0)); + } + } + catch (SaslException e) + { + disposeSaslServer(_connection); + throw new AMQException("SASL error: " + e, e); + } + return true; + } + + public boolean dispatchConnectionTuneOk(ConnectionTuneOkBody body, int channelId) throws AMQException + { + final AMQProtocolSession<?> connection = getConnection(); + + if (_logger.isDebugEnabled()) + { + _logger.debug(body); + } + + connection.initHeartbeats(body.getHeartbeat()); + + int brokerFrameMax = connection.getBroker().getContextValue(Integer.class, Broker.BROKER_FRAME_SIZE); + if(brokerFrameMax <= 0) + { + brokerFrameMax = Integer.MAX_VALUE; + } + + if(body.getFrameMax() > (long) brokerFrameMax) + { + throw new AMQConnectionException(AMQConstant.SYNTAX_ERROR, + "Attempt to set max frame size to " + body.getFrameMax() + + " greater than the broker will allow: " + + brokerFrameMax, + body.getClazz(), body.getMethod(), + connection.getMethodRegistry(),null); + } + else if(body.getFrameMax() > 0 && body.getFrameMax() < AMQConstant.FRAME_MIN_SIZE.getCode()) + { + throw new AMQConnectionException(AMQConstant.SYNTAX_ERROR, + "Attempt to set max frame size to " + body.getFrameMax() + + " which is smaller than the specification definined minimum: " + + AMQConstant.FRAME_MIN_SIZE.getCode(), + body.getClazz(), body.getMethod(), + connection.getMethodRegistry(),null); + } + int frameMax = body.getFrameMax() == 0 ? brokerFrameMax : (int) body.getFrameMax(); + connection.setMaxFrameSize(frameMax); + + long maxChannelNumber = body.getChannelMax(); + //0 means no implied limit, except that forced by protocol limitations (0xFFFF) + connection.setMaximumNumberOfChannels(maxChannelNumber == 0 ? 0xFFFFL : maxChannelNumber); + return true; + } + + public static final int OK = 0; + public static final int EXCHANGE_NOT_FOUND = 1; + public static final int QUEUE_NOT_FOUND = 2; + public static final int NO_BINDINGS = 3; + public static final int QUEUE_NOT_BOUND = 4; + public static final int NO_QUEUE_BOUND_WITH_RK = 5; + public static final int SPECIFIC_QUEUE_NOT_BOUND_WITH_RK = 6; + + public boolean dispatchExchangeBound(ExchangeBoundBody body, int channelId) throws AMQException + { + VirtualHostImpl virtualHost = _connection.getVirtualHost(); + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + + final AMQChannel channel = _connection.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + channel.sync(); + + + AMQShortString exchangeName = body.getExchange(); + AMQShortString queueName = body.getQueue(); + AMQShortString routingKey = body.getRoutingKey(); + ExchangeBoundOkBody response; + + if(isDefaultExchange(exchangeName)) + { + if(routingKey == null) + { + if(queueName == null) + { + response = methodRegistry.createExchangeBoundOkBody(virtualHost.getQueues().isEmpty() ? NO_BINDINGS : OK, null); + } + else + { + AMQQueue queue = virtualHost.getQueue(queueName.toString()); + if (queue == null) + { + + response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode + AMQShortString.validValueOf("Queue '" + queueName + "' not found")); // replyText + } + else + { + response = methodRegistry.createExchangeBoundOkBody(OK, null); + } + } + } + else + { + if(queueName == null) + { + response = methodRegistry.createExchangeBoundOkBody(virtualHost.getQueue(routingKey.toString()) == null ? NO_QUEUE_BOUND_WITH_RK : OK, null); + } + else + { + AMQQueue queue = virtualHost.getQueue(queueName.toString()); + if (queue == null) + { + + response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode + AMQShortString.validValueOf("Queue '" + queueName + "' not found")); // replyText + } + else + { + response = methodRegistry.createExchangeBoundOkBody(queueName.equals(routingKey) ? OK : SPECIFIC_QUEUE_NOT_BOUND_WITH_RK, null); + } + } + } + } + else + { + ExchangeImpl exchange = virtualHost.getExchange(exchangeName.toString()); + if (exchange == null) + { + + + response = methodRegistry.createExchangeBoundOkBody(EXCHANGE_NOT_FOUND, + AMQShortString.validValueOf("Exchange '" + exchangeName + "' not found")); + } + else if (routingKey == null) + { + if (queueName == null) + { + if (exchange.hasBindings()) + { + response = methodRegistry.createExchangeBoundOkBody(OK, null); + } + else + { + + response = methodRegistry.createExchangeBoundOkBody(NO_BINDINGS, // replyCode + null); // replyText + } + } + else + { + + AMQQueue queue = virtualHost.getQueue(queueName.toString()); + if (queue == null) + { + + response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode + AMQShortString.validValueOf("Queue '" + queueName + "' not found")); // replyText + } + else + { + if (exchange.isBound(queue)) + { + + response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode + null); // replyText + } + else + { + + response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_BOUND, // replyCode + AMQShortString.validValueOf("Queue '" + queueName + "' not bound to exchange '" + exchangeName + "'")); // replyText + } + } + } + } + else if (queueName != null) + { + AMQQueue queue = virtualHost.getQueue(queueName.toString()); + if (queue == null) + { + + response = methodRegistry.createExchangeBoundOkBody(QUEUE_NOT_FOUND, // replyCode + AMQShortString.validValueOf("Queue '" + queueName + "' not found")); // replyText + } + else + { + String bindingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().asString(); + if (exchange.isBound(bindingKey, queue)) + { + + response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode + null); // replyText + } + else + { + + String message = "Queue '" + queueName + "' not bound with routing key '" + + body.getRoutingKey() + "' to exchange '" + exchangeName + "'"; + + response = methodRegistry.createExchangeBoundOkBody(SPECIFIC_QUEUE_NOT_BOUND_WITH_RK, // replyCode + AMQShortString.validValueOf(message)); // replyText + } + } + } + else + { + if (exchange.isBound(body.getRoutingKey() == null ? "" : body.getRoutingKey().asString())) + { + + response = methodRegistry.createExchangeBoundOkBody(OK, // replyCode + null); // replyText + } + else + { + + response = methodRegistry.createExchangeBoundOkBody(NO_QUEUE_BOUND_WITH_RK, // replyCode + AMQShortString.validValueOf("No queue bound with routing key '" + body.getRoutingKey() + + "' to exchange '" + exchangeName + "'")); // replyText + } + } + } + _connection.writeFrame(response.generateFrame(channelId)); + return true; + } + + public boolean dispatchExchangeDeclare(ExchangeDeclareBody body, int channelId) throws AMQException + { + VirtualHostImpl virtualHost = _connection.getVirtualHost(); + final AMQChannel channel = _connection.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + + final AMQShortString exchangeName = body.getExchange(); + if (_logger.isDebugEnabled()) + { + _logger.debug("Request to declare exchange of type " + body.getType() + " with name " + exchangeName); + } + + ExchangeImpl exchange; + + if(isDefaultExchange(exchangeName)) + { + if(!new AMQShortString(ExchangeDefaults.DIRECT_EXCHANGE_CLASS).equals(body.getType())) + { + throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare default exchange: " + + " of type " + + ExchangeDefaults.DIRECT_EXCHANGE_CLASS + + " to " + body.getType() +".", + body.getClazz(), body.getMethod(), + _connection.getMethodRegistry(),null); + } + } + else + { + if (body.getPassive()) + { + exchange = virtualHost.getExchange(exchangeName.toString()); + if(exchange == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Unknown exchange: " + exchangeName, + _connection.getMethodRegistry()); + } + else if (!(body.getType() == null || body.getType().length() ==0) && !exchange.getType().equals(body.getType().asString())) + { + + throw new AMQConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + + exchangeName + " of type " + exchange.getType() + + " to " + body.getType() +".", + body.getClazz(), body.getMethod(), + _connection.getMethodRegistry(),null); + } + + } + else + { + try + { + String name = exchangeName == null ? null : exchangeName.intern().toString(); + String type = body.getType() == null ? null : body.getType().intern().toString(); + + Map<String,Object> attributes = new HashMap<String, Object>(); + if(body.getArguments() != null) + { + attributes.putAll(FieldTable.convertToMap(body.getArguments())); + } + attributes.put(org.apache.qpid.server.model.Exchange.ID, null); + attributes.put(org.apache.qpid.server.model.Exchange.NAME,name); + attributes.put(org.apache.qpid.server.model.Exchange.TYPE,type); + attributes.put(org.apache.qpid.server.model.Exchange.DURABLE, body.getDurable()); + attributes.put(org.apache.qpid.server.model.Exchange.LIFETIME_POLICY, + body.getAutoDelete() ? LifetimePolicy.DELETE_ON_NO_LINKS : LifetimePolicy.PERMANENT); + if(!attributes.containsKey(org.apache.qpid.server.model.Exchange.ALTERNATE_EXCHANGE)) + { + attributes.put(org.apache.qpid.server.model.Exchange.ALTERNATE_EXCHANGE, null); + } + exchange = virtualHost.createExchange(attributes); + + } + catch(ReservedExchangeNameException e) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Attempt to declare exchange: " + exchangeName + + " which begins with reserved prefix.", + _connection.getMethodRegistry()); + + } + catch(ExchangeExistsException e) + { + exchange = e.getExistingExchange(); + if(!new AMQShortString(exchange.getType()).equals(body.getType())) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, "Attempt to redeclare exchange: " + + exchangeName + " of type " + + exchange.getType() + + " to " + body.getType() + ".", + _connection.getMethodRegistry()); + } + } + catch(NoFactoryForTypeException e) + { + throw body.getConnectionException(AMQConstant.COMMAND_INVALID, + "Unknown exchange type '" + + e.getType() + + "' for exchange '" + + exchangeName + + "'", + _connection.getMethodRegistry()); + } + catch (AccessControlException e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + e.getMessage(), + _connection.getMethodRegistry()); + } + catch (UnknownConfiguredObjectException e) + { + // note - since 0-8/9/9-1 can't set the alt. exchange this exception should never occur + throw body.getConnectionException(AMQConstant.NOT_FOUND, + "Unknown alternate exchange " + + (e.getName() != null + ? "name: \"" + e.getName() + "\"" + : "id: " + e.getId()), + _connection.getMethodRegistry()); + } + catch (IllegalArgumentException e) + { + throw body.getConnectionException(AMQConstant.COMMAND_INVALID, + "Error creating exchange '" + + exchangeName + + "': " + + e.getMessage(), + _connection.getMethodRegistry()); + } + } + } + + if(!body.getNowait()) + { + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createExchangeDeclareOkBody(); + channel.sync(); + _connection.writeFrame(responseBody.generateFrame(channelId)); + } + return true; + } + + public boolean dispatchExchangeDelete(ExchangeDeleteBody body, int channelId) throws AMQException + { + VirtualHostImpl virtualHost = _connection.getVirtualHost(); + final AMQChannel channel = _connection.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + channel.sync(); + try + { + + if(isDefaultExchange(body.getExchange())) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Default Exchange cannot be deleted", + _connection.getMethodRegistry()); + } + + final String exchangeName = body.getExchange().toString(); + + final ExchangeImpl exchange = virtualHost.getExchange(exchangeName); + if(exchange == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "No such exchange: " + body.getExchange(), + _connection.getMethodRegistry()); + } + + virtualHost.removeExchange(exchange, !body.getIfUnused()); + + ExchangeDeleteOkBody responseBody = _connection.getMethodRegistry().createExchangeDeleteOkBody(); + + _connection.writeFrame(responseBody.generateFrame(channelId)); + } + + catch (ExchangeIsAlternateException e) + { + throw body.getChannelException(AMQConstant.NOT_ALLOWED, "Exchange in use as an alternate exchange", + _connection.getMethodRegistry()); + + } + catch (RequiredExchangeException e) + { + throw body.getChannelException(AMQConstant.NOT_ALLOWED, + "Exchange '" + body.getExchange() + "' cannot be deleted", + _connection.getMethodRegistry()); + } + catch (AccessControlException e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + e.getMessage(), + _connection.getMethodRegistry()); + } + return true; + } + + private boolean isDefaultExchange(final AMQShortString exchangeName) + { + return exchangeName == null || exchangeName.equals(AMQShortString.EMPTY_STRING); + } + + public boolean dispatchQueueBind(QueueBindBody body, int channelId) throws AMQException + { + VirtualHostImpl virtualHost = _connection.getVirtualHost(); + AMQChannel channel = _connection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + + final AMQQueue queue; + final AMQShortString routingKey; + + final AMQShortString queueName = body.getQueue(); + + if (queueName == null) + { + + queue = channel.getDefaultQueue(); + + if (queue == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, + "No default queue defined on channel and queue was null", + _connection.getMethodRegistry()); + } + + if (body.getRoutingKey() == null) + { + routingKey = AMQShortString.valueOf(queue.getName()); + } + else + { + routingKey = body.getRoutingKey().intern(); + } + } + else + { + queue = virtualHost.getQueue(queueName.toString()); + routingKey = body.getRoutingKey() == null ? AMQShortString.EMPTY_STRING : body.getRoutingKey().intern(); + } + + if (queue == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + queueName + " does not exist.", + _connection.getMethodRegistry()); + } + + if(isDefaultExchange(body.getExchange())) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Cannot bind the queue " + queueName + " to the default exchange", + _connection.getMethodRegistry()); + } + + final String exchangeName = body.getExchange().toString(); + + final ExchangeImpl exch = virtualHost.getExchange(exchangeName); + if (exch == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + exchangeName + " does not exist.", + _connection.getMethodRegistry()); + } + + + try + { + + Map<String,Object> arguments = FieldTable.convertToMap(body.getArguments()); + String bindingKey = String.valueOf(routingKey); + + if (!exch.isBound(bindingKey, arguments, queue)) + { + + if(!exch.addBinding(bindingKey, queue, arguments) && ExchangeDefaults.TOPIC_EXCHANGE_CLASS.equals(exch.getType())) + { + exch.replaceBinding(bindingKey, queue, arguments); + } + } + } + catch (AccessControlException e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + e.getMessage(), + _connection.getMethodRegistry()); + } + + if (_logger.isInfoEnabled()) + { + _logger.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey); + } + if (!body.getNowait()) + { + channel.sync(); + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createQueueBindOkBody(); + _connection.writeFrame(responseBody.generateFrame(channelId)); + + } + return true; + } + + public boolean dispatchQueueDeclare(QueueDeclareBody body, int channelId) throws AMQException + { + final AMQSessionModel session = _connection.getChannel(channelId); + VirtualHostImpl virtualHost = _connection.getVirtualHost(); + + final AMQShortString queueName; + + // if we aren't given a queue name, we create one which we return to the client + if ((body.getQueue() == null) || (body.getQueue().length() == 0)) + { + queueName = new AMQShortString("tmp_" + UUID.randomUUID()); + } + else + { + queueName = body.getQueue().intern(); + } + + AMQQueue queue; + + //TODO: do we need to check that the queue already exists with exactly the same "configuration"? + + AMQChannel channel = _connection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + + if(body.getPassive()) + { + queue = virtualHost.getQueue(queueName.toString()); + if (queue == null) + { + String msg = "Queue: " + queueName + " not found on VirtualHost(" + virtualHost + ")."; + throw body.getChannelException(AMQConstant.NOT_FOUND, msg, _connection.getMethodRegistry()); + } + else + { + if (!queue.verifySessionAccess(channel)) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Queue " + + queue.getName() + + " is exclusive, but not created on this Connection.", + _connection.getMethodRegistry()); + } + + //set this as the default queue on the channel: + channel.setDefaultQueue(queue); + } + } + else + { + + try + { + + queue = createQueue(channel, queueName, body, virtualHost, _connection); + + } + catch(QueueExistsException qe) + { + + queue = qe.getExistingQueue(); + + if (!queue.verifySessionAccess(channel)) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Queue " + + queue.getName() + + " is exclusive, but not created on this Connection.", + _connection.getMethodRegistry()); + } + else if(queue.isExclusive() != body.getExclusive()) + { + + throw body.getChannelException(AMQConstant.ALREADY_EXISTS, + "Cannot re-declare queue '" + + queue.getName() + + "' with different exclusivity (was: " + + queue.isExclusive() + + " requested " + + body.getExclusive() + + ")", + _connection.getMethodRegistry()); + } + else if((body.getAutoDelete() && queue.getLifetimePolicy() != LifetimePolicy.DELETE_ON_NO_OUTBOUND_LINKS) + || (!body.getAutoDelete() && queue.getLifetimePolicy() != ((body.getExclusive() && !body.getDurable()) ? LifetimePolicy.DELETE_ON_CONNECTION_CLOSE : LifetimePolicy.PERMANENT))) + { + throw body.getChannelException(AMQConstant.ALREADY_EXISTS, + "Cannot re-declare queue '" + + queue.getName() + + "' with different lifetime policy (was: " + + queue.getLifetimePolicy() + + " requested autodelete: " + + body.getAutoDelete() + + ")", + _connection.getMethodRegistry()); + } + else if(queue.isDurable() != body.getDurable()) + { + throw body.getChannelException(AMQConstant.ALREADY_EXISTS, + "Cannot re-declare queue '" + + queue.getName() + + "' with different durability (was: " + + queue.isDurable() + + " requested " + + body.getDurable() + + ")", + _connection.getMethodRegistry()); + } + + } + catch (AccessControlException e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + e.getMessage(), + _connection.getMethodRegistry()); + } + + //set this as the default queue on the channel: + channel.setDefaultQueue(queue); + } + + if (!body.getNowait()) + { + channel.sync(); + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + QueueDeclareOkBody responseBody = + methodRegistry.createQueueDeclareOkBody(queueName, + queue.getQueueDepthMessages(), + queue.getConsumerCount()); + _connection.writeFrame(responseBody.generateFrame(channelId)); + + _logger.info("Queue " + queueName + " declared successfully"); + } + return true; + } + + protected AMQQueue createQueue(final AMQChannel channel, final AMQShortString queueName, + QueueDeclareBody body, + final VirtualHostImpl virtualHost, + final AMQProtocolSession session) + throws AMQException, QueueExistsException + { + + final boolean durable = body.getDurable(); + final boolean autoDelete = body.getAutoDelete(); + final boolean exclusive = body.getExclusive(); + + + Map<String, Object> attributes = + QueueArgumentsConverter.convertWireArgsToModel(FieldTable.convertToMap(body.getArguments())); + final String queueNameString = AMQShortString.toString(queueName); + attributes.put(Queue.NAME, queueNameString); + attributes.put(Queue.ID, UUID.randomUUID()); + attributes.put(Queue.DURABLE, durable); + + LifetimePolicy lifetimePolicy; + ExclusivityPolicy exclusivityPolicy; + + if(exclusive) + { + lifetimePolicy = autoDelete + ? LifetimePolicy.DELETE_ON_NO_OUTBOUND_LINKS + : durable ? LifetimePolicy.PERMANENT : LifetimePolicy.DELETE_ON_CONNECTION_CLOSE; + exclusivityPolicy = durable ? ExclusivityPolicy.CONTAINER : ExclusivityPolicy.CONNECTION; + } + else + { + lifetimePolicy = autoDelete ? LifetimePolicy.DELETE_ON_NO_OUTBOUND_LINKS : LifetimePolicy.PERMANENT; + exclusivityPolicy = ExclusivityPolicy.NONE; + } + + attributes.put(Queue.EXCLUSIVE, exclusivityPolicy); + attributes.put(Queue.LIFETIME_POLICY, lifetimePolicy); + + + final AMQQueue queue = virtualHost.createQueue(attributes); + + return queue; + } + + public boolean dispatchQueueDelete(QueueDeleteBody body, int channelId) throws AMQException + { + VirtualHostImpl virtualHost = _connection.getVirtualHost(); + + AMQChannel channel = _connection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + channel.sync(); + AMQQueue queue; + if (body.getQueue() == null) + { + + //get the default queue on the channel: + queue = channel.getDefaultQueue(); + } + else + { + queue = virtualHost.getQueue(body.getQueue().toString()); + } + + if (queue == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist.", + _connection.getMethodRegistry()); + + } + else + { + if (body.getIfEmpty() && !queue.isEmpty()) + { + throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is not empty.", + _connection.getMethodRegistry()); + } + else if (body.getIfUnused() && !queue.isUnused()) + { + // TODO - Error code + throw body.getChannelException(AMQConstant.IN_USE, "Queue: " + body.getQueue() + " is still used.", + _connection.getMethodRegistry()); + } + else + { + if (!queue.verifySessionAccess(channel)) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Queue " + + queue.getName() + + " is exclusive, but not created on this Connection.", + _connection.getMethodRegistry()); + } + + int purged = 0; + try + { + purged = virtualHost.removeQueue(queue); + } + catch (AccessControlException e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + e.getMessage(), + _connection.getMethodRegistry()); + } + + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + QueueDeleteOkBody responseBody = methodRegistry.createQueueDeleteOkBody(purged); + _connection.writeFrame(responseBody.generateFrame(channelId)); + } + } + return true; + } + + public boolean dispatchQueuePurge(QueuePurgeBody body, int channelId) throws AMQException + { + VirtualHostImpl virtualHost = _connection.getVirtualHost(); + + AMQChannel channel = _connection.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + AMQQueue queue; + if(body.getQueue() == null) + { + + //get the default queue on the channel: + queue = channel.getDefaultQueue(); + + if(queue == null) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "No queue specified.", + _connection.getMethodRegistry()); + } + } + else + { + queue = virtualHost.getQueue(body.getQueue().toString()); + } + + if(queue == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist.", + _connection.getMethodRegistry()); + } + else + { + if (!queue.verifySessionAccess(channel)) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Queue is exclusive, but not created on this Connection.", + _connection.getMethodRegistry()); + } + + long purged = 0; + try + { + purged = queue.clearQueue(); + } + catch (AccessControlException e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + e.getMessage(), + _connection.getMethodRegistry()); + } + + + if(!body.getNowait()) + { + channel.sync(); + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createQueuePurgeOkBody(purged); + _connection.writeFrame(responseBody.generateFrame(channelId)); + + } + } + return true; + } + + + public boolean dispatchTxCommit(TxCommitBody body, final int channelId) throws AMQException + { + try + { + if (_logger.isDebugEnabled()) + { + _logger.debug("Commit received on channel " + channelId); + } + AMQChannel channel = _connection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + channel.commit(new Runnable() + { + + @Override + public void run() + { + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + AMQMethodBody responseBody = methodRegistry.createTxCommitOkBody(); + _connection.writeFrame(responseBody.generateFrame(channelId)); + } + }, true); + + + + } + catch (AMQException e) + { + throw body.getChannelException(e.getErrorCode(), "Failed to commit: " + e.getMessage(), + _connection.getMethodRegistry()); + } + return true; + } + + public boolean dispatchTxRollback(TxRollbackBody body, final int channelId) throws AMQException + { + try + { + AMQChannel channel = _connection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + + + + final MethodRegistry methodRegistry = _connection.getMethodRegistry(); + final AMQMethodBody responseBody = methodRegistry.createTxRollbackOkBody(); + + Runnable task = new Runnable() + { + + public void run() + { + _connection.writeFrame(responseBody.generateFrame(channelId)); + } + }; + + channel.rollback(task); + + //Now resend all the unacknowledged messages back to the original subscribers. + //(Must be done after the TxnRollback-ok response). + // Why, are we not allowed to send messages back to client before the ok method? + channel.resend(); + + } + catch (AMQException e) + { + throw body.getChannelException(e.getErrorCode(), "Failed to rollback: " + e.getMessage(), + _connection.getMethodRegistry()); + } + return true; + } + + public boolean dispatchTxSelect(TxSelectBody body, int channelId) throws AMQException + { + AMQChannel channel = _connection.getChannel(channelId); + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + + channel.setLocalTransactional(); + + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + TxSelectOkBody responseBody = methodRegistry.createTxSelectOkBody(); + _connection.writeFrame(responseBody.generateFrame(channelId)); + return true; + } + + public boolean dispatchBasicRecoverSync(BasicRecoverSyncBody body, int channelId) throws AMQException + { + final AMQProtocolSession<?> connection = getConnection(); + + _logger.debug("Recover received on protocol session " + connection + " and channel " + channelId); + AMQChannel channel = connection.getChannel(channelId); + + + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, connection.getMethodRegistry()); + } + channel.sync(); + channel.resend(); + + MethodRegistry methodRegistry = connection.getMethodRegistry(); + AMQMethodBody recoverOk = methodRegistry.createBasicRecoverSyncOkBody(); + connection.writeFrame(recoverOk.generateFrame(channelId)); + + return true; + } + + public boolean dispatchBasicRecoverSyncOk(BasicRecoverSyncOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + @Override + public boolean dispatchChannelAlert(final ChannelAlertBody body, final int channelId) + throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueUnbindOk(QueueUnbindOkBody body, int channelId) throws AMQException + { + throw new UnexpectedMethodException(body); + } + + public boolean dispatchQueueUnbind(QueueUnbindBody body, int channelId) throws AMQException + { + final AMQProtocolSession<?> connection = getConnection(); + + if (ProtocolVersion.v8_0.equals(connection.getProtocolVersion())) + { + // 0-8 does not support QueueUnbind + throw new AMQException(AMQConstant.COMMAND_INVALID, "QueueUnbind not present in AMQP version: " + connection.getProtocolVersion(), null); + } + + VirtualHostImpl virtualHost = connection.getVirtualHost(); + + final AMQQueue queue; + final AMQShortString routingKey; + + + AMQChannel channel = connection.getChannel(channelId); + if (channel == null) + { + throw body.getChannelNotFoundException(channelId, connection.getMethodRegistry()); + } + + if (body.getQueue() == null) + { + + queue = channel.getDefaultQueue(); + + if (queue == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, + "No default queue defined on channel and queue was null", + connection.getMethodRegistry()); + } + + routingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().intern(false); + + } + else + { + queue = virtualHost.getQueue(body.getQueue().toString()); + routingKey = body.getRoutingKey() == null ? null : body.getRoutingKey().intern(false); + } + + if (queue == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Queue " + body.getQueue() + " does not exist.", + connection.getMethodRegistry()); + } + + if(isDefaultExchange(body.getExchange())) + { + throw body.getConnectionException(AMQConstant.NOT_ALLOWED, + "Cannot unbind the queue " + + queue.getName() + + " from the default exchange", connection.getMethodRegistry()); + } + + final ExchangeImpl exch = virtualHost.getExchange(body.getExchange() == null ? null : body.getExchange().toString()); + if (exch == null) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "Exchange " + body.getExchange() + " does not exist.", + connection.getMethodRegistry()); + } + + if(!exch.hasBinding(String.valueOf(routingKey), queue)) + { + throw body.getChannelException(AMQConstant.NOT_FOUND, "No such binding", connection.getMethodRegistry()); + } + else + { + try + { + exch.deleteBinding(String.valueOf(routingKey), queue); + } + catch (AccessControlException e) + { + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + e.getMessage(), + connection.getMethodRegistry()); + } + } + + + if (_logger.isInfoEnabled()) + { + _logger.info("Binding queue " + queue + " to exchange " + exch + " with routing key " + routingKey); + } + + + final AMQMethodBody responseBody = connection.getMethodRegistry().createQueueUnbindOkBody(); + channel.sync(); + connection.writeFrame(responseBody.generateFrame(channelId)); + return true; + } + +} diff --git a/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ServerMethodProcessor.java b/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ServerMethodProcessor.java new file mode 100644 index 0000000000..40e1af10c6 --- /dev/null +++ b/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ServerMethodProcessor.java @@ -0,0 +1,957 @@ +/* + * + * 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.protocol.v0_8; + +import java.security.PrivilegedAction; + +import javax.security.auth.Subject; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.log4j.Logger; + +import org.apache.qpid.framing.*; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.security.SubjectCreator; +import org.apache.qpid.server.security.auth.SubjectAuthenticationResult; + +public class ServerMethodProcessor implements MethodProcessor +{ + private static final Logger LOGGER = Logger.getLogger(ServerMethodProcessor.class); + + + private static interface ChannelAction + { + void onChannel(ChannelMethodProcessor channel); + } + + private ProtocolVersion _protocolVersion; + private ServerMethodDispatcherImpl _dispatcher; + private AMQProtocolEngine _connection; + + public ServerMethodProcessor(final ProtocolVersion protocolVersion) + { + _protocolVersion = protocolVersion; + } + + + private void processChannelMethod(int channelId, final ChannelAction action) + { + final AMQChannel channel = _connection.getChannel(channelId); + if (channel == null) + { + // TODO throw body.getChannelNotFoundException(channelId, _connection.getMethodRegistry()); + } + else + { + Subject.doAs(channel.getSubject(), new PrivilegedAction<Void>() + { + @Override + public Void run() + { + action.onChannel(channel.getMethodProcessor()); + return null; + } + }); + } + + } + + @Override + public void receiveConnectionStart(final short versionMajor, + final short versionMinor, + final FieldTable serverProperties, + final byte[] mechanisms, + final byte[] locales) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, + new ConnectionStartBody(versionMajor, + versionMinor, + serverProperties, + mechanisms, + locales)); + } + _connection.closeConnection(AMQConstant.COMMAND_INVALID, "Unexpected method received: ConnectionStart", 0, + ConnectionStartBody.CLASS_ID, ConnectionStartBody.METHOD_ID); + + } + + @Override + public void receiveConnectionStartOk(final FieldTable clientProperties, + final AMQShortString mechanism, + final byte[] response, + final AMQShortString locale) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, new ConnectionStartOkBody(clientProperties, mechanism, response, locale)); + } + + Broker<?> broker = _connection.getBroker(); + + SubjectCreator subjectCreator = _connection.getSubjectCreator(); + SaslServer ss = null; + try + { + ss = subjectCreator.createSaslServer(String.valueOf(mechanism), + _connection.getLocalFQDN(), + _connection.getPeerPrincipal()); + + if (ss == null) + { + _connection.closeConnection(AMQConstant.RESOURCE_ERROR, + "Unable to create SASL Server:" + mechanism, 0, + ConnectionStartOkBody.CLASS_ID, + ConnectionStartOkBody.METHOD_ID); + } + else + { + _connection.setSaslServer(ss); + + final SubjectAuthenticationResult authResult = subjectCreator.authenticate(ss, response); + //save clientProperties + _connection.setClientProperties(clientProperties); + + MethodRegistry methodRegistry = _connection.getMethodRegistry(); + + switch (authResult.getStatus()) + { + case ERROR: + Exception cause = authResult.getCause(); + + LOGGER.info("Authentication failed:" + (cause == null ? "" : cause.getMessage())); + + _connection.closeConnection(AMQConstant.NOT_ALLOWED, + AMQConstant.NOT_ALLOWED.getName().toString(), 0, + ConnectionStartOkBody.CLASS_ID, + ConnectionStartOkBody.METHOD_ID); + + disposeSaslServer(); + break; + + case SUCCESS: + if (LOGGER.isInfoEnabled()) + { + LOGGER.info("Connected as: " + authResult.getSubject()); + } + _connection.setAuthorizedSubject(authResult.getSubject()); + + int frameMax = broker.getContextValue(Integer.class, Broker.BROKER_FRAME_SIZE); + + if (frameMax <= 0) + { + frameMax = Integer.MAX_VALUE; + } + + ConnectionTuneBody + tuneBody = + methodRegistry.createConnectionTuneBody(broker.getConnection_sessionCountLimit(), + frameMax, + broker.getConnection_heartBeatDelay()); + _connection.writeFrame(tuneBody.generateFrame(0)); + break; + case CONTINUE: + ConnectionSecureBody + secureBody = methodRegistry.createConnectionSecureBody(authResult.getChallenge()); + _connection.writeFrame(secureBody.generateFrame(0)); + } + } + } + catch (SaslException e) + { + disposeSaslServer(); + + _connection.closeConnection(AMQConstant.RESOURCE_ERROR, "SASL error: " + e.getMessage(), 0, + ConnectionStartOkBody.CLASS_ID, ConnectionStartOkBody.METHOD_ID); + } + + } + + @Override + public void receiveTxSelect(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, TxSelectBody.INSTANCE); + } + + } + + @Override + public void receiveTxSelectOk(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, TxSelectOkBody.INSTANCE); + } + + } + + @Override + public void receiveTxCommit(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, TxCommitBody.INSTANCE); + } + + } + + @Override + public void receiveTxCommitOk(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, TxCommitOkBody.INSTANCE); + } + + } + + @Override + public void receiveTxRollback(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, TxRollbackBody.INSTANCE); + } + + } + + @Override + public void receiveTxRollbackOk(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, TxRollbackOkBody.INSTANCE); + } + + } + + @Override + public void receiveConnectionSecure(final byte[] challenge) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, new ConnectionSecureBody(challenge)); + } + + } + + @Override + public void receiveConnectionSecureOk(final byte[] response) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, new ConnectionSecureOkBody(response)); + } + + } + + @Override + public void receiveConnectionTune(final int channelMax, final long frameMax, final int heartbeat) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, new ConnectionTuneBody(channelMax, frameMax, heartbeat)); + } + + } + + @Override + public void receiveConnectionTuneOk(final int channelMax, final long frameMax, final int heartbeat) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, new ConnectionTuneOkBody(channelMax, frameMax, heartbeat)); + } + + } + + @Override + public void receiveConnectionOpen(final AMQShortString virtualHost, + final AMQShortString capabilities, + final boolean insist) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, new ConnectionOpenBody(virtualHost, capabilities, insist)); + } + + } + + @Override + public void receiveConnectionOpenOk(final AMQShortString knownHosts) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, new ConnectionOpenOkBody(knownHosts)); + } + + } + + @Override + public void receiveConnectionRedirect(final AMQShortString host, final AMQShortString knownHosts) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, new ConnectionRedirectBody(getProtocolVersion(), host, knownHosts)); + } + + } + + @Override + public void receiveConnectionClose(final int replyCode, + final AMQShortString replyText, + final int classId, + final int methodId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, + new ConnectionCloseBody(getProtocolVersion(), + replyCode, + replyText, + classId, + methodId)); + } + + } + + @Override + public void receiveConnectionCloseOk() + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, ProtocolVersion.v8_0.equals(getProtocolVersion()) + ? ConnectionCloseOkBody.CONNECTION_CLOSE_OK_0_8 + : ConnectionCloseOkBody.CONNECTION_CLOSE_OK_0_9); + } + } + + @Override + public void receiveChannelOpen(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ChannelOpenBody()); + } + + } + + @Override + public void receiveChannelOpenOk(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, ProtocolVersion.v8_0.equals(getProtocolVersion()) + ? ChannelOpenOkBody.INSTANCE_0_8 + : ChannelOpenOkBody.INSTANCE_0_9); + } + } + + @Override + public void receiveChannelFlow(final int channelId, final boolean active) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ChannelFlowBody(active)); + } + + } + + @Override + public void receiveChannelFlowOk(final int channelId, final boolean active) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ChannelFlowOkBody(active)); + } + + } + + @Override + public void receiveChannelAlert(final int channelId, + final int replyCode, + final AMQShortString replyText, + final FieldTable details) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ChannelAlertBody(replyCode, replyText, details)); + } + + } + + @Override + public void receiveChannelClose(final int channelId, + final int replyCode, + final AMQShortString replyText, + final int classId, + final int methodId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ChannelCloseBody(replyCode, replyText, classId, methodId)); + } + + } + + @Override + public void receiveChannelCloseOk(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, ChannelCloseOkBody.INSTANCE); + } + + } + + @Override + public void receiveAccessRequest(final int channelId, + final AMQShortString realm, + final boolean exclusive, + final boolean passive, + final boolean active, + final boolean write, + final boolean read) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = + new AMQFrame(channelId, new AccessRequestBody(realm, exclusive, passive, active, write, read)); + } + + } + + @Override + public void receiveAccessRequestOk(final int channelId, final int ticket) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new AccessRequestOkBody(ticket)); + } + + } + + @Override + public void receiveExchangeDeclare(final int channelId, + final AMQShortString exchange, + final AMQShortString type, + final boolean passive, + final boolean durable, + final boolean autoDelete, + final boolean internal, + final boolean nowait, final FieldTable arguments) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, + new ExchangeDeclareBody(0, + exchange, + type, + passive, + durable, + autoDelete, + internal, + nowait, + arguments)); + } + + } + + @Override + public void receiveExchangeDeclareOk(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ExchangeDeclareOkBody()); + } + + } + + @Override + public void receiveExchangeDelete(final int channelId, + final AMQShortString exchange, + final boolean ifUnused, + final boolean nowait) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ExchangeDeleteBody(0, exchange, ifUnused, nowait)); + } + + } + + @Override + public void receiveExchangeDeleteOk(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ExchangeDeleteOkBody()); + } + + } + + @Override + public void receiveExchangeBound(final int channelId, + final AMQShortString exchange, + final AMQShortString routingKey, + final AMQShortString queue) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ExchangeBoundBody(exchange, routingKey, queue)); + } + + } + + @Override + public void receiveExchangeBoundOk(final int channelId, final int replyCode, final AMQShortString replyText) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ExchangeBoundOkBody(replyCode, replyText)); + } + + } + + @Override + public void receiveQueueBindOk(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new QueueBindOkBody()); + } + + } + + @Override + public void receiveQueueUnbindOk(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new QueueUnbindOkBody()); + } + + } + + @Override + public void receiveQueueDeclare(final int channelId, + final AMQShortString queue, + final boolean passive, + final boolean durable, + final boolean exclusive, + final boolean autoDelete, + final boolean nowait, + final FieldTable arguments) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, + new QueueDeclareBody(0, + queue, + passive, + durable, + exclusive, + autoDelete, + nowait, + arguments)); + } + + } + + @Override + public void receiveQueueDeclareOk(final int channelId, + final AMQShortString queue, + final long messageCount, + final long consumerCount) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new QueueDeclareOkBody(queue, messageCount, consumerCount)); + } + + } + + @Override + public void receiveQueueBind(final int channelId, + final AMQShortString queue, + final AMQShortString exchange, + final AMQShortString bindingKey, + final boolean nowait, + final FieldTable arguments) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = + new AMQFrame(channelId, new QueueBindBody(0, queue, exchange, bindingKey, nowait, arguments)); + } + + } + + @Override + public void receiveQueuePurge(final int channelId, final AMQShortString queue, final boolean nowait) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new QueuePurgeBody(0, queue, nowait)); + } + + } + + @Override + public void receiveQueuePurgeOk(final int channelId, final long messageCount) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new QueuePurgeOkBody(messageCount)); + } + + } + + @Override + public void receiveQueueDelete(final int channelId, + final AMQShortString queue, + final boolean ifUnused, + final boolean ifEmpty, + final boolean nowait) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new QueueDeleteBody(0, queue, ifUnused, ifEmpty, nowait)); + } + + } + + @Override + public void receiveQueueDeleteOk(final int channelId, final long messageCount) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new QueueDeleteOkBody(messageCount)); + } + + } + + @Override + public void receiveQueueUnbind(final int channelId, + final AMQShortString queue, + final AMQShortString exchange, + final AMQShortString bindingKey, + final FieldTable arguments) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new QueueUnbindBody(0, queue, exchange, bindingKey, arguments)); + } + + } + + @Override + public void receiveBasicRecoverSyncOk(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicRecoverSyncOkBody(getProtocolVersion())); + } + + } + + @Override + public void receiveBasicRecover(final int channelId, final boolean requeue, final boolean sync) + { + if (ProtocolVersion.v8_0.equals(getProtocolVersion()) || !sync) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicRecoverBody(requeue)); + } + + } + else + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicRecoverSyncBody(getProtocolVersion(), requeue)); + } + + } + } + + @Override + public void receiveBasicQos(final int channelId, + final long prefetchSize, + final int prefetchCount, + final boolean global) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicQosBody(prefetchSize, prefetchCount, global)); + } + + } + + @Override + public void receiveBasicQosOk(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicQosOkBody()); + } + + } + + @Override + public void receiveBasicConsume(final int channelId, + final AMQShortString queue, + final AMQShortString consumerTag, + final boolean noLocal, + final boolean noAck, + final boolean exclusive, + final boolean nowait, + final FieldTable arguments) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, + new BasicConsumeBody(0, + queue, + consumerTag, + noLocal, + noAck, + exclusive, + nowait, + arguments)); + } + + } + + @Override + public void receiveBasicConsumeOk(final int channelId, final AMQShortString consumerTag) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicConsumeOkBody(consumerTag)); + } + + } + + @Override + public void receiveBasicCancel(final int channelId, final AMQShortString consumerTag, final boolean noWait) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicCancelBody(consumerTag, noWait)); + } + + } + + @Override + public void receiveBasicCancelOk(final int channelId, final AMQShortString consumerTag) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicCancelOkBody(consumerTag)); + } + + } + + @Override + public void receiveBasicPublish(final int channelId, + final AMQShortString exchange, + final AMQShortString routingKey, + final boolean mandatory, + final boolean immediate) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = + new AMQFrame(channelId, new BasicPublishBody(0, exchange, routingKey, mandatory, immediate)); + } + + } + + @Override + public void receiveBasicReturn(final int channelId, final int replyCode, + final AMQShortString replyText, + final AMQShortString exchange, + final AMQShortString routingKey) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicReturnBody(replyCode, replyText, exchange, routingKey)); + } + + } + + @Override + public void receiveBasicDeliver(final int channelId, + final AMQShortString consumerTag, + final long deliveryTag, + final boolean redelivered, + final AMQShortString exchange, + final AMQShortString routingKey) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, + new BasicDeliverBody(consumerTag, + deliveryTag, + redelivered, + exchange, + routingKey)); + } + + } + + @Override + public void receiveBasicGet(final int channelId, final AMQShortString queue, final boolean noAck) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicGetBody(0, queue, noAck)); + } + + } + + @Override + public void receiveBasicGetOk(final int channelId, + final long deliveryTag, + final boolean redelivered, + final AMQShortString exchange, + final AMQShortString routingKey, + final long messageCount) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, + new BasicGetOkBody(deliveryTag, + redelivered, + exchange, + routingKey, + messageCount)); + } + + } + + @Override + public void receiveBasicGetEmpty(final int channelId) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicGetEmptyBody((AMQShortString) null)); + } + + } + + @Override + public void receiveBasicAck(final int channelId, final long deliveryTag, final boolean multiple) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicAckBody(deliveryTag, multiple)); + } + + } + + @Override + public void receiveBasicReject(final int channelId, final long deliveryTag, final boolean requeue) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new BasicRejectBody(deliveryTag, requeue)); + } + + } + + @Override + public void receiveHeartbeat() + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(0, new HeartbeatBody()); + } + + } + + @Override + public ProtocolVersion getProtocolVersion() + { + return _protocolVersion; + } + + public void setProtocolVersion(final ProtocolVersion protocolVersion) + { + _protocolVersion = protocolVersion; + } + + @Override + public void receiveMessageContent(final int channelId, final byte[] data) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ContentBody(data)); + } + + } + + @Override + public void receiveMessageHeader(final int channelId, + final BasicContentHeaderProperties properties, + final long bodySize) + { + if (LOGGER.isDebugEnabled()) + { + AMQFrame frame = new AMQFrame(channelId, new ContentHeaderBody(properties, bodySize)); + } + + } + + @Override + public void receiveProtocolHeader(final ProtocolInitiation protocolInitiation) + { + if (LOGGER.isDebugEnabled()) + { + AMQDataBlock frame = protocolInitiation; + } + + } + + private void disposeSaslServer() + { + SaslServer ss = _connection.getSaslServer(); + if (ss != null) + { + _connection.setSaslServer(null); + try + { + ss.dispose(); + } + catch (SaslException e) + { + LOGGER.error("Error disposing of Sasl server: " + e); + } + } + } +} diff --git a/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/store/derby/DerbySystemConfigImpl.java b/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/store/derby/DerbySystemConfigImpl.java index 32c5bcd541..a8b9edaa12 100644 --- a/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/store/derby/DerbySystemConfigImpl.java +++ b/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/store/derby/DerbySystemConfigImpl.java @@ -26,6 +26,7 @@ import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.LogRecorder; import org.apache.qpid.server.model.AbstractSystemConfig; import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerShutdownProvider; import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.SystemConfigFactoryConstructor; @@ -47,9 +48,10 @@ public class DerbySystemConfigImpl extends AbstractSystemConfig<DerbySystemConfi public DerbySystemConfigImpl(final TaskExecutor taskExecutor, final EventLogger eventLogger, final LogRecorder logRecorder, - final BrokerOptions brokerOptions) + final BrokerOptions brokerOptions, + final BrokerShutdownProvider brokerShutdownProvider) { - super(taskExecutor, eventLogger, logRecorder, brokerOptions); + super(taskExecutor, eventLogger, logRecorder, brokerOptions, brokerShutdownProvider); } @Override diff --git a/java/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSystemConfigImpl.java b/java/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSystemConfigImpl.java index fd1cad7de4..a552b170a0 100644 --- a/java/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSystemConfigImpl.java +++ b/java/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSystemConfigImpl.java @@ -26,6 +26,7 @@ import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.LogRecorder; import org.apache.qpid.server.model.AbstractSystemConfig; import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerShutdownProvider; import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.SystemConfigFactoryConstructor; @@ -49,9 +50,10 @@ public class JDBCSystemConfigImpl extends AbstractSystemConfig<JDBCSystemConfigI public JDBCSystemConfigImpl(final TaskExecutor taskExecutor, final EventLogger eventLogger, final LogRecorder logRecorder, - final BrokerOptions brokerOptions) + final BrokerOptions brokerOptions, + final BrokerShutdownProvider brokerShutdownProvider) { - super(taskExecutor, eventLogger, logRecorder, brokerOptions); + super(taskExecutor, eventLogger, logRecorder, brokerOptions, brokerShutdownProvider); } @Override diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java index e07705656a..936cc4789a 100644 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java @@ -122,7 +122,7 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem super(attributes, broker); } - @StateTransition(currentState = State.UNINITIALIZED, desiredState = State.ACTIVE) + @StateTransition(currentState = {State.UNINITIALIZED,State.ERRORED}, desiredState = State.ACTIVE) private void doStart() { getBroker().getEventLogger().message(ManagementConsoleMessages.STARTUP(OPERATIONAL_LOGGING_NAME)); diff --git a/java/broker-plugins/management-http/src/main/java/resources/addQueue.html b/java/broker-plugins/management-http/src/main/java/resources/addQueue.html index 352e69893b..042d6d7ad7 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/addQueue.html +++ b/java/broker-plugins/management-http/src/main/java/resources/addQueue.html @@ -39,19 +39,75 @@ <div class="clear"> <div class="formLabel-labelCell">Queue Type:</div> <div class="formLabel-controlCell"> - <input type="radio" id="formAddQueueTypeStandard" name="type" value="standard" checked="checked" dojoType="dijit.form.RadioButton" /> - <label for="formAddQueueTypeStandard">Standard</label> - - <input type="radio" id="formAddQueueTypePriority" name="type" value="priority" dojoType="dijit.form.RadioButton" /> - <label for="formAddQueueTypePriority">Priority</label> - - <input type="radio" id="formAddQueueTypeLVQ" name="type" value="lvq" dojoType="dijit.form.RadioButton" /> - <label for="formAddQueueTypeLVQ">LVQ</label> - - <input type="radio" id="formAddQueueTypeSorted" name="type" value="sorted" dojoType="dijit.form.RadioButton" /> - <label for="formAddQueueTypeSorted">Sorted</label> + <select id="formAddQueue.type" + dojoType="dijit.form.FilteringSelect" + data-dojo-props=" + name: 'type', + value: 'standard', + searchAttr: 'name', + required: true, + promptMessage: 'Type of Queue', + title: 'Enter the queue type'"> + <option value="standard">Standard</option> + <option value="priority">Priority</option> + <option value="lvq">LVQ</option> + <option value="sorted">Sorted</option> + </select> + </div> + </div> + <div class="clear"></div> + + <div id="formAddQueueType:priority" class="hidden typeSpecificDiv"> + <div class="clear"> + <div class="formLabel-labelCell">Priorities:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.priorities" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'priorities', + placeHolder: 'number of priorities', + promptMessage: 'Number of priorities supported by the queue', + title: 'Enter the number of priorities supported by the queue', + trim: true"/> + </div> + </div> + <div class="clear"></div> + </div> + + <div id="formAddQueueType:lvq" class="hidden typeSpecificDiv"> + <div class="clear"> + <div class="formLabel-labelCell">LVQ Message Property:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.lvqKey" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'lvqKey', + placeHolder: 'lvq key', + promptMessage: 'Name of the message property used to perform the conflation', + title: 'Enter the name of the message property used to perform the conflation', + trim: true"/> + </div> + </div> + <div class="clear"></div> + </div> + + <div id="formAddQueueType:sorted" class="hidden typeSpecificDiv"> + <div class="clear"> + <div class="formLabel-labelCell">Sort Message Property*:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.sortKey" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'sortKey', + placeHolder: 'sort key', + promptMessage: 'Name of the message property used for sorting the messages on the queue', + title: 'Enter the name of the message property used for sorting the messages on the queue', + trim: true"/> + </div> </div> + <div class="clear"></div> </div> + <div class="clear"> <div class="formLabel-labelCell">Durable?</div> <div class="formLabel-controlCell"> @@ -73,8 +129,8 @@ value: '', searchAttr: 'name', required: false, - promptMessage: 'Message durability override. If not default, messages arriving will have durability setting overridden', - title: 'Enter message durability override'"> + promptMessage: 'Message persistence override. If not default, messages arriving will have persistence setting overridden', + title: 'Enter message persistence override'"> <option value="ALWAYS">Always</option> <option value="DEFAULT">Default</option> <option value="NEVER">Never</option> @@ -108,66 +164,9 @@ </div> </div> - <br/> - <div class="clear"></div> - - - <div id="formAddQueueTypePriority:fields" class="hidden" - data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Priority Queue Settings'"> - <div class="clear"> - <div class="formLabel-labelCell">Priorities:</div> - <div class="formLabel-controlCell"> - <input type="text" id="formAddQueue.priorities" - data-dojo-type="dijit/form/ValidationTextBox" - data-dojo-props=" - name: 'priorities', - placeHolder: 'number of priorities', - promptMessage: 'Number of priorities supported by the queue', - title: 'Enter the number of priorities supported by the queue', - trim: true"/> - </div> - </div> - <div class="clear"></div> - </div> - - <div id="formAddQueueTypeLVQ:fields" class="hidden" - data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Last Value Queue Settings'"> - <div class="clear"> - <div class="formLabel-labelCell">LVQ Message Property:</div> - <div class="formLabel-controlCell"> - <input type="text" id="formAddQueue.lvqkey" - data-dojo-type="dijit/form/ValidationTextBox" - data-dojo-props=" - name: 'lvqKey', - placeHolder: 'lvq key', - promptMessage: 'Name of the message property used to perform the conflation', - title: 'Enter the name of the message property used to perform the conflation', - trim: true"/> - </div> - </div> - <div class="clear"></div> - </div> - - <div id="formAddQueueTypeSorted:fields" class="hidden" - data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Sorted Queue Settings'"> - <div class="clear"> - <div class="formLabel-labelCell">Sort Message Property*:</div> - <div class="formLabel-controlCell"> - <input type="text" id="formAddQueue.sortkey" - data-dojo-type="dijit/form/ValidationTextBox" - data-dojo-props=" - name: 'sortKey', - placeHolder: 'sort key', - promptMessage: 'Name of the message property used for sorting the messages on the queue', - title: 'Enter the name of the message property used for sorting the messages on the queue', - trim: true"/> - </div> - </div> - <div class="clear"></div> - </div> - - <br/> - <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Flow Control Settings', open: false"> + <div class="clear formBox"> + <fieldset> + <legend>Flow Control Settings</legend> <div class="clear"> <div class="formLabel-labelCell">Capacity:</div> <div class="formLabel-controlCell"> @@ -194,11 +193,13 @@ trim: true"/> </div> </div> + </fieldset> <div class="clear"></div> </div> - <br/> - <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Alerting Settings', open: false"> + <div class="clear formBox"> + <fieldset> + <legend>Alerting Settings</legend> <div class="clear"> <div class="formLabel-labelCell">Queue Depth:</div> <div class="formLabel-controlCell"> @@ -264,11 +265,13 @@ trim: true"/> </div> </div> + </fieldset> <div class="clear"></div> </div> - <br/> - <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Other Settings', open: false"> + <div class="clear formBox"> + <fieldset> + <legend>Other Settings</legend> <div class="clear"> <div class="formLabel-labelCell">Maximum Delivery Retries:</div> <div class="formLabel-controlCell"> @@ -323,9 +326,14 @@ title: 'Controls where a shared groups feature is enabled'"/> </div> </div> + </fieldset> <div class="clear"></div> </div> + <div class="clear" data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'Context variables', open: false"> + <div id="formAddQueue.context" ></div> + </div> + <div class="dijitDialogPaneActionBar"> <!-- submit buttons --> <input type="submit" value="Create Queue" label="Create Queue" dojoType="dijit.form.Button" /> diff --git a/java/broker-plugins/management-http/src/main/java/resources/css/common.css b/java/broker-plugins/management-http/src/main/java/resources/css/common.css index 7c8ca2e644..d04117b266 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/css/common.css +++ b/java/broker-plugins/management-http/src/main/java/resources/css/common.css @@ -262,7 +262,6 @@ div .messages { /* Required to keep queue type radio buttons on one line when dialog adds scrollbar */ #addQueue { - max-height: 350px; overflow: auto; width: 630px; } @@ -305,4 +304,4 @@ div .messages { width:100%; max-height: 140px; overflow: auto; -}
\ No newline at end of file +} diff --git a/java/broker-plugins/management-http/src/main/java/resources/editQueue.html b/java/broker-plugins/management-http/src/main/java/resources/editQueue.html new file mode 100644 index 0000000000..aff2b5dfa5 --- /dev/null +++ b/java/broker-plugins/management-http/src/main/java/resources/editQueue.html @@ -0,0 +1,300 @@ +<!-- + ~ 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. + --> +<div class="dijitHidden"> + <div data-dojo-type="dijit.Dialog" data-dojo-props="title:'Edit Queue'" id="editQueue"> + <form id="formEditQueue" method="post" dojoType="dijit.form.Form"> + <div id="formEditQueue.allFields"> + <div id="formEditQueue.contentPane"> + <div class="editNoteBanner">NOTE: All changes will only take effect after Virtual Host restart.</div> + <div class="clear"> + <div class="formLabel-labelCell">Queue Name:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.name" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'name', + placeHolder: 'queue name', + required: true, + promptMessage: 'Name of queue', + disabled: 'true'"/> + </div> + </div> + + <div class="clear"> + <div class="formLabel-labelCell">Queue Type:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.type" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'type', + placeHolder: 'queue type', + required: true, + promptMessage: 'Type of queue', + disabled: 'true'"/> + </div> + </div> + <div class="clear"></div> + + <div id="formEditQueueType:priority" class="hidden typeSpecificDiv"> + <div class="clear"> + <div class="formLabel-labelCell">Priorities:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.priorities" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'priorities', + disabled: 'true', + promptMessage: 'Number of priorities supported by the queue', + title: 'Enter the number of priorities supported by the queue', + trim: true"/> + </div> + </div> + <div class="clear"></div> + </div> + + <div id="formEditQueueType:lvq" class="hidden typeSpecificDiv"> + <div class="clear"> + <div class="formLabel-labelCell">LVQ Message Property:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.lvqKey" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'lvqKey', + disabled: 'true', + promptMessage: 'Name of the message property used to perform the conflation', + title: 'Enter the name of the message property used to perform the conflation', + trim: true"/> + </div> + </div> + <div class="clear"></div> + </div> + + <div id="formEditQueueType:sorted" class="hidden typeSpecificDiv"> + <div class="clear"> + <div class="formLabel-labelCell">Sort Message Property*:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.sortKey" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'sortKey', + disabled: 'true', + promptMessage: 'Name of the message property used for sorting the messages on the queue', + title: 'Enter the name of the message property used for sorting the messages on the queue', + trim: true"/> + </div> + </div> + <div class="clear"></div> + </div> + + <div class="clear"> + <div class="formLabel-labelCell">Durable?</div> + <div class="formLabel-controlCell"> + <input type="checkbox" id="formEditQueue.durable" + dojoType="dijit.form.CheckBox" + data-dojo-props=" + name: 'durable', + value: 'durable', + disabled: 'true'"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Persist Messages?</div> + <div class="formLabel-controlCell"> + <select id="formEditQueue.messageDurability" + dojoType="dijit.form.FilteringSelect" + data-dojo-props=" + name: 'messageDurability', + value: '', + searchAttr: 'name', + required: false, + promptMessage: 'Message persistence override. If not default, messages arriving will have persistence setting overridden', + title: 'Enter message persistence override'"> + <option value="ALWAYS">Always</option> + <option value="DEFAULT">Default</option> + <option value="NEVER">Never</option> + </select> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Maximum Ttl:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.maximumMessageTtl" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'maximumMessageTtl', + placeHolder: 'ttl in ms', + promptMessage: 'Maximum message time to live (ttl) in ms. Messages arriving with larger ttl values will be overridden by this value', + title: 'Enter the maximum message time to live in milliseconds', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Minimum Ttl:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.minimumMessageTtl" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'minimumMessageTtl', + placeHolder: 'ttl in ms', + promptMessage: 'Minimum message time to live (ttl) in ms. Messages arriving with smaller ttl values will be overridden by this value', + title: 'Enter the minimum message time to live in milliseconds', + trim: true"/> + </div> + </div> + + <div class="clear"></div> + + <div class="clear formBox"> + <fieldset> + <legend>Flow Control Settings</legend> + <div class="clear"> + <div class="formLabel-labelCell">Capacity:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.queueFlowControlSizeBytes" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'queueFlowControlSizeBytes', + placeHolder: 'size in bytes', + promptMessage: 'Ceiling (in bytes) at which queue will begin to throttle sessions producing messages', + title: 'Enter the ceiling (in bytes) at which queue will begin to throttle sessions producing messages', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Resume Capacity:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.queueFlowResumeSizeBytes" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'queueFlowResumeSizeBytes', + placeHolder: 'size in bytes', + promptMessage: 'Floor (in bytes) at which queue will cease to throttle sessions producing messages', + title: 'Enter the floor (in bytes) at which queue will cease to throttle sessions producing messages', + trim: true"/> + </div> + </div> + </fieldset> + <div class="clear"></div> + </div> + + <div class="clear formBox"> + <fieldset> + <legend>Alerting Settings</legend> + <div class="clear"> + <div class="formLabel-labelCell">Queue Depth:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.alertThresholdQueueDepthMessages" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'alertThresholdQueueDepthMessages', + placeHolder: 'number of messages', + promptMessage: 'Ceiling value for number of messages on queue before alerts will be generated', + title: 'Enter the ceiling value for number of messages on queue before alerts will be generated', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Queue Depth:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.alertThresholdQueueDepthBytes" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'alertThresholdQueueDepthBytes', + placeHolder: 'total message size in bytes', + promptMessage: 'Ceiling value (in bytes) for total size of all messages on the queue before alerts will be generated', + title: 'Enter the ceiling value (in bytes) for total size of all messages on the queue before alerts will be generated', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Message Age:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.alertThresholdMessageAge" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'alertThresholdMessageAge', + placeHolder: 'time in ms', + promptMessage: 'Message age (in milliseconds) above which alerts will be generated', + title: 'Enter the message age (in milliseconds) above which alerts will be generated', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Message Size:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.alertThresholdMessageSize" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'alertThresholdMessageSize', + placeHolder: 'message size in bytes', + promptMessage: 'Message size (in bytes) above which alerts will be generated', + title: 'Enter the message size (in bytes) above which alerts will be generated', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Gap between alerts:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.alertRepeatGap" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'alertRepeatGap', + placeHolder: 'time in ms', + promptMessage: 'Minimum time (in milliseconds) between each alert', + title: 'Enter the minimum time (in milliseconds) between each alert.', + trim: true"/> + </div> + </div> + </fieldset> + <div class="clear"></div> + </div> + + <div class="clear formBox"> + <fieldset> + <legend>Other Settings</legend> + <div class="clear"> + <div class="formLabel-labelCell">Maximum Delivery Retries:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formEditQueue.maximumDeliveryAttempts" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'maximumDeliveryAttempts', + placeHolder: 'number of retries', + promptMessage: 'Maximum number of delivery attempts before the message will be sent to the alternate exchange', + title: 'Enter the maximum number of delivery attempts before the message will be sent to the alternate exchange', + trim: true"/> + </div> + </div> + </fieldset> + <div class="clear"></div> + </div> + + <div data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'Context variables', open: false"> + <div id="formEditQueue.context" ></div> + </div> + </div> + <div class="dijitDialogPaneActionBar"> + <button data-dojo-type="dijit/form/Button" id="formEditQueue.saveButton" data-dojo-props="label: 'Save'">Save</button> + <button data-dojo-type="dijit/form/Button" id="formEditQueue.cancelButton" data-dojo-props="label: 'Cancel'" ></button> + </div> + </div> + + </form> + </div> +</div> diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ContextVariablesEditor.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ContextVariablesEditor.js index e5d341de91..a3e4023273 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ContextVariablesEditor.js +++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ContextVariablesEditor.js @@ -77,8 +77,8 @@ function (util, xhr, declare, array, connect, lang, domConstruct, parser, query, var addButton = registry.byNode(addButtonNode); var deleteButton = registry.byNode(deleteButtonNode); var layout = [[ - { name: "Name", field: "name", width: "40%", editable: true, selectOnClick: false, type: dojox.grid.cells._Widget, widgetClass: dijit.form.TextBox }, - { name: 'Actual Value', field: 'actualValue', width: '30%', editable: true, selectOnClick: false, type: dojox.grid.cells._Widget, widgetClass: dijit.form.TextBox}, + { name: "Name", field: "name", width: "40%", editable: true}, + { name: 'Actual Value', field: 'actualValue', width: '30%', editable: true}, { name: 'Effective Value', field: 'effectiveValue', width: '30%', editable: false} ]]; var data = []; @@ -177,6 +177,38 @@ function (util, xhr, declare, array, connect, lang, domConstruct, parser, query, } this.setData(actualValues, allEffectiveValues, inheritedActualValues); }, + loadInheritedData: function(restUrl) + { + var allEffectiveValues = null; + xhr.get( + { + url: restUrl, + sync: true, + content: { actuals: false }, + handleAs: "json", + load: function(data) + { + allEffectiveValues = data[0].context; + } + } + ); + + var inheritedActualValues = null; + xhr.get( + { + url: restUrl, + sync: true, + content: { actuals: true, inheritedActuals: true}, + handleAs: "json", + load: function(data) + { + inheritedActualValues = data[0].context; + } + } + ); + + this.setData({}, allEffectiveValues, inheritedActualValues); + }, setData: function(actualValues, allEffectiveValues, inheritedActualValues) { this.value = actualValues; @@ -523,4 +555,4 @@ function (util, xhr, declare, array, connect, lang, domConstruct, parser, query, } }); -});
\ No newline at end of file +}); diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js index b4ef7b4403..5b441a7b2f 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js +++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Queue.js @@ -34,6 +34,7 @@ define(["dojo/_base/xhr", "qpid/management/moveCopyMessages", "qpid/management/showMessage", "qpid/management/UserPreferences", + "qpid/management/editQueue", "dojo/store/JsonRest", "dojox/grid/EnhancedGrid", "dojo/data/ObjectStore", @@ -42,7 +43,7 @@ define(["dojo/_base/xhr", "dojox/grid/enhanced/plugins/IndirectSelection", "dojo/domReady!"], function (xhr, parser, query, registry, connect, event, json, properties, updater, util, formatter, - UpdatableStore, addBinding, moveMessages, showMessage, UserPreferences, JsonRest, EnhancedGrid, ObjectStore, entities) { + UpdatableStore, addBinding, moveMessages, showMessage, UserPreferences, editQueue, JsonRest, EnhancedGrid, ObjectStore, entities) { function Queue(name, parent, controller) { this.name = name; @@ -172,6 +173,12 @@ define(["dojo/_base/xhr", event.stop(evt); that.deleteQueue(); }); + var editQueueButton = query(".editQueueButton", contentPane.containerNode)[0]; + connect.connect(registry.byNode(editQueueButton), "onClick", + function(evt){ + event.stop(evt); + editQueue.show({nodeName:that.modelObj.parent.parent.name, hostName:that.modelObj.parent.name,queueName:that.name}); + }); UserPreferences.addListener(that); }}); diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js index 444ed67d63..236efb2efa 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js +++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js @@ -27,7 +27,9 @@ define(["dojo/_base/xhr", "dojo/_base/array", "dojo/_base/event", 'dojo/_base/json', + "dojo/query", 'qpid/common/util', + "qpid/common/ContextVariablesEditor", "dijit/form/NumberSpinner", // required by the form /* dojox/ validate resources */ "dojox/validate/us", "dojox/validate/web", @@ -42,22 +44,14 @@ define(["dojo/_base/xhr", /* basic dojox classes */ "dojox/form/BusyButton", "dojox/form/CheckedMultiSelect", "dojo/domReady!"], - function (xhr, dom, construct, win, registry, parser, array, event, json, util) { + function (xhr, dom, construct, win, registry, parser, array, event, json, query, util) { var addQueue = {}; var node = construct.create("div", null, win.body(), "last"); - var typeSpecificFields = { - priorities: "priority", - lvqKey: "lvq", - sortKey: "sorted" - }; - - var requiredFields = { - priority: "priorities", - sorted: "sortkey" - }; + var typeSpecificFields = { priorities: "priority", lvqKey: "lvq", sortKey: "sorted" }; + var requiredFields = { sorted: "sortKey"}; var fieldConverters = { queueFlowControlSizeBytes: parseInt, @@ -96,8 +90,8 @@ define(["dojo/_base/xhr", newQueue["messageGroupSharedGroups"] = true; } } - else if (!typeSpecificFields.hasOwnProperty(propName) || - formValues[ "type" ] === typeSpecificFields[ propName ]) { + else if (!typeSpecificFields.hasOwnProperty(propName) || formValues[ "type" ] === typeSpecificFields[ propName ]) + { if(formValues[ propName ] !== "") { if (fieldConverters.hasOwnProperty(propName)) { @@ -125,36 +119,29 @@ define(["dojo/_base/xhr", addQueue.dialogNode = dom.byId("addQueue"); parser.instantiate([addQueue.dialogNode]); - // for children which have name type, add a function to make all the associated rows - // visible / invisible as the radio button is checked / unchecked - + // for children which have name type, add a function to make all the associated atrributes + // visible / invisible as the select is changed theForm = registry.byId("formAddQueue"); - array.forEach(theForm.getDescendants(), function(widget) + var typeSelector = registry.byId("formAddQueue.type"); + typeSelector.on("change", function(value) + { + query(".typeSpecificDiv").forEach(function(node, index, arr) { - if(widget.name === "type") { - widget.on("change", function(isChecked) { - - var objId = widget.id + ":fields"; - var obj = registry.byId(objId); - if(obj) { - if(isChecked) { - obj.domNode.style.display = "block"; - } else { - obj.domNode.style.display = "none"; - } - obj.resize(); - var widgetValue = widget.value; - if (requiredFields.hasOwnProperty(widgetValue)) - { - dijit.byId('formAddQueue.' + requiredFields[widgetValue]).required = isChecked; - } - - util.applyMetadataToWidgets(obj.domNode, "Queue", widgetValue); - } - }) + if (node.id === "formAddQueueType:" + value) + { + node.style.display = "block"; + util.applyMetadataToWidgets(node, "Queue", value); + } + else + { + node.style.display = "none"; } - }); + for(var requiredField in requiredFields) + { + dijit.byId('formAddQueue.' + requiredFields[requiredField]).required = (requiredField == value); + } + }); theForm.on("submit", function(e) { @@ -200,6 +187,14 @@ define(["dojo/_base/xhr", registry.byId("addQueue").show(); util.applyMetadataToWidgets(form.domNode, "Queue", "standard"); + if (!this.context) + { + this.context = new qpid.common.ContextVariablesEditor({name: 'context', title: 'Context variables'}); + this.context.placeAt(dom.byId("formAddQueue.context")); + } + + var escapedUrl = "api/latest/virtualhost/" + encodeURIComponent(addQueue.vhostnode) + "/" + encodeURIComponent(addQueue.vhost); + this.context.loadInheritedData(escapedUrl); }; return addQueue; diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js index 226674bf5a..0a18a8909b 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js +++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js @@ -134,35 +134,10 @@ define(["dojo/_base/xhr", this.virtualHostContext.placeAt(dom.byId("addVirtualHost.context")); } - var inheritedActualValues = null; - xhr.get( - { - url: "api/latest/broker", - sync: true, - content: { actuals: true, inheritedActuals: true}, - handleAs: "json", - load: function(data) - { - inheritedActualValues = data[0].context; - } - } - ); - var effectiveValues = null; - xhr.get( - { - url: "api/latest/broker", - sync: true, - handleAs: "json", - load: function(data) - { - effectiveValues = data[0].context; - } - } - ); + this.virtualHostNodeContext.loadInheritedData("api/latest/broker"); + this.virtualHostContext.setData({}, this.virtualHostNodeContext.effectiveValues,this.virtualHostNodeContext.inheritedActualValues); - this.virtualHostNodeContext.setData({},effectiveValues,inheritedActualValues); - this.virtualHostContext.setData({},effectiveValues,inheritedActualValues); this.dialog.show(); if (!this.resizeEventRegistered) { diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editQueue.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editQueue.js new file mode 100644 index 0000000000..06c9672efe --- /dev/null +++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editQueue.js @@ -0,0 +1,232 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", + "dojox/html/entities", + "dojo/_base/array", + "dojo/_base/event", + "dojo/_base/lang", + "dojo/_base/window", + "dojo/dom", + "dojo/dom-construct", + "dijit/registry", + "dojo/parser", + 'dojo/json', + "dojo/query", + "qpid/common/util", + "dojo/text!editQueue.html", + "qpid/common/ContextVariablesEditor", + "dijit/Dialog", + "dijit/form/CheckBox", + "dijit/form/FilteringSelect", + "dijit/form/ValidationTextBox", + "dijit/form/Button", + "dijit/form/Form", + "dojox/validate/us", + "dojox/validate/web", + "dojo/domReady!"], + function (xhr, entities, array, event, lang, win, dom, domConstruct, registry, parser, json, query, util, template) + { + var fields = ["name", + "type", + "durable", + "messageDurability", + "maximumMessageTtl", + "minimumMessageTtl", + "queueFlowControlSizeBytes", + "queueFlowResumeSizeBytes", + "alertThresholdQueueDepthMessages", + "alertThresholdQueueDepthBytes", + "alertThresholdMessageAge", + "alertThresholdMessageSize", + "alertRepeatGap", + "maximumDeliveryAttempts", + "priorities", + "lvqKey", + "sortKey"]; + + var numericFieldNames = ["maximumMessageTtl", + "minimumMessageTtl", + "queueFlowControlSizeBytes", + "queueFlowResumeSizeBytes", + "alertThresholdQueueDepthMessages", + "alertThresholdQueueDepthBytes", + "alertThresholdMessageAge", + "alertThresholdMessageSize", + "alertRepeatGap", + "maximumDeliveryAttempts"]; + + var queueEditor = + { + init: function() + { + var that=this; + this.containerNode = domConstruct.create("div", {innerHTML: template}); + parser.parse(this.containerNode); + this.allFieldsContainer = dom.byId("formEditQueue.allFields"); + this.dialog = registry.byId("editQueue"); + this.saveButton = registry.byId("formEditQueue.saveButton"); + this.cancelButton = registry.byId("formEditQueue.cancelButton"); + this.cancelButton.on("click", function(e){that._cancel(e);}); + this.saveButton.on("click", function(e){that._save(e);}); + for(var i = 0; i < fields.length; i++) + { + var fieldName = fields[i]; + this[fieldName] = registry.byId("formEditQueue." + fieldName); + } + this.form = registry.byId("formEditQueue"); + this.form.on("submit", function(){return false;}); + this.typeSelector = registry.byId("formEditQueue.type"); + }, + show: function(hostData) + { + var that=this; + if (!this.context) + { + this.context = new qpid.common.ContextVariablesEditor({name: 'context', title: 'Context variables'}); + this.context.placeAt(dom.byId("formEditQueue.context")); + } + this.query = "api/latest/queue/" + encodeURIComponent(hostData.nodeName) + "/" + encodeURIComponent(hostData.hostName) + "/" + encodeURIComponent(hostData.queueName); + this.dialog.set("title", "Edit Queue - " + entities.encode(String(hostData.queueName))); + xhr.get( + { + url: this.query, + sync: true, + content: { actuals: true }, + handleAs: "json", + load: function(data) + { + that._show(data[0], hostData); + } + } + ); + var queueType = this.typeSelector.get("value"); + query(".typeSpecificDiv").forEach(function(node, index, arr){ + if (node.id === "formEditQueueType:" + queueType) + { + node.style.display = "block"; + util.applyMetadataToWidgets(node, "Queue", queueType); + } + else + { + node.style.display = "none"; + } + }); + }, + destroy: function() + { + if (this.dialog) + { + this.dialog.destroyRecursive(); + this.dialog = null; + } + + if (this.containerNode) + { + domConstruct.destroy(this.containerNode); + this.containerNode = null; + } + }, + _cancel: function(e) + { + this.dialog.hide(); + }, + _save: function(e) + { + event.stop(e); + if(this.form.validate()) + { + var data = util.getFormWidgetValues(this.form, this.initialData); + var context = this.context.get("value"); + if (context && !util.equals(context, this.initialData.context)) + { + data["context"] = context; + } + var success = false,failureReason=null; + xhr.put({ + url: this.query, + sync: true, + handleAs: "json", + headers: { "Content-Type": "application/json"}, + putData: json.stringify(data), + load: function(x) {success = true; }, + error: function(error) {success = false; failureReason = error;} + }); + + if(success === true) + { + this.dialog.hide(); + } + else + { + util.xhrErrorHandler(failureReason); + } + } + else + { + alert('Form contains invalid data. Please correct first'); + } + }, + _show:function(actualData, effectiveData) + { + + this.initialData = actualData; + for(var i = 0; i < fields.length; i++) + { + var fieldName = fields[i]; + var widget = this[fieldName]; + widget.reset(); + + if (widget instanceof dijit.form.CheckBox) + { + widget.set("checked", actualData[fieldName]); + } + else + { + widget.set("value", actualData[fieldName]); + } + } + + var that = this; + util.applyMetadataToWidgets(that.allFieldsContainer, "Queue", actualData.type); + + this.context.load(this.query, {actualValues:actualData.context, effectiveValues:effectiveData.context}); + + // Add regexp to the numeric fields + for(var i = 0; i < numericFieldNames.length; i++) + { + this[numericFieldNames[i]].set("regExpGen", util.numericOrContextVarRegexp); + } + + this.dialog.startup(); + this.dialog.show(); + if (!this.resizeEventRegistered) + { + this.resizeEventRegistered = true; + util.resizeContentAreaAndRepositionDialog(dom.byId("formEditQueue.contentPane"), this.dialog); + } + } + }; + + queueEditor.init(); + + return queueEditor; + } +); diff --git a/java/broker-plugins/management-http/src/main/java/resources/showQueue.html b/java/broker-plugins/management-http/src/main/java/resources/showQueue.html index e5b9699c64..a068868e7f 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/showQueue.html +++ b/java/broker-plugins/management-http/src/main/java/resources/showQueue.html @@ -198,7 +198,7 @@ </div> </div> <div class="clear"> - <div class="formLabel-labelCell">Alert frequency:</div> + <div class="formLabel-labelCell">Gap between alerts:</div> <div> <span class="alertRepeatGap"></span> <span class="alertRepeatGapUnits"></span> @@ -208,6 +208,7 @@ </div> <div class="dijitDialogPaneActionBar"> + <button data-dojo-type="dijit.form.Button" class="editQueueButton" type="button">Edit Queue</button> <button data-dojo-type="dijit.form.Button" class="deleteQueueButton" type="button">Delete Queue</button> </div> </div> diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java index a38aa9e349..6c962c2901 100644 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java @@ -29,6 +29,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; +import javax.management.InstanceAlreadyExistsException; import javax.management.JMException; import org.apache.log4j.Logger; @@ -103,7 +104,7 @@ public class JMXManagementPluginImpl return _usePlatformMBeanServer; } - @StateTransition(currentState = State.UNINITIALIZED, desiredState = State.ACTIVE) + @StateTransition(currentState = {State.UNINITIALIZED,State.ERRORED}, desiredState = State.ACTIVE) private void doStart() throws JMException, IOException { _allowPortActivation = true; @@ -340,8 +341,8 @@ public class JMXManagementPluginImpl mbean = new UserManagementMBean((PasswordCredentialManagingAuthenticationProvider<?>) object, _objectRegistry); registerMBean(object, _pluginMBeanProvider, mbean); } - createAdditionalMBeansFromProvidersIfNecessary(object, _objectRegistry); } + createAdditionalMBeansFromProvidersIfNecessary(object, _objectRegistry); } } return mbean; @@ -351,10 +352,27 @@ public class JMXManagementPluginImpl { if (!providerMBeanExists(host, _pluginMBeanProvider)) { - VirtualHostMBean mbean = new VirtualHostMBean(host, _objectRegistry); - registerMBean(host, _pluginMBeanProvider, mbean); host.addChangeListener(_changeListener); - return mbean; + try + { + VirtualHostMBean mbean = new VirtualHostMBean(host, _objectRegistry); + registerMBean(host, _pluginMBeanProvider, mbean); + return mbean; + } + catch (InstanceAlreadyExistsException e) + { + VirtualHostNode parent = host.getParent(VirtualHostNode.class); + Set<ConfiguredObject<?>> registered = _children.keySet(); + for (ConfiguredObject<?> object: registered) + { + if (object instanceof VirtualHost && object.getParent(VirtualHostNode.class) == parent) + { + LOGGER.warn("Unexpected MBean is found for VirtualHost " + object + " belonging to node " + parent); + } + } + + throw e; + } } return null; } @@ -392,24 +410,21 @@ public class JMXManagementPluginImpl } unregisterObjectMBeans(object); _children.remove(object); - destroyChildrenMBeansIfVirtualHostNode(object); + destroyChildrenMBeans(object); } } } - private void destroyChildrenMBeansIfVirtualHostNode(ConfiguredObject<?> child) + private void destroyChildrenMBeans(ConfiguredObject<?> object) { - if (child instanceof VirtualHostNode) + for (Iterator<ConfiguredObject<?>> iterator = _children.keySet().iterator(); iterator.hasNext();) { - for (Iterator<ConfiguredObject<?>> iterator = _children.keySet().iterator(); iterator.hasNext();) + ConfiguredObject<?> registeredObject = iterator.next(); + ConfiguredObject<?> parent = registeredObject.getParent(object.getCategoryClass()); + if (parent == object) { - ConfiguredObject<?> registeredObject = iterator.next(); - ConfiguredObject<?> parent = registeredObject.getParent(VirtualHostNode.class); - if (parent == child) - { - registeredObject.removeChangeListener(_changeListener); - unregisterObjectMBeans(registeredObject); - } + registeredObject.removeChangeListener(_changeListener); + unregisterObjectMBeans(registeredObject); iterator.remove(); } } diff --git a/java/broker-plugins/memory-store/src/main/java/org/apache/qpid/server/store/MemorySystemConfigImpl.java b/java/broker-plugins/memory-store/src/main/java/org/apache/qpid/server/store/MemorySystemConfigImpl.java index f644b8f46b..3f5215219b 100644 --- a/java/broker-plugins/memory-store/src/main/java/org/apache/qpid/server/store/MemorySystemConfigImpl.java +++ b/java/broker-plugins/memory-store/src/main/java/org/apache/qpid/server/store/MemorySystemConfigImpl.java @@ -26,6 +26,7 @@ import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.LogRecorder; import org.apache.qpid.server.model.AbstractSystemConfig; import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerShutdownProvider; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.SystemConfigFactoryConstructor; @@ -39,9 +40,10 @@ public class MemorySystemConfigImpl extends AbstractSystemConfig<MemorySystemCon public MemorySystemConfigImpl(final TaskExecutor taskExecutor, final EventLogger eventLogger, final LogRecorder logRecorder, - final BrokerOptions brokerOptions) + final BrokerOptions brokerOptions, + final BrokerShutdownProvider brokerShutdownProvider) { - super(taskExecutor, eventLogger, logRecorder, brokerOptions); + super(taskExecutor, eventLogger, logRecorder, brokerOptions, brokerShutdownProvider); } @Override diff --git a/java/perftests/etc/chartdefs/1001-MessageSize-Transient-ByteSec.chartdef b/java/perftests/etc/chartdefs/1001-MessageSize-Transient-ByteSec.chartdef index 73d1a93b11..2327fb610f 100644 --- a/java/perftests/etc/chartdefs/1001-MessageSize-Transient-ByteSec.chartdef +++ b/java/perftests/etc/chartdefs/1001-MessageSize-Transient-ByteSec.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Impact of Message Size Bytes/S chartSubtitle=Transient messages -chartDescription=1P 1C, transient, auto-ack, with message payload between 256-262144 bytes ${baselineName}. +chartDescription=1P 1C, transient, auto-ack, with message payload between 256-262144 bytes ${baselineName}, single queue. xAxisTitle=Message Size (B) yAxisTitle=Throughput (KB/s) diff --git a/java/perftests/etc/chartdefs/1002-MessageSize-Persistent-ByteSec.chartdef b/java/perftests/etc/chartdefs/1002-MessageSize-Persistent-ByteSec.chartdef index 2cd5e8d9d5..cd7029963b 100644 --- a/java/perftests/etc/chartdefs/1002-MessageSize-Persistent-ByteSec.chartdef +++ b/java/perftests/etc/chartdefs/1002-MessageSize-Persistent-ByteSec.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Impact of Message Size Bytes/S chartSubtitle=Persistent messages -chartDescription=1P 1C, persistent, auto-ack, with message payload between 256-262144 bytes. +chartDescription=1P 1C, persistent, auto-ack, with message payload between 256-262144 bytes, single queue. xAxisTitle=Message Size (B) yAxisTitle=Throughput (KB/s) diff --git a/java/perftests/etc/chartdefs/1003-MessageSize-Transient-MsgSec.chartdef b/java/perftests/etc/chartdefs/1003-MessageSize-Transient-MsgSec.chartdef index ae59f61741..979136e2ed 100644 --- a/java/perftests/etc/chartdefs/1003-MessageSize-Transient-MsgSec.chartdef +++ b/java/perftests/etc/chartdefs/1003-MessageSize-Transient-MsgSec.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Impact of Message Size chartSubtitle=Transient messages -chartDescription=1P 1C, transient, auto-ack, with message payload between 256-262144 bytes. +chartDescription=1P 1C, transient, auto-ack, with message payload between 256-262144 bytes, single queue. xAxisTitle=Message Size (B) yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1004-MessageSize-Persistent-MsgSec.chartdef b/java/perftests/etc/chartdefs/1004-MessageSize-Persistent-MsgSec.chartdef index f5ce7662f3..fef5509107 100644 --- a/java/perftests/etc/chartdefs/1004-MessageSize-Persistent-MsgSec.chartdef +++ b/java/perftests/etc/chartdefs/1004-MessageSize-Persistent-MsgSec.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Impact of Message Size chartSubtitle=Persistent messages -chartDescription=1P 1C, persistent, auto-ack, with message payload between 256-262144 bytes. +chartDescription=1P 1C, persistent, auto-ack, with message payload between 256-262144 bytes, single queue. xAxisTitle=Message Size (B) yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1011-VaryingNumberOfProducers-AutoAck.chartdef b/java/perftests/etc/chartdefs/1011-VaryingNumberOfProducers-AutoAck.chartdef index d67c8881de..8ad987ea74 100644 --- a/java/perftests/etc/chartdefs/1011-VaryingNumberOfProducers-AutoAck.chartdef +++ b/java/perftests/etc/chartdefs/1011-VaryingNumberOfProducers-AutoAck.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Varying number of producers - auto ack chartSubtitle=Persistent 1KB messages -chartDescription=1,2,5,10 P/Cs, persistent, auto-ack, with message payload 1KB. +chartDescription=1,2,5,10 P/Cs, persistent, auto-ack, with message payload 1KB, single queue. xAxisTitle=Producers yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1012-VaryingNumberOfConsumers-AutoAck.chartdef b/java/perftests/etc/chartdefs/1012-VaryingNumberOfConsumers-AutoAck.chartdef index b78c7c53d2..599c37cf60 100644 --- a/java/perftests/etc/chartdefs/1012-VaryingNumberOfConsumers-AutoAck.chartdef +++ b/java/perftests/etc/chartdefs/1012-VaryingNumberOfConsumers-AutoAck.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Varying number of consumers - auto ack chartSubtitle=Persistent 1KB messages -chartDescription=1,2,5,10 P/Cs, persistent, auto-ack, with message payload 1KB. +chartDescription=1,2,5,10 P/Cs, persistent, auto-ack, with message payload 1KB, single queue. xAxisTitle=Consumers yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1015-VaryingNumberOfProducers-SessionTrans.chartdef b/java/perftests/etc/chartdefs/1015-VaryingNumberOfProducers-SessionTrans.chartdef index d00d1e9d00..d22594ca89 100644 --- a/java/perftests/etc/chartdefs/1015-VaryingNumberOfProducers-SessionTrans.chartdef +++ b/java/perftests/etc/chartdefs/1015-VaryingNumberOfProducers-SessionTrans.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Varying number of producers - transacted chartSubtitle=Persistent 1KB messages -chartDescription=1,2,5,10 P/Cs, persistent, transacted, with message payload 1KB. +chartDescription=1,2,5,10 P/Cs, persistent, transacted, with message payload 1KB, single queue. xAxisTitle=Producers yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1016-VaryingNumberOfConsumers-SessionTrans.chartdef b/java/perftests/etc/chartdefs/1016-VaryingNumberOfConsumers-SessionTrans.chartdef index a808334560..0e781177fe 100644 --- a/java/perftests/etc/chartdefs/1016-VaryingNumberOfConsumers-SessionTrans.chartdef +++ b/java/perftests/etc/chartdefs/1016-VaryingNumberOfConsumers-SessionTrans.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Varying number of consumers - transacted chartSubtitle=Persistent 1KB messages -chartDescription=1,2,5,10 P/Cs, persistent, transacted, with message payload 1KB. +chartDescription=1,2,5,10 P/Cs, persistent, transacted, with message payload 1KB, single queue. xAxisTitle=Consumers yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1021-AcknowledgementModes-Persistent.chartdef b/java/perftests/etc/chartdefs/1021-AcknowledgementModes-Persistent.chartdef index a8abd6f02c..7d1abe6418 100644 --- a/java/perftests/etc/chartdefs/1021-AcknowledgementModes-Persistent.chartdef +++ b/java/perftests/etc/chartdefs/1021-AcknowledgementModes-Persistent.chartdef @@ -20,7 +20,7 @@ chartType=BAR chartTitle=Performance of acknowledgement modes chartSubtitle=Persistent messages (1KB) -chartDescription=1P 1C, persistent, with message payload 1KB. +chartDescription=1P 1C, persistent, with message payload 1KB, single queue. xAxisTitle=Acknowledge mode (0=session transacted; 1=auto-acknowledge) yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1022-AcknowledgementModes-Transient.chartdef b/java/perftests/etc/chartdefs/1022-AcknowledgementModes-Transient.chartdef index ebc040cd25..662cb8529d 100644 --- a/java/perftests/etc/chartdefs/1022-AcknowledgementModes-Transient.chartdef +++ b/java/perftests/etc/chartdefs/1022-AcknowledgementModes-Transient.chartdef @@ -20,7 +20,7 @@ chartType=BAR chartTitle=Performance of acknowledgement modes chartSubtitle=Transient messages (1024b) -chartDescription=1P 1C, transient, with message payload 1KB. +chartDescription=1P 1C, transient, with message payload 1KB, single queue. xAxisTitle=Acknowledge mode (0=session transacted; 1=auto-acknowledge) yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1030-BatchSize-Equal.chartdef b/java/perftests/etc/chartdefs/1030-BatchSize-Equal.chartdef index bf55750c4a..1b37d50c33 100644 --- a/java/perftests/etc/chartdefs/1030-BatchSize-Equal.chartdef +++ b/java/perftests/etc/chartdefs/1030-BatchSize-Equal.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Transaction Batch Sizes Equal chartSubtitle=Persistent 1KB messages -chartDescription=1P 1C, persistent, transacted with message payload 1KB with producer/consumer batch size varying between 1-400 messages for both P and C +chartDescription=1P 1C, persistent, transacted with message payload 1KB with producer/consumer batch size varying between 1-400 messages for both P and C, single queue. xAxisTitle=Batch Size yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1031-BatchSize-Unequal.chartdef b/java/perftests/etc/chartdefs/1031-BatchSize-Unequal.chartdef index 5f846c6ca0..cd72663552 100644 --- a/java/perftests/etc/chartdefs/1031-BatchSize-Unequal.chartdef +++ b/java/perftests/etc/chartdefs/1031-BatchSize-Unequal.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Transaction Batch Size Unequal chartSubtitle=Persistent 1KB messages -chartDescription=1P 1C, persistent, transacted with message payload 1KB with fixed batch size 1 for one party whilst other varies between 1-400 messages +chartDescription=1P 1C, persistent, transacted with message payload 1KB with fixed batch size 1 for one party whilst other varies between 1-400 messages, single queue. xAxisTitle=Batch Size yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1040-QueueTypes.chartdef b/java/perftests/etc/chartdefs/1040-QueueTypes.chartdef index 248db4905f..3ba42e2c00 100644 --- a/java/perftests/etc/chartdefs/1040-QueueTypes.chartdef +++ b/java/perftests/etc/chartdefs/1040-QueueTypes.chartdef @@ -20,7 +20,7 @@ chartType=BAR chartTitle=Queue Types chartSubtitle=Persistent 1KB messages -chartDescription=1P 1C, persistent, auto-ack with message payload 1KB. Sorted queue - 160,000 random keys, Priority - iteriates priority 0..9. +chartDescription=1P 1C, persistent, auto-ack with message payload 1KB. Sorted queue - 160,000 random keys, Priority - iteriates priority 0..9, single queue. xAxisTitle=Queue Types yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1050-VaryingNumberOfProducerSessionsSingleConnection.chartdef b/java/perftests/etc/chartdefs/1050-VaryingNumberOfProducerSessionsSingleConnection.chartdef index 50816a8cd3..c92974ddc0 100644 --- a/java/perftests/etc/chartdefs/1050-VaryingNumberOfProducerSessionsSingleConnection.chartdef +++ b/java/perftests/etc/chartdefs/1050-VaryingNumberOfProducerSessionsSingleConnection.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Varying number of producer sessions on single connection chartSubtitle=Persistent messages (1024b) -chartDescription=1-80P transacted on single connection, 20C transacted on separate connections, persistent, message payload 1KB. +chartDescription=1-80P transacted on single connection, 20C transacted on separate connections, persistent, message payload 1KB, single queue. xAxisTitle=Number of producer sessions yAxisTitle=Throughput (KB/s) diff --git a/java/perftests/etc/chartdefs/1300-QueueConsumersWithNonOverlappingSelectors-Transient.chartdef b/java/perftests/etc/chartdefs/1300-QueueConsumersWithNonOverlappingSelectors-Transient.chartdef index 67821b8581..95f717ad95 100644 --- a/java/perftests/etc/chartdefs/1300-QueueConsumersWithNonOverlappingSelectors-Transient.chartdef +++ b/java/perftests/etc/chartdefs/1300-QueueConsumersWithNonOverlappingSelectors-Transient.chartdef @@ -22,7 +22,7 @@ chartTitle=Impact of non-overlapping selectors on queue consumers with transient chartSubtitle=Transient 1KB messages xAxisTitle=Consumers yAxisTitle=Throughput (messages/s) -chartDescription=Impact of non-overlapping selectors on queue consumers with transient messages, auto-ack, message payload of 1024 bytes, 1 producer, varying number of consumers from 1 to 32. +chartDescription=Impact of non-overlapping selectors on queue consumers with transient messages, auto-ack, message payload of 1024 bytes, 1 producer, varying number of consumers from 1 to 32, single queue. series.1.statement=SELECT totalNumberOfConsumers, throughputMessagesPerS FROM QueueConsumersWithNonOverlappingSelectors WHERE participantName = 'All' and testName like '%non overlapping - NON_PERSISTENT%' series.1.legend=Current diff --git a/java/perftests/etc/chartdefs/1301-QueueConsumersWithNonOverlappingSelectors-Persistent.chartdef b/java/perftests/etc/chartdefs/1301-QueueConsumersWithNonOverlappingSelectors-Persistent.chartdef index 7fbf55a2ab..302b508413 100644 --- a/java/perftests/etc/chartdefs/1301-QueueConsumersWithNonOverlappingSelectors-Persistent.chartdef +++ b/java/perftests/etc/chartdefs/1301-QueueConsumersWithNonOverlappingSelectors-Persistent.chartdef @@ -22,7 +22,7 @@ chartTitle=Impact of non-overlapping selectors on queue consumers with persisten chartSubtitle=Persistent 1KB messages xAxisTitle=Consumers yAxisTitle=Throughput (messages/s) -chartDescription=Impact of non-overlapping selectors on queue consumers with persistent messages, auto-ack, message payload of 1024 bytes, 1 producer, varying number of consumers from 1 to 32.. +chartDescription=Impact of non-overlapping selectors on queue consumers with persistent messages, auto-ack, message payload of 1024 bytes, 1 producer, varying number of consumers from 1 to 32, single queue. series.1.statement=SELECT totalNumberOfConsumers, throughputMessagesPerS FROM QueueConsumersWithNonOverlappingSelectors WHERE participantName = 'All' and testName like '%non overlapping - PERSISTENT' diff --git a/java/perftests/etc/chartdefs/1302-QueueConsumersWithOverlappingSelectors-Transient.chartdef b/java/perftests/etc/chartdefs/1302-QueueConsumersWithOverlappingSelectors-Transient.chartdef index 1734265adf..c0796ca8a3 100644 --- a/java/perftests/etc/chartdefs/1302-QueueConsumersWithOverlappingSelectors-Transient.chartdef +++ b/java/perftests/etc/chartdefs/1302-QueueConsumersWithOverlappingSelectors-Transient.chartdef @@ -22,7 +22,7 @@ chartTitle=Impact of 50%-overlapping selectors in queue consumers with transient chartSubtitle=Transient 1KB messages xAxisTitle=Consumers yAxisTitle=Throughput (messages/s) -chartDescription=Impact of 50%-overlapping selectors in queue consumers with transient messages, auto-ack, message payload 1KB, 1 producer, varying number of consumers from 2 to 32. +chartDescription=Impact of 50%-overlapping selectors in queue consumers with transient messages, auto-ack, message payload 1KB, 1 producer, varying number of consumers from 2 to 32, single queue. series.1.statement=SELECT totalNumberOfConsumers,throughputMessagesPerS FROM QueueConsumersWithOverlappingSelectors WHERE participantName = 'All' and testName like '%50_ overlapping - NON_PERSISTENT%' series.1.legend=Current diff --git a/java/perftests/etc/chartdefs/1303-QueueConsumersWithOverlappingSelectors-Persistent.chartdef b/java/perftests/etc/chartdefs/1303-QueueConsumersWithOverlappingSelectors-Persistent.chartdef index ef7beb252d..a2c75c1037 100644 --- a/java/perftests/etc/chartdefs/1303-QueueConsumersWithOverlappingSelectors-Persistent.chartdef +++ b/java/perftests/etc/chartdefs/1303-QueueConsumersWithOverlappingSelectors-Persistent.chartdef @@ -19,7 +19,7 @@ chartType=XYLINE chartTitle=Impact of 50%-overlapping selectors in queue consumers with persistent messages -chartDescription=Impact of 50%-overlapping selectors in queue consumers with persistent messages, auto-ack, message payload of 1KB, 1 producer, varying number of consumers from 2 to 32. +chartDescription=Impact of 50%-overlapping selectors in queue consumers with persistent messages, auto-ack, message payload of 1KB, 1 producer, varying number of consumers from 2 to 32, single queue. chartSubtitle=Persistent 1KB messages xAxisTitle=Consumers yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1500-Topic-NumberOfConsumers.chartdef b/java/perftests/etc/chartdefs/1500-Topic-NumberOfConsumers.chartdef index ef82fdf45f..96f0ce3284 100644 --- a/java/perftests/etc/chartdefs/1500-Topic-NumberOfConsumers.chartdef +++ b/java/perftests/etc/chartdefs/1500-Topic-NumberOfConsumers.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Number of topic consumers chartSubtitle=Transient 1KB messages -chartDescription=1P 1-100C transient, transacted, with message payload 1KB. +chartDescription=1P 1-100C transient, transacted, with message payload 1KB, single queue. xAxisTitle=Numer of consumers yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1501-Topic-NumberOfTopics.chartdef b/java/perftests/etc/chartdefs/1501-Topic-NumberOfTopics.chartdef index 394b23227c..5eac3d90c9 100644 --- a/java/perftests/etc/chartdefs/1501-Topic-NumberOfTopics.chartdef +++ b/java/perftests/etc/chartdefs/1501-Topic-NumberOfTopics.chartdef @@ -20,7 +20,7 @@ chartType=XYLINE chartTitle=Number of topics chartSubtitle=Transient 1KB messages -chartDescription=1,10,50,100 PC, transient, transacted, with each PC pair having own topic, message payload 1KB. +chartDescription=1,10,50,100 PC, transient, transacted, with each PC pair having own topic, message payload 1KB, single topic. xAxisTitle=Numer of topics yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1502-Topic-Persistence.chartdef b/java/perftests/etc/chartdefs/1502-Topic-Persistence.chartdef index c418709a82..25e64ea1c9 100644 --- a/java/perftests/etc/chartdefs/1502-Topic-Persistence.chartdef +++ b/java/perftests/etc/chartdefs/1502-Topic-Persistence.chartdef @@ -20,7 +20,7 @@ chartType=BAR chartTitle=Topic transient/durable subscriptions chartSubtitle=1KB messages -chartDescription=1P 10C, transacted, message payload 1KB, transient messages on non-durable sub, persistent messages on durable sub +chartDescription=1P 10C, transacted, message payload 1KB, transient messages on non-durable sub, persistent messages on durable sub, single topic, xAxisTitle=Subscription type (true durable, false non durable) yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/1503-Topic-AckModes.chartdef b/java/perftests/etc/chartdefs/1503-Topic-AckModes.chartdef index f25dd89a2b..8d549abcc9 100644 --- a/java/perftests/etc/chartdefs/1503-Topic-AckModes.chartdef +++ b/java/perftests/etc/chartdefs/1503-Topic-AckModes.chartdef @@ -20,7 +20,7 @@ chartType=BAR chartTitle=Topic acknowledge modes chartSubtitle=Transient 1KB messages -chartDescription=1P 10C, transient, non-durable subscription, message payload 1KB +chartDescription=1P 10C, transient, non-durable subscription, message payload 1KB, single topic. xAxisTitle=Ack Mode (0=transaction 1=auto-ack) yAxisTitle=Throughput (messages/s) diff --git a/java/perftests/etc/chartdefs/2001-Latency-MessageSize-Transient.chartdef b/java/perftests/etc/chartdefs/2001-Latency-MessageSize-Transient.chartdef index 6b7939157a..bd252d1b6e 100644 --- a/java/perftests/etc/chartdefs/2001-Latency-MessageSize-Transient.chartdef +++ b/java/perftests/etc/chartdefs/2001-Latency-MessageSize-Transient.chartdef @@ -20,7 +20,7 @@ chartType=STATISTICAL_BAR chartTitle=Impact of message size on latency chartSubtitle=Transient messages -chartDescription=1P 1C, transient, auto-ack, with message payload between 256-262144 bytes. +chartDescription=1P 1C, transient, auto-ack, with message payload between 256-262144 bytes, single queue. xAxisTitle=Message Size (B) yAxisTitle=Latency (millis) diff --git a/java/perftests/etc/chartdefs/2002-Latency-MessageSize-Persistent.chartdef b/java/perftests/etc/chartdefs/2002-Latency-MessageSize-Persistent.chartdef index c04e393046..36acdb6cd7 100644 --- a/java/perftests/etc/chartdefs/2002-Latency-MessageSize-Persistent.chartdef +++ b/java/perftests/etc/chartdefs/2002-Latency-MessageSize-Persistent.chartdef @@ -20,7 +20,7 @@ chartType=STATISTICAL_BAR chartTitle=Impact of message size on latency chartSubtitle=Persistent messages -chartDescription=1P 1C, persistent, auto-ack, with message payload between 256-262144 bytes. +chartDescription=1P 1C, persistent, auto-ack, with message payload between 256-262144 bytes, single queue. xAxisTitle=Message Size (B) yAxisTitle=Latency (millis) diff --git a/java/perftests/etc/chartdefs/2031-Latency-VaryingNumberOfParticipants.chartdef b/java/perftests/etc/chartdefs/2031-Latency-VaryingNumberOfParticipants.chartdef index fa688feb1f..bb19eb2aca 100644 --- a/java/perftests/etc/chartdefs/2031-Latency-VaryingNumberOfParticipants.chartdef +++ b/java/perftests/etc/chartdefs/2031-Latency-VaryingNumberOfParticipants.chartdef @@ -20,7 +20,7 @@ chartType=STATISTICAL_BAR chartTitle=Latency, varying number of participants chartSubtitle=Persistent 1KB messages -chartDescription=1,2,5,10 P/Cs, persistent, auto-ack, with message payload 1KB. +chartDescription=1,2,5,10 P/Cs, persistent, auto-ack, with message payload 1KB, single queue. xAxisTitle=Consumers yAxisTitle=Latency (millis) diff --git a/java/perftests/etc/testdefs/Latency-MessageSize.json b/java/perftests/etc/testdefs/Latency-MessageSize.json index 4486d7a4b5..f93d1ecaab 100644 --- a/java/perftests/etc/testdefs/Latency-MessageSize.json +++ b/java/perftests/etc/testdefs/Latency-MessageSize.json @@ -136,7 +136,7 @@ "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer1", @@ -160,7 +160,7 @@ "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer1", diff --git a/java/perftests/etc/testdefs/Latency-VaryingNumberOfParticipants.json b/java/perftests/etc/testdefs/Latency-VaryingNumberOfParticipants.json index aefd51dde0..50f00a8c45 100644 --- a/java/perftests/etc/testdefs/Latency-VaryingNumberOfParticipants.json +++ b/java/perftests/etc/testdefs/Latency-VaryingNumberOfParticipants.json @@ -18,7 +18,7 @@ "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer1", @@ -43,7 +43,7 @@ "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer1", @@ -79,7 +79,7 @@ "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer1", @@ -99,7 +99,7 @@ "_sessions": [ { "_sessionName": "session2", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer2", @@ -119,7 +119,7 @@ "_sessions": [ { "_sessionName": "session3", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer3", @@ -139,7 +139,7 @@ "_sessions": [ { "_sessionName": "session4", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer4", @@ -159,7 +159,7 @@ "_sessions": [ { "_sessionName": "session5", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer5", @@ -179,7 +179,7 @@ "_sessions": [ { "_sessionName": "session6", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer6", @@ -199,7 +199,7 @@ "_sessions": [ { "_sessionName": "session7", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer7", @@ -219,7 +219,7 @@ "_sessions": [ { "_sessionName": "session8", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer8", @@ -239,7 +239,7 @@ "_sessions": [ { "_sessionName": "session9", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer9", @@ -259,7 +259,7 @@ "_sessions": [ { "_sessionName": "session10", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer10", @@ -284,7 +284,7 @@ "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer1", @@ -319,7 +319,7 @@ "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer1", @@ -339,7 +339,7 @@ "_sessions": [ { "_sessionName": "session2", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer2", @@ -359,7 +359,7 @@ "_sessions": [ { "_sessionName": "session3", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer3", @@ -379,7 +379,7 @@ "_sessions": [ { "_sessionName": "session4", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer4", @@ -399,7 +399,7 @@ "_sessions": [ { "_sessionName": "session5", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer5", @@ -419,7 +419,7 @@ "_sessions": [ { "_sessionName": "session6", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer6", @@ -439,7 +439,7 @@ "_sessions": [ { "_sessionName": "session7", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer7", @@ -459,7 +459,7 @@ "_sessions": [ { "_sessionName": "session8", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer8", @@ -479,7 +479,7 @@ "_sessions": [ { "_sessionName": "session9", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer9", @@ -499,7 +499,7 @@ "_sessions": [ { "_sessionName": "session10", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer10", @@ -524,7 +524,7 @@ "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer1", @@ -542,7 +542,7 @@ "_sessions": [ { "_sessionName": "session2", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer2", @@ -560,7 +560,7 @@ "_sessions": [ { "_sessionName": "session3", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer3", @@ -578,7 +578,7 @@ "_sessions": [ { "_sessionName": "session4", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer4", @@ -596,7 +596,7 @@ "_sessions": [ { "_sessionName": "session5", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer5", @@ -614,7 +614,7 @@ "_sessions": [ { "_sessionName": "session6", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer6", @@ -632,7 +632,7 @@ "_sessions": [ { "_sessionName": "session7", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer7", @@ -650,7 +650,7 @@ "_sessions": [ { "_sessionName": "session8", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer8", @@ -668,7 +668,7 @@ "_sessions": [ { "_sessionName": "session9", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer9", @@ -686,7 +686,7 @@ "_sessions": [ { "_sessionName": "session10", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer10", diff --git a/java/perftests/etc/testdefs/MessageSize.json b/java/perftests/etc/testdefs/MessageSize.json index 6d796bd824..c97815507b 100644 --- a/java/perftests/etc/testdefs/MessageSize.json +++ b/java/perftests/etc/testdefs/MessageSize.json @@ -153,7 +153,7 @@ "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_producers": [ { "_name": "Producer1", @@ -177,7 +177,7 @@ "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": 0, "_consumers": [ { "_name": "Consumer1", diff --git a/java/perftests/etc/testdefs/QueueConsumersWithNonOverlappingSelectors.js b/java/perftests/etc/testdefs/QueueConsumersWithNonOverlappingSelectors.js index 0dd45b0392..72b77e0e93 100644 --- a/java/perftests/etc/testdefs/QueueConsumersWithNonOverlappingSelectors.js +++ b/java/perftests/etc/testdefs/QueueConsumersWithNonOverlappingSelectors.js @@ -25,11 +25,11 @@ var jsonObject = { for (var i=0; i<2; i++) { var deliveryMode = i+1; + var acknowledgeMode = ((i==0) ? 1 : 0); var durable = (deliveryMode == 2); var suffix = durable ? "PERSISTENT" : "NON-PERSISTENT"; var queueName = "direct://amq.direct//queue-selectors-" + suffix + "?durable='" + durable + "'"; var consumerNumbers = [1, 2, 4, 8, 16, 32]; - var consumerAcknowledgeMode = 1; for (var j=0; j<consumerNumbers.length; j++) { var consumerNumber = consumerNumbers[j]; @@ -70,7 +70,7 @@ for (var i=0; i<2; i++) "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": acknowledgeMode, "_producers": [ { "_name": "Producer1", @@ -100,7 +100,7 @@ for (var i=0; i<2; i++) "_sessions": [ { "_sessionName": "session" + n, - "_acknowledgeMode": consumerAcknowledgeMode, + "_acknowledgeMode": acknowledgeMode, "_consumers": [ { "_name": "Consumer" + n, diff --git a/java/perftests/etc/testdefs/QueueConsumersWithOverlappingSelectors.js b/java/perftests/etc/testdefs/QueueConsumersWithOverlappingSelectors.js index 20cfb4ad45..e4c076b9f4 100644 --- a/java/perftests/etc/testdefs/QueueConsumersWithOverlappingSelectors.js +++ b/java/perftests/etc/testdefs/QueueConsumersWithOverlappingSelectors.js @@ -26,6 +26,7 @@ for (var i=0; i<2; i++) { var deliveryMode = i+1; var durable = (deliveryMode == 2); + var acknowledgeMode = ((i==0) ? 1 : 0); var suffix = durable ? "PERSISTENT" : "NON-PERSISTENT"; var queueName = "direct://amq.direct//queue-selectors-overlapping-" + suffix + "?durable='" + durable + "'"; var consumerNumbers = [2, 4, 8, 16, 32]; @@ -70,7 +71,7 @@ for (var i=0; i<2; i++) "_sessions": [ { "_sessionName": "session1", - "_acknowledgeMode": 1, + "_acknowledgeMode": acknowledgeMode, "_producers": [ { "_name": "Producer1", @@ -111,7 +112,7 @@ for (var i=0; i<2; i++) "_sessions": [ { "_sessionName": "session" + n, - "_acknowledgeMode": consumerAcknowledgeMode, + "_acknowledgeMode": acknowledgeMode, "_consumers": [ { "_name": "Consumer" + n, diff --git a/java/perftests/pom.xml b/java/perftests/pom.xml index c395069e84..7787c82b74 100644 --- a/java/perftests/pom.xml +++ b/java/perftests/pom.xml @@ -156,6 +156,48 @@ <skip>true</skip> </configuration> </plugin> + + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.3.2</version> + <executions> + <execution> + <goals> + <goal>java</goal> + </goals> + </execution> + </executions> + <configuration> + <mainClass>org.apache.qpid.disttest.ControllerRunner</mainClass> + <includePluginDependencies>true</includePluginDependencies> + <arguments> + <argument>jndi-config=${basedir}/etc/perftests-jndi.properties</argument> + <argument>test-config=${basedir}/etc/testdefs</argument> + <argument>distributed=false</argument> + <argument>writeToDb=false</argument> + </arguments> + <systemProperties> + <systemProperty> + <key>qpid.amqp</key><value>0-91</value> + </systemProperty> + <systemProperty> + <key>qpid.dest_syntax</key><value>BURL</value> + </systemProperty> + <systemProperty> + <key>qpid.disttest.duration</key><value>5000</value> + </systemProperty> + </systemProperties> + </configuration> + <dependencies> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jms_1.1_spec</artifactId> + <version>${geronimo-jms-1-1-version}</version> + </dependency> + </dependencies> + </plugin> + </plugins> </build> diff --git a/java/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/TestFileUtils.java b/java/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/TestFileUtils.java index 26bbe151d2..00231039c3 100644 --- a/java/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/TestFileUtils.java +++ b/java/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/TestFileUtils.java @@ -121,33 +121,38 @@ public class TestFileUtils File file = createTempFile(testcase, suffix); if (content != null) { - FileOutputStream fos = null; - try - { - fos = new FileOutputStream(file); - fos.write(content.getBytes("UTF-8")); - fos.flush(); - } - catch (Exception e) - { - throw new RuntimeException("Cannot add the content into temp file " + file.getAbsolutePath(), e); - } - finally + saveTextContentInFile(content, file); + } + return file; + } + + public static void saveTextContentInFile(String content, File file) + { + FileOutputStream fos = null; + try + { + fos = new FileOutputStream(file); + fos.write(content.getBytes("UTF-8")); + fos.flush(); + } + catch (Exception e) + { + throw new RuntimeException("Cannot add the content into temp file " + file.getAbsolutePath(), e); + } + finally + { + if (fos != null) { - if (fos != null) + try { - try - { - fos.close(); - } - catch (IOException e) - { - throw new RuntimeException("Cannot close output stream into temp file " + file.getAbsolutePath(), e); - } + fos.close(); + } + catch (IOException e) + { + throw new RuntimeException("Cannot close output stream into temp file " + file.getAbsolutePath(), e); } } } - return file; } /** diff --git a/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java b/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java index 70e1b27fba..c7bcdd2edb 100644 --- a/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java +++ b/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java @@ -49,6 +49,7 @@ import org.apache.qpid.server.model.AccessControlProvider; import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.BrokerShutdownProvider; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.GroupProvider; import org.apache.qpid.server.model.JsonSystemConfigImpl; @@ -105,7 +106,8 @@ public class TestBrokerConfiguration final AbstractSystemConfig parentObject = new JsonSystemConfigImpl(taskExecutor, mock(EventLogger.class), mock(LogRecorder.class), - brokerOptions); + brokerOptions, + mock(BrokerShutdownProvider.class)); ConfiguredObjectRecordConverter converter = new ConfiguredObjectRecordConverter(BrokerModel.getInstance()); @@ -215,7 +217,8 @@ public class TestBrokerConfiguration final SystemConfig parentObject = configFactory.newInstance(_taskExecutor, mock(EventLogger.class), mock(LogRecorder.class), - brokerOptions); + brokerOptions, + mock(BrokerShutdownProvider.class)); parentObject.open(); DurableConfigurationStore configurationStore = parentObject.getConfigurationStore(); diff --git a/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java b/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java index 8b86163aa6..538bd3b32a 100644 --- a/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java +++ b/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java @@ -358,9 +358,9 @@ public class PortRestTest extends QpidRestTestCase attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); int responseCode = getRestTestHelper().submitRequest("port/" + newPortName, "PUT", attributes); - assertEquals("Unexpected response code for port creation", 201, responseCode); + assertEquals("Unexpected response code for port creation", 409, responseCode); - portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(newPortName, "UTF-8")); - Asserts.assertPortAttributes(portData, State.ERRORED); + List<Map<String,Object>> ports = getRestTestHelper().getJsonAsList("port/" + URLDecoder.decode(newPortName, "UTF-8")); + assertTrue("Port should not be created", ports.isEmpty()); } } |