diff options
Diffstat (limited to 'qpid/java/broker-core')
36 files changed, 981 insertions, 156 deletions
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java index a6fae97aaa..9b3f290723 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/BrokerOptions.java @@ -85,7 +85,6 @@ public class BrokerOptions Map<String,Object> attributes = new HashMap<String, Object>(); attributes.put("storePath", getConfigurationStoreLocation()); - attributes.put("storeTye", getConfigurationStoreType()); attributes.put(ConfiguredObject.CONTEXT, getConfigProperties()); return attributes; } 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 8eb0b4feb0..a910eea657 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 @@ -36,6 +36,7 @@ import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.messages.BindingMessages; import org.apache.qpid.server.logging.subjects.BindingLogSubject; import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.Binding; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.Queue; @@ -66,12 +67,31 @@ public class BindingImpl public BindingImpl(Map<String, Object> attributes, AMQQueue queue, ExchangeImpl exchange) { - super(parentsMap(queue,exchange),enhanceWithDurable(attributes,queue,exchange)); + super(parentsMap(queue,exchange),stripEmptyArguments(enhanceWithDurable(attributes, queue, exchange))); _bindingKey = getName(); _queue = queue; _exchange = exchange; } + private static Map<String, Object> stripEmptyArguments(final Map<String, Object> attributes) + { + Map<String,Object> returnVal; + if(attributes != null + && attributes.containsKey(Binding.ARGUMENTS) + && (attributes.get(Binding.ARGUMENTS) instanceof Map) + && ((Map)(attributes.get(Binding.ARGUMENTS))).isEmpty()) + { + returnVal = new HashMap<>(attributes); + returnVal.remove(Binding.ARGUMENTS); + } + else + { + returnVal = attributes; + } + + return returnVal; + } + @Override protected void onOpen() { @@ -113,7 +133,7 @@ public class BindingImpl { if(!attributes.containsKey(DURABLE)) { - attributes = new HashMap<String, Object>(attributes); + attributes = new HashMap(attributes); attributes.put(DURABLE, queue.isDurable() && exchange.isDurable()); } return attributes; 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 4472669f4a..af1de8b099 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 @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -111,6 +112,12 @@ public abstract class AbstractExchange<T extends AbstractExchange<T>> public AbstractExchange(Map<String, Object> attributes, VirtualHostImpl vhost) { super(parentsMap(vhost), attributes); + Set<String> providedAttributeNames = new HashSet<>(attributes.keySet()); + providedAttributeNames.removeAll(getAttributeNames()); + if(!providedAttributeNames.isEmpty()) + { + throw new IllegalArgumentException("Unknown attributes provided: " + providedAttributeNames); + } _virtualHost = vhost; // check ACL try diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 67bbc26f74..a5c74cb286 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -123,7 +123,6 @@ public class HeadersExchange extends AbstractExchange<HeadersExchange> { String bindingKey = binding.getBindingKey(); AMQQueue queue = binding.getAMQQueue(); - Map<String,Object> args = binding.getArguments(); assert queue != null; assert bindingKey != null; @@ -143,7 +142,7 @@ public class HeadersExchange extends AbstractExchange<HeadersExchange> if(_logger.isDebugEnabled()) { _logger.debug("Exchange " + getName() + ": Binding " + queue.getName() + - " with binding key '" +bindingKey + "' and args: " + args); + " with binding key '" +bindingKey + "' and args: " + binding.getArguments()); } _bindingHeaderMatchers.add(new HeadersBinding(binding)); 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 18930d8817..31de8118dd 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 @@ -469,7 +469,6 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { if(_dynamicState.compareAndSet(DynamicState.UNINIT, DynamicState.OPENED)) { - registerWithParents(); final AuthenticatedPrincipal currentUser = SecurityManager.getCurrentUser(); if(currentUser != null) { @@ -487,6 +486,9 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im doResolution(true); doValidation(true); + + registerWithParents(); + doCreation(true); doOpening(true); doAttainState(); @@ -1100,7 +1102,7 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im @Override public Map<String, Object> run() { - Map<String,Object> attributes = new HashMap<String, Object>(); + Map<String,Object> attributes = new LinkedHashMap<String, Object>(); Map<String,Object> actualAttributes = getActualAttributes(); for(ConfiguredObjectAttribute<?,?> attr : _attributeTypes.values()) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AttributeValueConverter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AttributeValueConverter.java index b7b56db15c..15e804e6f5 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AttributeValueConverter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AttributeValueConverter.java @@ -89,7 +89,15 @@ abstract class AttributeValueConverter<T> } else if(value instanceof String) { - return Long.valueOf(AbstractConfiguredObject.interpolate(object, (String) value)); + String interpolated = AbstractConfiguredObject.interpolate(object, (String) value); + try + { + return Long.valueOf(interpolated); + } + catch(NumberFormatException e) + { + throw new IllegalArgumentException("Cannot convert string '" + interpolated + "'",e); + } } else if(value == null) { @@ -117,7 +125,15 @@ abstract class AttributeValueConverter<T> } else if(value instanceof String) { - return Integer.valueOf(AbstractConfiguredObject.interpolate(object, (String) value)); + String interpolated = AbstractConfiguredObject.interpolate(object, (String) value); + try + { + return Integer.valueOf(interpolated); + } + catch(NumberFormatException e) + { + throw new IllegalArgumentException("Cannot convert string '" + interpolated + "'",e); + } } else if(value == null) { @@ -145,7 +161,15 @@ abstract class AttributeValueConverter<T> } else if(value instanceof String) { - return Short.valueOf(AbstractConfiguredObject.interpolate(object, (String) value)); + String interpolated = AbstractConfiguredObject.interpolate(object, (String) value); + try + { + return Short.valueOf(interpolated); + } + catch(NumberFormatException e) + { + throw new IllegalArgumentException("Cannot convert string '" + interpolated + "'",e); + } } else if(value == null) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java index 011aaeee23..78da1227d5 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java @@ -47,8 +47,6 @@ public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventL String DEFAULT_VIRTUAL_HOST = "defaultVirtualHost"; String STATISTICS_REPORTING_PERIOD = "statisticsReportingPeriod"; String STATISTICS_REPORTING_RESET_ENABLED = "statisticsReportingResetEnabled"; - String STORE_TYPE = "storeType"; - String STORE_VERSION = "storeVersion"; String STORE_PATH = "storePath"; String MODEL_VERSION = "modelVersion"; String CONFIDENTIAL_CONFIGURATION_ENCRYPTION_PROVIDER = "confidentialConfigurationEncryptionProvider"; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectAttribute.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectAttribute.java index 6f6ef7f6e1..1d1c736cd3 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectAttribute.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectAttribute.java @@ -21,11 +21,10 @@ package org.apache.qpid.server.model; import java.lang.reflect.Method; +import java.lang.reflect.Type; public abstract class ConfiguredObjectAttribute<C extends ConfiguredObject, T> extends ConfiguredObjectAttributeOrStatistic<C,T> { - - ConfiguredObjectAttribute(Class<C> clazz, final Method getter) { @@ -48,6 +47,20 @@ public abstract class ConfiguredObjectAttribute<C extends ConfiguredObject, T> e public T convert(final Object value, C object) { - return getConverter().convert(value, object); + final AttributeValueConverter<T> converter = getConverter(); + try + { + return converter.convert(value, object); + } + catch (IllegalArgumentException iae) + { + Type returnType = getGetter().getGenericReturnType(); + String simpleName = returnType instanceof Class ? ((Class) returnType).getSimpleName() : returnType.toString(); + + throw new IllegalArgumentException("Cannot convert '" + value + + "' into a " + simpleName + + " for attribute " + getName() + + " (" + iae.getMessage() + ")", iae); + } } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectTypeRegistry.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectTypeRegistry.java index 3201ff16f1..e377d31baf 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectTypeRegistry.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObjectTypeRegistry.java @@ -24,6 +24,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.AbstractCollection; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -33,6 +34,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.SortedSet; +import java.util.TreeMap; import java.util.TreeSet; import org.apache.log4j.Logger; @@ -45,16 +47,106 @@ public class ConfiguredObjectTypeRegistry { private static final Logger LOGGER = Logger.getLogger(ConfiguredObjectTypeRegistry.class); - private static final Comparator<ConfiguredObjectAttributeOrStatistic<?,?>> NAME_COMPARATOR = new Comparator<ConfiguredObjectAttributeOrStatistic<?, ?>>() + private static Map<String,Integer> STANDARD_FIRST_FIELDS_ORDER = new HashMap<>(); + static + { + int i = 0; + for(String name : Arrays.asList(ConfiguredObject.ID, + ConfiguredObject.NAME, + ConfiguredObject.DESCRIPTION, + ConfiguredObject.TYPE, + ConfiguredObject.DESIRED_STATE, + ConfiguredObject.STATE, + ConfiguredObject.DURABLE, + ConfiguredObject.LIFETIME_POLICY, + ConfiguredObject.CONTEXT)) + { + STANDARD_FIRST_FIELDS_ORDER.put(name, i++); + } + + } + + private static Map<String,Integer> STANDARD_LAST_FIELDS_ORDER = new HashMap<>(); + static + { + int i = 0; + for(String name : Arrays.asList(ConfiguredObject.LAST_UPDATED_BY, + ConfiguredObject.LAST_UPDATED_TIME, + ConfiguredObject.CREATED_BY, + ConfiguredObject.CREATED_TIME)) + { + STANDARD_LAST_FIELDS_ORDER.put(name, i++); + } + + } + + + private static final Comparator<ConfiguredObjectAttributeOrStatistic<?,?>> OBJECT_NAME_COMPARATOR = new Comparator<ConfiguredObjectAttributeOrStatistic<?, ?>>() { @Override public int compare(final ConfiguredObjectAttributeOrStatistic<?, ?> left, final ConfiguredObjectAttributeOrStatistic<?, ?> right) { - return left.getName().compareTo(right.getName()); + String leftName = left.getName(); + String rightName = right.getName(); + return compareAttributeNames(leftName, rightName); } }; + private static final Comparator<String> NAME_COMPARATOR = new Comparator<String>() + { + @Override + public int compare(final String left, final String right) + { + return compareAttributeNames(left, right); + } + }; + + private static int compareAttributeNames(final String leftName, final String rightName) + { + int result; + if(leftName.equals(rightName)) + { + result = 0; + } + else if(STANDARD_FIRST_FIELDS_ORDER.containsKey(leftName)) + { + if(STANDARD_FIRST_FIELDS_ORDER.containsKey(rightName)) + { + result = STANDARD_FIRST_FIELDS_ORDER.get(leftName) - STANDARD_FIRST_FIELDS_ORDER.get(rightName); + } + else + { + result = -1; + } + } + else if(STANDARD_FIRST_FIELDS_ORDER.containsKey(rightName)) + { + result = 1; + } + else if(STANDARD_LAST_FIELDS_ORDER.containsKey(rightName)) + { + if(STANDARD_LAST_FIELDS_ORDER.containsKey(leftName)) + { + result = STANDARD_LAST_FIELDS_ORDER.get(leftName) - STANDARD_LAST_FIELDS_ORDER.get(rightName); + } + else + { + result = -1; + } + } + else if(STANDARD_LAST_FIELDS_ORDER.containsKey(leftName)) + { + result = 1; + } + else + { + result = leftName.compareTo(rightName); + } + + return result; + } + private final Map<Class<? extends ConfiguredObject>, Collection<ConfiguredObjectAttribute<?,?>>> _allAttributes = Collections.synchronizedMap(new HashMap<Class<? extends ConfiguredObject>, Collection<ConfiguredObjectAttribute<?, ?>>>()); @@ -373,8 +465,8 @@ public class ConfiguredObjectTypeRegistry process((Class<? extends ConfiguredObject>) superclass); } - final SortedSet<ConfiguredObjectAttribute<?, ?>> attributeSet = new TreeSet<>(NAME_COMPARATOR); - final SortedSet<ConfiguredObjectStatistic<?, ?>> statisticSet = new TreeSet<>(NAME_COMPARATOR); + final SortedSet<ConfiguredObjectAttribute<?, ?>> attributeSet = new TreeSet<>(OBJECT_NAME_COMPARATOR); + final SortedSet<ConfiguredObjectStatistic<?, ?>> statisticSet = new TreeSet<>(OBJECT_NAME_COMPARATOR); _allAttributes.put(clazz, attributeSet); _allStatistics.put(clazz, statisticSet); @@ -480,7 +572,7 @@ public class ConfiguredObjectTypeRegistry private <X extends ConfiguredObject> void processAttributesTypesAndFields(final Class<X> clazz) { - Map<String,ConfiguredObjectAttribute<?,?>> attrMap = new HashMap<String, ConfiguredObjectAttribute<?, ?>>(); + Map<String,ConfiguredObjectAttribute<?,?>> attrMap = new TreeMap<>(NAME_COMPARATOR); Map<String,AutomatedField> fieldMap = new HashMap<String, AutomatedField>(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Model.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Model.java index 9f671b47a8..6f5bd2b405 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Model.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Model.java @@ -98,7 +98,7 @@ public abstract class Model return null; } - private Class<? extends ConfiguredObject> getAncestorClassWithGivenDescendant( + public Class<? extends ConfiguredObject> getAncestorClassWithGivenDescendant( final Class<? extends ConfiguredObject> category, final Class<? extends ConfiguredObject> descendantClass) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Port.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Port.java index eca3b0c7b1..6937d31b3a 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Port.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Port.java @@ -45,9 +45,6 @@ public interface Port<X extends Port<X>> extends ConfiguredObject<X> // Attributes - @ManagedAttribute(defaultValue = "*") - String getBindingAddress(); - @ManagedAttribute( mandatory = true ) int getPort(); 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/model/adapter/VirtualHostAliasAdapter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAliasAdapter.java index 50f98c7f03..cc1f557df1 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAliasAdapter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAliasAdapter.java @@ -52,6 +52,7 @@ public class VirtualHostAliasAdapter extends AbstractConfiguredObject<VirtualHos final Map<String, Object> attributes = new HashMap<String, Object>(); attributes.put(ID, UUID.randomUUID()); attributes.put(NAME, virtualHost.getName()); + attributes.put(DURABLE, false); return attributes; } 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 61790441f9..d1abded988 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 @@ -61,9 +61,6 @@ abstract public class AbstractPort<X extends AbstractPort<X>> extends AbstractCo private int _port; @ManagedAttributeField - private String _bindingAddress; - - @ManagedAttributeField private KeyStore<?> _keyStore; @ManagedAttributeField @@ -172,12 +169,6 @@ abstract public class AbstractPort<X extends AbstractPort<X>> extends AbstractCo } @Override - public String getBindingAddress() - { - return _bindingAddress; - } - - @Override public int getPort() { return _port; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java index b50a289b22..5c74beb5b7 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java @@ -48,6 +48,9 @@ public interface AmqpPort<X extends AmqpPort<X>> extends Port<X> @ManagedContextDefault(name = DEFAULT_AMQP_PROTOCOLS) String INSTALLED_PROTOCOLS = AmqpPortImpl.getInstalledProtocolsAsString(); + @ManagedAttribute(defaultValue = "*") + String getBindingAddress(); + @ManagedAttribute( defaultValue = AmqpPort.DEFAULT_AMQP_TCP_NO_DELAY ) boolean isTcpNoDelay(); 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 2c958b00d0..9a0ea3548e 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 @@ -71,6 +71,9 @@ public class AmqpPortImpl extends AbstractPortWithAuthProvider<AmqpPortImpl> imp @ManagedAttributeField private int _receiveBufferSize; + @ManagedAttributeField + private String _bindingAddress; + private final Broker<?> _broker; private AcceptingTransport _transport; @@ -81,6 +84,13 @@ public class AmqpPortImpl extends AbstractPortWithAuthProvider<AmqpPortImpl> imp _broker = broker; } + + @Override + public String getBindingAddress() + { + return _bindingAddress; + } + @Override public boolean isTcpNoDelay() { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPort.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPort.java index 51d31cb8ab..d8c87fb123 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPort.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPort.java @@ -36,6 +36,8 @@ public interface HttpPort<X extends HttpPort<X>> extends Port<X> String DEFAULT_AMQP_NEED_CLIENT_AUTH = "false"; String DEFAULT_AMQP_WANT_CLIENT_AUTH = "false"; + @ManagedAttribute(defaultValue = "*") + String getBindingAddress(); @ManagedAttribute( defaultValue = DEFAULT_AMQP_NEED_CLIENT_AUTH ) boolean getNeedClientAuth(); 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 33abee9bde..80e79a68ca 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 @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Set; 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.Protocol; import org.apache.qpid.server.model.State; @@ -33,6 +34,9 @@ public class HttpPortImpl extends AbstractPortWithAuthProvider<HttpPortImpl> imp { private PortManager _portManager; + @ManagedAttributeField + private String _bindingAddress; + @ManagedObjectFactoryConstructor public HttpPortImpl(final Map<String, Object> attributes, final Broker<?> broker) @@ -45,6 +49,13 @@ public class HttpPortImpl extends AbstractPortWithAuthProvider<HttpPortImpl> imp _portManager = manager; } + + @Override + public String getBindingAddress() + { + return _bindingAddress; + } + @Override protected State onActivate() { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPort.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPort.java index 981d81a342..fdfe6f1d5d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPort.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPort.java @@ -32,21 +32,9 @@ import org.apache.qpid.server.model.Transport; @ManagedObject( category = false, type = "JMX") public interface JmxPort<X extends JmxPort<X>> extends Port<X> { - - String DEFAULT_AMQP_NEED_CLIENT_AUTH = "false"; - String DEFAULT_AMQP_WANT_CLIENT_AUTH = "false"; - - - @ManagedAttribute( defaultValue = DEFAULT_AMQP_NEED_CLIENT_AUTH ) - boolean getNeedClientAuth(); - - @ManagedAttribute( defaultValue = DEFAULT_AMQP_WANT_CLIENT_AUTH ) - boolean getWantClientAuth(); - @ManagedAttribute( mandatory = true ) AuthenticationProvider getAuthenticationProvider(); - @ManagedAttribute( defaultValue = "TCP", validValues = {"[ \"TCP\" ]", "[ \"SSL\" ]"}) Set<Transport> getTransports(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueArgumentsConverter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueArgumentsConverter.java index 37e82b0771..49732e8345 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueArgumentsConverter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueArgumentsConverter.java @@ -23,6 +23,8 @@ package org.apache.qpid.server.queue; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; + +import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.Queue; import org.apache.qpid.server.virtualhost.AbstractVirtualHost; @@ -87,6 +89,8 @@ public class QueueArgumentsConverter ATTRIBUTE_MAPPINGS.put(X_QPID_PRIORITIES, PriorityQueue.PRIORITIES); ATTRIBUTE_MAPPINGS.put(X_QPID_DESCRIPTION, Queue.DESCRIPTION); + ATTRIBUTE_MAPPINGS.put(Queue.ALTERNATE_EXCHANGE, Queue.ALTERNATE_EXCHANGE); + ATTRIBUTE_MAPPINGS.put(X_QPID_DLQ_ENABLED, AbstractVirtualHost.CREATE_DLQ_ON_CREATION); ATTRIBUTE_MAPPINGS.put(QPID_GROUP_HEADER_KEY, Queue.MESSAGE_GROUP_KEY); @@ -147,6 +151,10 @@ public class QueueArgumentsConverter { value = ((Enum) value).name(); } + else if(value instanceof ConfiguredObject) + { + value = ((ConfiguredObject)value).getName(); + } wireArguments.put(entry.getKey(), value); } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/ConfiguredObjectRecordConverter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/ConfiguredObjectRecordConverter.java index cc284a33f4..5f1c0b4b7f 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/ConfiguredObjectRecordConverter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/ConfiguredObjectRecordConverter.java @@ -22,8 +22,11 @@ package org.apache.qpid.server.store; import java.io.IOException; import java.io.Reader; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.UUID; @@ -37,6 +40,11 @@ public class ConfiguredObjectRecordConverter { private final Model _model; + private static interface NameToIdResolver + { + public boolean resolve(Map<UUID, ConfiguredObjectRecord> objectsById); + } + public ConfiguredObjectRecordConverter(final Model model) { _model = model; @@ -52,16 +60,32 @@ public class ConfiguredObjectRecordConverter Map data = objectMapper.readValue(reader, Map.class); if(!data.isEmpty()) { - loadChild(rootClass, data, parent.getCategoryClass(), parent.getId(), objectsById); + Collection<NameToIdResolver> unresolved = + loadChild(rootClass, data, parent.getCategoryClass(), parent.getId(), objectsById); + + Iterator<NameToIdResolver> iterator = unresolved.iterator(); + while(iterator.hasNext()) + { + if(iterator.next().resolve(objectsById)) + { + iterator.remove(); + } + } + + if(!unresolved.isEmpty()) + { + throw new IllegalArgumentException("Initial configuration has unresolved references"); + } } return objectsById.values(); } - private void loadChild(final Class<? extends ConfiguredObject> clazz, - final Map<String, Object> data, - final Class<? extends ConfiguredObject> parentClass, - final UUID parentId, final Map<UUID, ConfiguredObjectRecord> records) + private Collection<NameToIdResolver> loadChild(final Class<? extends ConfiguredObject> clazz, + final Map<String, Object> data, + final Class<? extends ConfiguredObject> parentClass, + final UUID parentId, + final Map<UUID, ConfiguredObjectRecord> records) { String idStr = (String) data.remove("id"); @@ -70,6 +94,7 @@ public class ConfiguredObjectRecordConverter Map<String,UUID> parentMap = new HashMap<>(); Collection<Class<? extends ConfiguredObject>> childClasses = _model.getChildTypes(clazz); + List<NameToIdResolver> requiringResolution = new ArrayList<>(); for(Class<? extends ConfiguredObject> childClass : childClasses) { final String childType = childClass.getSimpleName(); @@ -83,13 +108,14 @@ public class ConfiguredObjectRecordConverter { if(child instanceof Map) { - loadChild(childClass, (Map)child, clazz, id, records); + requiringResolution.addAll(loadChild(childClass, (Map) child, clazz, id, records)); } } } } } + if(parentId != null) { parentMap.put(parentClass.getSimpleName(),parentId); @@ -107,7 +133,15 @@ public class ConfiguredObjectRecordConverter } catch(IllegalArgumentException e) { - // TODO + final String ancestorClassName = + _model.getAncestorClassWithGivenDescendant(clazz, otherParent).getSimpleName(); + final String parentName = (String) otherParentId; + final String parentType = otherParent.getSimpleName(); + + requiringResolution.add(new AncestorFindingResolver(id, + parentType, + parentName, + ancestorClassName)); } } } @@ -117,7 +151,79 @@ public class ConfiguredObjectRecordConverter records.put(id, new ConfiguredObjectRecordImpl(id, type, data, parentMap)); + return requiringResolution; } + private static class AncestorFindingResolver implements NameToIdResolver + { + private final String _parentType; + private final String _parentName; + private final String _commonAncestorType; + private final UUID _id; + + public AncestorFindingResolver(final UUID id, + final String parentType, + final String parentName, + final String commonAncestorType) + { + _id = id; + _parentType = parentType; + _parentName = parentName; + _commonAncestorType = commonAncestorType; + } + + @Override + public boolean resolve(final Map<UUID, ConfiguredObjectRecord> objectsById) + { + + ConfiguredObjectRecord record = objectsById.get(_id); + Collection<ConfiguredObjectRecord> recordsWithMatchingName = new ArrayList<>(); + for(ConfiguredObjectRecord possibleParentRecord : objectsById.values()) + { + if(possibleParentRecord.getType().equals(_parentType) + && _parentName.equals(possibleParentRecord.getAttributes().get(ConfiguredObject.NAME))) + { + recordsWithMatchingName.add(possibleParentRecord); + } + } + for(ConfiguredObjectRecord candidate : recordsWithMatchingName) + { + UUID candidateAncestor = findAncestor(candidate, _commonAncestorType, objectsById); + UUID recordAncestor = findAncestor(record, _commonAncestorType, objectsById); + if(recordAncestor.equals(candidateAncestor)) + { + HashMap<String, UUID> parents = new HashMap<>(record.getParents()); + parents.put(_parentType, candidate.getId()); + objectsById.put(_id, new ConfiguredObjectRecordImpl(_id, record.getType(), record.getAttributes(), parents)); + + return true; + } + } + return false; + } + + private UUID findAncestor(final ConfiguredObjectRecord record, + final String commonAncestorType, + final Map<UUID, ConfiguredObjectRecord> objectsById) + { + UUID id = record.getParents().get(commonAncestorType); + if(id == null) + { + for(UUID parentId : record.getParents().values()) + { + ConfiguredObjectRecord parent = objectsById.get(parentId); + if(parent != null) + { + id = findAncestor(parent, commonAncestorType, objectsById); + } + if(id != null) + { + break; + } + } + } + return id; + } + } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/JsonFileConfigStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/JsonFileConfigStore.java index 78d2b6507a..1f5665a0a5 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/JsonFileConfigStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/JsonFileConfigStore.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; @@ -57,6 +58,28 @@ public class JsonFileConfigStore implements DurableConfigurationStore { private static final Logger _logger = Logger.getLogger(JsonFileConfigStore.class); + private static final Comparator<Class<? extends ConfiguredObject>> CATEGORY_CLASS_COMPARATOR = + new Comparator<Class<? extends ConfiguredObject>>() + { + @Override + public int compare(final Class<? extends ConfiguredObject> left, + final Class<? extends ConfiguredObject> right) + { + return left.getSimpleName().compareTo(right.getSimpleName()); + } + }; + private static final Comparator<ConfiguredObjectRecord> CONFIGURED_OBJECT_RECORD_COMPARATOR = + new Comparator<ConfiguredObjectRecord>() + { + @Override + public int compare(final ConfiguredObjectRecord left, final ConfiguredObjectRecord right) + { + String leftName = (String) left.getAttributes().get(ConfiguredObject.NAME); + String rightName = (String) right.getAttributes().get(ConfiguredObject.NAME); + return leftName.compareTo(rightName); + } + }; + private final Map<UUID, ConfiguredObjectRecord> _objectsById = new HashMap<UUID, ConfiguredObjectRecord>(); private final Map<String, List<UUID>> _idsByType = new HashMap<String, List<UUID>>(); private final ObjectMapper _objectMapper = new ObjectMapper(); @@ -313,6 +336,14 @@ public class JsonFileConfigStore implements DurableConfigurationStore { throw new StoreException("Cannot create object of unknown type " + record.getType()); } + else if(record.getAttributes() == null || !(record.getAttributes().get(ConfiguredObject.NAME) instanceof String)) + { + throw new StoreException("The record " + record.getId() + + " of type " + record.getType() + + " does not have an attribute '" + + ConfiguredObject.NAME + + "' of type String"); + } else { record = new ConfiguredObjectRecordImpl(record); @@ -385,8 +416,6 @@ public class JsonFileConfigStore implements DurableConfigurationStore { ConfiguredObjectRecord record = _objectsById.get(id); Map<String,Object> map = new LinkedHashMap<String, Object>(); - map.put("id", id); - map.putAll(record.getAttributes()); Collection<Class<? extends ConfiguredObject>> parentTypes = _parent.getModel().getParentTypes(type); if(parentTypes.size() > 1) @@ -403,9 +432,14 @@ public class JsonFileConfigStore implements DurableConfigurationStore } } - Collection<Class<? extends ConfiguredObject>> childClasses = + map.put("id", id); + map.putAll(record.getAttributes()); + + List<Class<? extends ConfiguredObject>> childClasses = new ArrayList<Class<? extends ConfiguredObject>>(_parent.getModel().getChildTypes(type)); + Collections.sort(childClasses, CATEGORY_CLASS_COMPARATOR); + for(Class<? extends ConfiguredObject> childClass : childClasses) { // only add if this is the "first" parent @@ -416,6 +450,7 @@ public class JsonFileConfigStore implements DurableConfigurationStore if(childIds != null) { List<Map<String,Object>> entities = new ArrayList<Map<String, Object>>(); + List<ConfiguredObjectRecord> sortedChildren = new ArrayList<>(); for(UUID childId : childIds) { ConfiguredObjectRecord childRecord = _objectsById.get(childId); @@ -424,9 +459,17 @@ public class JsonFileConfigStore implements DurableConfigurationStore String parentId = parent.toString(); if(id.toString().equals(parentId)) { - entities.add(build(childClass,childId)); + sortedChildren.add(childRecord); } } + + Collections.sort(sortedChildren, CONFIGURED_OBJECT_RECORD_COMPARATOR); + + for(ConfiguredObjectRecord childRecord : sortedChildren) + { + entities.add(build(childClass, childRecord.getId())); + } + if(!entities.isEmpty()) { map.put(attrName,entities); @@ -475,6 +518,13 @@ public class JsonFileConfigStore implements DurableConfigurationStore final UUID id = record.getId(); final String type = record.getType(); + if(record.getAttributes() == null || !(record.getAttributes().get(ConfiguredObject.NAME) instanceof String)) + { + throw new StoreException("The record " + id + " of type " + type + " does not have an attribute '" + + ConfiguredObject.NAME + + "' of type String"); + } + if(_objectsById.containsKey(id)) { final ConfiguredObjectRecord existingRecord = _objectsById.get(id); 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..5ee820d9ac 100644 --- a/qpid/java/broker-core/src/main/resources/initial-config.json +++ b/qpid/java/broker-core/src/main/resources/initial-config.json @@ -20,7 +20,6 @@ */ { "name": "${broker.name}", - "storeVersion": 1, "modelVersion": "2.0", "defaultVirtualHost" : "default", "authenticationproviders" : [ { @@ -55,9 +54,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/model/AbstractConfiguredObjectTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/AbstractConfiguredObjectTest.java index e147abd170..e5c5a89c10 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,6 +26,7 @@ import java.util.Map; import junit.framework.TestCase; +import org.apache.qpid.server.model.testmodel.TestChildCategory; import org.apache.qpid.server.model.testmodel.TestModel; import org.apache.qpid.server.model.testmodel.TestRootCategory; import org.apache.qpid.server.store.ConfiguredObjectRecord; @@ -187,4 +188,73 @@ public class AbstractConfiguredObjectTest extends TestCase assertEquals("myValue", object1.getStringValue()); } -}
\ No newline at end of file + public void testCreationOfObjectWithInvalidInterpolatedValues() + { + final String parentName = "parent"; + TestRootCategory parent = + _model.getObjectFactory().create(TestRootCategory.class, + Collections.<String, Object>singletonMap(ConfiguredObject.NAME, + parentName) + ); + + parent.setAttributes(Collections.singletonMap(ConfiguredObject.CONTEXT, + Collections.singletonMap("contextVal", "foo"))); + + final Map<String, Object> attributes = new HashMap<>(); + attributes.put("intValue", "${contextVal}"); + attributes.put("name", "child"); + attributes.put("integerSet", "[ ]"); + attributes.put(ConfiguredObject.TYPE, "test"); + + try + { + _model.getObjectFactory().create(TestChildCategory.class, attributes, parent); + fail("creation of child object should have failed due to invalid value"); + } + catch (IllegalArgumentException e) + { + // PASS + String message = e.getMessage(); + assertTrue("Message does not contain the attribute name", message.contains("intValue")); + assertTrue("Message does not contain the non-interpolated value", message.contains("contextVal")); + assertTrue("Message does not contain the interpolated value", message.contains("foo")); + + } + + assertTrue("Child should not have been registered with parent", + parent.getChildren(TestChildCategory.class).isEmpty()); + } + + public void testCreationOfObjectWithInvalidDefaultValues() + { + final String parentName = "parent"; + TestRootCategory parent = + _model.getObjectFactory().create(TestRootCategory.class, + Collections.<String, Object>singletonMap(ConfiguredObject.NAME, + parentName) + ); + + final Map<String, Object> attributes = new HashMap<>(); + attributes.put("intValue", "1"); + attributes.put("name", "child"); + attributes.put(ConfiguredObject.TYPE, "test"); + + try + { + _model.getObjectFactory().create(TestChildCategory.class, attributes, parent); + fail("creation of child object should have failed due to invalid value"); + } + catch (IllegalArgumentException e) + { + // PASS + String message = e.getMessage(); + assertTrue("Message does not contain the attribute name", message.contains("integerSet")); + assertTrue("Message does not contain the error value", message.contains("foo")); + + } + + assertTrue("Child should not have been registered with parent", + parent.getChildren(TestChildCategory.class).isEmpty()); + } + +} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestChildCategory.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestChildCategory.java index 0c8dcc8744..d3fe14b7d8 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestChildCategory.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestChildCategory.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.model.testmodel; +import java.util.Set; + import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.model.ManagedObject; @@ -30,6 +32,12 @@ public interface TestChildCategory<X extends TestChildCategory<X>> extends Confi String NON_INTERPOLATED_VALID_VALUE = "${file.separator}"; - @ManagedAttribute(validValues = { NON_INTERPOLATED_VALID_VALUE }) + @ManagedAttribute(validValues = { NON_INTERPOLATED_VALID_VALUE }, defaultValue = "") String getValidValueNotInterpolated(); + + @ManagedAttribute( defaultValue = "3" ) + int getIntValue(); + + @ManagedAttribute( defaultValue = "[ \"1\", \"2\", \"foo\" ]" ) + Set<Integer> getIntegerSet(); } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestChildCategoryImpl.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestChildCategoryImpl.java index b5a4182f79..080a352f11 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestChildCategoryImpl.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestChildCategoryImpl.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.model.testmodel; import java.util.Map; +import java.util.Set; import org.apache.qpid.server.model.AbstractConfiguredObject; import org.apache.qpid.server.model.ManagedAttributeField; @@ -37,6 +38,12 @@ public class TestChildCategoryImpl @ManagedAttributeField private String _validValueNotInterpolated; + @ManagedAttributeField + private int _intValue; + + @ManagedAttributeField + private Set<Integer> _integerSet; + @ManagedObjectFactoryConstructor public TestChildCategoryImpl(final Map<String, Object> attributes, TestRootCategory<?> parent) @@ -57,4 +64,16 @@ public class TestChildCategoryImpl { return _validValueNotInterpolated; } + + @Override + public int getIntValue() + { + return _intValue; + } + + @Override + public Set<Integer> getIntegerSet() + { + return _integerSet; + } } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactoryTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactoryTest.java index 56283b1392..6001ed1750 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactoryTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactoryTest.java @@ -36,7 +36,6 @@ import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.BrokerModel; import org.apache.qpid.server.model.ConfiguredObjectFactory; import org.apache.qpid.server.model.TrustStore; -import org.apache.qpid.server.model.UnknownConfiguredObjectException; import org.apache.qpid.server.util.BrokerTestHelper; public class SimpleLDAPAuthenticationManagerFactoryTest extends TestCase @@ -108,10 +107,12 @@ public class SimpleLDAPAuthenticationManagerFactoryTest extends TestCase _factory.create(AuthenticationProvider.class, _configuration, _broker); fail("Exception not thrown"); } - catch(UnknownConfiguredObjectException e) + catch(IllegalArgumentException e) { - assertEquals(e.getCategory(), TrustStore.class); - assertEquals(e.getName(), "notfound"); + // PASS + assertTrue("Message does not include underlying issue", e.getMessage().contains("name 'notfound'")); + assertTrue("Message does not include the attribute name", e.getMessage().contains("trustStore")); + assertTrue("Message does not include the expected type", e.getMessage().contains("TrustStore")); } } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/AbstractDurableConfigurationStoreTestCase.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/AbstractDurableConfigurationStoreTestCase.java index 6d84c7b602..dd8b4cf4dd 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/AbstractDurableConfigurationStoreTestCase.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/AbstractDurableConfigurationStoreTestCase.java @@ -115,7 +115,7 @@ public abstract class AbstractDurableConfigurationStoreTestCase extends QpidTest _configStore = createConfigStore(); _configStore.openConfigurationStore(_parent, false); - _rootRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), VirtualHost.class.getSimpleName(), Collections.<String, Object>emptyMap()); + _rootRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), VirtualHost.class.getSimpleName(), Collections.<String, Object>singletonMap(ConfiguredObject.NAME, "vhost")); _configStore.create(_rootRecord); } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/ConfiguredObjectRecordConverterTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/ConfiguredObjectRecordConverterTest.java new file mode 100644 index 0000000000..bef3cdcac9 --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/ConfiguredObjectRecordConverterTest.java @@ -0,0 +1,142 @@ +/* + * + * 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.store; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.StringReader; +import java.util.Collection; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.model.Binding; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.test.utils.QpidTestCase; + +public class ConfiguredObjectRecordConverterTest extends QpidTestCase +{ + + public void testSecondParentReferencedByName() throws Exception + { + + String jsonData = "{\n" + + " \"name\" : \"test\",\n" + + " \"exchanges\" : [ {\n" + + " \"name\" : \"amq.direct\",\n" + + " \"type\" : \"direct\"\n" + + " } ],\n" + + " \"queues\" : [ {\n" + + " \"name\" : \"foo\",\n" + + " \"bindings\" : [ {\n" + + " \"exchange\" : \"amq.direct\",\n" + + " \"name\" : \"foo\"\n" + + " } ]\n" + + " } ]\n" + + "} "; + + ConfiguredObjectRecordConverter converter = new ConfiguredObjectRecordConverter(BrokerModel.getInstance()); + ConfiguredObject parent = mock(ConfiguredObject.class); + when(parent.getId()).thenReturn(UUID.randomUUID()); + when(parent.getCategoryClass()).thenReturn(VirtualHostNode.class); + Collection<ConfiguredObjectRecord> records = + converter.readFromJson(VirtualHost.class, parent, new StringReader(jsonData)); + + UUID exchangeId = null; + for (ConfiguredObjectRecord record : records) + { + if (record.getType().equals(Exchange.class.getSimpleName())) + { + assertNull("Only one exchange record expected", exchangeId); + exchangeId = record.getId(); + } + } + assertNotNull("No exchange record found", exchangeId); + + UUID queueId = null; + for (ConfiguredObjectRecord record : records) + { + if (record.getType().equals(Queue.class.getSimpleName())) + { + assertNull("Only one queue record expected", queueId); + queueId = record.getId(); + } + } + assertNotNull("No queueId record found", queueId); + + boolean bindingFound = false; + for (ConfiguredObjectRecord record : records) + { + if (record.getType().equals(Binding.class.getSimpleName())) + { + assertFalse("Expecting only one binding", bindingFound); + bindingFound = true; + Map<String,UUID> parents = record.getParents(); + assertEquals("Two parents expected", 2, parents.size()); + assertEquals("Queue parent id not as expected", queueId, parents.get(Queue.class.getSimpleName())); + assertEquals("Exchange parent id not as expected", exchangeId, parents.get(Exchange.class.getSimpleName())); + + } + } + assertTrue("No binding found", bindingFound); + } + + public void testUnresolvedSecondParentFailsToCovert() throws Exception + { + { + + String jsonData = "{\n" + + " \"name\" : \"test\",\n" + + " \"exchanges\" : [ {\n" + + " \"name\" : \"amq.direct\",\n" + + " \"type\" : \"direct\"\n" + + " } ],\n" + + " \"queues\" : [ {\n" + + " \"name\" : \"foo\",\n" + + " \"bindings\" : [ {\n" + + " \"exchange\" : \"amq.topic\",\n" + + " \"name\" : \"foo\"\n" + + " } ]\n" + + " } ]\n" + + "} "; + + ConfiguredObjectRecordConverter converter = new ConfiguredObjectRecordConverter(BrokerModel.getInstance()); + ConfiguredObject parent = mock(ConfiguredObject.class); + when(parent.getId()).thenReturn(UUID.randomUUID()); + when(parent.getCategoryClass()).thenReturn(VirtualHostNode.class); + try + { + converter.readFromJson(VirtualHost.class, parent, new StringReader(jsonData)); + fail("The records should not be converted as there is an unresolved reference"); + } + catch (IllegalArgumentException e) + { + // pass + } + + } + } +} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/JsonFileConfigStoreTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/JsonFileConfigStoreTest.java index ee8f6497bc..b652992021 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/JsonFileConfigStoreTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/store/JsonFileConfigStoreTest.java @@ -38,6 +38,7 @@ import org.mockito.ArgumentMatcher; import org.mockito.InOrder; 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.ConfiguredObjectFactoryImpl; import org.apache.qpid.server.model.Queue; @@ -248,10 +249,14 @@ public class JsonFileConfigStoreTest extends QpidTestCase createRootRecord(); final UUID id = UUID.randomUUID(); - _store.create(new ConfiguredObjectRecordImpl(id, "Queue", Collections.<String, Object>emptyMap(), getRootAsParentMap())); + _store.create(new ConfiguredObjectRecordImpl(id, "Queue", + Collections.<String, Object>singletonMap(ConfiguredObject.NAME, "queue"), + getRootAsParentMap())); try { - _store.create(new ConfiguredObjectRecordImpl(id, "Exchange", Collections.<String, Object>emptyMap(), getRootAsParentMap())); + _store.create(new ConfiguredObjectRecordImpl(id, "Exchange", + Collections.<String, Object>singletonMap(ConfiguredObject.NAME, "exchange"), + getRootAsParentMap())); fail("Should not be able to create two objects with same id"); } catch (StoreException e) @@ -261,19 +266,61 @@ public class JsonFileConfigStoreTest extends QpidTestCase } + public void testObjectWithoutName() throws Exception + { + _store.openConfigurationStore(_parent, false); + createRootRecord(); + + final UUID id = UUID.randomUUID(); + try + { + _store.create(new ConfiguredObjectRecordImpl(id, "Exchange", + Collections.<String, Object>emptyMap(), + getRootAsParentMap())); + fail("Should not be able to create an object without a name"); + } + catch (StoreException e) + { + // pass + } + } + + public void testObjectWithNonStringName() throws Exception + { + _store.openConfigurationStore(_parent, false); + createRootRecord(); + + final UUID id = UUID.randomUUID(); + try + { + _store.update(true, new ConfiguredObjectRecordImpl(id, "Exchange", + Collections.<String, Object>singletonMap(ConfiguredObject.NAME, 3), + getRootAsParentMap())); + fail("Should not be able to create an object without a name"); + } + catch (StoreException e) + { + // pass + } + } + public void testChangeTypeOfObject() throws Exception { _store.openConfigurationStore(_parent, false); createRootRecord(); final UUID id = UUID.randomUUID(); - _store.create(new ConfiguredObjectRecordImpl(id, "Queue", Collections.<String, Object>emptyMap(), getRootAsParentMap())); + _store.create(new ConfiguredObjectRecordImpl(id, "Queue", + Collections.<String, Object>singletonMap(ConfiguredObject.NAME, "queue"), + getRootAsParentMap())); _store.closeConfigurationStore(); _store.openConfigurationStore(_parent, false); try { - _store.update(false, new ConfiguredObjectRecordImpl(id, "Exchange", Collections.<String, Object>emptyMap(), getRootAsParentMap())); + _store.update(false, new ConfiguredObjectRecordImpl(id, "Exchange", + Collections.<String, Object>singletonMap(ConfiguredObject.NAME, "exchange"), + getRootAsParentMap())); fail("Should not be able to update object to different type"); } catch (StoreException e) @@ -329,40 +376,57 @@ public class JsonFileConfigStoreTest extends QpidTestCase final UUID queueId = new UUID(0, 1); final UUID queue2Id = new UUID(1, 1); - final Map<String, Object> EMPTY_ATTR = Collections.emptyMap(); final UUID exchangeId = new UUID(0, 2); final UUID bindingId = new UUID(0, 3); final UUID binding2Id = new UUID(1, 3); Map<String, UUID> parents = getRootAsParentMap(); - final ConfiguredObjectRecordImpl queueRecord = new ConfiguredObjectRecordImpl(queueId, "Queue", EMPTY_ATTR, parents); + Map<String, Object> queueAttr = Collections.<String, Object>singletonMap(ConfiguredObject.NAME, "queue"); + final ConfiguredObjectRecordImpl queueRecord = + new ConfiguredObjectRecordImpl(queueId, "Queue", + queueAttr, + parents); _store.create(queueRecord); - final ConfiguredObjectRecordImpl queue2Record = new ConfiguredObjectRecordImpl(queue2Id, "Queue", EMPTY_ATTR, parents); + Map<String, Object> queue2Attr = Collections.<String, Object>singletonMap(ConfiguredObject.NAME, "queue2"); + final ConfiguredObjectRecordImpl queue2Record = + new ConfiguredObjectRecordImpl(queue2Id, "Queue", + queue2Attr, + parents); _store.create(queue2Record); - final ConfiguredObjectRecordImpl exchangeRecord = new ConfiguredObjectRecordImpl(exchangeId, "Exchange", EMPTY_ATTR, parents); + Map<String, Object> exchangeAttr = Collections.<String, Object>singletonMap(ConfiguredObject.NAME, "exchange"); + final ConfiguredObjectRecordImpl exchangeRecord = + new ConfiguredObjectRecordImpl(exchangeId, "Exchange", + exchangeAttr, + parents); _store.create(exchangeRecord); Map<String,UUID> bindingParents = new HashMap(); bindingParents.put("Exchange", exchangeRecord.getId()); bindingParents.put("Queue", queueRecord.getId()); + Map<String, Object> bindingAttr = Collections.<String, Object>singletonMap(ConfiguredObject.NAME, "binding"); final ConfiguredObjectRecordImpl bindingRecord = - new ConfiguredObjectRecordImpl(bindingId, "Binding", EMPTY_ATTR, bindingParents); + new ConfiguredObjectRecordImpl(bindingId, "Binding", + bindingAttr, + bindingParents); Map<String,UUID> binding2Parents = new HashMap(); binding2Parents.put("Exchange", exchangeRecord.getId()); binding2Parents.put("Queue", queue2Record.getId()); + Map<String, Object> binding2Attr = Collections.<String, Object>singletonMap(ConfiguredObject.NAME, "binding2"); final ConfiguredObjectRecordImpl binding2Record = - new ConfiguredObjectRecordImpl(binding2Id, "Binding", EMPTY_ATTR, binding2Parents); + new ConfiguredObjectRecordImpl(binding2Id, "Binding", + binding2Attr, + binding2Parents); _store.update(true, bindingRecord, binding2Record); _store.closeConfigurationStore(); _store.openConfigurationStore(_parent, false); _store.visitConfiguredObjectRecords(_handler); - verify(_handler).handle(matchesRecord(queueId, "Queue", EMPTY_ATTR)); - verify(_handler).handle(matchesRecord(queue2Id, "Queue", EMPTY_ATTR)); - verify(_handler).handle(matchesRecord(exchangeId, "Exchange", EMPTY_ATTR)); - verify(_handler).handle(matchesRecord(bindingId, "Binding", EMPTY_ATTR)); - verify(_handler).handle(matchesRecord(binding2Id, "Binding", EMPTY_ATTR)); + verify(_handler).handle(matchesRecord(queueId, "Queue", queueAttr)); + verify(_handler).handle(matchesRecord(queue2Id, "Queue", queue2Attr)); + verify(_handler).handle(matchesRecord(exchangeId, "Exchange", exchangeAttr)); + verify(_handler).handle(matchesRecord(bindingId, "Binding", bindingAttr)); + verify(_handler).handle(matchesRecord(binding2Id, "Binding", binding2Attr)); _store.closeConfigurationStore(); } @@ -371,7 +435,10 @@ public class JsonFileConfigStoreTest extends QpidTestCase private void createRootRecord() { UUID rootRecordId = UUID.randomUUID(); - _rootRecord = new ConfiguredObjectRecordImpl(rootRecordId, VIRTUAL_HOST_TYPE, Collections.<String, Object>emptyMap()); + _rootRecord = + new ConfiguredObjectRecordImpl(rootRecordId, + VIRTUAL_HOST_TYPE, + Collections.<String, Object>singletonMap(ConfiguredObject.NAME, "root")); _store.create(_rootRecord); } 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 9c8f4ed3ae..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 @@ -22,6 +22,7 @@ package org.apache.qpid.server.util; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -90,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); @@ -117,9 +119,11 @@ public class BrokerTestHelper VirtualHostNode virtualHostNode = mock(VirtualHostNode.class); when(virtualHostNode.getTaskExecutor()).thenReturn(TASK_EXECUTOR); + when(virtualHostNode.getParent(eq(Broker.class))).thenReturn(broker); + DurableConfigurationStore dcs = mock(DurableConfigurationStore.class); when(virtualHostNode.getConfigurationStore()).thenReturn(dcs); - when(virtualHostNode.getParent(Broker.class)).thenReturn(broker); + when(virtualHostNode.getParent(eq(VirtualHostNode.class))).thenReturn(virtualHostNode); when(virtualHostNode.getModel()).thenReturn(objectFactory.getModel()); when(virtualHostNode.getObjectFactory()).thenReturn(objectFactory); when(virtualHostNode.getCategoryClass()).thenReturn(VirtualHostNode.class); 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(); |