diff options
| author | Robert Godfrey <rgodfrey@apache.org> | 2014-08-22 19:36:40 +0000 |
|---|---|---|
| committer | Robert Godfrey <rgodfrey@apache.org> | 2014-08-22 19:36:40 +0000 |
| commit | 50848155750de045ff7099f7ea3561f41a1887b8 (patch) | |
| tree | d7f036b163bb4737d3ba93bf72f594cab0d78e1a /qpid/java | |
| parent | d42d6b5305b6617bd5bdc7417500e115e2346a88 (diff) | |
| download | qpid-python-50848155750de045ff7099f7ea3561f41a1887b8.tar.gz | |
QPID-6036 : [Java Broker] Allow complete virtual host initial configuration to be passed in on creation of a virtualhost node
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1619918 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java')
12 files changed, 347 insertions, 144 deletions
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 fd098a8ef6..06e97afd98 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 @@ -26,6 +26,7 @@ import java.text.MessageFormat; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -63,6 +64,8 @@ import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.StateTransition; import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.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; import org.apache.qpid.server.store.berkeleydb.BDBConfigurationStore; @@ -434,41 +437,40 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu { LOGGER.debug("Creating new virtualhost with name : " + getGroupName()); } - - boolean hasBlueprint = getContextKeys(false).contains(VIRTUALHOST_BLUEPRINT_CONTEXT_VAR); - boolean blueprintUtilised = getContext().containsKey(VIRTUALHOST_BLUEPRINT_UTILISED_CONTEXT_VAR) - && Boolean.parseBoolean(String.valueOf(getContext().get( - VIRTUALHOST_BLUEPRINT_UTILISED_CONTEXT_VAR))); - - Map<String, Object> hostAttributes = new HashMap<>(); - if (hasBlueprint && !blueprintUtilised) + ConfiguredObjectRecord[] initialRecords = getInitialRecords(); + if(initialRecords != null && initialRecords.length > 0) { - Map<String, Object> virtualhostBlueprint = - getContextValue(Map.class, VIRTUALHOST_BLUEPRINT_CONTEXT_VAR); - - if (LOGGER.isDebugEnabled()) + getConfigurationStore().update(true, initialRecords); + getEventLogger().message(getConfigurationStoreLogSubject(), ConfigStoreMessages.RECOVERY_START()); + upgraderAndRecoverer = new VirtualHostStoreUpgraderAndRecoverer(this); + upgraderAndRecoverer.perform(getConfigurationStore()); + getEventLogger().message(getConfigurationStoreLogSubject(), ConfigStoreMessages.RECOVERY_COMPLETE()); + setAttribute(VIRTUALHOST_INITIAL_CONFIGURATION, getVirtualHostInitialConfiguration(), "{}" ); + host = getVirtualHost(); + if(host != null) { - LOGGER.debug("Using virtualhost blueprint " + virtualhostBlueprint); + final VirtualHost<?,?,?> recoveredHost = host; + Subject.doAs(SecurityManager.getSubjectWithAddedSystemRights(), new PrivilegedAction<Object>() + { + @Override + public Object run() + { + recoveredHost.open(); + return null; + } + }); } - - hostAttributes.putAll(virtualhostBlueprint); - - } - - hostAttributes.put(VirtualHost.MODEL_VERSION, BrokerModel.MODEL_VERSION); - hostAttributes.put(VirtualHost.NAME, getGroupName()); - hostAttributes.put(VirtualHost.TYPE, BDBHAVirtualHostImpl.VIRTUAL_HOST_TYPE); - host = createChild(VirtualHost.class, hostAttributes); - - if (hasBlueprint && !blueprintUtilised) + else { - // Update the context with the utilised flag - Map<String, String> actualContext = (Map<String, String>) getActualAttributes().get(CONTEXT); - Map<String, String> context = new HashMap<>(actualContext); - context.put(VIRTUALHOST_BLUEPRINT_UTILISED_CONTEXT_VAR, Boolean.TRUE.toString()); - setAttribute(CONTEXT, getContext(), context); + Map<String, Object> hostAttributes = new HashMap<>(); + + hostAttributes.put(VirtualHost.MODEL_VERSION, BrokerModel.MODEL_VERSION); + hostAttributes.put(VirtualHost.NAME, getGroupName()); + hostAttributes.put(VirtualHost.TYPE, BDBHAVirtualHostImpl.VIRTUAL_HOST_TYPE); + host = createChild(VirtualHost.class, hostAttributes); } + } else { @@ -706,6 +708,17 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu return _groupLogSubject; } + @Override + protected ConfiguredObjectRecord enrichInitialVirtualHostRootRecord(final ConfiguredObjectRecord vhostRecord) + { + Map<String,Object> hostAttributes = new LinkedHashMap<>(vhostRecord.getAttributes()); + hostAttributes.put(VirtualHost.MODEL_VERSION, BrokerModel.MODEL_VERSION); + hostAttributes.put(VirtualHost.NAME, getGroupName()); + hostAttributes.put(VirtualHost.TYPE, BDBHAVirtualHostImpl.VIRTUAL_HOST_TYPE); + return new ConfiguredObjectRecordImpl(vhostRecord.getId(), vhostRecord.getType(), + hostAttributes, vhostRecord.getParents()); + } + private class RemoteNodesDiscoverer implements ReplicationGroupListener { @Override 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 c667e7f7bb..e69000ecd1 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 @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.store.berkeleydb; -import static java.util.Collections.*; import static org.mockito.Mockito.when; import java.io.File; @@ -29,7 +28,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -48,12 +46,10 @@ import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost; import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHostImpl; -import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHARemoteReplicationNode; import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHARemoteReplicationNodeImpl; import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNodeTestHelper; -import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNodeImpl; import org.apache.qpid.test.utils.QpidTestCase; public class BDBHAVirtualHostNodeTest extends QpidTestCase @@ -94,20 +90,6 @@ public class BDBHAVirtualHostNodeTest extends QpidTestCase context.put(ReplicationConfig.REP_STREAM_TIMEOUT, repStreamTimeout); BDBHAVirtualHostNode<?> node = _helper.createHaVHN(attributes); - final CountDownLatch virtualHostAddedLatch = new CountDownLatch(1); - node.addChangeListener(new NoopConfigurationChangeListener() - { - @Override - public void childAdded(ConfiguredObject<?> object, ConfiguredObject<?> child) - { - if (child instanceof VirtualHost) - { - child.addChangeListener(this); - virtualHostAddedLatch.countDown(); - } - } - }); - node.start(); _helper.assertNodeRole(node, "MASTER", "REPLICA"); @@ -128,7 +110,7 @@ public class BDBHAVirtualHostNodeTest extends QpidTestCase assertEquals("SYNC,NO_SYNC,SIMPLE_MAJORITY", environment.getConfig().getDurability().toString()); assertEquals("Unexpected JE replication stream timeout", repStreamTimeout, replicationConfig.getConfigParam(ReplicationConfig.REP_STREAM_TIMEOUT)); - assertTrue("Virtual host child has not been added", virtualHostAddedLatch.await(30, TimeUnit.SECONDS)); + _helper.awaitForVirtualhost(node, 30000); VirtualHost<?, ?, ?> virtualHost = node.getVirtualHost(); assertNotNull("Virtual host child was not added", virtualHost); assertEquals("Unexpected virtual host name", groupName, virtualHost.getName()); @@ -314,25 +296,11 @@ public class BDBHAVirtualHostNodeTest extends QpidTestCase Map<String, Object> nodeAttributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, node1PortNumber); BDBHAVirtualHostNode<?> node = _helper.createHaVHN(nodeAttributes); - final CountDownLatch virtualHostAddedLatch = new CountDownLatch(1); - node.addChangeListener(new NoopConfigurationChangeListener() - { - @Override - public void childAdded(ConfiguredObject<?> object, ConfiguredObject<?> child) - { - if (child instanceof VirtualHost) - { - child.addChangeListener(this); - virtualHostAddedLatch.countDown(); - } - } - }); - node.start(); _helper.assertNodeRole(node, "MASTER", "REPLICA"); assertEquals("Unexpected node state", State.ACTIVE, node.getState()); - assertTrue("Virtual host child has not been added", virtualHostAddedLatch.await(30, TimeUnit.SECONDS)); + _helper.awaitForVirtualhost(node,30000); BDBHAVirtualHostImpl virtualHost = (BDBHAVirtualHostImpl)node.getVirtualHost(); assertNotNull("Virtual host is not created", virtualHost); @@ -500,4 +468,4 @@ public class BDBHAVirtualHostNodeTest extends QpidTestCase assertTrue("Intruder protection was not triggered during expected timeout", stopLatch.await(20, TimeUnit.SECONDS)); } -}
\ No newline at end of file +} diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java index 07b5a8a21c..41c6c9a71c 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java @@ -38,10 +38,19 @@ import java.util.Set; import java.util.UUID; import com.sleepycat.je.rep.ReplicationConfig; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig; import org.apache.qpid.server.configuration.updater.TaskExecutor; import org.apache.qpid.server.configuration.updater.TaskExecutorImpl; -import org.apache.qpid.server.model.*; +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.ConfiguredObjectFactory; +import org.apache.qpid.server.model.RemoteReplicationNode; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostNode; import org.apache.qpid.server.store.ConfiguredObjectRecordImpl; import org.apache.qpid.server.store.UnresolvedConfiguredObject; import org.apache.qpid.server.util.BrokerTestHelper; @@ -50,8 +59,6 @@ import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHostImpl; import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.util.FileUtils; -import org.codehaus.jackson.map.ObjectMapper; -import org.codehaus.jackson.map.SerializationConfig; /** * Helper class to make the tests of BDB HA Virtual Host Nodes simpler and more concise. @@ -281,7 +288,7 @@ public class BDBHAVirtualHostNodeTestHelper if (ports != null) { String bluePrint = getBlueprint(ports); - context.put(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, bluePrint); + node1Attributes.put(AbstractVirtualHostNode.VIRTUALHOST_INITIAL_CONFIGURATION, bluePrint); } node1Attributes.put(BDBHAVirtualHostNode.CONTEXT, context); @@ -307,4 +314,24 @@ public class BDBHAVirtualHostNodeTestHelper return writer.toString(); } + public void awaitForVirtualhost(final VirtualHostNode<?> node, final int wait) + { + long endTime = System.currentTimeMillis() + wait; + do + { + if(node.getVirtualHost() != null) + { + return; + } + try + { + Thread.sleep(100); + } + catch (InterruptedException e) + { + // ignore + } + } + while(System.currentTimeMillis() < endTime); + } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostNode.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostNode.java index f4d9df6eff..ce1022c2d9 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostNode.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHostNode.java @@ -27,6 +27,16 @@ import org.apache.qpid.server.store.DurableConfigurationStore; @ManagedObject(category=true, managesChildren=false) public interface VirtualHostNode<X extends VirtualHostNode<X>> extends ConfiguredObject<X> { + String VIRTUALHOST_INITIAL_CONFIGURATION = "virtualHostInitialConfiguration"; + + String VIRTUALHOST_BLUEPRINT_CONTEXT_VAR = "virtualhostBlueprint"; + + @ManagedContextDefault(name = VIRTUALHOST_BLUEPRINT_CONTEXT_VAR) + String DEFAULT_INITIAL_CONFIGURATION = "{}"; + + @ManagedAttribute( defaultValue = "${" + VIRTUALHOST_BLUEPRINT_CONTEXT_VAR + "}") + String getVirtualHostInitialConfiguration(); + VirtualHost<?,?,?> getVirtualHost(); DurableConfigurationStore getConfigurationStore(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/NullMessageStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/NullMessageStore.java index 66975e1189..2e6c437e95 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/NullMessageStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/NullMessageStore.java @@ -29,6 +29,8 @@ import org.apache.qpid.server.store.handler.MessageInstanceHandler; public abstract class NullMessageStore implements MessageStore, DurableConfigurationStore, MessageStoreProvider { + private ConfiguredObjectRecord[] _initialRecords; + @Override public MessageStore getMessageStore() { @@ -40,6 +42,7 @@ public abstract class NullMessageStore implements MessageStore, DurableConfigura final boolean overwrite, final ConfiguredObjectRecord... initialRecords) { + _initialRecords = initialRecords; } @Override @@ -121,6 +124,18 @@ public abstract class NullMessageStore implements MessageStore, DurableConfigura @Override public void visitConfiguredObjectRecords(ConfiguredObjectRecordHandler handler) throws StoreException { + handler.begin(); + if(_initialRecords != null) + { + for(ConfiguredObjectRecord record : _initialRecords) + { + if(!handler.handle(record)) + { + break; + } + } + } + handler.end(); } @Override diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/urlstreamhandler/data/Handler.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/urlstreamhandler/data/Handler.java index fb0ab4f696..770991bd3d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/urlstreamhandler/data/Handler.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/util/urlstreamhandler/data/Handler.java @@ -136,13 +136,4 @@ public class Handler extends URLStreamHandler return new ByteArrayInputStream(_content); } } - - public static void main(String[] args) throws IOException - { - register(); - URL url = new URL("data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7"); - InputStream is = url.openStream(); - url = new URL("data:,A%20brief%20note"); - is = url.openStream(); - } } 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 b4374af0f0..ce97502124 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 @@ -20,24 +20,27 @@ */ package org.apache.qpid.server.virtualhostnode; +import java.io.IOException; import java.security.PrivilegedAction; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import javax.security.auth.Subject; import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.logging.messages.ConfigStoreMessages; 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.RemoteReplicationNode; 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.ConfiguredObjectRecord; +import org.apache.qpid.server.store.ConfiguredObjectRecordImpl; import org.apache.qpid.server.store.VirtualHostStoreUpgraderAndRecoverer; public abstract class AbstractStandardVirtualHostNode<X extends AbstractStandardVirtualHostNode<X>> extends AbstractVirtualHostNode<X> @@ -71,7 +74,20 @@ public abstract class AbstractStandardVirtualHostNode<X extends AbstractStandard LOGGER.debug("Activating virtualhost node " + this); } - getConfigurationStore().openConfigurationStore(this, false); + try + { + ConfiguredObjectRecord[] initialRecords = getInitialRecords(); + getConfigurationStore().openConfigurationStore(this, false, initialRecords); + if(initialRecords != null && initialRecords.length > 0) + { + setAttribute(VIRTUALHOST_INITIAL_CONFIGURATION, getVirtualHostInitialConfiguration(), "{}"); + } + } + catch (IOException e) + { + throw new IllegalConfigurationException("Could not process initial configuration", e); + } + getConfigurationStore().upgradeStoreStructure(); getEventLogger().message(getConfigurationStoreLogSubject(), ConfigStoreMessages.CREATED()); @@ -87,47 +103,7 @@ public abstract class AbstractStandardVirtualHostNode<X extends AbstractStandard VirtualHost<?,?,?> host = getVirtualHost(); - if (host == null) - { - - boolean hasBlueprint = getContextKeys(false).contains(VIRTUALHOST_BLUEPRINT_CONTEXT_VAR); - boolean blueprintUtilised = getContext().containsKey(VIRTUALHOST_BLUEPRINT_UTILISED_CONTEXT_VAR) - && Boolean.parseBoolean(String.valueOf(getContext().get(VIRTUALHOST_BLUEPRINT_UTILISED_CONTEXT_VAR))); - - if (hasBlueprint && !blueprintUtilised) - { - Map<String, Object> virtualhostBlueprint = getContextValue(Map.class, VIRTUALHOST_BLUEPRINT_CONTEXT_VAR); - - if (LOGGER.isDebugEnabled()) - { - LOGGER.debug("Using virtualhost blueprint " + virtualhostBlueprint); - } - - Map<String, Object> virtualhostAttributes = new HashMap<>(); - virtualhostAttributes.put(VirtualHost.MODEL_VERSION, BrokerModel.MODEL_VERSION); - virtualhostAttributes.put(VirtualHost.NAME, getName()); - virtualhostAttributes.putAll(virtualhostBlueprint); - - if (LOGGER.isDebugEnabled()) - { - LOGGER.debug("Creating new virtualhost named " + virtualhostAttributes.get(VirtualHost.NAME)); - } - - host = createChild(VirtualHost.class, virtualhostAttributes); - - if (LOGGER.isDebugEnabled()) - { - LOGGER.debug("Created new virtualhost: " + host); - } - - // Update the context with the utilised flag - Map<String, String> actualContext = (Map<String, String>) getActualAttributes().get(CONTEXT); - Map<String, String> context = new HashMap<>(actualContext); - context.put(VIRTUALHOST_BLUEPRINT_UTILISED_CONTEXT_VAR, Boolean.TRUE.toString()); - setAttribute(CONTEXT, getContext(), context); - } - } - else + if (host != null) { final VirtualHost<?,?,?> recoveredHost = host; Subject.doAs(SecurityManager.getSubjectWithAddedSystemRights(), new PrivilegedAction<Object>() @@ -142,6 +118,44 @@ public abstract class AbstractStandardVirtualHostNode<X extends AbstractStandard } } + + @Override + protected ConfiguredObjectRecord enrichInitialVirtualHostRootRecord(final ConfiguredObjectRecord vhostRecord) + { + ConfiguredObjectRecord replacementRecord; + if (vhostRecord.getAttributes().get(ConfiguredObject.NAME) == null) + { + Map<String, Object> updatedAttributes = new LinkedHashMap<>(vhostRecord.getAttributes()); + updatedAttributes.put(ConfiguredObject.NAME, getName()); + if (!updatedAttributes.containsKey(VirtualHost.MODEL_VERSION)) + { + updatedAttributes.put(VirtualHost.MODEL_VERSION, getBroker().getModelVersion()); + } + replacementRecord = new ConfiguredObjectRecordImpl(vhostRecord.getId(), + vhostRecord.getType(), + updatedAttributes, + vhostRecord.getParents()); + } + else if (vhostRecord.getAttributes().get(VirtualHost.MODEL_VERSION) == null) + { + Map<String, Object> updatedAttributes = new LinkedHashMap<>(vhostRecord.getAttributes()); + + updatedAttributes.put(VirtualHost.MODEL_VERSION, getBroker().getModelVersion()); + + replacementRecord = new ConfiguredObjectRecordImpl(vhostRecord.getId(), + vhostRecord.getType(), + updatedAttributes, + vhostRecord.getParents()); + } + else + { + replacementRecord = vhostRecord; + } + + return replacementRecord; + } + + protected abstract void writeLocationEventLog(); @Override 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 ad9df793c8..e866effc54 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 @@ -20,36 +20,61 @@ */ package org.apache.qpid.server.virtualhostnode; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +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; + +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.messages.ConfigStoreMessages; import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; import org.apache.qpid.server.model.AbstractConfiguredObject; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Exchange; import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.StateTransition; 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.access.Operation; +import org.apache.qpid.server.security.auth.AuthenticatedPrincipal; +import org.apache.qpid.server.store.ConfiguredObjectRecord; +import org.apache.qpid.server.store.ConfiguredObjectRecordConverter; +import org.apache.qpid.server.store.ConfiguredObjectRecordImpl; import org.apache.qpid.server.store.DurableConfigurationStore; - -import java.security.AccessControlException; -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.qpid.server.util.urlstreamhandler.data.Handler; public abstract class AbstractVirtualHostNode<X extends AbstractVirtualHostNode<X>> extends AbstractConfiguredObject<X> implements VirtualHostNode<X> { - public static final String VIRTUALHOST_BLUEPRINT_CONTEXT_VAR = "virtualhostBlueprint"; - public static final String VIRTUALHOST_BLUEPRINT_UTILISED_CONTEXT_VAR = "virtualhostBlueprintUtilised"; private static final Logger LOGGER = Logger.getLogger(AbstractVirtualHostNode.class); + + static + { + Handler.register(); + } + private final Broker<?> _broker; private final AtomicReference<State> _state = new AtomicReference<State>(State.UNINITIALIZED); private final EventLogger _eventLogger; @@ -58,6 +83,9 @@ public abstract class AbstractVirtualHostNode<X extends AbstractVirtualHostNode< private MessageStoreLogSubject _configurationStoreLogSubject; + @ManagedAttributeField + private String _virtualHostInitialConfiguration; + public AbstractVirtualHostNode(Broker<?> parent, Map<String, Object> attributes) { super(Collections.<Class<? extends ConfiguredObject>,ConfiguredObject<?>>singletonMap(Broker.class, parent), @@ -241,8 +269,152 @@ public abstract class AbstractVirtualHostNode<X extends AbstractVirtualHostNode< } } + @Override + public String getVirtualHostInitialConfiguration() + { + return _virtualHostInitialConfiguration; + } + protected abstract DurableConfigurationStore createConfigurationStore(); protected abstract void activate(); + + + protected abstract ConfiguredObjectRecord enrichInitialVirtualHostRootRecord(final ConfiguredObjectRecord vhostRecord); + + protected final ConfiguredObjectRecord[] getInitialRecords() throws IOException + { + ConfiguredObjectRecordConverter converter = new ConfiguredObjectRecordConverter(getModel()); + + Collection<ConfiguredObjectRecord> records = + new ArrayList<>(converter.readFromJson(VirtualHost.class,this,getInitialConfigReader())); + + if(!records.isEmpty()) + { + ConfiguredObjectRecord vhostRecord = null; + for(ConfiguredObjectRecord record : records) + { + if(record.getType().equals(VirtualHost.class.getSimpleName())) + { + vhostRecord = record; + break; + } + } + if(vhostRecord != null) + { + records.remove(vhostRecord); + vhostRecord = enrichInitialVirtualHostRootRecord(vhostRecord); + records.add(vhostRecord); + } + else + { + // this should be impossible as the converter should always generate a parent record + throw new IllegalConfigurationException("Somehow the initial configuration has records but " + + "not a VirtualHost. This must be a coding error in Qpid"); + } + addStandardExchangesIfNecessary(records, vhostRecord); + enrichWithAuditInformation(records); + } + + + return records.toArray(new ConfiguredObjectRecord[records.size()]); + } + + private void enrichWithAuditInformation(final Collection<ConfiguredObjectRecord> records) + { + List<ConfiguredObjectRecord> replacements = new ArrayList<>(records.size()); + + for(ConfiguredObjectRecord record : records) + { + replacements.add(new ConfiguredObjectRecordImpl(record.getId(), record.getType(), + enrichAttributesWithAuditInformation(record.getAttributes()), + record.getParents())); + } + records.clear(); + records.addAll(replacements); + } + + private Map<String, Object> enrichAttributesWithAuditInformation(final Map<String, Object> attributes) + { + LinkedHashMap<String,Object> enriched = new LinkedHashMap<>(attributes); + final AuthenticatedPrincipal currentUser = org.apache.qpid.server.security.SecurityManager.getCurrentUser(); + + if(currentUser != null) + { + enriched.put(ConfiguredObject.LAST_UPDATED_BY, currentUser.getName()); + enriched.put(ConfiguredObject.CREATED_BY, currentUser.getName()); + } + long currentTime = System.currentTimeMillis(); + enriched.put(ConfiguredObject.LAST_UPDATED_TIME, currentTime); + enriched.put(ConfiguredObject.CREATED_TIME, currentTime); + + return enriched; + } + + private void addStandardExchangesIfNecessary(final Collection<ConfiguredObjectRecord> records, + final ConfiguredObjectRecord vhostRecord) + { + addExchangeIfNecessary(ExchangeDefaults.FANOUT_EXCHANGE_CLASS, ExchangeDefaults.FANOUT_EXCHANGE_NAME, records, vhostRecord); + addExchangeIfNecessary(ExchangeDefaults.HEADERS_EXCHANGE_CLASS, ExchangeDefaults.HEADERS_EXCHANGE_NAME, records, vhostRecord); + addExchangeIfNecessary(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, ExchangeDefaults.TOPIC_EXCHANGE_NAME, records, vhostRecord); + addExchangeIfNecessary(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, ExchangeDefaults.DIRECT_EXCHANGE_NAME, records, vhostRecord); + } + + private void addExchangeIfNecessary(final String exchangeClass, + final String exchangeName, + final Collection<ConfiguredObjectRecord> records, + final ConfiguredObjectRecord vhostRecord) + { + boolean found = false; + + for(ConfiguredObjectRecord record : records) + { + if(Exchange.class.getSimpleName().equals(record.getType()) + && exchangeName.equals(record.getAttributes().get(ConfiguredObject.NAME))) + { + found = true; + break; + } + } + + if(!found) + { + final Map<String, Object> exchangeAttributes = new HashMap<>(); + exchangeAttributes.put(ConfiguredObject.NAME, exchangeName); + exchangeAttributes.put(ConfiguredObject.TYPE, exchangeClass); + + records.add(new ConfiguredObjectRecordImpl(UUID.randomUUID(), Exchange.class.getSimpleName(), + exchangeAttributes, Collections.singletonMap(VirtualHost.class.getSimpleName(), vhostRecord.getId()))); + } + } + + protected final Reader getInitialConfigReader() throws IOException + { + Reader initialConfigReader; + if(getVirtualHostInitialConfiguration() != null) + { + String initialContextString = getVirtualHostInitialConfiguration(); + + + try + { + URL url = new URL(initialContextString); + + initialConfigReader =new InputStreamReader(url.openStream()); + } + catch (MalformedURLException e) + { + initialConfigReader = new StringReader(initialContextString); + } + + } + else + { + LOGGER.warn("No initial configuration found for the virtual host"); + initialConfigReader = new StringReader("{}"); + } + return initialConfigReader; + } + } diff --git a/qpid/java/broker-core/src/main/resources/initial-config.json b/qpid/java/broker-core/src/main/resources/initial-config.json index 9f1f779559..1403b1bd12 100644 --- a/qpid/java/broker-core/src/main/resources/initial-config.json +++ b/qpid/java/broker-core/src/main/resources/initial-config.json @@ -55,9 +55,7 @@ "virtualhostnodes" : [ { "name" : "default", "type" : "JSON", - "context" : { - "virtualhostBlueprint" : "{ \"type\" : \"DERBY\" }" - } + "virtualHostInitialConfiguration" : "{ \"type\" : \"DERBY\" }" } ], "plugins" : [ { "type" : "MANAGEMENT-HTTP", diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/BrokerTestHelper.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/BrokerTestHelper.java index 53c7f0334a..8573ae3a42 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/BrokerTestHelper.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/util/BrokerTestHelper.java @@ -91,6 +91,7 @@ public class BrokerTestHelper when(broker.getSecurityManager()).thenReturn(new SecurityManager(broker, false)); when(broker.getObjectFactory()).thenReturn(objectFactory); when(broker.getModel()).thenReturn(objectFactory.getModel()); + when(broker.getModelVersion()).thenReturn(BrokerModel.MODEL_VERSION); when(broker.getEventLogger()).thenReturn(eventLogger); when(broker.getCategoryClass()).thenReturn(Broker.class); when(broker.getParent(SystemConfig.class)).thenReturn(systemConfig); 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 19436627ce..971c96b2ff 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 @@ -139,7 +139,7 @@ public class AbstractStandardVirtualHostNodeTest extends QpidTestCase */ public void testActivateVHNWithVHBlueprint_StoreHasNoVH() throws Exception { - DurableConfigurationStore configStore = configStoreThatProducesNoRecords(); + DurableConfigurationStore configStore = new NullMessageStore() {}; String vhBlueprint = String.format("{ \"type\" : \"%s\", \"name\" : \"%s\"}", TestMemoryVirtualHost.VIRTUAL_HOST_TYPE, @@ -162,18 +162,12 @@ public class AbstractStandardVirtualHostNodeTest extends QpidTestCase assertEquals("Unexpected virtual host state", State.ACTIVE, virtualHost.getState()); assertNotNull("Unexpected virtual host id", virtualHost.getId()); - Map<String, String> updatedContext = node.getContext(); - - assertTrue("Context should now have utilised flag", updatedContext.containsKey( - AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_UTILISED_CONTEXT_VAR)); - assertEquals("Utilised flag should be true", - Boolean.TRUE.toString(), - updatedContext.get(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_UTILISED_CONTEXT_VAR)); + assertEquals("Initial configuration should be empty", "{}", node.getVirtualHostInitialConfiguration()); } /** * Tests activating a virtualhostnode with blueprint context variable and the - * marked utilised flag. Config store does not specify a virtualhost. + * but the virtualhostInitialConfiguration set to empty. Config store does not specify a virtualhost. * Checks virtualhost is not recreated from the blueprint. */ public void testActivateVHNWithVHBlueprintUsed_StoreHasNoVH() throws Exception @@ -185,12 +179,12 @@ public class AbstractStandardVirtualHostNodeTest extends QpidTestCase TEST_VIRTUAL_HOST_NAME); Map<String, String> context = new HashMap<>(); context.put(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, vhBlueprint); - context.put(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_UTILISED_CONTEXT_VAR, Boolean.TRUE.toString()); Map<String, Object> nodeAttributes = new HashMap<>(); nodeAttributes.put(VirtualHostNode.NAME, TEST_VIRTUAL_HOST_NODE_NAME); nodeAttributes.put(VirtualHostNode.ID, _nodeId); nodeAttributes.put(VirtualHostNode.CONTEXT, context); + nodeAttributes.put(VirtualHostNode.VIRTUALHOST_INITIAL_CONFIGURATION, "{}"); VirtualHostNode<?> node = new TestVirtualHostNode(_broker, nodeAttributes, configStore); node.open(); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java index 861b0c15a6..efe644ca43 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java @@ -350,7 +350,7 @@ public class RestServlet extends AbstractServlet Writer writer = getOutputWriter(request, response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); - mapper.writeValue(writer, output); + mapper.writeValue(writer, extractInitialConfig && output.size() == 1 ? output.get(0) : output); response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_OK); |
