Author: kwall
Date: Sun Jul 17 20:05:03 2016
New Revision: 1753106
URL: http://svn.apache.org/viewvc?rev=1753106&view=rev
Log:
QPID-7327: [Java Broker] Improve state management within the redirecting
virtualhostnode/virtualhost implementation.
Added:
qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeTest.java
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHost.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNode.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeImpl.java
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHost.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHost.java?rev=1753106&r1=1753105&r2=1753106&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHost.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHost.java
Sun Jul 17 20:05:03 2016
@@ -27,4 +27,8 @@ public interface RedirectingVirtualHost<
extends VirtualHost<X>,
NonStandardVirtualHost<X>
{
+ String CLASS_DESCRIPTION = "A special virtualhost type that merely
redirects all incoming connections to an"
+ + " alternative broker. The mapping which
governs the redirect is held by the"
+ + " the parent virtual host node.";
+
}
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java?rev=1753106&r1=1753105&r2=1753106&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java
Sun Jul 17 20:05:03 2016
@@ -32,6 +32,7 @@ import java.util.concurrent.ScheduledFut
import com.google.common.util.concurrent.ListenableFuture;
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.logging.EventLogger;
import org.apache.qpid.server.message.MessageDestination;
import org.apache.qpid.server.message.MessageSource;
@@ -55,12 +56,14 @@ import org.apache.qpid.server.transport.
import org.apache.qpid.server.txn.DtxRegistry;
import org.apache.qpid.server.virtualhost.*;
-@ManagedObject( category = false, type = RedirectingVirtualHostImpl.TYPE,
register = false )
+@ManagedObject( category = false, type =
RedirectingVirtualHostImpl.VIRTUAL_HOST_TYPE, register = false,
+ description = RedirectingVirtualHostImpl.CLASS_DESCRIPTION)
class RedirectingVirtualHostImpl
extends AbstractConfiguredObject<RedirectingVirtualHostImpl>
implements RedirectingVirtualHost<RedirectingVirtualHostImpl>
{
- public static final String TYPE = "REDIRECTOR";
+ public static final String VIRTUAL_HOST_TYPE = "REDIRECTOR";
+
private final StatisticsCounter _messagesDelivered, _dataDelivered,
_messagesReceived, _dataReceived;
private final Broker<?> _broker;
private final VirtualHostPrincipal _principal;
@@ -128,7 +131,16 @@ class RedirectingVirtualHostImpl
{
super.validateChange(proxyForValidation, changedAttributes);
- throwUnsupportedForRedirector();
+ if (changedAttributes.contains(DESIRED_STATE) &&
proxyForValidation.getDesiredState() == State.DELETED)
+ {
+ throw new IllegalConfigurationException("Directly deleting a
redirecting virtualhost is not supported. "
+ + "Delete the parent virtual host node '" +
getParent(VirtualHostNode.class) + "' instead.");
+ }
+ else
+ {
+ throw new IllegalConfigurationException("A redirecting virtualhost
does not support changing of"
+ + " its attributes");
+ }
}
@Override
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNode.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNode.java?rev=1753106&r1=1753105&r2=1753106&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNode.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNode.java
Sun Jul 17 20:05:03 2016
@@ -30,7 +30,10 @@ import org.apache.qpid.server.model.Virt
@ManagedObject(type= RedirectingVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE,
category=false, validChildTypes =
"org.apache.qpid.server.virtualhostnode.RedirectingVirtualHostNodeImpl#getSupportedChildTypes()")
public interface RedirectingVirtualHostNode<X extends
RedirectingVirtualHostNode<X>> extends VirtualHostNode<X>
{
+ public static final String REDIRECTS = "redirects";
- @ManagedAttribute( defaultValue = "{}")
+ @ManagedAttribute( defaultValue = "{}", description = "Port to hostname
mapping. Connections made to this virtual"
+ + " host node on a
mapped port will be automatically"
+ + " redirected to
the given hostname.")
Map<Port<?>, String> getRedirects();
}
Modified:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeImpl.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeImpl.java?rev=1753106&r1=1753105&r2=1753106&view=diff
==============================================================================
---
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeImpl.java
(original)
+++
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeImpl.java
Sun Jul 17 20:05:03 2016
@@ -22,11 +22,15 @@ package org.apache.qpid.server.virtualho
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Callable;
+import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -66,7 +70,7 @@ public class RedirectingVirtualHostNodeI
@ManagedAttributeField
private Map<Port<?>,String> _redirects;
- private RedirectingVirtualHostImpl _virtualHost;
+ private volatile RedirectingVirtualHostImpl _virtualHost;
@ManagedObjectFactoryConstructor
public RedirectingVirtualHostNodeImpl(Map<String, Object> attributes,
Broker<?> parent)
@@ -74,31 +78,121 @@ public class RedirectingVirtualHostNodeI
super(Collections.<Class<? extends
ConfiguredObject>,ConfiguredObject<?>>singletonMap(Broker.class, parent),
attributes);
_broker = parent;
-
}
@StateTransition( currentState = {State.UNINITIALIZED, State.STOPPED,
State.ERRORED }, desiredState = State.ACTIVE )
- protected ListenableFuture<Void> doActivate()
+ private ListenableFuture<Void> doActivate()
{
- try
- {
- _virtualHost = new
RedirectingVirtualHostImpl(Collections.<String,Object>singletonMap(ConfiguredObject.NAME,getName()),
this);
- _virtualHost.create();
- setState(State.ACTIVE);
- }
- catch(RuntimeException e)
+ final SettableFuture<Void> resultFuture = SettableFuture.create();
+ Map<String, Object> attributes = new HashMap<>();
+ attributes.put(ConfiguredObject.NAME, getName());
+ attributes.put(ConfiguredObject.TYPE,
RedirectingVirtualHostImpl.VIRTUAL_HOST_TYPE);
+
+ final ListenableFuture<VirtualHost> virtualHostFuture =
getObjectFactory().createAsync(VirtualHost.class, attributes, this);
+
+ Futures.addCallback(virtualHostFuture, new
FutureCallback<VirtualHost>()
{
- setState(State.ERRORED);
- if (getParent(Broker.class).isManagementMode())
+ @Override
+ public void onSuccess(final VirtualHost virtualHost)
{
- LOGGER.warn("Failed to make " + this + " active.", e);
+ _virtualHost = (RedirectingVirtualHostImpl) virtualHost;
+ setState(State.ACTIVE);
+ resultFuture.set(null);
+
}
- else
+
+ @Override
+ public void onFailure(final Throwable t)
{
- throw e;
+ setState(State.ERRORED);
+ if (getParent(Broker.class).isManagementMode())
+ {
+ LOGGER.warn("Failed to make {} active.", this, t);
+ resultFuture.set(null);
+ }
+ else
+ {
+ resultFuture.setException(t);
+ }
}
+ });
+
+ return resultFuture;
+ }
+
+ @StateTransition( currentState = { State.ACTIVE, State.STOPPED,
State.ERRORED}, desiredState = State.DELETED )
+ private ListenableFuture<Void> doDelete()
+ {
+ final ListenableFuture<Void> future = Futures.immediateFuture(null);
+ final RedirectingVirtualHostImpl virtualHost = _virtualHost;
+ if (virtualHost != null)
+ {
+ return doAfter(virtualHost.closeAsync(), new
Callable<ListenableFuture<Void>>()
+ {
+ @Override
+ public ListenableFuture<Void> call() throws Exception
+ {
+ _virtualHost = null;
+ deleted();
+ setState(State.DELETED);
+ return future;
+ }
+ });
+ }
+ else
+ {
+ setState(State.DELETED);
+ deleted();
+ return future;
+ }
+ }
+
+ @StateTransition( currentState = { State.ACTIVE, State.ERRORED,
State.UNINITIALIZED }, desiredState = State.STOPPED )
+ private ListenableFuture<Void> doStop()
+ {
+ final ListenableFuture<Void> future = Futures.immediateFuture(null);
+ final RedirectingVirtualHostImpl virtualHost = _virtualHost;
+ if (virtualHost != null)
+ {
+ return doAfter(virtualHost.closeAsync(), new
Callable<ListenableFuture<Void>>()
+ {
+ @Override
+ public ListenableFuture<Void> call() throws Exception
+ {
+ _virtualHost = null;
+ setState(State.STOPPED);
+ return future;
+ }
+ });
+ }
+ else
+ {
+ setState(State.STOPPED);
+ return future;
+ }
+ }
+
+ @Override
+ protected ListenableFuture<Void> beforeClose()
+ {
+ final ListenableFuture<Void> superFuture = super.beforeClose();
+ final RedirectingVirtualHostImpl virtualHost = _virtualHost;
+ if (virtualHost != null)
+ {
+ return doAfter(virtualHost.closeAsync(), new
Callable<ListenableFuture<Void>>()
+ {
+ @Override
+ public ListenableFuture<Void> call() throws Exception
+ {
+ _virtualHost = null;
+ return superFuture;
+ }
+ });
+ }
+ else
+ {
+ return superFuture;
}
- return Futures.immediateFuture(null);
}
@Override
@@ -149,7 +243,6 @@ public class RedirectingVirtualHostNodeI
return _redirects;
}
-
@Override
protected void validateOnCreate()
{
@@ -165,7 +258,6 @@ public class RedirectingVirtualHostNodeI
+ "' is already the
default for the Broker.");
}
}
-
}
@Override
@@ -186,6 +278,19 @@ public class RedirectingVirtualHostNodeI
}
}
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ protected <C extends ConfiguredObject> ListenableFuture<C>
addChildAsync(Class<C> childClass, Map<String, Object> attributes,
+
ConfiguredObject... otherParents)
+ {
+ if(childClass == VirtualHost.class)
+ {
+ throw new UnsupportedOperationException("The redirecting
virtualhost node automatically manages the creation"
+ + " of the redirecting
virtualhost. Creating it explicitly is not supported.");
+ }
+ return super.addChildAsync(childClass, attributes, otherParents);
+ }
+
public static Map<String, Collection<String>> getSupportedChildTypes()
{
Collection<String> validVhostTypes =
Collections.singleton(RedirectingVirtualHostImpl.TYPE);
Added:
qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeTest.java
URL:
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeTest.java?rev=1753106&view=auto
==============================================================================
---
qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeTest.java
(added)
+++
qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostNodeTest.java
Sun Jul 17 20:05:03 2016
@@ -0,0 +1,154 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.virtualhostnode;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
+import org.apache.qpid.server.configuration.updater.TaskExecutor;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.BrokerTestHelper;
+import org.apache.qpid.server.model.ConfiguredObjectFactoryImpl;
+import org.apache.qpid.server.model.Model;
+import org.apache.qpid.server.model.Port;
+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.model.port.AmqpPort;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class RedirectingVirtualHostNodeTest extends QpidTestCase
+{
+ private static final String TEST_VIRTUAL_HOST_NODE_NAME = "testNode";
+
+ private final UUID _nodeId = UUID.randomUUID();
+ private Broker<?> _broker;
+ private TaskExecutor _taskExecutor;
+ private AmqpPort _port;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ _broker = BrokerTestHelper.createBrokerMock();
+ SystemConfig<?> systemConfig = _broker.getParent(SystemConfig.class);
+ when(systemConfig.getObjectFactory()).thenReturn(new
ConfiguredObjectFactoryImpl(mock(Model.class)));
+
+ _taskExecutor = new CurrentThreadTaskExecutor();
+ _taskExecutor.start();
+ when(_broker.getTaskExecutor()).thenReturn(_taskExecutor);
+ when(_broker.getChildExecutor()).thenReturn(_taskExecutor);
+
+ AuthenticationProvider dummyAuthProvider =
mock(AuthenticationProvider.class);
+ when(dummyAuthProvider.getName()).thenReturn("dummy");
+ when(dummyAuthProvider.getId()).thenReturn(UUID.randomUUID());
+
when(dummyAuthProvider.getMechanisms()).thenReturn(Arrays.asList("PLAIN"));
+
when(_broker.getChildren(eq(AuthenticationProvider.class))).thenReturn(Collections.singleton(dummyAuthProvider));
+
+ final Map<String, Object> attributes = new HashMap<>();
+ attributes.put(Port.NAME, getTestName());
+ attributes.put(Port.PORT, 0);
+ attributes.put(Port.AUTHENTICATION_PROVIDER, "dummy");
+ attributes.put(Port.TYPE, "AMQP");
+ _port = (AmqpPort) _broker.getObjectFactory().create(Port.class,
attributes, _broker);
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ try
+ {
+ _taskExecutor.stopImmediately();
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ public void testRedirectingVHNHasRedirectingVHToo() throws Exception
+ {
+ final Map<String, Object> attributes =
createVirtualHostNodeAttributes();
+
+ RedirectingVirtualHostNode node =
+ (RedirectingVirtualHostNode)
_broker.getObjectFactory().create(VirtualHostNode.class,
+
attributes,
+
_broker);
+ assertEquals("Unexpected number of virtualhost children",
+ 1, node.getChildren(VirtualHost.class).size());
+ assertTrue("Virtualhost child is of unexpected type",
+ node.getChildren(VirtualHost.class).iterator().next()
instanceof RedirectingVirtualHost);
+ }
+
+ public void testStopAndRestartVHN() throws Exception
+ {
+ final Map<String, Object> attributes =
createVirtualHostNodeAttributes();
+
+ RedirectingVirtualHostNode node =
+ (RedirectingVirtualHostNode)
_broker.getObjectFactory().create(VirtualHostNode.class,
+
attributes,
+
_broker);
+ assertEquals("Unexpected number of virtualhost children before stop",
+ 1, node.getChildren(VirtualHost.class).size());
+ node.stop();
+ assertEquals("Unexpected number of virtualhost children after stop",
+ 0, node.getChildren(VirtualHost.class).size());
+ node.start();
+ assertEquals("Unexpected number of virtualhost children after restart",
+ 1, node.getChildren(VirtualHost.class).size());
+ }
+
+ public void testDeleteVHN() throws Exception
+ {
+ final Map<String, Object> attributes =
createVirtualHostNodeAttributes();
+
+ RedirectingVirtualHostNode node =
+ (RedirectingVirtualHostNode)
_broker.getObjectFactory().create(VirtualHostNode.class,
+
attributes,
+
_broker);
+ assertEquals("Unexpected number of virtualhost children before delete",
+ 1, node.getChildren(VirtualHost.class).size());
+ node.delete();
+ assertEquals("Unexpected number of virtualhost children after delete",
+ 0, node.getChildren(VirtualHost.class).size());
+ }
+
+ private Map<String, Object> createVirtualHostNodeAttributes()
+ {
+ final Map<String, Object> attributes = new HashMap<>();
+ attributes.put(VirtualHostNode.TYPE,
RedirectingVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE);
+ attributes.put(VirtualHostNode.NAME, TEST_VIRTUAL_HOST_NODE_NAME);
+ attributes.put(RedirectingVirtualHostNode.REDIRECTS,
Collections.singletonMap(_port, "myalternativehostname"));
+ return attributes;
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]