diff options
Diffstat (limited to 'qpid/java/broker-core/src/main/java/org/apache/qpid/server')
26 files changed, 641 insertions, 118 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; + } + } |