diff options
| author | Alex Rudyy <orudyy@apache.org> | 2014-10-01 23:48:14 +0000 |
|---|---|---|
| committer | Alex Rudyy <orudyy@apache.org> | 2014-10-01 23:48:14 +0000 |
| commit | a638bc903339cac26e522df787ad4fcbca2344aa (patch) | |
| tree | 94a5bae92749b96c229ca36590e681032f6aa752 /qpid/java | |
| parent | f84ed512e919a6c717cbdbcc22e8139bc64bc205 (diff) | |
| download | qpid-python-a638bc903339cac26e522df787ad4fcbca2344aa.tar.gz | |
QPID-6126: Add ability to validate CO attributes on creation, transit COs into ERRORED state if exception occurs on recovery, allow ERRORED CO restart after remediation of configuration problem
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1628867 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java')
52 files changed, 2420 insertions, 333 deletions
diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBSystemConfigImpl.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBSystemConfigImpl.java index 0fc44605fe..5d65d6e16d 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBSystemConfigImpl.java +++ b/qpid/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/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java index e6109954c0..98b9cc3cf0 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java @@ -20,7 +20,9 @@ */ package org.apache.qpid.server.virtualhostnode.berkeleydb; +import java.io.File; import java.net.InetSocketAddress; +import java.nio.file.Files; import java.security.PrivilegedAction; import java.text.MessageFormat; import java.util.ArrayList; @@ -74,6 +76,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; @@ -280,20 +283,6 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu public void onCreate() { 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; - } - } getEventLogger().message(getVirtualHostNodeLogSubject(), HighAvailabilityMessages.CREATED()); } @@ -435,19 +424,102 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu public void onValidate() { super.onValidate(); + validatePermittedNodes(_permittedNodes); + } + + @Override + protected void postResolve() + { + 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(); - validatePermittedNodes(_permittedNodes); + validateAddress(); + + validateStorePath(); + + if (!isFirstNodeInAGroup()) + { + // validate that helper address points to valid node + // we need _permittedNodes for the further validation in onValidate + _permittedNodes = new ArrayList<>(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(); + + if (address == null || "".equals(address)) + { + throw new IllegalConfigurationException("Node address is not set"); + } + + String[] tokens = address.split(":"); + if (tokens.length != 2) + { + throw new IllegalConfigurationException(String.format("Invalid address specified '%s'. ", address)); + } + + String hostName = tokens[0]; + if ("".equals(hostName.trim())) + { + throw new IllegalConfigurationException(String.format("Invalid address specified '%s'. ", address)); + } + + int port = -1; + try + { + port = Integer.parseInt(tokens[1]); + } + catch(Exception e) + { + throw new IllegalConfigurationException(String.format("Invalid port is specified in address '%s'. ", address)); + } + if (!PortUtil.isPortAvailable(hostName, port)) + { + throw new IllegalConfigurationException(String.format("Cannot bind to address '%s'. Address is already in use.", address)); + } + } + + + private void onMaster() { try @@ -761,7 +833,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,28 +844,32 @@ 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) + { + throw new IllegalArgumentException(String.format("The current group node '%s' cannot be removed from '%s' as its already a group member", missingNodeAddress, PERMITTED_NODES)); + } } for (String permittedNode: proposedPermittedNodes) diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java index e9bcc5d754..16486e3564 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java @@ -23,6 +23,8 @@ 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; @@ -53,6 +55,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 { @@ -587,4 +591,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 '%s'", "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/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBVirtualHostImplTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBVirtualHostImplTest.java new file mode 100644 index 0000000000..92da465dbd --- /dev/null +++ b/qpid/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/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBVirtualHostNodeTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBVirtualHostNodeTest.java new file mode 100644 index 0000000000..6608312088 --- /dev/null +++ b/qpid/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/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/SystemConfigFactoryGenerator.java b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/SystemConfigFactoryGenerator.java index c569bc4641..317e0f7c74 100644 --- a/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/SystemConfigFactoryGenerator.java +++ b/qpid/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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java index 0a1979128f..0b925d130c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java @@ -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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java index b71d667fe0..6c67a44bb0 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/binding/BindingImpl.java @@ -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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index fd0333f6e7..989a4abea5 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java index d3741cd846..9ff7e224cd 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java @@ -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,84 @@ 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); + validateOnCreate(); + doValidation(true, createExceptionHandler); + registerWithParents(); + } + catch(RuntimeException e) + { + createExceptionHandler.handleException(e, this); + } + + AbstractConfiguredObjectExceptionHandler unregisteringExceptionHandler = new CreateExceptionHandler(true); + try + { + doCreation(true, unregisteringExceptionHandler); + } + catch(RuntimeException e) + { + unregisteringExceptionHandler.handleException(e, this); + } + + OpenExceptionHandler openExceptionHandler = new OpenExceptionHandler(); + try + { + doOpening(true, openExceptionHandler); + doAttainState(openExceptionHandler); + } + catch(RuntimeException e) + { + openExceptionHandler.handleException(e, this); + } + } + } + + protected void validateOnCreate() + { + } + + protected final void handleExceptionOnOpen(RuntimeException e, AbstractConfiguredObject<?> configuredObject) + { + if (e instanceof ServerScopedRuntimeException) + { + throw e; + } - registerWithParents(); + LOGGER.error("Exception occurred on open for " + configuredObject.getName(), e); - doCreation(true); - doOpening(true); - doAttainState(); + try + { + configuredObject.onExceptionInOpen(e); + } + catch (RuntimeException re) + { + LOGGER.error("Unexpected exception while handling exception on open for " + configuredObject.getName(), e); } + + if (!configuredObject._openComplete) + { + configuredObject._openFailed = true; + configuredObject._dynamicState.compareAndSet(DynamicState.OPENED, DynamicState.UNINIT); + } + configuredObject.closeChildren(); + configuredObject.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 +584,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)) { @@ -525,7 +615,15 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { if (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 +631,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) { @@ -544,7 +642,15 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { if (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 +658,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 +690,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 +702,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 +833,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,7 +956,7 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im State state = getState(); if(desiredState == getDesiredState() && desiredState != state) { - attainState(); + attainStateIfOpenedOrReopenFailed(); return getState(); } else @@ -1217,7 +1343,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 +1881,54 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im return _name; } } + + interface AbstractConfiguredObjectExceptionHandler + { + void handleException(RuntimeException exception, AbstractConfiguredObject<?> source); + } + + private class OpenExceptionHandler implements AbstractConfiguredObjectExceptionHandler + { + @Override + public void handleException(RuntimeException exception, AbstractConfiguredObject<?> source) + { + handleExceptionOnOpen(exception, source); + } + } + + private class CreateExceptionHandler implements AbstractConfiguredObjectExceptionHandler + { + private boolean _unregister; + + private CreateExceptionHandler() + { + this(false); + } + + private CreateExceptionHandler(boolean unregister) + { + this._unregister = unregister; + } + + @Override + + public void handleException(RuntimeException exception, AbstractConfiguredObject<?> source) + { + if (source.getState() != State.DELETED) + { + try + { + source.delete(); + } + finally + { + if (_unregister) + { + source.unregister(false); + } + throw exception; + } + } + } + } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractSystemConfig.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractSystemConfig.java index 19f6139387..f8dac7cbe9 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractSystemConfig.java +++ b/qpid/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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/BrokerShutdownProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/BrokerShutdownProvider.java new file mode 100644 index 0000000000..5c8ab3e850 --- /dev/null +++ b/qpid/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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/JsonSystemConfigImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/JsonSystemConfigImpl.java index 1763aca524..c9a828e7e4 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/JsonSystemConfigImpl.java +++ b/qpid/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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java index 7943c32c42..ec063142b4 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemConfig.java @@ -37,4 +37,6 @@ public interface SystemConfig<X extends SystemConfig<X>> extends ConfiguredObjec LogRecorder getLogRecorder(); DurableConfigurationStore getConfigurationStore(); + + BrokerShutdownProvider getBrokerShutdownProvider(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java index 92ac43e629..109aaff5bd 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java +++ b/qpid/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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java index c96f4c0849..1b3d0591c0 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java @@ -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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java index f2be4fd861..60be3592f8 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java @@ -76,20 +76,72 @@ 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 onCreate() + { + super.validateOnCreate(); + File storeFile = new File(_path); + if (!storeFile.exists() ) + { + new FileSystemPreferencesStore(storeFile).createIfNotExist(); + } + } + + @Override + protected void onOpen() + { + FileSystemPreferencesStore store = new FileSystemPreferencesStore(new File(_path)); + 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 +200,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 +215,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 +287,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 +338,6 @@ public class FileSystemPreferencesProviderImpl } - private void createStoreIfNotExist() - { - _store.createIfNotExist(); - } - public static class FileSystemPreferencesStore { private final ObjectMapper _objectMapper; @@ -294,18 +362,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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java index c0aa99a7d6..e2e7eff322 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java +++ b/qpid/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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java index fe7d419c78..afe3c9a44e 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java +++ b/qpid/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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java index 1774f16ab6..3be5854645 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java +++ b/qpid/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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/SystemConfigFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/SystemConfigFactory.java index 9162f9e095..885194d939 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/plugin/SystemConfigFactory.java +++ b/qpid/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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java index a5156c9073..38cea2cdb7 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java @@ -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); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index a6a2ea8d34..192a096d12 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/PortUtil.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/PortUtil.java new file mode 100644 index 0000000000..5d093bd3d5 --- /dev/null +++ b/qpid/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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java index f52c1967f8..26ce6aca4c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java @@ -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(); @@ -1355,7 +1395,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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNode.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNode.java index ce97502124..03c30a9cd4 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNode.java +++ b/qpid/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/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java index 5cbfb0942a..1b363890dc 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/AbstractVirtualHostNode.java +++ b/qpid/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; @@ -205,11 +197,29 @@ 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() + { + DurableConfigurationStore store = getConfigurationStore(); + if (store == null) + { + store = createConfigurationStore(); + } + _configurationStoreLogSubject = new MessageStoreLogSubject(getName(), store.getClass().getSimpleName()); + } + + @Override protected void onClose() { closeConfigurationStore(); @@ -262,6 +272,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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/binding/BindingImplTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/binding/BindingImplTest.java new file mode 100644 index 0000000000..93fa9114fb --- /dev/null +++ b/qpid/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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/FileKeyStoreCreationTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/FileKeyStoreCreationTest.java index 4b4891d838..b4f92990eb 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/FileKeyStoreCreationTest.java +++ b/qpid/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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandlerTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandlerTest.java index 36353f0dba..fbb08cdd2a 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandlerTest.java +++ b/qpid/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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/AbstractConfiguredObjectTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/AbstractConfiguredObjectTest.java index e5c5a89c10..a09910b7e2 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/AbstractConfiguredObjectTest.java +++ b/qpid/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,129 @@ 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); + object.create(); + 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 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()); + } } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImplTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImplTest.java new file mode 100644 index 0000000000..50a4e5a86e --- /dev/null +++ b/qpid/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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderTest.java index 9bb004e4c2..f532a9325b 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderTest.java +++ b/qpid/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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java index 523203c756..642ea06ede 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java +++ b/qpid/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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/port/AmqpPortImplTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/port/AmqpPortImplTest.java new file mode 100644 index 0000000000..78ce0d1356 --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/port/AmqpPortImplTest.java @@ -0,0 +1,104 @@ +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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestConfiguredObject.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestConfiguredObject.java new file mode 100644 index 0000000000..0ba5673f91 --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestConfiguredObject.java @@ -0,0 +1,123 @@ +package org.apache.qpid.server.model.testmodel; + +import static org.mockito.Mockito.mock; + +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.ManagedObject; +import org.apache.qpid.server.model.Model; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.StateTransition; + +@ManagedObject +public class TestConfiguredObject extends AbstractConfiguredObject +{ + private boolean _throwExceptionOnOpen; + private boolean _opened; + private boolean _throwExceptionOnValidationOnCreate; + private boolean _throwExceptionOnPostResolve; + private boolean _throwExceptionOnCreate; + + public TestConfiguredObject(String name) + { + this(createParents(), Collections.<String, Object>singletonMap(ConfiguredObject.NAME, name), createTaskExecutor(), new TestModel(null)); + } + + public final static Map<Class<? extends ConfiguredObject>, ConfiguredObject<?>> createParents() + { + return Collections.<Class<? extends ConfiguredObject>, ConfiguredObject<?>>singletonMap(null, mock(ConfiguredObject.class)); + } + + public final static TaskExecutor createTaskExecutor() + { + TaskExecutor taskExecutor = new CurrentThreadTaskExecutor(); + taskExecutor.start(); + return taskExecutor; + } + + 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"); + } + } + + @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"); + } + } + + @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; + } +} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java index 703a8d43c9..84ba7a3822 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java +++ b/qpid/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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerRecovererTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerRecovererTest.java index 52f70e7fd6..c220876a23 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerRecovererTest.java +++ b/qpid/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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecovererTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecovererTest.java index c94a0ef9c4..45b595b62e 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecovererTest.java +++ b/qpid/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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhost/AbstractVirtualHostTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhost/AbstractVirtualHostTest.java new file mode 100644 index 0000000000..889097f850 --- /dev/null +++ b/qpid/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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java index 971c96b2ff..b17f383217 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/AbstractStandardVirtualHostNodeTest.java +++ b/qpid/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/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/TestVirtualHostNode.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/TestVirtualHostNode.java index 277ef8b400..4fe8136624 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/TestVirtualHostNode.java +++ b/qpid/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/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImpl.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImpl.java index f0edc59025..1adc6561c7 100644 --- a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImpl.java +++ b/qpid/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/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImplTest.java b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImplTest.java new file mode 100644 index 0000000000..781e553fe5 --- /dev/null +++ b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImplTest.java @@ -0,0 +1,79 @@ +/* + * + * 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 = TMP_FOLDER + File.separator + "test_" + getTestName() + System.nanoTime() + ".acl"; + 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/qpid/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/store/derby/DerbySystemConfigImpl.java b/qpid/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/store/derby/DerbySystemConfigImpl.java index 32c5bcd541..a8b9edaa12 100644 --- a/qpid/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/store/derby/DerbySystemConfigImpl.java +++ b/qpid/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/qpid/java/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSystemConfigImpl.java b/qpid/java/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSystemConfigImpl.java index fd1cad7de4..a552b170a0 100644 --- a/qpid/java/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSystemConfigImpl.java +++ b/qpid/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/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java index e07705656a..936cc4789a 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java @@ -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/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java index a38aa9e349..85916bf5f2 100644 --- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java +++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java @@ -103,7 +103,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; diff --git a/qpid/java/broker-plugins/memory-store/src/main/java/org/apache/qpid/server/store/MemorySystemConfigImpl.java b/qpid/java/broker-plugins/memory-store/src/main/java/org/apache/qpid/server/store/MemorySystemConfigImpl.java index f644b8f46b..3f5215219b 100644 --- a/qpid/java/broker-plugins/memory-store/src/main/java/org/apache/qpid/server/store/MemorySystemConfigImpl.java +++ b/qpid/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/qpid/java/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/TestFileUtils.java b/qpid/java/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/TestFileUtils.java index 26bbe151d2..00231039c3 100644 --- a/qpid/java/qpid-test-utils/src/main/java/org/apache/qpid/test/utils/TestFileUtils.java +++ b/qpid/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/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java index 70e1b27fba..c7bcdd2edb 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java +++ b/qpid/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/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java index 8b86163aa6..538bd3b32a 100644 --- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java @@ -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()); } } |
