diff options
author | Robert Godfrey <rgodfrey@apache.org> | 2014-08-25 15:25:00 +0000 |
---|---|---|
committer | Robert Godfrey <rgodfrey@apache.org> | 2014-08-25 15:25:00 +0000 |
commit | 19478e74524f27e26f01117b1b973829718ed44d (patch) | |
tree | 214cee6e0e1fb25a553aaaa490b775450ea9e8e2 | |
parent | e0e8f4c5087c1c5dc787740d6bd862755bd8daf1 (diff) | |
download | qpid-python-19478e74524f27e26f01117b1b973829718ed44d.tar.gz |
Merging from trunk r1618230:1618433 in the Java tree
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/0.30@1620344 13f79535-47bb-0310-9956-ffa450edef68
102 files changed, 2812 insertions, 831 deletions
diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js index 087caf34c6..ed34bbbd7a 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js @@ -16,10 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -define(["qpid/common/util", "dijit/registry", "dojo/_base/window", "dojo/domReady!"], - function (util, registry, win) +define(["qpid/common/util", "qpid/common/metadata", "dijit/registry", "dojo/_base/window", "dojo/domReady!"], + function (util, metadata, registry, win) { - var fieldNames = ["storeUnderfullSize", "storeOverfullSize"]; + var fieldNames = ["storeUnderfullSize", "storeOverfullSize", + "localTransactionSynchronizationPolicy", "remoteTransactionSynchronizationPolicy"]; return { show: function(data) { @@ -28,17 +29,6 @@ define(["qpid/common/util", "dijit/registry", "dojo/_base/window", "dojo/domRead registry.byId("editVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); registry.byId("editVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); - var widget = registry.byId("editVirtualHost.localTransactionSynchronizationPolicy-" + data.data["localTransactionSynchronizationPolicy"]); - if (widget) - { - widget.set("checked", true); - } - widget = registry.byId("editVirtualHost.remoteTransactionSynchronizationPolicy-" + data.data["remoteTransactionSynchronizationPolicy"]); - if (widget) - { - widget.set("checked", true); - } - var that = this; this.permittedNodes = registry.byId("editVirtualHost.permittedNodes"); this.permittedNodesList = registry.byId("editVirtualHost.permittedNodesList"); diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js index 9cf6bdea66..f211d19d16 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js @@ -47,8 +47,8 @@ define(["qpid/common/util", "dojo/query", "dojo/domReady!"], } this["permittedNodes"].innerHTML = permittedNodesMarkup ; - var localSyncPolicy = data[localTransactionSynchronizationPolicy].toLowerCase(); - var remoteSyncPolicy = data[remoteTransactionSynchronizationPolicy].toLowerCase(); + var localSyncPolicy = data[localTransactionSynchronizationPolicy] ? data[localTransactionSynchronizationPolicy].toLowerCase() : ""; + var remoteSyncPolicy = data[remoteTransactionSynchronizationPolicy] ? data[remoteTransactionSynchronizationPolicy].toLowerCase() : ""; for(var i=0; i<this[localTransactionSynchronizationPolicy].children.length;i++) { diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/edit.html b/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/edit.html index cad6b9301e..9d0b0ab860 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/edit.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/edit.html @@ -27,7 +27,8 @@ name: 'storeOverfullSize', placeHolder: 'size in bytes', required: false, - title: 'Enter ceiling (in bytes) at which store will begin to throttle sessions producing messages'"/> + title: 'Enter ceiling (in bytes) at which store will begin to throttle sessions producing messages', + promptMessage: 'Ceiling (in bytes) at which store will begin to throttle sessions producing messages'"/> </div> </div> <div class="clear"> @@ -39,7 +40,8 @@ name: 'storeUnderfullSize', placeHolder: 'size in bytes', required: false, - title: 'Enter floor (in bytes) at which store will cease to throttle sessions producing messages'"/> + title: 'Enter floor (in bytes) at which store will cease to throttle sessions producing messages', + promptMessage: 'Floor (in bytes) at which store will cease to throttle sessions producing messages'"/> </div> </div> @@ -74,8 +76,9 @@ data-dojo-props=" name: 'permittedNode', placeHolder: 'host:port', - title: 'Enter address', - intermediateChanges: true" /> + intermediateChanges: true, + title: 'Enter address of node to be permitted into the group', + promptMessage: 'Address of node to be permitted into the group'" /> </div> <button data-dojo-type="dijit/form/Button" id="editVirtualHost.permittedNodeAdd" data-dojo-props="label: '+'"></button> </div> @@ -86,42 +89,30 @@ <div class="formBox clear"> <fieldset> - <legend>High availability durability</legend> - <div> - <div class="haOptionLabel">Master transaction sync policy</div> + <legend>High availability durability</legend> <div> - <input data-dojo-type="dijit/form/RadioButton" type="radio" name="localTransactionSynchronizationPolicy" value="SYNC" id="editVirtualHost.localTransactionSynchronizationPolicy-SYNC"/> - <label>SYNC (the transaction will be written and synchronized to the disk; highest durability)</label> - </div> - - <div> - <input data-dojo-type="dijit/form/RadioButton" type="radio" name="localTransactionSynchronizationPolicy" value="WRITE_NO_SYNC" id="editVirtualHost.localTransactionSynchronizationPolicy-WRITE_NO_SYNC"/> - <label>WRITE_NO_SYNC (the transaction will be written only; the synchronization will be performed later)</label> - </div> + <div class="haOptionLabel">Master transaction sync policy</div> - <div> - <input data-dojo-type="dijit/form/RadioButton" type="radio" name="localTransactionSynchronizationPolicy" value="NO_SYNC" id="editVirtualHost.localTransactionSynchronizationPolicy-NO_SYNC"/> - <label>NO_SYNC (write later; the transaction will be written and synchronized later; lowest durability)</label> - </div> - </div> - <br/> - <div> - <div class="haOptionLabel">Replica transaction sync policy</div> - <div> - <input data-dojo-type="dijit/form/RadioButton" type="radio" name="remoteTransactionSynchronizationPolicy" value="SYNC" id="editVirtualHost.remoteTransactionSynchronizationPolicy-SYNC"/> - <label>SYNC (the transaction will be written and synchronized to the disk; highest durability)</label> + <select id="editVirtualHost.localTransactionSynchronizationPolicy" + name="localTransactionSynchronizationPolicy" + data-dojo-type="dojox/form/CheckedMultiSelect"> + <option value="SYNC">SYNC (the transaction will be written and synchronized to the disk; highest durability)</option> + <option value="WRITE_NO_SYNC">WRITE_NO_SYNC (the transaction will be written only; the synchronization will be performed later)</option> + <option value="NO_SYNC">NO_SYNC (write later; the transaction will be written and synchronized later; lowest durability)</option> + </select> </div> - + <br/> <div> - <input data-dojo-type="dijit/form/RadioButton" type="radio" name="remoteTransactionSynchronizationPolicy" value="WRITE_NO_SYNC" id="editVirtualHost.remoteTransactionSynchronizationPolicy-WRITE_NO_SYNC"/> - <label>WRITE_NO_SYNC (the transaction will be written only; the synchronization will be performed later)</label> - </div> + <div class="haOptionLabel">Replica transaction sync policy</div> - <div> - <input data-dojo-type="dijit/form/RadioButton" type="radio" name="remoteTransactionSynchronizationPolicy" value="NO_SYNC" id="editVirtualHost.remoteTransactionSynchronizationPolicy-NO_SYNC"/> - <label>NO_SYNC (write later; the transaction will be written and synchronized later; lowest durability)</label> + <select id="editVirtualHost.remoteTransactionSynchronizationPolicy" + name="remoteTransactionSynchronizationPolicy" + data-dojo-type="dojox/form/CheckedMultiSelect"> + <option value="SYNC">SYNC (the transaction will be written and synchronized to the disk; highest durability)</option> + <option value="WRITE_NO_SYNC">WRITE_NO_SYNC (the transaction will be written only; the synchronization will be performed later)</option> + <option value="NO_SYNC">NO_SYNC (write later; the transaction will be written and synchronized later; lowest durability)</option> + </select> </div> - </div> </fieldset> </div> diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb/add.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb/add.html index 9ce23084c5..c16dd675d2 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb/add.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb/add.html @@ -27,7 +27,8 @@ data-dojo-props=" name: 'storePath', placeHolder: 'path/to/store', - title: 'Enter store path'" /> + title: 'Enter store path', + promptMessage: 'File system location for the configuration store.'"/> </div> </div> diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add.html index c7e44a38b2..6973cf9002 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add.html @@ -31,7 +31,9 @@ data-dojo-props="store:groupStore, searchAttr:'name', required: true, - placeHolder: 'choose new or existing'" + placeHolder: 'choose new or existing', + promptMessage: 'Create a new group or join to an existing one', + title: 'Choose whether to create a new group or join to an existing one'" name="group" id="addVirtualHostNode.group" /> </div> diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/existinggroup/add.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/existinggroup/add.html index 820a94e754..d8f1ae5c57 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/existinggroup/add.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/existinggroup/add.html @@ -30,8 +30,8 @@ name: 'groupName', placeHolder: 'group name', required: true, - missingMessage: 'The group name must be supplied', - title: 'Enter the group name'" /> + promptMessage: 'Name of the existing group', + title: 'Enter name of the existing group'," /> </div> </div> <div class="clear"> @@ -43,8 +43,8 @@ name: 'helperNodeName', placeHolder: 'node name from group', required: true, - missingMessage: 'A node name must be supplied', - title: 'Enter a node name'" /> + promptMessage: 'Node name of an existing group member.', + title: 'Enter node name of an existing member of the group'" /> </div> </div> <div class="clear"> @@ -56,8 +56,8 @@ name: 'helperAddress', placeHolder: 'node address from group', required: true, - missingMessage: 'Node host and port must be supplied', - title: 'Enter address'" /> + promptMessage: 'Node address of the existing group member.', + title: 'Enter node address of the existing group member'" /> </div> </div> </fieldset> @@ -76,8 +76,8 @@ name: 'address', placeHolder: 'host:port', required: true, - missingMessage: 'Node host and port must be supplied', - title: 'Enter address'" /> + promptMessage: 'Node hostname and port number that new node will use.<br/>Other nodes will use connect to this address to replicate messages', + title: 'Enter node hostname and port number that new node will use'" /> </div> </div> <div class="clear"> @@ -88,7 +88,8 @@ data-dojo-props=" name: 'storePath', placeHolder: 'path/to/store', - title: 'Enter store path'" /> + promptMessage: 'File system location for the store', + title: 'Enter file system location for the store'" /> </div> </div> </fieldset> diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html index 1d3b2a1906..c25bae3419 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html @@ -27,8 +27,8 @@ name: 'groupName', placeHolder: 'group name', required: true, - missingMessage: 'A group name must be supplied', - title: 'Enter a group name'" /> + title: 'Enter name to identify the new group', + promptMessage: 'Name to identify the new group.'"/> </div> </div> <div class="clear"> @@ -40,8 +40,8 @@ name: 'address', placeHolder: 'host:port', required: true, - missingMessage: 'Node host and port must be supplied', - title: 'Enter address'" /> + title: 'Enter node hostname and port number that new node will use', + promptMessage: 'Node hostname and port number that new node will use.<br/>Other nodes will use connect to this address to replicate messages'" /> </div> </div> <div class="clear"> @@ -52,7 +52,8 @@ data-dojo-props=" name: 'storePath', placeHolder: 'path/to/store', - title: 'Enter store path'" /> + title: 'Enter file system location for the store', + promptMessage: 'File system location for the store'" /> </div> </div> <div class="clear formBox"> @@ -66,7 +67,7 @@ data-dojo-props=" name: 'permittedNodesList', readOnly : 'true', - title: 'Enter permitted nodes'"> + title: 'Enter list of the other node address that will form the group'"> </select> <!-- must use closing tag rather than shorthand - dojo bug? --> </div> <button data-dojo-type="dijit/form/Button" id="addVirtualHostNode.permittedNodeRemove" data-dojo-props="label: '-'" ></button> @@ -81,8 +82,9 @@ data-dojo-props=" name: 'permittedNode', placeHolder: 'host:port', - title: 'Enter address', - intermediateChanges: true" /> + intermediateChanges: true, + title: 'Enter address of node to be permitted into the group', + promptMessage: 'Address of node to be permitted into the group'" /> </div> <button data-dojo-type="dijit/form/Button" id="addVirtualHostNode.permittedNodeAdd" data-dojo-props="label: '+'"></button> </div> diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html index 189eb6f7b6..f163390fa2 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html @@ -25,8 +25,7 @@ placeHolder: 'Group Name', required: true, disabled: true, - missingMessage: 'A group name must be supplied', - title: 'Enter group name'" /> + title: 'Name of the group'" /> </div> </div> <div class="clear"> @@ -39,9 +38,7 @@ placeHolder: 'host:port', required: true, disabled: true, - missingMessage: 'A Host and Port must be supplied', - invalidMessage: 'Must be of the form host:port', - title: 'Enter Host and Port name'" /> + title: 'Node address of the group member'" /> </div> </div> <div class="clear"> @@ -51,8 +48,9 @@ data-dojo-type="dijit/form/ValidationTextBox" data-dojo-props=" name: 'storePath', - placeHolder: 'path/to/store', - title: 'Enter configuration store path'" /> + title: 'File system location for the store', + promptMessage: 'File system location for the store'" /> + </div> </div> <div class="clear"> @@ -63,7 +61,8 @@ data-dojo-props=" name: 'designatedPrimary', required: false, - title: 'Designate node as primary. It is applicable only to 2-nodes cluster'" /> + title: 'Designate node as primary allowing it to operate solo in a group of two.', + promptMessage: 'Designate node as primary allowing it to operate solo operate solo in a group of two'" /> </div> </div> <div class="clear"> @@ -80,8 +79,9 @@ data-dojo-props=" name: 'priority', required: false, - title: 'Select node priority for election as a Master', store: nodePriorityStore, + title: 'Set the election priority associated with this node', + promptMessage: 'Election priority associated with this node.<br/>Elections will choose the node with the most recent transactions.<br/>If there is a tie, priority is used as a tie-breaker.', searchAttr: 'name'" /> </div> </div> @@ -95,7 +95,8 @@ data-dojo-props=" name: 'quorumOverride', required: false, - title: 'Enter quorum override. 0 signifies simple majority', + title: 'Select minimum required number of nodes or choose Majority', + promptMessage: 'Modifies the minimum number of nodes required to be present to elect a master or commit transactions.<br/>Majority signifies that a natural majority of nodes must be present.', store: nodeQuorumOverrideStore, searchAttr: 'name'" /> </div> diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerTarget.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerTarget.java index f8585344b0..b7be1bfd9b 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerTarget.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerTarget.java @@ -50,7 +50,7 @@ public interface ConsumerTarget AMQSessionModel getSessionModel(); - void send(MessageInstance entry, boolean batch); + long send(MessageInstance entry, boolean batch); void flushBatched(); 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 f944821c6f..b191db8523 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 @@ -1431,15 +1431,22 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im static String interpolate(ConfiguredObject<?> object, String value) { - Map<String,String> inheritedContext = new HashMap<String, String>(); - generateInheritedContext(object.getModel(), object, inheritedContext); - return Strings.expand(value, false, - JSON_SUBSTITUTION_RESOLVER, - getOwnAttributeResolver(object), - new Strings.MapResolver(inheritedContext), - Strings.JAVA_SYS_PROPS_RESOLVER, - Strings.ENV_VARS_RESOLVER, - object.getModel().getTypeRegistry().getDefaultContextResolver()); + if(object == null) + { + return value; + } + else + { + Map<String, String> inheritedContext = new HashMap<String, String>(); + generateInheritedContext(object.getModel(), object, inheritedContext); + return Strings.expand(value, false, + JSON_SUBSTITUTION_RESOLVER, + getOwnAttributeResolver(object), + new Strings.MapResolver(inheritedContext), + Strings.JAVA_SYS_PROPS_RESOLVER, + Strings.ENV_VARS_RESOLVER, + object.getModel().getTypeRegistry().getDefaultContextResolver()); + } } private static OwnAttributeResolver getOwnAttributeResolver(final ConfiguredObject<?> object) 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 982ebb01c6..1a9390f210 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 @@ -128,6 +128,18 @@ public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventL @ManagedAttribute( defaultValue = "false") boolean getStatisticsReportingResetEnabled(); + String BROKER_MESSAGE_COMPRESSION_ENABLED = "broker.messageCompressionEnabled"; + @ManagedContextDefault(name = BROKER_MESSAGE_COMPRESSION_ENABLED) + boolean DEFAULT_MESSAGE_COMPRESSION_ENABLED = true; + + @ManagedAttribute( defaultValue = "${"+ BROKER_MESSAGE_COMPRESSION_ENABLED +"}") + boolean isMessageCompressionEnabled(); + + String MESSAGE_COMPRESSION_THRESHOLD_SIZE = "connection.messageCompressionThresholdSize"; + @ManagedContextDefault(name = MESSAGE_COMPRESSION_THRESHOLD_SIZE) + int DEFAULT_MESSAGE_COMPRESSION_THRESHOLD_SIZE = 102400; + + @DerivedAttribute( persist = true ) String getModelVersion(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java index 236e7fdccc..4ef1d315dd 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredAutomatedAttribute.java @@ -20,11 +20,23 @@ */ package org.apache.qpid.server.model; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import org.apache.log4j.Logger; public class ConfiguredAutomatedAttribute<C extends ConfiguredObject, T> extends ConfiguredObjectAttribute<C,T> { + private static final Logger LOGGER = Logger.getLogger(ConfiguredAutomatedAttribute.class); + private final ManagedAttribute _annotation; + private final Method _validValuesMethod; ConfiguredAutomatedAttribute(final Class<C> clazz, final Method getter, @@ -32,6 +44,53 @@ public class ConfiguredAutomatedAttribute<C extends ConfiguredObject, T> extend { super(clazz, getter); _annotation = annotation; + Method validValuesMethod = null; + + if(_annotation.validValues().length == 1) + { + String validValue = _annotation.validValues()[0]; + + validValuesMethod = getValidValuesMethod(validValue, clazz); + } + _validValuesMethod = validValuesMethod; + } + + private Method getValidValuesMethod(final String validValue, final Class<C> clazz) + { + if(validValue.matches("([\\w][\\w\\d_]+\\.)+[\\w][\\w\\d_\\$]*#[\\w\\d_]+\\s*\\(\\s*\\)")) + { + String function = validValue; + try + { + String className = function.split("#")[0].trim(); + String methodName = function.split("#")[1].split("\\(")[0].trim(); + Class<?> validValueCalculatingClass = Class.forName(className); + Method method = validValueCalculatingClass.getMethod(methodName); + if (Modifier.isStatic(method.getModifiers()) && Modifier.isPublic(method.getModifiers())) + { + if (Collection.class.isAssignableFrom(method.getReturnType())) + { + if (method.getGenericReturnType() instanceof ParameterizedType) + { + Type parameterizedType = + ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0]; + if (parameterizedType == String.class) + { + return method; + } + } + } + } + + } + catch (ClassNotFoundException | NoSuchMethodException e) + { + LOGGER.warn("The validValues of the " + getName() + " attribute in class " + clazz.getSimpleName() + + " has value '" + validValue + "' which looks like it should be a method," + + " but no such method could be used.", e ); + } + } + return null; } public boolean isAutomated() @@ -69,4 +128,21 @@ public class ConfiguredAutomatedAttribute<C extends ConfiguredObject, T> extend return _annotation.description(); } + public Collection<String> validValues() + { + if(_validValuesMethod != null) + { + try + { + return (Collection<String>) _validValuesMethod.invoke(null); + } + catch (InvocationTargetException | IllegalAccessException e) + { + LOGGER.warn("Could not execute the validValues generation method " + _validValuesMethod.getName(), e); + return Collections.emptySet(); + } + } + return Arrays.asList(_annotation.validValues()); + } + } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java index 7a965c19d7..5b3965904e 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Connection.java @@ -43,6 +43,7 @@ public interface Connection<X extends Connection<X>> extends ConfiguredObject<X> String TRANSPORT = "transport"; String PORT = "port"; + @DerivedAttribute String getClientId(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttribute.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttribute.java index 2a72c5c5ac..d8b36f487c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttribute.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttribute.java @@ -34,4 +34,5 @@ public @interface ManagedAttribute boolean persist() default true; String defaultValue() default ""; String description() default ""; + String[] validValues() default {}; } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Protocol.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Protocol.java index 22ea1d9706..a943c0f54c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Protocol.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Protocol.java @@ -87,6 +87,6 @@ public enum Protocol public static enum ProtocolType { - AMQP, HTTP, JMX, RMI; + AMQP, HTTP, JMX, RMI } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java index 67c713e9d9..af46bae1c4 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java @@ -92,6 +92,8 @@ public class BrokerAdapter extends AbstractConfiguredObject<BrokerAdapter> imple private int _statisticsReportingPeriod; @ManagedAttributeField private boolean _statisticsReportingResetEnabled; + @ManagedAttributeField + private boolean _messageCompressionEnabled; private State _state = State.UNINITIALIZED; @@ -360,6 +362,12 @@ public class BrokerAdapter extends AbstractConfiguredObject<BrokerAdapter> imple } @Override + public boolean isMessageCompressionEnabled() + { + return _messageCompressionEnabled; + } + + @Override public String getModelVersion() { return BrokerModel.MODEL_VERSION; 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 0d3ec6d3bb..fa599b4d5f 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 @@ -20,10 +20,14 @@ */ package org.apache.qpid.server.model.port; +import java.util.Set; + import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.Transport; import org.apache.qpid.server.virtualhost.VirtualHostImpl; @ManagedObject( category = false, type = "AMQP") @@ -57,5 +61,13 @@ public interface AmqpPort<X extends AmqpPort<X>> extends Port<X> @ManagedAttribute( mandatory = true ) AuthenticationProvider getAuthenticationProvider(); + + @ManagedAttribute( defaultValue = "TCP", + validValues = {"org.apache.qpid.server.model.port.AmqpPortImpl#getAllAvailableTransportCombinations()"}) + Set<Transport> getTransports(); + + @ManagedAttribute( validValues = {"org.apache.qpid.server.model.port.AmqpPortImpl#getAllAvailableProtocolCombinations()"} ) + Set<Protocol> getProtocols(); + VirtualHostImpl getVirtualHost(String name); } 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 e6e2d7bbb8..6f6d04c335 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 @@ -19,9 +19,12 @@ */ package org.apache.qpid.server.model.port; +import java.io.IOException; +import java.io.StringWriter; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.Map; @@ -32,6 +35,8 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import org.codehaus.jackson.map.ObjectMapper; + import org.apache.qpid.server.configuration.BrokerProperties; import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.logging.messages.BrokerMessages; @@ -43,6 +48,7 @@ import org.apache.qpid.server.model.Protocol; import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.Transport; import org.apache.qpid.server.model.TrustStore; +import org.apache.qpid.server.plugin.ProtocolEngineCreator; import org.apache.qpid.server.plugin.QpidServiceLoader; import org.apache.qpid.server.plugin.TransportProviderFactory; import org.apache.qpid.server.transport.AcceptingTransport; @@ -275,4 +281,87 @@ public class AmqpPortImpl extends AbstractPortWithAuthProvider<AmqpPortImpl> imp return null; } + public static Set<Protocol> getInstalledProtocols() + { + Set<Protocol> protocols = new HashSet<>(); + for(ProtocolEngineCreator installedEngine : (new QpidServiceLoader<ProtocolEngineCreator>()).instancesOf(ProtocolEngineCreator.class)) + { + protocols.add(installedEngine.getVersion()); + } + return protocols; + } + + @SuppressWarnings("unused") + public static Collection<String> getAllAvailableProtocolCombinations() + { + Set<Protocol> protocols = getInstalledProtocols(); + + Set<Set<String>> last = new HashSet<>(); + for(Protocol protocol : protocols) + { + last.add(Collections.singleton(protocol.name())); + } + + Set<Set<String>> protocolCombinations = new HashSet<>(last); + for(int i = 1; i < protocols.size(); i++) + { + Set<Set<String>> current = new HashSet<>(); + for(Set<String> set : last) + { + for(Protocol p : protocols) + { + if(!set.contains(p.name())) + { + Set<String> potential = new HashSet<>(set); + potential.add(p.name()); + current.add(potential); + } + } + } + protocolCombinations.addAll(current); + last = current; + } + Set<String> combinationsAsString = new HashSet<>(protocolCombinations.size()); + ObjectMapper mapper = new ObjectMapper(); + for(Set<String> combination : protocolCombinations) + { + try(StringWriter writer = new StringWriter()) + { + mapper.writeValue(writer, combination); + combinationsAsString.add(writer.toString()); + } + catch (IOException e) + { + throw new IllegalArgumentException("Unexpected IO Exception generating JSON string", e); + } + } + return Collections.unmodifiableSet(combinationsAsString); + } + + @SuppressWarnings("unused") + public static Collection<String> getAllAvailableTransportCombinations() + { + Set<Set<Transport>> combinations = new HashSet<>(); + + for(TransportProviderFactory providerFactory : (new QpidServiceLoader<TransportProviderFactory>()).instancesOf(TransportProviderFactory.class)) + { + combinations.addAll(providerFactory.getSupportedTransports()); + } + + Set<String> combinationsAsString = new HashSet<>(combinations.size()); + ObjectMapper mapper = new ObjectMapper(); + for(Set<Transport> combination : combinations) + { + try(StringWriter writer = new StringWriter()) + { + mapper.writeValue(writer, combination); + combinationsAsString.add(writer.toString()); + } + catch (IOException e) + { + throw new IllegalArgumentException("Unexpected IO Exception generating JSON string", e); + } + } + return Collections.unmodifiableSet(combinationsAsString); + } } 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 b169b07e35..fa2af121ae 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 @@ -20,10 +20,14 @@ */ package org.apache.qpid.server.model.port; +import java.util.Set; + import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.Transport; @ManagedObject( category = false, type = "HTTP") public interface HttpPort<X extends HttpPort<X>> extends Port<X> @@ -42,5 +46,13 @@ public interface HttpPort<X extends HttpPort<X>> extends Port<X> @ManagedAttribute( mandatory = true ) AuthenticationProvider getAuthenticationProvider(); + + @ManagedAttribute( defaultValue = "TCP", + validValues = {"[ \"TCP\" ]", "[ \"SSL\" ]", "[ \"TCP\", \"SSL\" ]"}) + Set<Transport> getTransports(); + + @ManagedAttribute( validValues = { "[ \"HTTP\"]"} ) + Set<Protocol> getProtocols(); + void setPortManager(PortManager manager); } 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 56c77cbb03..48754e92e4 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 @@ -20,10 +20,14 @@ */ package org.apache.qpid.server.model.port; +import java.util.Set; + import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.Transport; @ManagedObject( category = false, type = "JMX") public interface JmxPort<X extends JmxPort<X>> extends Port<X> @@ -42,5 +46,13 @@ public interface JmxPort<X extends JmxPort<X>> extends Port<X> @ManagedAttribute( mandatory = true ) AuthenticationProvider getAuthenticationProvider(); + + @ManagedAttribute( defaultValue = "TCP", + validValues = {"[ \"TCP\" ]", "[ \"SSL\" ]"}) + Set<Transport> getTransports(); + + @ManagedAttribute( validValues = { "[ \"JMX_RMI\"]"} ) + Set<Protocol> getProtocols(); + void setPortManager(PortManager manager); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/RmiPort.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/RmiPort.java index ed975d041a..d2420aa343 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/RmiPort.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/RmiPort.java @@ -20,65 +20,27 @@ */ package org.apache.qpid.server.model.port; -import java.util.Collections; -import java.util.Map; import java.util.Set; -import org.apache.qpid.server.configuration.IllegalConfigurationException; -import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.model.ManagedObject; -import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; +import org.apache.qpid.server.model.Port; import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.Transport; @ManagedObject( category = false, type = "RMI") -public class RmiPort extends AbstractPort<RmiPort> +public interface RmiPort<X extends RmiPort<X>> extends Port<X> { - private PortManager _portManager; - @ManagedObjectFactoryConstructor - public RmiPort(final Map<String, Object> attributes, - final Broker<?> broker) - { - super(attributes, broker); - } + @ManagedAttribute( validValues = { "[ \"RMI\"]"} ) + Set<Protocol> getProtocols(); - @Override - public void onValidate() - { - super.onValidate(); + @ManagedAttribute( defaultValue = "TCP", + validValues = {"[ \"TCP\" ]"}) + Set<Transport> getTransports(); - validateOnlyOneInstance(); - if (getTransports().contains(Transport.SSL)) - { - throw new IllegalConfigurationException("Can't create RMI registry port which requires SSL"); - } + public void setPortManager(PortManager manager); - } - @Override - protected Set<Protocol> getDefaultProtocols() - { - return Collections.singleton(Protocol.RMI); - } - - public void setPortManager(PortManager manager) - { - _portManager = manager; - } - - @Override - protected State onActivate() - { - if(_portManager != null && _portManager.isActivationAllowed(this)) - { - return super.onActivate(); - } - else - { - return State.QUIESCED; - } - } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/RmiPortImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/RmiPortImpl.java new file mode 100644 index 0000000000..e236b7cb91 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/RmiPortImpl.java @@ -0,0 +1,82 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.model.port; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Transport; + +public class RmiPortImpl extends AbstractPort<RmiPortImpl> implements RmiPort<RmiPortImpl> +{ + private PortManager _portManager; + + @ManagedObjectFactoryConstructor + public RmiPortImpl(final Map<String, Object> attributes, + final Broker<?> broker) + { + super(attributes, broker); + } + + @Override + public void onValidate() + { + super.onValidate(); + + validateOnlyOneInstance(); + + if (getTransports().contains(Transport.SSL)) + { + throw new IllegalConfigurationException("Can't create RMI registry port which requires SSL"); + } + + } + + @Override + protected Set<Protocol> getDefaultProtocols() + { + return Collections.singleton(Protocol.RMI); + } + + public void setPortManager(PortManager manager) + { + _portManager = manager; + } + + @Override + protected State onActivate() + { + if(_portManager != null && _portManager.isActivationAllowed(this)) + { + return super.onActivate(); + } + else + { + return State.QUIESCED; + } + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java index d80aa92007..4044c938db 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java @@ -471,9 +471,8 @@ class QueueConsumerImpl public final void send(final QueueEntry entry, final boolean batch) { _deliveredCount.incrementAndGet(); - ServerMessage message = entry.getMessage(); - _deliveredBytes.addAndGet(message.getSize()); - _target.send(entry, batch); + long size = _target.send(entry, batch); + _deliveredBytes.addAndGet(size); } @Override diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java index 8d025c50dc..ad33ecadcf 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java @@ -167,13 +167,15 @@ public class MockConsumer implements ConsumerTarget { } - public void send(MessageInstance entry, boolean batch) + public long send(MessageInstance entry, boolean batch) { + long size = entry.getMessage().getSize(); if (messages.contains(entry)) { entry.setRedelivered(); } messages.add(entry); + return size; } public void flushBatched() diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/ConfigureObjectTypeRegistryTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/ConfigureObjectTypeRegistryTest.java index 8bd599f22f..3301c046a8 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/ConfigureObjectTypeRegistryTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/ConfigureObjectTypeRegistryTest.java @@ -20,12 +20,14 @@ */ package org.apache.qpid.server.model; +import java.util.Arrays; import java.util.Collection; import junit.framework.TestCase; import org.apache.qpid.server.model.testmodel.Test2RootCategory; import org.apache.qpid.server.model.testmodel.Test2RootCategoryImpl; +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.model.testmodel.TestRootCategoryImpl; @@ -76,6 +78,21 @@ public class ConfigureObjectTypeRegistryTest extends TestCase Test2RootCategory.DEFAULTED_VALUE_DEFAULT); } + public void testValidValues() + { + checkValidValues("validValue",_typeRegistry.getAttributes((Class) TestRootCategoryImpl.class), + Arrays.asList( TestRootCategory.VALID_VALUE1, TestRootCategory.VALID_VALUE2 ) ); + + checkValidValues("validValue", _typeRegistry.getAttributes((Class) Test2RootCategoryImpl.class), + Test2RootCategoryImpl.functionGeneratedValidValues()); + + + checkValidValues("validValueNotInterpolated", _typeRegistry.getAttributes((Class) TestChildCategory.class), + Arrays.asList(TestChildCategory.NON_INTERPOLATED_VALID_VALUE)); + + + } + private void checkDefaultedValue(final Collection<ConfiguredObjectAttribute<?, ?>> attrs, final String defaultedValueDefault) { @@ -92,4 +109,24 @@ public class ConfigureObjectTypeRegistryTest extends TestCase } assertTrue("Could not find attribute defaultedValue", found); } + + private void checkValidValues(final String attrName, final Collection<ConfiguredObjectAttribute<?, ?>> attrs, + final Collection<String> validValues) + { + boolean found = false; + for(ConfiguredObjectAttribute<?, ?> attr : attrs) + { + if(attr.getName().equals(attrName)) + { + Collection<String> foundValues = ((ConfiguredAutomatedAttribute<?, ?>) attr).validValues(); + assertEquals("Valid values not as expected, counts differ", validValues.size(), foundValues.size()); + assertTrue("Valid values do not include all expected values", foundValues.containsAll(validValues)); + assertTrue("Valid values contain unexpected addtional values", validValues.containsAll(foundValues)); + found = true; + break; + } + + } + assertTrue("Could not find attribute " + attrName, found); + } } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/Test2RootCategory.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/Test2RootCategory.java index e47c76cbbb..23f03db507 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/Test2RootCategory.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/Test2RootCategory.java @@ -26,10 +26,15 @@ import org.apache.qpid.server.model.ManagedAttribute; public interface Test2RootCategory<X extends Test2RootCategory<X>> extends TestRootCategory<X> { String DEFAULTED_VALUE_DEFAULT = "differentDefault"; + @Override @ManagedAttribute( defaultValue = DEFAULTED_VALUE_DEFAULT) String getDefaultedValue(); + @Override + @ManagedAttribute( validValues = {"org.apache.qpid.server.model.testmodel.Test2RootCategoryImpl#functionGeneratedValidValues()"}) + String getValidValue(); + @DerivedAttribute public int getDerivedAttribute(); } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/Test2RootCategoryImpl.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/Test2RootCategoryImpl.java index 022e0a256f..e98a9fa3dc 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/Test2RootCategoryImpl.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/Test2RootCategoryImpl.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.model.testmodel; +import java.util.Collection; +import java.util.Collections; import java.util.Map; import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor; @@ -49,6 +51,9 @@ public class Test2RootCategoryImpl extends AbstractConfiguredObject<Test2RootCat @ManagedAttributeField private Map<String,String> _mapValue; + @ManagedAttributeField + private String _validValue; + @ManagedObjectFactoryConstructor public Test2RootCategoryImpl(final Map<String, Object> attributes) { @@ -93,6 +98,12 @@ public class Test2RootCategoryImpl extends AbstractConfiguredObject<Test2RootCat } @Override + public String getValidValue() + { + return _validValue; + } + + @Override public int getDerivedAttribute() { return 0; @@ -115,4 +126,9 @@ public class Test2RootCategoryImpl extends AbstractConfiguredObject<Test2RootCat { return null; } + + public static Collection<String> functionGeneratedValidValues() + { + return Collections.singleton("generated"); + } } 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 new file mode 100644 index 0000000000..0c8dcc8744 --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestChildCategory.java @@ -0,0 +1,35 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.model.testmodel; + +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.ManagedAttribute; +import org.apache.qpid.server.model.ManagedObject; + +@ManagedObject +public interface TestChildCategory<X extends TestChildCategory<X>> extends ConfiguredObject<X> +{ + + String NON_INTERPOLATED_VALID_VALUE = "${file.separator}"; + + @ManagedAttribute(validValues = { NON_INTERPOLATED_VALID_VALUE }) + String getValidValueNotInterpolated(); +} 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 new file mode 100644 index 0000000000..b5a4182f79 --- /dev/null +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestChildCategoryImpl.java @@ -0,0 +1,60 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.model.testmodel; + +import java.util.Map; + +import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.ManagedAttributeField; +import org.apache.qpid.server.model.ManagedObject; +import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; +import org.apache.qpid.server.model.State; + +@ManagedObject( category = false , type = "test" ) +public class TestChildCategoryImpl + extends AbstractConfiguredObject<TestChildCategoryImpl> implements TestChildCategory<TestChildCategoryImpl> +{ + + + @ManagedAttributeField + private String _validValueNotInterpolated; + + + @ManagedObjectFactoryConstructor + public TestChildCategoryImpl(final Map<String, Object> attributes, TestRootCategory<?> parent) + { + super(parentsMap(parent), attributes); + } + + @Override + public State getState() + { + return null; + } + + + + @Override + public String getValidValueNotInterpolated() + { + return _validValueNotInterpolated; + } +} diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestModel.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestModel.java index fc98b51731..ab9d753b7d 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestModel.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestModel.java @@ -36,7 +36,8 @@ public class TestModel extends Model private static final Model INSTANCE = new TestModel(); private Class<? extends ConfiguredObject>[] _supportedClasses = new Class[] { - TestRootCategory.class + TestRootCategory.class, + TestChildCategory.class }; private final ConfiguredObjectFactory _objectFactory; @@ -77,7 +78,9 @@ public class TestModel extends Model @Override public Collection<Class<? extends ConfiguredObject>> getChildTypes(final Class<? extends ConfiguredObject> parent) { - return Collections.emptySet(); + return TestRootCategory.class.isAssignableFrom(parent) + ? Collections.<Class<? extends ConfiguredObject>>singleton(TestChildCategory.class) + : Collections.<Class<? extends ConfiguredObject>>emptySet(); } @Override @@ -89,7 +92,9 @@ public class TestModel extends Model @Override public Collection<Class<? extends ConfiguredObject>> getParentTypes(final Class<? extends ConfiguredObject> child) { - return Collections.emptySet(); + return TestChildCategory.class.isAssignableFrom(child) + ? Collections.<Class<? extends ConfiguredObject>>singleton(TestRootCategory.class) + : Collections.<Class<? extends ConfiguredObject>>emptySet(); } @Override diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestRootCategory.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestRootCategory.java index 954fe4dcb1..7f804006b2 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestRootCategory.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestRootCategory.java @@ -42,9 +42,15 @@ public interface TestRootCategory<X extends TestRootCategory<X>> extends Configu String getAutomatedNonPersistedValue(); String DEFAULTED_VALUE_DEFAULT = "myDefaultVar"; + String VALID_VALUE1 = "FOO"; + String VALID_VALUE2 = "BAR"; + @ManagedAttribute( defaultValue = DEFAULTED_VALUE_DEFAULT) String getDefaultedValue(); + @ManagedAttribute(validValues = {VALID_VALUE1, VALID_VALUE2} ) + String getValidValue(); + @ManagedAttribute String getStringValue(); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestRootCategoryImpl.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestRootCategoryImpl.java index d549086686..0c6a0cb0ca 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestRootCategoryImpl.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/testmodel/TestRootCategoryImpl.java @@ -49,6 +49,10 @@ public class TestRootCategoryImpl extends AbstractConfiguredObject<TestRootCateg @ManagedAttributeField private Map<String,String> _mapValue; + @ManagedAttributeField + private String _validValue; + + @ManagedObjectFactoryConstructor public TestRootCategoryImpl(final Map<String, Object> attributes) { @@ -109,4 +113,10 @@ public class TestRootCategoryImpl extends AbstractConfiguredObject<TestRootCateg { return null; } + + @Override + public String getValidValue() + { + return _validValue; + } } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.java index ce1c95e674..f13886d2b2 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.java @@ -208,10 +208,11 @@ public class StandardQueueTest extends AbstractQueueTestBase * @param entry * @param batch */ - public void send(MessageInstance entry, boolean batch) + public long send(MessageInstance entry, boolean batch) { - super.send(entry, batch); + long size = super.send(entry, batch); latch.countDown(); + return size; } }; diff --git a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ConsumerTarget_0_10.java b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ConsumerTarget_0_10.java index 7ab3fbb1f5..ec0c38ec42 100644 --- a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ConsumerTarget_0_10.java +++ b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ConsumerTarget_0_10.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.protocol.v0_10; +import java.nio.ByteBuffer; import java.util.Collections; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; @@ -51,6 +52,7 @@ import org.apache.qpid.transport.MessageProperties; import org.apache.qpid.transport.MessageTransfer; import org.apache.qpid.transport.Method; import org.apache.qpid.transport.Option; +import org.apache.qpid.util.GZIPUtils; public class ConsumerTarget_0_10 extends AbstractConsumerTarget implements FlowCreditManager.FlowCreditManagerListener { @@ -198,7 +200,7 @@ public class ConsumerTarget_0_10 extends AbstractConsumerTarget implements FlowC private final AddMessageDispositionListenerAction _postIdSettingAction; - public void send(final MessageInstance entry, boolean batch) + public long send(final MessageInstance entry, boolean batch) { ServerMessage serverMsg = entry.getMessage(); @@ -264,11 +266,44 @@ public class ConsumerTarget_0_10 extends AbstractConsumerTarget implements FlowC deliveryProps.setRedelivered(entry.isRedelivered()); - Header header = new Header(deliveryProps, messageProps, msg.getHeader() == null ? null : msg.getHeader().getNonStandardProperties()); + boolean msgCompressed = messageProps != null && GZIPUtils.GZIP_CONTENT_ENCODING.equals(messageProps.getContentEncoding()); + + ByteBuffer body = msg.getBody(); - xfr = batch ? new MessageTransfer(getConsumer().getName(),_acceptMode,_acquireMode,header,msg.getBody(), BATCHED) - : new MessageTransfer(getConsumer().getName(),_acceptMode,_acquireMode,header,msg.getBody()); + boolean compressionSupported = _session.getConnection().getConnectionDelegate().isCompressionSupported(); + + if(msgCompressed && !compressionSupported) + { + byte[] uncompressed = GZIPUtils.uncompressBufferToArray(body); + if(uncompressed != null) + { + messageProps.setContentEncoding(null); + body = ByteBuffer.wrap(uncompressed); + } + } + else if(!msgCompressed + && compressionSupported + && (messageProps == null || messageProps.getContentEncoding()==null) + && body.remaining() > _session.getConnection().getMessageCompressionThreshold()) + { + byte[] compressed = GZIPUtils.compressBufferToArray(body); + if(compressed != null) + { + if(messageProps == null) + { + messageProps = new MessageProperties(); + } + messageProps.setContentEncoding(GZIPUtils.GZIP_CONTENT_ENCODING); + body = ByteBuffer.wrap(compressed); + } + } + long size = body == null ? 0 : body.remaining(); + + Header header = new Header(deliveryProps, messageProps, msg.getHeader() == null ? null : msg.getHeader().getNonStandardProperties()); + + xfr = batch ? new MessageTransfer(getConsumer().getName(),_acceptMode,_acquireMode,header, body, BATCHED) + : new MessageTransfer(getConsumer().getName(),_acceptMode,_acquireMode,header, body); if(_acceptMode == MessageAcceptMode.NONE && _acquireMode != MessageAcquireMode.PRE_ACQUIRED) { @@ -311,7 +346,7 @@ public class ConsumerTarget_0_10 extends AbstractConsumerTarget implements FlowC { recordUnacknowledged(entry); } - + return size; } void recordUnacknowledged(MessageInstance entry) diff --git a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnection.java b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnection.java index 8ddd04f51a..60bb5c6112 100644 --- a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnection.java +++ b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnection.java @@ -74,7 +74,7 @@ public class ServerConnection extends Connection implements AMQConnectionModel<S private final StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived; private final long _connectionId; private final Object _reference = new Object(); - private VirtualHostImpl _virtualHost; + private VirtualHostImpl<?,?,?> _virtualHost; private Port<?> _port; private AtomicLong _lastIoTime = new AtomicLong(); private boolean _blocking; @@ -87,6 +87,7 @@ public class ServerConnection extends Connection implements AMQConnectionModel<S new CopyOnWriteArrayList<SessionModelListener>(); private volatile boolean _stopped; + private int _messageCompressionThreshold; public ServerConnection(final long connectionId, Broker broker) { @@ -172,14 +173,22 @@ public class ServerConnection extends Connection implements AMQConnectionModel<S super.setConnectionDelegate(delegate); } - public VirtualHostImpl getVirtualHost() + public VirtualHostImpl<?,?,?> getVirtualHost() { return _virtualHost; } - public void setVirtualHost(VirtualHostImpl virtualHost) + public void setVirtualHost(VirtualHostImpl<?,?,?> virtualHost) { _virtualHost = virtualHost; + _messageCompressionThreshold = + virtualHost.getContextValue(Integer.class, + Broker.MESSAGE_COMPRESSION_THRESHOLD_SIZE); + + if(_messageCompressionThreshold <= 0) + { + _messageCompressionThreshold = Integer.MAX_VALUE; + } } @Override @@ -639,4 +648,9 @@ public class ServerConnection extends Connection implements AMQConnectionModel<S { _taskList.remove(task); } + + public int getMessageCompressionThreshold() + { + return _messageCompressionThreshold; + } } diff --git a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java index bab2d802e8..cc9d66756b 100644 --- a/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java +++ b/qpid/java/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerConnectionDelegate.java @@ -64,6 +64,8 @@ public class ServerConnectionDelegate extends ServerDelegate private final SubjectCreator _subjectCreator; private int _maximumFrameSize; + private boolean _compressionSupported; + public ServerConnectionDelegate(Broker<?> broker, String localFQDN, SubjectCreator subjectCreator) { this(createConnectionProperties(broker), Collections.singletonList((Object)"en_US"), broker, localFQDN, subjectCreator); @@ -111,6 +113,7 @@ public class ServerConnectionDelegate extends ServerDelegate map.put(ServerPropertyNames.VERSION, QpidProperties.getReleaseVersion()); map.put(ServerPropertyNames.QPID_BUILD, QpidProperties.getBuildVersion()); map.put(ServerPropertyNames.QPID_INSTANCE_NAME, broker.getName()); + map.put(ConnectionStartProperties.QPID_MESSAGE_COMPRESSION_SUPPORTED, String.valueOf(broker.isMessageCompressionEnabled())); return map; } @@ -366,6 +369,16 @@ public class ServerConnectionDelegate extends ServerDelegate public void connectionStartOk(Connection conn, ConnectionStartOk ok) { _clientProperties = ok.getClientProperties(); + if(_clientProperties != null) + { + Object compressionSupported = + _clientProperties.get(ConnectionStartProperties.QPID_MESSAGE_COMPRESSION_SUPPORTED); + if (compressionSupported != null) + { + _compressionSupported = Boolean.parseBoolean(String.valueOf(compressionSupported)); + + } + } super.connectionStartOk(conn, ok); } @@ -400,4 +413,9 @@ public class ServerConnectionDelegate extends ServerDelegate int delay = (Integer)_broker.getAttribute(Broker.CONNECTION_HEART_BEAT_DELAY); return delay == 0 ? super.getHeartbeatMax() : delay; } + + public boolean isCompressionSupported() + { + return _compressionSupported && _broker.isMessageCompressionEnabled(); + } } diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolEngine.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolEngine.java index 1c264e52c6..c193491e1e 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolEngine.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolEngine.java @@ -103,7 +103,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, AMQProtocolSessi private String _clientProduct = null; private String _remoteProcessPid = null; - private VirtualHostImpl _virtualHost; + private VirtualHostImpl<?,?,?> _virtualHost; private final Map<Integer, AMQChannel<AMQProtocolEngine>> _channelMap = new HashMap<Integer, AMQChannel<AMQProtocolEngine>>(); @@ -175,6 +175,8 @@ public class AMQProtocolEngine implements ServerProtocolEngine, AMQProtocolSessi private volatile boolean _stopped; private long _readBytes; private boolean _authenticated; + private boolean _compressionSupported; + private int _messageCompressionThreshold; public AMQProtocolEngine(Broker broker, final NetworkConnection network, @@ -208,7 +210,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, AMQProtocolSessi return null; } }); - + _messagesDelivered = new StatisticsCounter("messages-delivered-" + getSessionID()); _dataDelivered = new StatisticsCounter("data-delivered-" + getSessionID()); _messagesReceived = new StatisticsCounter("messages-received-" + getSessionID()); @@ -539,6 +541,8 @@ public class AMQProtocolEngine implements ServerProtocolEngine, AMQProtocolSessi _broker.getName()); serverProperties.setString(ConnectionStartProperties.QPID_CLOSE_WHEN_NO_ROUTE, String.valueOf(_closeWhenNoRoute)); + serverProperties.setString(ConnectionStartProperties.QPID_MESSAGE_COMPRESSION_SUPPORTED, + String.valueOf(_broker.isMessageCompressionEnabled())); AMQMethodBody responseBody = getMethodRegistry().createConnectionStartBody((short) getProtocolMajorVersion(), (short) pv.getActualMinorVersion(), @@ -1131,6 +1135,15 @@ public class AMQProtocolEngine implements ServerProtocolEngine, AMQProtocolSessi _logger.debug("Client set closeWhenNoRoute=" + _closeWhenNoRoute + " for protocol engine " + this); } } + String compressionSupported = clientProperties.getString(ConnectionStartProperties.QPID_MESSAGE_COMPRESSION_SUPPORTED); + if (compressionSupported != null) + { + _compressionSupported = Boolean.parseBoolean(compressionSupported); + if(_logger.isDebugEnabled()) + { + _logger.debug("Client set compressionSupported=" + _compressionSupported + " for protocol engine " + this); + } + } _clientVersion = clientProperties.getString(ConnectionStartProperties.VERSION_0_8); _clientProduct = clientProperties.getString(ConnectionStartProperties.PRODUCT); @@ -1181,17 +1194,24 @@ public class AMQProtocolEngine implements ServerProtocolEngine, AMQProtocolSessi return getMethodRegistry(); } - public VirtualHostImpl getVirtualHost() + public VirtualHostImpl<?,?,?> getVirtualHost() { return _virtualHost; } - public void setVirtualHost(VirtualHostImpl virtualHost) throws AMQException + public void setVirtualHost(VirtualHostImpl<?,?,?> virtualHost) throws AMQException { _virtualHost = virtualHost; _virtualHost.getConnectionRegistry().registerConnection(this); + + _messageCompressionThreshold = virtualHost.getContextValue(Integer.class, + Broker.MESSAGE_COMPRESSION_THRESHOLD_SIZE); + if(_messageCompressionThreshold <= 0) + { + _messageCompressionThreshold = Integer.MAX_VALUE; + } } public void addDeleteTask(Action<? super AMQProtocolEngine> task) @@ -1595,15 +1615,16 @@ public class AMQProtocolEngine implements ServerProtocolEngine, AMQProtocolSessi } @Override - public void deliverToClient(final ConsumerImpl sub, final ServerMessage message, + public long deliverToClient(final ConsumerImpl sub, final ServerMessage message, final InstanceProperties props, final long deliveryTag) { - registerMessageDelivered(message.getSize()); - _protocolOutputConverter.writeDeliver(message, + long size = _protocolOutputConverter.writeDeliver(message, props, _channelId, deliveryTag, new AMQShortString(sub.getName())); + registerMessageDelivered(size); + return size; } } @@ -1636,6 +1657,18 @@ public class AMQProtocolEngine implements ServerProtocolEngine, AMQProtocolSessi return _closeWhenNoRoute; } + @Override + public boolean isCompressionSupported() + { + return _compressionSupported && _broker.isMessageCompressionEnabled(); + } + + @Override + public int getMessageCompressionThreshold() + { + return _messageCompressionThreshold; + } + public EventLogger getEventLogger() { if(_virtualHost != null) diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolSession.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolSession.java index bab0aaf3da..8d5142338a 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolSession.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQProtocolSession.java @@ -174,9 +174,9 @@ public interface AMQProtocolSession<T extends AMQProtocolSession<T>> Object getReference(); - VirtualHostImpl getVirtualHost(); + VirtualHostImpl<?,?,?> getVirtualHost(); - void setVirtualHost(VirtualHostImpl virtualHost) throws AMQException; + void setVirtualHost(VirtualHostImpl<?,?,?> virtualHost) throws AMQException; public ProtocolOutputConverter getProtocolOutputConverter(); @@ -210,4 +210,8 @@ public interface AMQProtocolSession<T extends AMQProtocolSession<T>> * can't be routed rather than returning the message. */ boolean isCloseWhenNoRoute(); + + boolean isCompressionSupported(); + + int getMessageCompressionThreshold(); } diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ClientDeliveryMethod.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ClientDeliveryMethod.java index fa26a73f93..c7871e8b9a 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ClientDeliveryMethod.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ClientDeliveryMethod.java @@ -26,6 +26,6 @@ import org.apache.qpid.server.message.ServerMessage; public interface ClientDeliveryMethod { - void deliverToClient(final ConsumerImpl sub, final ServerMessage message, final InstanceProperties props, + long deliverToClient(final ConsumerImpl sub, final ServerMessage message, final InstanceProperties props, final long deliveryTag); } diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ConsumerTarget_0_8.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ConsumerTarget_0_8.java index 7c2efe64e6..d5eed242e7 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ConsumerTarget_0_8.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ConsumerTarget_0_8.java @@ -116,7 +116,7 @@ public abstract class ConsumerTarget_0_8 extends AbstractConsumerTarget implemen * @throws org.apache.qpid.AMQException */ @Override - public void send(MessageInstance entry, boolean batch) + public long send(MessageInstance entry, boolean batch) { // We don't decrement the reference here as we don't want to consume the message // but we do want to send it to the client. @@ -124,7 +124,7 @@ public abstract class ConsumerTarget_0_8 extends AbstractConsumerTarget implemen synchronized (getChannel()) { long deliveryTag = getChannel().getNextDeliveryTag(); - sendToClient(entry.getMessage(), entry.getInstanceProperties(), deliveryTag); + return sendToClient(entry.getMessage(), entry.getInstanceProperties(), deliveryTag); } } @@ -177,7 +177,7 @@ public abstract class ConsumerTarget_0_8 extends AbstractConsumerTarget implemen * @param batch */ @Override - public void send(MessageInstance entry, boolean batch) + public long send(MessageInstance entry, boolean batch) { // if we do not need to wait for client acknowledgements // we can decrement the reference count immediately. @@ -194,17 +194,17 @@ public abstract class ConsumerTarget_0_8 extends AbstractConsumerTarget implemen MessageReference ref = message.newReference(); InstanceProperties props = entry.getInstanceProperties(); entry.delete(); - + long size; synchronized (getChannel()) { getChannel().getProtocolSession().setDeferFlush(batch); long deliveryTag = getChannel().getNextDeliveryTag(); - sendToClient(message, props, deliveryTag); + size = sendToClient(message, props, deliveryTag); } ref.release(); - + return size; } @@ -291,7 +291,7 @@ public abstract class ConsumerTarget_0_8 extends AbstractConsumerTarget implemen * @param batch */ @Override - public void send(MessageInstance entry, boolean batch) + public long send(MessageInstance entry, boolean batch) { @@ -303,9 +303,9 @@ public abstract class ConsumerTarget_0_8 extends AbstractConsumerTarget implemen addUnacknowledgedMessage(entry); recordMessageDelivery(entry, deliveryTag); entry.addStateChangeListener(getReleasedStateChangeListener()); - sendToClient(entry.getMessage(), entry.getInstanceProperties(), deliveryTag); + long size = sendToClient(entry.getMessage(), entry.getInstanceProperties(), deliveryTag); entry.incrementDeliveryCount(); - + return size; } } @@ -502,9 +502,9 @@ public abstract class ConsumerTarget_0_8 extends AbstractConsumerTarget implemen } } - protected void sendToClient(final ServerMessage message, final InstanceProperties props, final long deliveryTag) + protected long sendToClient(final ServerMessage message, final InstanceProperties props, final long deliveryTag) { - _deliveryMethod.deliverToClient(getConsumer(), message, props, deliveryTag); + return _deliveryMethod.deliverToClient(getConsumer(), message, props, deliveryTag); } diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/handler/BasicGetMethodHandler.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/handler/BasicGetMethodHandler.java index 0026bad063..c3bdedf44d 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/handler/BasicGetMethodHandler.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/handler/BasicGetMethodHandler.java @@ -21,6 +21,9 @@ package org.apache.qpid.server.protocol.v0_8.handler; +import java.security.AccessControlException; +import java.util.EnumSet; + import org.apache.log4j.Logger; import org.apache.qpid.AMQException; @@ -30,26 +33,23 @@ import org.apache.qpid.framing.BasicGetEmptyBody; import org.apache.qpid.framing.MethodRegistry; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.consumer.ConsumerImpl; +import org.apache.qpid.server.flow.FlowCreditManager; +import org.apache.qpid.server.flow.MessageOnlyCreditManager; import org.apache.qpid.server.message.InstanceProperties; import org.apache.qpid.server.message.MessageInstance; import org.apache.qpid.server.message.MessageSource; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.protocol.v0_8.AMQChannel; -import org.apache.qpid.server.flow.FlowCreditManager; -import org.apache.qpid.server.flow.MessageOnlyCreditManager; import org.apache.qpid.server.protocol.v0_8.AMQMessage; import org.apache.qpid.server.protocol.v0_8.AMQProtocolSession; +import org.apache.qpid.server.protocol.v0_8.ClientDeliveryMethod; import org.apache.qpid.server.protocol.v0_8.ConsumerTarget_0_8; -import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.protocol.v0_8.RecordDeliveryMethod; import org.apache.qpid.server.protocol.v0_8.state.AMQStateManager; import org.apache.qpid.server.protocol.v0_8.state.StateAwareMethodListener; -import org.apache.qpid.server.protocol.v0_8.ClientDeliveryMethod; -import org.apache.qpid.server.protocol.v0_8.RecordDeliveryMethod; +import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.virtualhost.VirtualHostImpl; -import java.security.AccessControlException; -import java.util.EnumSet; - public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetBody> { private static final Logger _log = Logger.getLogger(BasicGetMethodHandler.class); @@ -202,17 +202,18 @@ public class BasicGetMethodHandler implements StateAwareMethodListener<BasicGetB } @Override - public void deliverToClient(final ConsumerImpl sub, final ServerMessage message, + public long deliverToClient(final ConsumerImpl sub, final ServerMessage message, final InstanceProperties props, final long deliveryTag) { _singleMessageCredit.useCreditForMessage(message.getSize()); - _session.getProtocolOutputConverter().writeGetOk(message, + long size =_session.getProtocolOutputConverter().writeGetOk(message, props, _channel.getChannelId(), deliveryTag, _queue.getQueueDepthMessages()); _deliveredMessage = true; + return size; } public boolean hasDeliveredMessage() diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/output/ProtocolOutputConverter.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/output/ProtocolOutputConverter.java index 7678ce812b..4ee5cbc17d 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/output/ProtocolOutputConverter.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/output/ProtocolOutputConverter.java @@ -26,7 +26,6 @@ */ package org.apache.qpid.server.protocol.v0_8.output; -import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.ContentHeaderBody; @@ -35,7 +34,6 @@ import org.apache.qpid.server.message.InstanceProperties; import org.apache.qpid.server.message.MessageContentSource; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.protocol.v0_8.AMQProtocolSession; -import org.apache.qpid.server.queue.QueueEntry; public interface ProtocolOutputConverter { @@ -46,12 +44,12 @@ public interface ProtocolOutputConverter ProtocolOutputConverter newInstance(AMQProtocolSession session); } - void writeDeliver(final ServerMessage msg, + long writeDeliver(final ServerMessage msg, final InstanceProperties props, int channelId, long deliveryTag, AMQShortString consumerTag); - void writeGetOk(final ServerMessage msg, + long writeGetOk(final ServerMessage msg, final InstanceProperties props, int channelId, long deliveryTag, diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/output/ProtocolOutputConverterImpl.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/output/ProtocolOutputConverterImpl.java index f786cb113a..9e41f7884c 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/output/ProtocolOutputConverterImpl.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/output/ProtocolOutputConverterImpl.java @@ -20,6 +20,10 @@ */ package org.apache.qpid.server.protocol.v0_8.output; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.ByteBuffer; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQBody; import org.apache.qpid.framing.AMQDataBlock; @@ -27,6 +31,7 @@ import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.AMQMethodBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicCancelOkBody; +import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.BasicGetOkBody; import org.apache.qpid.framing.BasicReturnBody; import org.apache.qpid.framing.ContentHeaderBody; @@ -34,16 +39,13 @@ import org.apache.qpid.framing.MethodRegistry; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.protocol.AMQVersionAwareProtocolSession; import org.apache.qpid.server.message.InstanceProperties; +import org.apache.qpid.server.message.MessageContentSource; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.plugin.MessageConverter; import org.apache.qpid.server.protocol.MessageConverterRegistry; import org.apache.qpid.server.protocol.v0_8.AMQMessage; -import org.apache.qpid.server.message.MessageContentSource; import org.apache.qpid.server.protocol.v0_8.AMQProtocolSession; - -import java.io.DataOutput; -import java.io.IOException; -import java.nio.ByteBuffer; +import org.apache.qpid.util.GZIPUtils; class ProtocolOutputConverterImpl implements ProtocolOutputConverter { @@ -51,6 +53,7 @@ class ProtocolOutputConverterImpl implements ProtocolOutputConverter private final MethodRegistry _methodRegistry; private final AMQProtocolSession _protocolSession; + private static final AMQShortString GZIP_ENCODING = AMQShortString.valueOf(GZIPUtils.GZIP_CONTENT_ENCODING); ProtocolOutputConverterImpl(AMQProtocolSession session, MethodRegistry methodRegistry) { @@ -64,7 +67,7 @@ class ProtocolOutputConverterImpl implements ProtocolOutputConverter return _protocolSession; } - public void writeDeliver(final ServerMessage m, + public long writeDeliver(final ServerMessage m, final InstanceProperties props, int channelId, long deliveryTag, AMQShortString consumerTag) @@ -72,7 +75,7 @@ class ProtocolOutputConverterImpl implements ProtocolOutputConverter final AMQMessage msg = convertToAMQMessage(m); final boolean isRedelivered = Boolean.TRUE.equals(props.getProperty(InstanceProperties.Property.REDELIVERED)); AMQBody deliverBody = createEncodedDeliverBody(msg, isRedelivered, deliveryTag, consumerTag); - writeMessageDelivery(msg, channelId, deliverBody); + return writeMessageDelivery(msg, channelId, deliverBody); } private AMQMessage convertToAMQMessage(ServerMessage serverMessage) @@ -93,21 +96,97 @@ class ProtocolOutputConverterImpl implements ProtocolOutputConverter return MessageConverterRegistry.getConverter(clazz, AMQMessage.class); } - private void writeMessageDelivery(AMQMessage message, int channelId, AMQBody deliverBody) + private long writeMessageDelivery(AMQMessage message, int channelId, AMQBody deliverBody) { - writeMessageDelivery(message, message.getContentHeaderBody(), channelId, deliverBody); + return writeMessageDelivery(message, message.getContentHeaderBody(), channelId, deliverBody); } - private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody) + private long writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody) { - int bodySize = (int) message.getSize(); + boolean msgCompressed = isCompressed(contentHeaderBody); + byte[] modifiedContent; + + // straight through case + boolean compressionSupported = _protocolSession.isCompressionSupported(); + + if(msgCompressed && !compressionSupported && + (modifiedContent = GZIPUtils.uncompressBufferToArray(message.getContent(0,bodySize))) != null) + { + BasicContentHeaderProperties modifiedProps = + new BasicContentHeaderProperties(contentHeaderBody.getProperties()); + modifiedProps.setEncoding((String)null); + + writeMessageDeliveryModified(channelId, deliverBody, modifiedProps, modifiedContent); + + return modifiedContent.length; + } + else if(!msgCompressed + && compressionSupported + && contentHeaderBody.getProperties().getEncoding()==null + && bodySize > _protocolSession.getMessageCompressionThreshold() + && (modifiedContent = GZIPUtils.compressBufferToArray(message.getContent(0, bodySize))) != null) + { + BasicContentHeaderProperties modifiedProps = + new BasicContentHeaderProperties(contentHeaderBody.getProperties()); + modifiedProps.setEncoding(GZIP_ENCODING); + + writeMessageDeliveryModified(channelId, deliverBody, modifiedProps, modifiedContent); + + return modifiedContent.length; + } + else + { + writeMessageDeliveryUnchanged(message, contentHeaderBody, channelId, deliverBody, bodySize); + + return bodySize; + } + } - if(bodySize == 0) + private int writeMessageDeliveryModified(final int channelId, + final AMQBody deliverBody, + final BasicContentHeaderProperties modifiedProps, + final byte[] content) + { + final int bodySize; + bodySize = content.length; + ContentHeaderBody modifiedHeaderBody = + new ContentHeaderBody(BASIC_CLASS_ID, 0, modifiedProps, bodySize); + final MessageContentSource wrappedSource = new MessageContentSource() + { + @Override + public int getContent(final ByteBuffer buf, final int offset) + { + int size = Math.min(buf.remaining(), content.length - offset); + buf.put(content, offset, size); + return size; + } + + @Override + public ByteBuffer getContent(final int offset, final int size) + { + return ByteBuffer.wrap(content, offset, size); + } + + @Override + public long getSize() + { + return content.length; + } + }; + writeMessageDeliveryUnchanged(wrappedSource, modifiedHeaderBody, channelId, deliverBody, bodySize); + return bodySize; + } + + private void writeMessageDeliveryUnchanged(final MessageContentSource message, + final ContentHeaderBody contentHeaderBody, + final int channelId, final AMQBody deliverBody, final int bodySize) + { + if (bodySize == 0) { SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody, - contentHeaderBody); + contentHeaderBody); writeFrame(compositeBlock); } @@ -120,13 +199,14 @@ class ProtocolOutputConverterImpl implements ProtocolOutputConverter int writtenSize = capacity; - AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity); + AMQBody firstContentBody = new MessageContentSourceBody(message, 0, capacity); CompositeAMQBodyBlock - compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); + compositeBlock = + new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody); writeFrame(compositeBlock); - while(writtenSize < bodySize) + while (writtenSize < bodySize) { capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize; MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity); @@ -137,6 +217,11 @@ class ProtocolOutputConverterImpl implements ProtocolOutputConverter } } + private boolean isCompressed(final ContentHeaderBody contentHeaderBody) + { + return GZIP_ENCODING.equals(contentHeaderBody.getProperties().getEncoding()); + } + private class MessageContentSourceBody implements AMQBody { public static final byte TYPE = 3; @@ -186,14 +271,14 @@ class ProtocolOutputConverterImpl implements ProtocolOutputConverter } } - public void writeGetOk(final ServerMessage msg, + public long writeGetOk(final ServerMessage msg, final InstanceProperties props, int channelId, long deliveryTag, int queueSize) { AMQBody deliver = createEncodedGetOkBody(msg, props, deliveryTag, queueSize); - writeMessageDelivery(convertToAMQMessage(msg), channelId, deliver); + return writeMessageDelivery(convertToAMQMessage(msg), channelId, deliver); } diff --git a/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/InternalTestProtocolSession.java b/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/InternalTestProtocolSession.java index 7f4a3701cd..05ae5285ad 100644 --- a/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/InternalTestProtocolSession.java +++ b/qpid/java/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/InternalTestProtocolSession.java @@ -141,13 +141,13 @@ public class InternalTestProtocolSession extends AMQProtocolEngine implements Pr { } - public void writeDeliver(final ServerMessage msg, + public long writeDeliver(final ServerMessage msg, final InstanceProperties props, int channelId, long deliveryTag, AMQShortString consumerTag) { _deliveryCount.incrementAndGet(); - + long size = msg.getSize(); synchronized (_channelDelivers) { Map<String, LinkedList<DeliveryPair>> consumers = _channelDelivers.get(channelId); @@ -168,14 +168,16 @@ public class InternalTestProtocolSession extends AMQProtocolEngine implements Pr consumerDelivers.add(new DeliveryPair(deliveryTag, msg)); } + return size; } - public void writeGetOk(final ServerMessage msg, + public long writeGetOk(final ServerMessage msg, final InstanceProperties props, int channelId, long deliveryTag, int queueSize) { + return msg.getSize(); } public void awaitDelivery(int msgs) @@ -244,11 +246,11 @@ public class InternalTestProtocolSession extends AMQProtocolEngine implements Pr @Override - public void deliverToClient(ConsumerImpl sub, ServerMessage message, + public long deliverToClient(ConsumerImpl sub, ServerMessage message, InstanceProperties props, long deliveryTag) { _deliveryCount.incrementAndGet(); - + long size = message.getSize(); synchronized (_channelDelivers) { Map<String, LinkedList<DeliveryPair>> consumers = _channelDelivers.get(_channelId); @@ -269,6 +271,7 @@ public class InternalTestProtocolSession extends AMQProtocolEngine implements Pr consumerDelivers.add(new DeliveryPair(deliveryTag, message)); } + return size; } } diff --git a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ConsumerTarget_1_0.java b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ConsumerTarget_1_0.java index bceae85896..918a890af5 100644 --- a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ConsumerTarget_1_0.java +++ b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ConsumerTarget_1_0.java @@ -112,10 +112,12 @@ class ConsumerTarget_1_0 extends AbstractConsumerTarget } } - public void send(MessageInstance entry, boolean batch) + public long send(MessageInstance entry, boolean batch) { // TODO + long size = entry.getMessage().getSize(); send(entry); + return size; } public void flushBatched() diff --git a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_to_1_0.java b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_to_1_0.java index 5b9bdc7244..3572b98cad 100644 --- a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_to_1_0.java +++ b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageConverter_to_1_0.java @@ -32,6 +32,7 @@ import org.apache.qpid.amqp_1_0.messaging.SectionEncoder; import org.apache.qpid.amqp_1_0.messaging.SectionEncoderImpl; import org.apache.qpid.amqp_1_0.type.Binary; import org.apache.qpid.amqp_1_0.type.Section; +import org.apache.qpid.amqp_1_0.type.Symbol; import org.apache.qpid.amqp_1_0.type.codec.AMQPDescribedTypeRegistry; import org.apache.qpid.amqp_1_0.type.messaging.AmqpValue; import org.apache.qpid.amqp_1_0.type.messaging.Data; @@ -43,6 +44,7 @@ import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.transport.codec.BBDecoder; import org.apache.qpid.typedmessage.TypedBytesContentReader; import org.apache.qpid.typedmessage.TypedBytesFormatException; +import org.apache.qpid.util.GZIPUtils; public abstract class MessageConverter_to_1_0<M extends ServerMessage> implements MessageConverter<M, Message_1_0> { @@ -202,7 +204,19 @@ public abstract class MessageConverter_to_1_0<M extends ServerMessage> implement SectionEncoder sectionEncoder) { final String mimeType = serverMessage.getMessageHeader().getMimeType(); - Section bodySection = getBodySection(serverMessage, mimeType); + byte[] data = new byte[(int) serverMessage.getSize()]; + serverMessage.getContent(ByteBuffer.wrap(data), 0); + byte[] uncompressed; + + if(Symbol.valueOf(GZIPUtils.GZIP_CONTENT_ENCODING).equals(metaData.getPropertiesSection().getContentEncoding()) + && (uncompressed = GZIPUtils.uncompressBufferToArray(ByteBuffer.wrap(data)))!=null) + { + data = uncompressed; + metaData.getPropertiesSection().setContentEncoding(null); + } + + + Section bodySection = convertMessageBody(mimeType, data); final ByteBuffer allData = encodeConvertedMessage(metaData, bodySection, sectionEncoder); @@ -279,14 +293,6 @@ public abstract class MessageConverter_to_1_0<M extends ServerMessage> implement }; } - protected Section getBodySection(final M serverMessage, final String mimeType) - { - byte[] data = new byte[(int) serverMessage.getSize()]; - serverMessage.getContent(ByteBuffer.wrap(data), 0); - - return convertMessageBody(mimeType, data); - } - private ByteBuffer encodeConvertedMessage(MessageMetaData_1_0 metaData, Section bodySection, SectionEncoder sectionEncoder) { int headerSize = (int) metaData.getStorableSize(); diff --git a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageMetaData_1_0.java b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageMetaData_1_0.java index 4540308f61..fbc24ba454 100755 --- a/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageMetaData_1_0.java +++ b/qpid/java/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/MessageMetaData_1_0.java @@ -72,6 +72,17 @@ public class MessageMetaData_1_0 implements StorableMessageMetaData this(sections, encodeSections(sections, encoder)); } + public Properties getPropertiesSection() + { + return _properties; + } + + + public Header getHeaderSection() + { + return _header; + } + private static ArrayList<ByteBuffer> encodeSections(final List<Section> sections, final SectionEncoder encoder) { ArrayList<ByteBuffer> encodedSections = new ArrayList<ByteBuffer>(sections.size()); diff --git a/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/edit.js b/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/edit.js index c71c2c28de..3a3107b01a 100644 --- a/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/edit.js +++ b/qpid/java/broker-plugins/derby-store/src/main/java/resources/js/qpid/management/virtualhost/derby/edit.js @@ -16,8 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -define(["qpid/common/util", "dojo/domReady!"], - function (util) +define(["qpid/common/util", "dijit/registry", "dojo/domReady!"], + function (util, registry) { var fieldNames = ["storeUnderfullSize", "storeOverfullSize", "storePath"]; return { diff --git a/qpid/java/broker-plugins/derby-store/src/main/java/resources/virtualhostnode/derby/add.html b/qpid/java/broker-plugins/derby-store/src/main/java/resources/virtualhostnode/derby/add.html index 0ec1e89c24..4e82ab09e9 100644 --- a/qpid/java/broker-plugins/derby-store/src/main/java/resources/virtualhostnode/derby/add.html +++ b/qpid/java/broker-plugins/derby-store/src/main/java/resources/virtualhostnode/derby/add.html @@ -27,7 +27,8 @@ data-dojo-props=" name: 'storePath', placeHolder: 'path/to/store', - title: 'Enter store path'" /> + title: 'Enter store path', + promptMessage: 'File system location for the configuration store'"/> </div> </div> <div class="clear"></div> diff --git a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/virtualhostnode/jdbc/add.html b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/virtualhostnode/jdbc/add.html index f60f54e7d8..f9561d4c51 100644 --- a/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/virtualhostnode/jdbc/add.html +++ b/qpid/java/broker-plugins/jdbc-store/src/main/java/resources/virtualhostnode/jdbc/add.html @@ -28,7 +28,7 @@ name: 'connectionUrl', placeHolder: 'jdbc:provider:info', required: true, - missingMessage: 'JDBC URL must be supplied', + promptMessage: 'JDBC URL specifying the connection to the database', title: 'Enter JDBC URL'"/> </div> </div> @@ -41,7 +41,7 @@ name: 'username', placeHolder: 'username', required: true, - missingMessage: 'Username must be supplied', + promptMessage: 'Database user name', title: 'Enter username'" /> </div> </div> @@ -54,7 +54,7 @@ name: 'password', placeHolder: 'password', required: true, - missingMessage: 'Password must be supplied', + promptMessage: 'Database password', title: 'Enter password'" /> </div> </div> @@ -66,8 +66,8 @@ data-dojo-props=" name: 'connectionPoolType', required: true, - missingMessage: 'Connection Pool type must be supplied', - title: 'Select Connection Pool', + promptMessage: 'Connection pool type to use when connecting to the database', + title: 'Select the connection pool type', placeHolder: 'Select pool type'" /> </div> </div> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java index 8de74d189b..cb77735a7b 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java @@ -143,7 +143,12 @@ public class MessageServlet extends AbstractServlet throw new IllegalArgumentException("Could not find virtual host with name '" + vhostName + "'"); } - return getQueueFromVirtualHost(queueName, vhost); + Queue queueFromVirtualHost = getQueueFromVirtualHost(queueName, vhost); + if (queueFromVirtualHost == null) + { + throw new IllegalArgumentException("Could not find queue with name '" + queueName + "' on virtual host '" + vhost.getName() + "'"); + } + return queueFromVirtualHost; } private Queue getQueueFromVirtualHost(String queueName, VirtualHost<?,?,?> vhost) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MetaDataServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MetaDataServlet.java index c84eb3200b..35eff5c0b7 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MetaDataServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MetaDataServlet.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.management.plugin.servlet.rest; import java.io.IOException; import java.io.Writer; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; @@ -52,8 +53,12 @@ public class MetaDataServlet extends AbstractServlet super.init(); _instance = BrokerModel.getInstance(); + + } + + @Override protected void doGetWithSubjectAndActor(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException @@ -124,6 +129,18 @@ public class MetaDataServlet extends AbstractServlet { attrDetails.put("mandatory",((ConfiguredAutomatedAttribute)attribute).isMandatory()); } + if(!(((ConfiguredAutomatedAttribute)attribute).validValues()).isEmpty()) + { + Collection<String> validValues = ((ConfiguredAutomatedAttribute<?,?>) attribute).validValues(); + + Collection<Object> convertedValues = new ArrayList<>(validValues.size()); + for(String value : validValues) + { + convertedValues.add(attribute.convert(value,null)); + } + attrDetails.put("validValues", convertedValues); + } + } if(attribute.isSecure()) { diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html index a07419977b..1b30c6ddcc 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html @@ -39,7 +39,7 @@ name: 'name', placeHolder: 'Binding Key', required: true, - missingMessage: 'A binding key must be supplied', + promptMessage: 'Binding key', title: 'Enter binding key'" /> </div> </div> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html index 8c9968e37a..77d5ed0bc1 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html @@ -21,32 +21,53 @@ <div class="dijitHidden"> <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add Exchange'" id="addExchange"> <form id="formAddExchange" method="post" dojoType="dijit.form.Form"> - <table cellpadding="0" cellspacing="2"> - <tr> - <td valign="top"><strong>Exchange Name*: </strong></td> - <td><input type="text" required="true" name="name" id="formAddExchange.name" placeholder="Exchange Name" - dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" - data-dojo-props="regExp:'^(?!qpid\.|amq\.|\<\<default\>\>)[\x20-\x2e\x30-\x7F]{1,255}$', invalidMessage:'Illegal or reserved exchange name!'"/></td> - </tr> - <tr> - <td valign="top"><strong>Durable? </strong></td> - <td><input type="checkbox" name="durable" id="formAddExchange.durable" value="durable" checked="checked" dojoType="dijit.form.CheckBox" /></td> - </tr> - <tr> - <td valign="top"><strong>Exchange Type: </strong></td> - <td> - <select name="type" id="formAddExchange.type" dojoType="dijit.form.FilteringSelect"> - <option value="direct">direct</option> - <option value="topic">topic</option> - <option value="headers">headers</option> - <option value="fanout">fanout</option> - </select> - </td> - </tr> - </table> + <div class="clear"> + <div class="formLabel-labelCell">Name*:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddExchange.name" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'name', + placeHolder: 'exchange name', + required: true, + promptMessage: 'Name of exchange', + title: 'Enter an exchange name', + regExp:'^(?!qpid\.|amq\.|\<\<default\>\>)[\x20-\x2e\x30-\x7F]{1,255}$', + invalidMessage:'Illegal or reserved exchange name!'"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Exchange Type:</div> + <div class="formLabel-controlCell"> + <select id="formAddExchange.type" + dojoType="dijit.form.FilteringSelect" + data-dojo-props=" + name: 'type', + promptMessage: 'Type of exchange - responsible for routing messages to queues'"> + <option value="direct">direct</option> + <option value="topic">topic</option> + <option value="headers">headers</option> + <option value="fanout">fanout</option> + </select> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Durable?</div> + <div class="formLabel-controlCell"> + <input type="checkbox" id="formAddExchange.durable" + dojoType="dijit.form.CheckBox" + data-dojo-props=" + name: 'durable', + value: 'durable', + checked: true"/> + </div> + </div> + + + <div class="clear"></div> + <div class="dijitDialogPaneActionBar"> - <!-- submit buttons --> - <input type="submit" value="Create Exchange" label="Create Exchange" dojoType="dijit.form.Button" /> + <input type="submit" value="Create Exchange" label="Create Exchange" dojoType="dijit.form.Button" /> </div> </form> </div> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html index 69d49248b8..a0f1d6d440 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html @@ -20,94 +20,267 @@ --> <div class="dijitHidden"> <div data-dojo-type="dijit.Dialog" data-dojo-props="title:'Port'" id="addPort"> - <form id="formAddPort" method="post" dojoType="dijit.form.Form"> - <div style="height:320px; width:420px; overflow: auto"> - <div class="hidden" id="portEditWarning">NOTE: changes will only take effect after Broker restart.</div> + <form id="formAddPort" method="post" data-dojo-type="dijit.form.Form"> + <div class="hidden infoMessage" id="portEditWarning">NOTE: changes will only take effect after Broker restart.</div> <div id="formAddPort:fields"> - <input type="text" required="true" name="name" id="formAddPort.name" placeholder="Name" - data-dojo-props="label: 'Name*:'" dojoType="dijit.form.ValidationTextBox" - missingMessage="A name must be supplied"/> - <input type="text" required="true" id="formAddPort.port" - data-dojo-props="label: 'Port Number*:', placeHolder: 'Enter port number'" dojoType="dijit.form.ValidationTextBox" - name="port" missingMessage="A port number must be supplied"/> - <select id="formAddPort.type" data-dojo-type="dijit.form.FilteringSelect" - data-dojo-props="name: 'type', value: '',placeHolder: 'Select Port Type', label: 'Port Type*:'"> - <option value="AMQP" selected="selected">AMQP</option> - <option value="JMX">JMX</option> - <option value="HTTP">HTTP</option> - </select> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.name">Name*:</label> + </div> + <div class="formLabel-controlCell"> + <input id="formAddPort.name" type="text" + data-dojo-type="dijit.form.ValidationTextBox" + data-dojo-props=" + name: 'name', + required: 'true', + placeHolder: 'name', + promptMessage: 'Name of port, must be unique', + title: 'Enter name of port'"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.port">Port Number*:</label> + </div> + <div class="formLabel-controlCell"> + <input id="formAddPort.port" type="text" + data-dojo-type="dijit.form.ValidationTextBox" + data-dojo-props=" + name: 'port', + required: 'true', + placeHolder: 'port number', + promptMessage: 'Port number to be bound', + title: 'Enter port number'"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.type">Port Type*:</label> + </div> + <div class="formLabel-controlCell"> + <select id="formAddPort.type" + data-dojo-type="dijit.form.FilteringSelect" + data-dojo-props=" + name: 'type', + label: 'Port Type*:', + value: '', + placeHolder: 'port type', + promptMessage: 'Port type', + title: 'Enter port type'"> + <option value="AMQP" selected="selected">AMQP</option> + <option value="JMX">JMX</option> + <option value="HTTP">HTTP</option> + </select> + </div> + </div> </div> <div id="formAddPort:fieldsAuthenticationProvider"> - <select id="formAddPort.authenticationProvider" data-dojo-type="dijit.form.FilteringSelect" - data-dojo-props="name:'authenticationProvider',label:'Authentication Provider*:', searchAttr: 'name', required: true, placeHolder: 'Select Provider'"> - </select> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.authenticationProvider">Authentication Provider*:</label> + </div> + <div class="formLabel-controlCell"> + <select id="formAddPort.authenticationProvider" + data-dojo-type="dijit.form.FilteringSelect" + data-dojo-props=" + name: 'authenticationProvider', + searchAttr: 'name', + required: true, + placeHolder: 'provider', + promptMessage: 'Authentication provider to authenticate users connecting to the port', + title: 'Associate the port with an authentication provider'"> + </select> + </div> + </div> </div> <div id="formAddPort:fieldsBindingAddress"> - <input id="formAddPort.bindingAddress" type="text" name="bindingAddress" placeholder="*" - dojoType="dijit.form.TextBox" data-dojo-props="label: 'Binding address:'"/> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.bindingAddress">Binding address:</label> + </div> + <div class="formLabel-controlCell"> + <input id="formAddPort.bindingAddress" type="text" + data-dojo-type="dijit.form.ValidationTextBox" + data-dojo-props=" + name: 'bindingAddress', + placeHolder: 'binding address', + promptMessage: 'Restricts the port to listen on the specified address only. The <code>*</code> wildcard signifies all addresses', + title: 'Enter a binding address'"/> + </div> + </div> </div> <div id="formAddPort:fieldsAMQP"> - <input id="formAddPort.protocolsDefault" type="checkbox" checked="checked" - dojoType="dijit.form.CheckBox" data-dojo-props="label: 'Support default protocols:'"/> - <select id="formAddPort.protocolsAMQP" name="protocols" data-dojo-type="dijit.form.MultiSelect" multiple="true" - data-dojo-props="name: 'protocols', value: '', placeHolder: 'Select AMQP versions', label: 'AMQP versions:'" - missingMessage="AMQP protocol(s) must be supplied"> - <option value="AMQP_0_8">AMQP 0.8</option> - <option value="AMQP_0_9">AMQP 0.9</option> - <option value="AMQP_0_9_1">AMQP 0.9.1</option> - <option value="AMQP_0_10">AMQP 0.10</option> - <option value="AMQP_1_0">AMQP 1.0</option> - </select> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.protocolsDefault">Support default protocols:</label> + </div> + <div class="formLabel-controlCell"> + <input id="formAddPort.protocolsDefault" type="checkbox" + dojoType="dijit.form.CheckBox" + data-dojo-props="checked: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.protocolsAMQP">AMQP protocols:</label> + </div> + <div class="formLabel-controlCell"> + <select id="formAddPort.protocolsAMQP" + data-dojo-type="dijit.form.MultiSelect" + data-dojo-props=" + name: 'protocols', + value: '', + placeHolder: 'AMQP protocols', + promptMessage: 'AMQP protocols to be associated with this port', + title: 'Select AMQP protocols to be associated with this port', + multiple: true"> + <option value="AMQP_0_8">AMQP 0.8</option> + <option value="AMQP_0_9">AMQP 0.9</option> + <option value="AMQP_0_9_1">AMQP 0.9.1</option> + <option value="AMQP_0_10">AMQP 0.10</option> + <option value="AMQP_1_0">AMQP 1.0</option> + </select> + </div> + </div> </div> <div id="formAddPort:fieldsJMX"> - <select id="formAddPort.protocolsJMX" name="protocols" data-dojo-type="dijit.form.FilteringSelect" - data-dojo-props="name: 'protocols', value: '', label: 'JMX protocol*:'" missingMessage="JMX protocol must be supplied"> - <option value="RMI">RMI</option> - <option value="JMX_RMI">JMX RMI</option> - </select> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.protocolsJMX">JMX protocol*:</label> + </div> + <div class="formLabel-controlCell"> + <select id="formAddPort.protocolsJMX" + data-dojo-type="dijit.form.FilteringSelect" + data-dojo-props=" + name: 'protocols', + value: '', + promptMessage: 'JMX protocol to be associated with this port', + title: 'Enter JMX protocol to be associated with this port'"> + <option value="RMI">RMI</option> + <option value="JMX_RMI">JMX RMI</option> + </select> + </div> + </div> </div> + <div id="formAddPort:fieldsHTTP"> - <select id="formAddPort.protocolsHTTP" name="protocols" data-dojo-type="dijit.form.FilteringSelect" - data-dojo-props="name: 'protocols', value: 'HTTP', label: 'HTTP protocol*:'" missingMessage="HTTP protocol must be supplied"> - <option value="HTTP">HTTP</option> - </select> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.protocolsHTTP">HTTP protocols*:</label> + </div> + <div class="formLabel-controlCell"> + <select id="formAddPort.protocolsHTTP" + data-dojo-type="dijit.form.FilteringSelect" + data-dojo-props=" + name: 'protocols', + value: 'HTTP', + label: 'HTTP protocol*:', + promptMessage: 'HTTP protocol to be associated with this port', + title: 'Enter HTTP protocol to be associated with this port'"> + <option value="HTTP">HTTP</option> + </select> + </div> + </div> </div> + <div id="formAddPort:transport" > - <select id="formAddPort.transports" name="transports" data-dojo-type="dijit.form.MultiSelect" multiple="true" - data-dojo-props="name: 'transports',label: 'Transport:',placeHolder: 'TCP', value: '' "> - <option value="TCP">TCP</option> - <option value="SSL">SSL</option> - </select> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.transports">Transport:</label> + </div> + <div class="formLabel-controlCell"> + <select id="formAddPort.transports" + data-dojo-type="dijit.form.MultiSelect" + data-dojo-props=" + name: 'transports', + placeHolder: 'TCP', + value: '', + multiple: true, + promptMessage: 'Transport(s)', + title: 'Select transports'"> + <option value="TCP">TCP</option> + <option value="SSL">SSL</option> + </select> + </div> + </div> + <div class="clear"/> </div> <div id="formAddPort:fieldsTransportSSL"> - <select id="formAddPort.keyStore" data-dojo-type="dijit.form.FilteringSelect" - data-dojo-props="name:'keyStore',label:'Key Store*:', searchAttr: 'name', placeHolder: 'Select keystore', value: '', required: true "> - </select> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.keyStore">Key Store*:</label> + </div> + <div class="formLabel-controlCell"> + <select id="formAddPort.keyStore" + data-dojo-type="dijit.form.FilteringSelect" + data-dojo-props=" + name: 'keyStore', + label: 'Key Store*:', + searchAttr: 'name', + placeHolder: 'keystore', + value: '', + required: true, + promptMessage: 'Keystore that provides the SSL certificate', + title: 'Select the keystore that provides the SSL certificate'"> + </select> + </div> + </div> </div> <div id="formAddPort:fieldsClientAuth"> <div id="formAddPort:fieldsClientAuthCheckboxes"> - <input id="formAddPort.needClientAuth" type="checkbox" name="needClientAuth" - dojoType="dijit.form.CheckBox" data-dojo-props="label: 'Need SSL Client Certificate:'" /> - <input id="formAddPort.wantClientAuth" type="checkbox" name="wantClientAuth" - dojoType="dijit.form.CheckBox" data-dojo-props="label: 'Want SSL Client Certificate:'" /> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.needClientAuth">Need SSL Client Certificate:</label> + </div> + <div class="formLabel-controlCell"> + <input id="formAddPort.needClientAuth" type="checkbox" + data-dojo-type="dijit.form.CheckBox" + data-dojo-props=" + name: 'needClientAuth'" /> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell"> + <label for="formAddPort.wantClientAuth">Want SSL Client Certificate:</label> + </div> + <div class="formLabel-controlCell"> + <input id="formAddPort.wantClientAuth" type="checkbox" + data-dojo-type="dijit.form.CheckBox" + data-dojo-props=" + name: 'wantClientAuth'" /> + </div> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell"> + Trust Stores: + </div> + </div> + + <div class="clear"> + <div class="formLabel-controlCell"> + <table id="formAddPort.trustStores" + data-dojo-type="dojox.grid.EnhancedGrid" + data-dojo-props=" + plugins: {indirectSelection: true}, + rowSelector:'0px'" + style="height: 100px; width:400px"> + <thead> + <tr> + <th field="name">Name</th> + <th field="peersOnly">Peers Only</th> + </tr> + </thead> + </table> + </div> </div> - <div><strong>Trust Stores:</strong></div> - <table id="formAddPort.trustStores" data-dojo-type="dojox.grid.EnhancedGrid" - data-dojo-props="label:'Trust Stores:',plugins:{indirectSelection: true},rowSelector:'0px' " style="height: 100px; width:400px"> - <thead> - <tr> - <th field="name">Name</th> - <th field="peersOnly">Peers Only</th> - </tr> - </thead> - </table> </div> <input type="hidden" id="formAddPort.id" name="id"/> - </div> + <div class="clear"/> <div class="dijitDialogPaneActionBar"> - <!-- submit buttons --> - <input type="submit" value="Save Port" label="Save Port" dojoType="dijit.form.Button" /> + <!-- submit buttons --> + <input type="submit" value="Save Port" label="Save Port" dojoType="dijit.form.Button" /> </div> </form> </div> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html index 75d0888200..352e69893b 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html @@ -21,216 +21,316 @@ <div class="dijitHidden"> <div data-dojo-type="dijit.Dialog" data-dojo-props="title:'Add Queue'" id="addQueue"> <form id="formAddQueue" method="post" dojoType="dijit.form.Form"> - <div style="height:250px; width:600px; overflow: auto"> - <table cellpadding="0" cellspacing="2"> - <tr> - <td valign="top"><strong>Queue Name*: </strong></td> - <td><input type="text" required="true" name="name" id="formAddQueue.name" placeholder="Queue Name" - dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" regexp="^[\x20-\x2e\x30-\x7F]{1,255}$"/></td> - </tr> - <tr> - <td valign="top"><strong>Durable? </strong></td> - <td><input type="checkbox" name="durable" id="formAddQueue.durable" value="durable" checked="checked" dojoType="dijit.form.CheckBox" /></td> - </tr> - <tr> - <td valign="top"><strong>Persist Messages? </strong></td> - <td> - <select id="formAddQueue.messageDurability" name="messageDurability" data-dojo-type="dijit.form.FilteringSelect" - data-dojo-props="name: 'messageDurability', value: '', searchAttr: 'name', placeHolder: '', value: '', required: false "> - <option value="ALWAYS">Always</option> - <option value="DEFAULT">Default</option> - <option value="NEVER">Never</option> - </select> - </td> - </tr> - <tr> - <td valign="top"><strong>Max Ttl: </strong></td> - <td><input type="text" required="false" name="maximumMessageTtl" id="formAddQueue.maximumMessageTtl" placeholder="Ttl in ms." - dojoType="dijit.form.ValidationTextBox" - trim="true" - regexp="[0-9]+" - invalidMessage= "Invalid value" /></td> - </tr> - <tr> - <td valign="top"><strong>Min Ttl: </strong></td> - <td><input type="text" required="false" name="minimumMessageTtl" id="formAddQueue.minimumMessageTtl" placeholder="Ttl in ms." - dojoType="dijit.form.ValidationTextBox" - trim="true" - regexp="[0-9]+" - invalidMessage= "Invalid value" /></td> - </tr> - <tr> - <td valign="top"><strong>Queue Type: </strong></td> - <td> + + <div class="clear"> + <div class="formLabel-labelCell">Queue Name*:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.name" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'name', + placeHolder: 'queue name', + required: true, + promptMessage: 'Name of queue', + title: 'Enter a queue name', + regExp:'^[\x20-\x2e\x30-\x7F]{1,255}$'"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Queue Type:</div> + <div class="formLabel-controlCell"> <input type="radio" id="formAddQueueTypeStandard" name="type" value="standard" checked="checked" dojoType="dijit.form.RadioButton" /> <label for="formAddQueueTypeStandard">Standard</label> - + <input type="radio" id="formAddQueueTypePriority" name="type" value="priority" dojoType="dijit.form.RadioButton" /> <label for="formAddQueueTypePriority">Priority</label> - + <input type="radio" id="formAddQueueTypeLVQ" name="type" value="lvq" dojoType="dijit.form.RadioButton" /> <label for="formAddQueueTypeLVQ">LVQ</label> - + <input type="radio" id="formAddQueueTypeSorted" name="type" value="sorted" dojoType="dijit.form.RadioButton" /> <label for="formAddQueueTypeSorted">Sorted</label> - </td> - </tr> - </table> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Durable?</div> + <div class="formLabel-controlCell"> + <input type="checkbox" id="formAddQueue.durable" + dojoType="dijit.form.CheckBox" + data-dojo-props=" + name: 'durable', + value: 'durable', + checked: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Persist Messages?</div> + <div class="formLabel-controlCell"> + <select id="formAddQueue.messageDurability" + dojoType="dijit.form.FilteringSelect" + data-dojo-props=" + name: 'messageDurability', + value: '', + searchAttr: 'name', + required: false, + promptMessage: 'Message durability override. If not default, messages arriving will have durability setting overridden', + title: 'Enter message durability override'"> + <option value="ALWAYS">Always</option> + <option value="DEFAULT">Default</option> + <option value="NEVER">Never</option> + </select> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Maximum Ttl:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.maximumMessageTtl" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'maximumMessageTtl', + placeHolder: 'ttl in ms', + promptMessage: 'Maximum message time to live (ttl) in ms. Messages arriving with larger ttl values will be overridden by this value', + title: 'Enter the maximum message time to live in milliseconds', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Minimum Ttl:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.minimumMessageTtl" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'minimumMessageTtl', + placeHolder: 'ttl in ms', + promptMessage: 'Minimum message time to live (ttl) in ms. Messages arriving with smaller ttl values will be overridden by this value', + title: 'Enter the minimum message time to live in milliseconds', + trim: true"/> + </div> + </div> + <br/> + <div class="clear"></div> + <div id="formAddQueueTypePriority:fields" class="hidden" data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Priority Queue Settings'"> - <table cellpadding="0" cellspacing="2"> - <tr> - <td valign="top"><strong>Priorities: </strong></td> - <td><input data-dojo-type="dijit.form.NumberSpinner" id="formAddQueue.priorities" - name="priorities" value="10" smallDelta="1" constraints="{min:1,max:10,places:0}"/> - </tr> - </table> + <div class="clear"> + <div class="formLabel-labelCell">Priorities:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.priorities" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'priorities', + placeHolder: 'number of priorities', + promptMessage: 'Number of priorities supported by the queue', + title: 'Enter the number of priorities supported by the queue', + trim: true"/> + </div> + </div> + <div class="clear"></div> </div> - <div id="formAddQueueTypeLVQ:fields" class="hidden" data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Last Value Queue Settings'"> - <table cellpadding="0" cellspacing="2"> - <tr> - <td valign="top"><strong>LVQ Message Property: </strong></td> - <td><input type="text" name="lvqKey" id="formAddQueue.lvqkey" - placeholder="qpid.LVQ_key" dojoType="dijit.form.ValidationTextBox" /></td> - </tr> - </table> + <div class="clear"> + <div class="formLabel-labelCell">LVQ Message Property:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.lvqkey" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'lvqKey', + placeHolder: 'lvq key', + promptMessage: 'Name of the message property used to perform the conflation', + title: 'Enter the name of the message property used to perform the conflation', + trim: true"/> + </div> + </div> + <div class="clear"></div> </div> <div id="formAddQueueTypeSorted:fields" class="hidden" data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Sorted Queue Settings'"> - <table cellpadding="0" cellspacing="2"> - <tr> - <td valign="top"><strong>Sort Message Property: </strong></td> - <td><input type="text" name="sortKey" id="formAddQueue.sortkey" required="false" - placeholder="" dojoType="dijit.form.ValidationTextBox" /></td> - </tr> - </table> + <div class="clear"> + <div class="formLabel-labelCell">Sort Message Property*:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.sortkey" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'sortKey', + placeHolder: 'sort key', + promptMessage: 'Name of the message property used for sorting the messages on the queue', + title: 'Enter the name of the message property used for sorting the messages on the queue', + trim: true"/> + </div> + </div> + <div class="clear"></div> </div> <br/> <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Flow Control Settings', open: false"> - <table cellpadding="0" cellspacing="2"> - - <!-- x-qpid-capacity --> - <tr> - <td valign="top"><strong>Capacity: </strong></td> - <td><input type="text" required="false" name="queueFlowControlSizeBytes" id="formAddQueue.capacity" placeholder="Size in bytes" - dojoType="dijit.form.ValidationTextBox" - trim="true" - regexp="[0-9]+" - invalidMessage= "Invalid value"/></td> - </tr> - <!-- x-qpid-flow-resume-capacity --> - <tr> - <td valign="top"><strong>Resume Capacity: </strong></td> - <td><input type="text" required="false" name="queueFlowResumeSizeBytes" id="formAddQueue.flowResumeCapacity" placeholder="Size in bytes" - dojoType="dijit.form.ValidationTextBox" - trim="true" - regexp="[0-9]+" - invalidMessage= "Invalid value"/></td> - </tr> - </table> + <div class="clear"> + <div class="formLabel-labelCell">Capacity:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.capacity" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'queueFlowControlSizeBytes', + placeHolder: 'size in bytes', + promptMessage: 'Ceiling (in bytes) at which queue will begin to throttle sessions producing messages', + title: 'Enter the ceiling (in bytes) at which queue will begin to throttle sessions producing messages', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Resume Capacity:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.flowResumeCapacity" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'queueFlowResumeSizeBytes', + placeHolder: 'size in bytes', + promptMessage: 'Floor (in bytes) at which queue will cease to throttle sessions producing messages', + title: 'Enter the floor (in bytes) at which queue will cease to throttle sessions producing messages', + trim: true"/> + </div> + </div> + <div class="clear"></div> </div> + <br/> <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Alerting Settings', open: false"> - <table cellpadding="0" cellspacing="2"> - <!-- x-qpid-maximum-message-count --> - <tr> - <td valign="top"><strong>Queue Depth: </strong></td> - <td><input type="text" required="false" name="alertThresholdQueueDepthMessages" id="formAddQueue.maximumMessageCount" placeholder="Number of messages" - dojoType="dijit.form.ValidationTextBox" - trim="true" - regexp="[0-9]+" - invalidMessage= "Invalid value" /></td> - </tr> - <!-- x-qpid-maximum-queue-depth --> - <tr> - <td valign="top"><strong>Queue Depth: </strong></td> - <td><input type="text" required="false" name="alertThresholdQueueDepthBytes" id="formAddQueue.maximumQueueDepth" placeholder="Total message size in bytes" - dojoType="dijit.form.ValidationTextBox" - trim="true" - regexp="[0-9]+" - invalidMessage= "Invalid value" /></td> - </tr> - <!-- x-qpid-maximum-message-age --> - <tr> - <td valign="top"><strong>Message Age: </strong></td> - <td><input type="text" required="false" name="alertThresholdMessageAge" id="formAddQueue.maximumMessageAge" placeholder="Time in ms" - dojoType="dijit.form.ValidationTextBox" - trim="true" - regexp="[0-9]+" - invalidMessage= "Invalid value" /></td> - </tr> - <!-- x-qpid-maximum-message-size --> - <tr> - <td valign="top"><strong>Message Size: </strong></td> - <td><input type="text" required="false" name="alertThresholdMessageSize" id="formAddQueue.maximumMessageSize" placeholder="Size in bytes" - dojoType="dijit.form.ValidationTextBox" - trim="true" - regexp="[0-9]+" - invalidMessage= "Invalid value"/></td> - </tr> - <!-- x-qpid-minimum-alert-repeat-gap --> - <tr> - <td valign="top"><strong>Gap between alerts: </strong></td> - <td><input type="text" required="false" name="alertRepeatGap" id="formAddQueue.minimumAlertRepeatGap" placeholder="Time in ms" - dojoType="dijit.form.ValidationTextBox" - trim="true" - regexp="[0-9]+" - invalidMessage= "Invalid value" /></td> - </tr> - </table> + <div class="clear"> + <div class="formLabel-labelCell">Queue Depth:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.maximumMessageCount" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'alertThresholdQueueDepthMessages', + placeHolder: 'number of messages', + promptMessage: 'Ceiling value for number of messages on queue before alerts will be generated', + title: 'Enter the ceiling value for number of messages on queue before alerts will be generated', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Queue Depth:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.maximumQueueDepth" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'alertThresholdQueueDepthBytes', + placeHolder: 'total message size in bytes', + promptMessage: 'Ceiling value (in bytes) for total size of all messages on the queue before alerts will be generated', + title: 'Enter the ceiling value (in bytes) for total size of all messages on the queue before alerts will be generated', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Message Age:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.maximumMessageAge" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'alertThresholdMessageAge', + placeHolder: 'time in ms', + promptMessage: 'Message age (in milliseconds) above which alerts will be generated', + title: 'Enter the message age (in milliseconds) above which alerts will be generated', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Message Size:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.maximumMessageSize" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'alertThresholdMessageSize', + placeHolder: 'message size in bytes', + promptMessage: 'Message size (in bytes) above which alerts will be generated', + title: 'Enter the message size (in bytes) above which alerts will be generated', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Gap between alerts:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.alertRepeatGap" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'alertRepeatGap', + placeHolder: 'time in ms', + promptMessage: 'Minimum time (in milliseconds) between each alert', + title: 'Enter the minimum time (in milliseconds) between each alert.', + trim: true"/> + </div> + </div> + <div class="clear"></div> </div> + <br/> <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Other Settings', open: false"> - <table cellpadding="0" cellspacing="2"> + <div class="clear"> + <div class="formLabel-labelCell">Maximum Delivery Retries:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.maximumDeliveryAttempts" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'maximumDeliveryAttempts', + placeHolder: 'number of retries', + promptMessage: 'Maximum number of delivery attempts before the message will be sent to the alternate exchange', + title: 'Enter the maximum number of delivery attempts before the message will be sent to the alternate exchange', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Create DLQ?</div> + <div class="formLabel-controlCell"> + <input type="checkbox" id="formAddQueue.dlqEnabled" + dojoType="dijit.form.CheckBox" + data-dojo-props=" + name: 'dlqEnabled', + value: 'dlqEnabled', + title: 'Controls where a dead letter queue is automatically created', + checked: false"/> + </div> + </div> - <!-- x-qpid-maximum-delivery-count --> - <tr> - <td valign="top"><strong>Maximum Delivery Retries: </strong></td> - <td><input type="text" required="false" name="maximumDeliveryAttempts" id="formAddQueue.maximumDeliveryCount" - dojoType="dijit.form.ValidationTextBox" - trim="true" - regexp="[0-9]+" - invalidMessage= "Invalid value"/></td> - </tr> - <tr> - <td valign="top"><strong>Create DLQ? </strong></td> - <td><input type="checkbox" name="dlqEnabled" id="formAddQueue.dlqEnabled" value="dlqEnabled" dojoType="dijit.form.CheckBox" /></td> - </tr> - </table> - <table cellpadding="0" cellspacing="2"> - <tr> - <td valign="top">NOTE: Configuring maximum delivery retries on a queue which has no DLQ / AlternateExchange will result in messages being discarded after the limit is reached.</td> - </tr> - </table> - <table cellpadding="0" cellspacing="2"> + <div class="clear"></div> + <div class="infoMessage">Configuring maximum delivery retries on a queue which has no DLQ or alternate <br/>exchange will result in messages being discarded after the limit is reached.</div> - <!-- qpid.group_header_key --> - <tr> - <td valign="top"><strong>Message Group Key: </strong></td> - <td><input type="text" required="false" name="messageGroupKey" id="formAddQueue.messageGroupKey" - dojoType="dijit.form.ValidationTextBox" - trim="true"/></td> - </tr> - - <!-- qpid.qpid.shared_msg_group --> - <tr> - <td valign="top"><strong>Shared Message Groups? </strong></td> - <td><input type="checkbox" name="messageGroupSharedGroups" id="formAddQueue.messageGroupSharedGroups" value="messageGroupSharedGroups" dojoType="dijit.form.CheckBox" /></td> - </tr> - </table> - </div> + <div class="clear"> + <div class="formLabel-labelCell">Message Group Key:</div> + <div class="formLabel-controlCell"> + <input type="text" id="formAddQueue.messageGroupKey" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'messageGroupKey', + placeHolder: 'message group key', + promptMessage: 'Name of the message property used for message grouping', + title: 'Enter the name of the message property used for message grouping', + trim: true"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Shared Message Groups?</div> + <div class="formLabel-controlCell"> + <input type="checkbox" id="formAddQueue.messageGroupSharedGroups" + dojoType="dijit.form.CheckBox" + data-dojo-props=" + name: 'messageGroupSharedGroups', + value: 'messageGroupSharedGroups', + checked: false, + title: 'Controls where a shared groups feature is enabled'"/> + </div> + </div> + <div class="clear"></div> </div> + <div class="dijitDialogPaneActionBar"> <!-- submit buttons --> <input type="submit" value="Create Queue" label="Create Queue" dojoType="dijit.form.Button" /> </div> + </form> </div> </div> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHostNodeAndVirtualHost.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHostNodeAndVirtualHost.html index d751a6c1cd..738af25332 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHostNodeAndVirtualHost.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHostNodeAndVirtualHost.html @@ -34,9 +34,9 @@ data-dojo-type="dijit/form/ValidationTextBox" data-dojo-props=" name: 'name', - placeHolder: 'unique node name per broker', + placeHolder: 'node name', required: true, - missingMessage: 'A node name must be supplied', + promptMessage: 'Name of node, must be unique', title: 'Enter a unique node name per broker'" /> </div> </div> @@ -49,6 +49,7 @@ required: true, disabled: true, placeHolder: 'select virtual host node type', + promptMessage: 'Type of virtual host node', title: 'Select virtual host node type', searchAttr: 'name'"> </select> @@ -75,6 +76,7 @@ required: true, disabled: true, placeHolder: 'select virtual host type', + promptMessage: 'Type of virtual host', title: 'Select virtual host type', searchAttr: 'name'"> </select> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css b/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css index bfe0839cbc..f49451b5d8 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/css/common.css @@ -239,8 +239,28 @@ div .messages { font-weight: bold; margin-left: 5px; } + .editNoteBanner { font-style: italic; margin: 0px 0px 10px 5px; } +/* Required to keep queue type radio buttons on one line when dialog adds scrollbar */ +#addQueue { + max-height: 350px; + overflow: auto; + width: 630px; +} + +#authenticatedUserControls { + max-width: 300px; +} + +.claro .dojoxCheckedMultiSelectWrapper { + height: auto; +} + +.claro .dojoxCheckedMultiSelect .dojoxCheckedMultiSelectWrapper { + border: none; + background-color: transparent; +} diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/editVirtualHost.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/editVirtualHost.html index 6f4db66c7d..9b981b055e 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/editVirtualHost.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/editVirtualHost.html @@ -19,111 +19,112 @@ <div class="dijitHidden"> <div data-dojo-type="dijit/Dialog" data-dojo-props="title:'Edit Virtual Host'" id="editVirtualHostDialog"> <form id="editVirtualHostForm" method="post" data-dojo-type="dijit/form/Form"> - <div class="editNoteBanner">NOTE: All changes will only take effect after Virtual Host restart.</div> - <div class="clear"> - <div class="formLabel-labelCell tableContainer-labelCell">Name*:</div> - <div class="formLabel-controlCell tableContainer-valueCell"> - <input type="text" id="editVirtualHost.name" - data-dojo-type="dijit/form/ValidationTextBox" - data-dojo-props=" + <div id="editVirtualHost.allFields"> + <div class="editNoteBanner">NOTE: All changes will only take effect after Virtual Host restart.</div> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Name*:</div> + <div class="formLabel-controlCell tableContainer-valueCell"> + <input type="text" id="editVirtualHost.name" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" name: 'name', placeHolder: 'name', required: true, - missingMessage: 'Name must be supplied', disabled: true, title: 'Enter virtual host name'" /> + </div> </div> - </div> - <div id="editVirtualHost.typeFields"></div> + <div id="editVirtualHost.typeFields"></div> - <div class="clear formBox"> - <fieldset> - <legend>Store transaction settings</legend> - <div class="clear"> - <div class="formLabel-labelCell tableContainer-labelCell">Idle Timeout Warn:</div> - <div class="tableContainer-valueCell formLabel-controlCell"> - <input data-dojo-type="dijit/form/ValidationTextBox" - id="editVirtualHost.storeTransactionIdleTimeoutWarn" - name="storeTransactionIdleTimeoutWarn" - placeHolder="idle timeout warn time in ms" - missingMessage="An idle timeout warn time in ms must be supplied"/> + <div class="clear formBox"> + <fieldset> + <legend>Store transaction settings</legend> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Idle Timeout Warn:</div> + <div class="tableContainer-valueCell formLabel-controlCell"> + <input data-dojo-type="dijit/form/ValidationTextBox" + id="editVirtualHost.storeTransactionIdleTimeoutWarn" + name="storeTransactionIdleTimeoutWarn" + placeHolder="idle timeout warn time in ms" + promptMessage="Length of time a transaction must be idle before warnings produced"/> + </div> </div> - </div> - <div class="clear"> - <div class="formLabel-labelCell tableContainer-labelCell">Idle Timeout Close:</div> - <div class="tableContainer-valueCell formLabel-controlCell"> - <input data-dojo-type="dijit/form/ValidationTextBox" - id="editVirtualHost.storeTransactionIdleTimeoutClose" - name="storeTransactionIdleTimeoutClose" - placeHolder="idle timeout close time in ms" - missingMessage="An idle timeout close time in ms must be supplied"/> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Idle Timeout Close:</div> + <div class="tableContainer-valueCell formLabel-controlCell"> + <input data-dojo-type="dijit/form/ValidationTextBox" + id="editVirtualHost.storeTransactionIdleTimeoutClose" + name="storeTransactionIdleTimeoutClose" + placeHolder="idle timeout close time in ms" + promptMessage="Length of time a transaction must be idle before the connection is closed"/> + </div> </div> - </div> - <div class="clear"> - <div class="formLabel-labelCell tableContainer-labelCell">Open Timeout Warn:</div> - <div class="tableContainer-valueCell formLabel-controlCell"> - <input data-dojo-type="dijit/form/ValidationTextBox" - id="editVirtualHost.storeTransactionOpenTimeoutWarn" - name="storeTransactionOpenTimeoutWarn" - placeHolder="open timeout warn time in ms" - missingMessage="An open timeout warn time in ms must be supplied"/> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Open Timeout Warn:</div> + <div class="tableContainer-valueCell formLabel-controlCell"> + <input data-dojo-type="dijit/form/ValidationTextBox" + id="editVirtualHost.storeTransactionOpenTimeoutWarn" + name="storeTransactionOpenTimeoutWarn" + placeHolder="open timeout warn time in ms" + promptMessage="Length of time a transaction must be open before warnings produced"/> + </div> </div> - </div> - <div class="clear"> - <div class="formLabel-labelCell tableContainer-labelCell">Open Timeout Close:</div> - <div class="tableContainer-valueCell formLabel-controlCell"> - <input data-dojo-type="dijit/form/ValidationTextBox" - id="editVirtualHost.storeTransactionOpenTimeoutClose" - name="storeTransactionOpenTimeoutClose" - placeHolder="open timeout close time in ms" - missingMessage="An open timeout close time in ms must be supplied"/> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Open Timeout Close:</div> + <div class="tableContainer-valueCell formLabel-controlCell"> + <input data-dojo-type="dijit/form/ValidationTextBox" + id="editVirtualHost.storeTransactionOpenTimeoutClose" + name="storeTransactionOpenTimeoutClose" + placeHolder="open timeout close time in ms" + promptMessage="Length of time a transaction must be open before the connection is closed"/> + </div> </div> - </div> - </fieldset> - </div> + </fieldset> + </div> - <div class="clear formBox"> - <fieldset> - <legend>House keeping settings</legend> - <div class="clear"> - <div class="formLabel-labelCell tableContainer-labelCell">Check period (ms):</div> - <div class="tableContainer-valueCell formLabel-controlCell"> - <input data-dojo-type="dijit/form/ValidationTextBox" - id="editVirtualHost.housekeepingCheckPeriod" - name="housekeepingCheckPeriod" - placeHolder="house keeping check period in ms" - missingMessage="A house keeping check period must be supplied"/> + <div class="clear formBox"> + <fieldset> + <legend>House keeping settings</legend> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Check period (ms):</div> + <div class="tableContainer-valueCell formLabel-controlCell"> + <input data-dojo-type="dijit/form/ValidationTextBox" + id="editVirtualHost.housekeepingCheckPeriod" + name="housekeepingCheckPeriod" + placeHolder="house keeping check period in ms" + promptMessage="Frequency with which the housekeeper runs"/> + </div> </div> - </div> - <div class="clear"> - <div class="formLabel-labelCell tableContainer-labelCell">Thread count:</div> - <div class="tableContainer-valueCell formLabel-controlCell"> - <input data-dojo-type="dijit/form/ValidationTextBox" - id="editVirtualHost.housekeepingThreadCount" - name="housekeepingThreadCount" - placeHolder="house keeping thread count" - missingMessage="A house keeping thread count must be supplied"/> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Thread count:</div> + <div class="tableContainer-valueCell formLabel-controlCell"> + <input data-dojo-type="dijit/form/ValidationTextBox" + id="editVirtualHost.housekeepingThreadCount" + name="housekeepingThreadCount" + placeHolder="house keeping thread count" + promptMessage="Number of threads used to perform housekeeping"/> + </div> </div> - </div> - </fieldset> - </div> - <div class="clear"></div> + </fieldset> + </div> + <div class="clear"></div> - <div class="clear"> - <div class="formLabel-labelCell tableContainer-labelCell">Dead letter queue enabled:</div> - <div class="tableContainer-valueCell formLabel-controlCell"> - <input type="checkbox" id="editVirtualHost.queue.deadLetterQueueEnabled" - data-dojo-type="dijit/form/CheckBox" - data-dojo-props="name: 'queue.deadLetterQueueEnabled'"> - </input> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Dead letter queue enabled:</div> + <div class="tableContainer-valueCell formLabel-controlCell"> + <input type="checkbox" id="editVirtualHost.queue.deadLetterQueueEnabled" + data-dojo-type="dijit/form/CheckBox" + data-dojo-props="name: 'queue.deadLetterQueueEnabled'"> + </input> + </div> </div> - </div> - <div class="clear"></div> + <div class="clear"></div> - <div class="dijitDialogPaneActionBar"> - <button data-dojo-type="dijit/form/Button" id="editVirtualHost.saveButton" data-dojo-props="label: 'Save'">Save</button> - <button data-dojo-type="dijit/form/Button" id="editVirtualHost.cancelButton" data-dojo-props="label: 'Cancel'" ></button> + <div class="dijitDialogPaneActionBar"> + <button data-dojo-type="dijit/form/Button" id="editVirtualHost.saveButton" data-dojo-props="label: 'Save'">Save</button> + <button data-dojo-type="dijit/form/Button" id="editVirtualHost.cancelButton" data-dojo-props="label: 'Cancel'" ></button> + </div> </div> </form> </div> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html index ee67e4ce21..dfbec13320 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html @@ -86,7 +86,7 @@ <div id="header" class="header" style="float: left; width: 300px"></div> <div style="float: right;"> <div id="login" class="hidden"><span id="authenticatedUser" class="hidden"></span> - <div id="authenticatedUserControls" data-dojo-type="dijit.form.DropDownButton" data-dojo-props="iconClass: 'preferencesIcon', style:{'max-width': '100px'}"> + <div id="authenticatedUserControls" data-dojo-type="dijit.form.DropDownButton" data-dojo-props="iconClass: 'preferencesIcon'"> <div data-dojo-type="dijit.Menu"> <div data-dojo-type="dijit.MenuItem" data-dojo-props="onClick: function(){window.location='logout';}" >Log out</div> <div data-dojo-type="dijit.MenuItem" diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/metadata.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/metadata.js new file mode 100644 index 0000000000..19ec53744f --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/metadata.js @@ -0,0 +1,57 @@ +/* + * 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. + */ +define(["dojo/_base/xhr", + "dojox/lang/functional/object", + "qpid/common/properties", + "dojo/domReady!" + ], + function (xhr, fobject, properties) + { + var metadata = + { + _init: function () + { + var that = this; + xhr.get({sync: true, handleAs: "json", url: "service/metadata", load: function(metadata){that._onMetadata(metadata)}}); + }, + _onMetadata: function (metadata) + { + this.metadata = metadata; + }, + getMetaData: function (category, type) + { + return this.metadata[category][type]; + }, + getDefaultValueForAttribute: function (category, type, attributeName) + { + var metaDataForInstance = this.getMetaData(category, type); + var attributesForType = metaDataForInstance["attributes"]; + var attributesForName = attributesForType[attributeName]; + return attributesForName ? attributesForName["defaultValue"] : undefined; + }, + getTypesForCategory: function (category) + { + return fobject.keys(this.metadata[category]); + } + }; + + metadata._init(); + + return metadata; + }); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js index 1a89bfb374..9e433bbb34 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js @@ -19,15 +19,19 @@ * */ define(["dojo/_base/xhr", + "dojo/_base/array", "dojo/_base/event", - "dojo/json", "dojo/_base/lang", + "dojo/json", "dojo/dom-construct", "dojo/dom-geometry", "dojo/window", "dojo/query", "dojo/parser", + "dojo/store/Memory", "dojox/html/entities", + "qpid/common/metadata", + "qpid/common/widgetconfigurer", "dijit/registry", "dijit/TitlePane", "dijit/Dialog", @@ -35,13 +39,15 @@ define(["dojo/_base/xhr", "dijit/form/Button", "dijit/form/RadioButton", "dijit/form/CheckBox", + "dijit/form/FilteringSelect", + "dijit/form/ValidationTextBox", "dojox/layout/TableContainer", "dijit/layout/ContentPane", "dojox/validate/us", "dojox/validate/web", "dojo/domReady!" ], - function (xhr, event, json, lang, dom, geometry, win, query, parser, entities, registry) { + function (xhr, array, event, lang, json, dom, geometry, win, query, parser, Memory, entities, metadata, widgetconfigurer, registry) { var util = {}; if (Array.isArray) { util.isArray = function (object) { @@ -146,7 +152,7 @@ define(["dojo/_base/xhr", return (type === "PlainPasswordFile" || type === "Base64MD5PasswordFile" || type === "SCRAM-SHA-1" || type === "SCRAM-SHA-256"); }; - util.showSetAttributesDialog = function(attributeWidgetFactories, data, putURL, dialogTitle, appendNameToUrl) + util.showSetAttributesDialog = function(attributeWidgetFactories, data, putURL, dialogTitle, category, type, appendNameToUrl) { var layout = new dojox.layout.TableContainer({ cols: 1, @@ -200,7 +206,7 @@ define(["dojo/_base/xhr", { groupFieldContainer = new dojox.layout.TableContainer({ cols: 1, - "labelWidth": "290", + "labelWidth": "300", showLabels: true, orientation: "horiz", customClass: "formLabel" @@ -220,6 +226,8 @@ define(["dojo/_base/xhr", } } + this.applyMetadataToWidgets(dialogContent, category, type); + // add onchange handler to set required property for dependent widget for(var widgetName in requiredFor) { @@ -310,14 +318,17 @@ define(["dojo/_base/xhr", aproximateHeight += 30; } } - var viewport = win.getBox(); - var maxHeight = Math.max(Math.floor(viewport.h * 0.6), 100); dialogContentArea.style.overflow= "auto"; - dialogContentArea.style.height = Math.min(aproximateHeight, maxHeight ) + "px"; + dialogContentArea.style.height = "300"; setAttributesDialog.on("hide", function(e){setAttributesDialog.destroy();}); setAttributesDialog.show(); }; + util.findAllWidgets = function(root) + { + return query("[widgetid]", root).map(registry.byNode).filter(function(w){ return w;}); + }; + util.xhrErrorHandler = function(error) { if (error) @@ -540,6 +551,16 @@ define(["dojo/_base/xhr", } } + util.applyMetadataToWidgets = function(domRoot, category, type) + { + var widgets = util.findAllWidgets(domRoot); + array.forEach(widgets, + function (widget) + { + widgetconfigurer.config(widget, category, type); + }); + } + util.getFormWidgetValues = function (form, initialData) { var values = {}; @@ -636,6 +657,16 @@ define(["dojo/_base/xhr", } } + util.makeTypeStore = function (types) + { + var typeData = []; + for (var i = 0; i < types.length; i++) { + var type = types[i]; + typeData.push({id: type, name: type}); + } + return new Memory({ data: typeData }); + } + var singleContextVarRegexp = "(\\${[\\w\\.\\-]+})"; util.numericOrContextVarRegexp = function(constraints) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/widgetconfigurer.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/widgetconfigurer.js new file mode 100644 index 0000000000..0b08dde615 --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/widgetconfigurer.js @@ -0,0 +1,97 @@ +/* + * 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. + */ + +define(["dojo/_base/xhr", + "dojo/string", + "dojo/query", + "dojo/dom", + "dojo/dom-construct", + "dojo/dom-attr", + "qpid/common/properties", + "qpid/common/metadata", + "dojo/text!strings.html", + "dojo/domReady!" + ], + function (xhr, string, query, dom, domConstruct, domAttr, properties, metadata, template) + { + var widgetconfigurer = + { + _init: function () + { + var stringsTemplate = domConstruct.create("div", {innerHTML: template}); + var promptTemplateWithDefaultNode = query("[id='promptTemplateWithDefault']", stringsTemplate)[0]; + + // The following will contain ${prompt} and ${default} formatted with html elements + this.promptTemplateWithDefault = promptTemplateWithDefaultNode.innerHTML; + + domConstruct.destroy(stringsTemplate); + }, + _processWidgetPrompt: function (widget, category, type) + { + var widgetName = widget.name; + if (widgetName && (widget instanceof dijit.form.ValidationTextBox || widget instanceof dijit.form.FilteringSelect)) + { + // If not done so already, save the prompt text specified on the widget. We do this so if we + // config the same widget again, we can apply the default again (which may be different if the user + // has selected a different type within the category). + if (typeof widget.get("qpid.originalPromptMessage") == "undefined") + { + widget.set("qpid.originalPromptMessage", widget.get("promptMessage")); + } + + var promptMessage = widget.get("qpid.originalPromptMessage"); + var defaultValue = metadata.getDefaultValueForAttribute(category, type, widgetName); + if (defaultValue) + { + var newPromptMessage = string.substitute(this.promptTemplateWithDefault, { 'default': defaultValue, 'prompt': promptMessage }); + + if (promptMessage != newPromptMessage) + { + widget.set("promptMessage", newPromptMessage); + } + } + } + }, + _processWidgetValue: function (widget, category, type) + { + var widgetName = widget.name; + + if (widgetName && (widget instanceof dijit.form.FilteringSelect || widget instanceof dojox.form.CheckedMultiSelect)) + { + if (!widget.get("value")) + { + var defaultValue = metadata.getDefaultValueForAttribute(category, type, widgetName); + if (defaultValue) + { + widget.set("value", defaultValue); + } + } + } + }, + config: function (widget, category, type) + { + this._processWidgetPrompt(widget, category, type); + this._processWidgetValue(widget, category, type); + } + }; + + widgetconfigurer._init(); + + return widgetconfigurer; + }); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js index 51a6c761f1..c52553c386 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js @@ -69,7 +69,8 @@ define(["dojo/_base/xhr", regExpGen: util.nameOrContextVarRegexp, value: brokerData.name, label: "Name*:", - name: "name"}) + name: "name", + promptMessage: "Identifies the broker instance."}) } }, { name: "defaultVirtualHost", @@ -89,7 +90,8 @@ define(["dojo/_base/xhr", required: true, store: hostsStore, value: brokerData.defaultVirtualHost, label: "Default Virtual Host*:", - name: "defaultVirtualHost"}) + name: "defaultVirtualHost", + promptMessage: "Default virtual host used for clients that don't specify one when connecting."}) } }, { name: "statisticsReportingPeriod", @@ -97,12 +99,12 @@ define(["dojo/_base/xhr", return new dijit.form.ValidationTextBox({ trim: "true", regExpGen: util.numericOrContextVarRegexp, - invalidMessage: "Invalid value", required: false, value: brokerData.statisticsReportingPeriod, placeholder: "Time in ms", label: "Statistics reporting period (ms):", - name: "statisticsReportingPeriod" + name: "statisticsReportingPeriod", + promptMessage: "Frequency with which statistics are reported to broker log." }); } }, { @@ -123,11 +125,12 @@ define(["dojo/_base/xhr", return new dijit.form.ValidationTextBox({ trim: "true", regExpGen: util.numericOrContextVarRegexp, - invalidMessage: "Invalid value", required: false, value: brokerData["connection.sessionCountLimit"], + placeholder: "Number of sessions", label: "Maximum number of sessions:", - name: "connection.sessionCountLimit" + name: "connection.sessionCountLimit", + promptMessage: "Maximum number of sessions per connection" }); } }, { @@ -141,7 +144,8 @@ define(["dojo/_base/xhr", value: brokerData["connection.heartBeatDelay"], placeholder: "Time in ms", label: "Heart beat delay (ms):", - name: "connection.heartBeatDelay" + name: "connection.heartBeatDelay", + promptMessage: "Interval between heart beat messages exchanged between broker and clients" }); } } ]; @@ -235,7 +239,7 @@ define(["dojo/_base/xhr", that.attributeWidgetFactories, brokerData, query, - "Set broker attributes"); + "Set broker attributes", "Broker", "broker"); }); } ); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js index 667c83c6ea..9f0ba9c16e 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js @@ -74,6 +74,7 @@ define(["dojo/dom", xhr.get({url: that.url, sync: properties.useSyncGet, handleAs: "json", content: { actuals: true }}) .then(function(data) { + // calls showKeystoreDialog that.dialog(data[0], that.url); }); }); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAccessControlProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAccessControlProvider.js index 49a99418bf..ac0493bfa5 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAccessControlProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAccessControlProvider.js @@ -56,6 +56,8 @@ define(["dojo/_base/lang", disabled: accessControlProvider.name ? true : false, label: "Name*:", regexp: "^[\x20-\x2e\x30-\x7F]{1,255}$", + promptMessage: "Name of access control provider.", + placeHolder: "name", name: "name"}); } }, { @@ -171,6 +173,8 @@ define(["dojo/_base/lang", accessControlProvider ? accessControlProvider : {}, "api/latest/accesscontrolprovider" + (name ? "/" + encodeURIComponent(name.name) : ""), accessControlProvider ? "Edit access control provider - " + accessControlProvider.name : "Add access control provider", + "AccessControlProvider", + accessControlProvider && accessControlProvider.type ? accessControlProvider.type : "AclFile", accessControlProvider ? false : true); }; return addAccessControlProvider; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addBinding.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addBinding.js index 8e70b78446..ac4937da68 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addBinding.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addBinding.js @@ -386,7 +386,9 @@ define(["dojo/_base/connect", that.queueChooser = new FilteringSelect({ id: "addBindingSelectQueue", name: "queue", store: queueStore, - searchAttr: "name"}, input); + searchAttr: "name", + promptMessage: "Name of the queue", + title: "Select the name of the queue"}, input); if(obj.queue) { @@ -414,7 +416,9 @@ define(["dojo/_base/connect", that.exchangeChooser = new FilteringSelect({ id: "addBindingSelectExchange", name: "exchange", store: exchangeStore, - searchAttr: "name"}, input); + searchAttr: "name", + promptMessage: "Name of the exchange", + title: "Select the name of the exchange"}, input); if(obj.exchange) { diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addGroupProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addGroupProvider.js index 5f01b9769b..82281ad3d3 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addGroupProvider.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addGroupProvider.js @@ -56,6 +56,8 @@ define(["dojo/_base/lang", disabled: groupProvider.name ? true : false, label: "Name*:", regexp: "^[\x20-\x2e\x30-\x7F]{1,255}$", + promptMessage: "Name of group provider.", + placeHolder: "name", name: "name"}); } }, { @@ -171,6 +173,8 @@ define(["dojo/_base/lang", groupProvider ? groupProvider : {}, "api/latest/groupprovider" + (name ? "/" + encodeURIComponent(name.name) : ""), groupProvider ? "Edit group provider - " + groupProvider.name : "Add group provider", + "Group", + groupProvider && groupProvider.type ? groupProvider.type : "Group", groupProvider ? false : true); }; return addGroupProvider; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addKeystore.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addKeystore.js index 0ec8fb6c6c..e7e79e742d 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addKeystore.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addKeystore.js @@ -57,6 +57,8 @@ define(["dojo/_base/lang", disabled: keystore.name ? true : false, label: "Name:", regExpGen: util.nameOrContextVarRegexp, + promptMessage: "Name of keystore. Used to refer to the keystore from other objects within the Broker.", + placeHolder: "name", name: "name"}); } }, { @@ -66,6 +68,8 @@ define(["dojo/_base/lang", required: true, value: keystore.path, label: "Path to keystore:", + promptMessage: "File system location to the keystore file", + placeHolder: "path/to/keystore", name: "path"}); } }, { @@ -75,7 +79,7 @@ define(["dojo/_base/lang", return new dijit.form.ValidationTextBox({ required: false, label: "Keystore password:", - invalidMessage: "Missed keystore password", + promptMessage: "Password used to open the keystore", name: "password", placeHolder: keystore["password"] ? keystore["password"] : "" }); @@ -96,10 +100,11 @@ define(["dojo/_base/lang", } fields.push({ name: "Options", + createWidget: function(keystore) { var optionalFieldContainer = new dojox.layout.TableContainer({ cols: 1, - "labelWidth": "290", + "labelWidth": "300", showLabels: true, orientation: "horiz", customClass: "formLabel" @@ -110,12 +115,16 @@ define(["dojo/_base/lang", required: false, value: keystore.certificateAlias, label: "Keystore certificate alias:", - name: "certificateAlias"})); + name: "certificateAlias", + placeHolder: "alias", + promptMessage: "Used to identify one certificate in a store that has many"})); + optionalFieldContainer.addChild( new dijit.form.ValidationTextBox({ required: false, value: keystore.keyManagerFactoryAlgorithm, label: "Key manager factory algorithm:", - placeHolder: "Use default", + placeHolder: "algorithm name", + promptMessage: "Name of the key manager algorithm known to Java", name: "keyManagerFactoryAlgorithm"})); } else @@ -124,16 +133,20 @@ define(["dojo/_base/lang", required: false, value: keystore.trustManagerFactoryAlgorithm, label: "Trust manager factory algorithm:", - placeHolder: "Use default", + placeHolder: "algorithm name", + promptMessage: "Name of the trust manager algorithm known to Java", name: "trustManagerFactoryAlgorithm"})); } optionalFieldContainer.addChild(new dijit.form.ValidationTextBox({ required: false, value: isKeystore ? keystore.keyStoreType : keystore.trustStoreType, label: "Key store type:", - placeHolder: "Use default", + placeHolder: "store type", + promptMessage: "Name of the store type known to Java", name: isKeystore ? "keyStoreType" : "trustStoreType"})); + var panel = new dijit.TitlePane({title: "Optional Attributes", content: optionalFieldContainer.domNode, open: false}); + return panel; } }); @@ -148,6 +161,8 @@ define(["dojo/_base/lang", keystore ? keystore : {}, keystore ? putURL : "api/latest/keystore", keystore ? "Edit keystore - " + keystore.name : "Add keystore", + "KeyStore", + keystore && keystore.type ? keystore.type : "FileKeyStore", // GET?actuals=true doesn't get type for objects of the default type for the category keystore ? false : true); }; @@ -158,6 +173,8 @@ define(["dojo/_base/lang", truststore ? truststore : {}, truststore ? putURL : "api/latest/truststore", truststore ? "Edit truststore - " + truststore.name : "Add truststore", + "TrustStore", + truststore && truststore.type ? truststore.type : "FileTrustStore", truststore ? false : true); }; return addKeystore; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js index 34e2d58afb..0c8a4660fd 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js @@ -72,7 +72,7 @@ define(["dojo/_base/xhr", } for(var propName in formValues) { - if(formValues.hasOwnProperty(propName)) + if(formValues.hasOwnProperty(propName) && formValues[propName]) { if (propName == "needClientAuth" || propName == "wantClientAuth") { @@ -81,6 +81,12 @@ define(["dojo/_base/xhr", else if (propName === "protocols") { var val = formValues[propName]; + + if(val === "" || (lang.isArray(val) && val.length == 0) ) + { + continue; + } + if (!lang.isArray(val)) { val = [ val ]; @@ -91,7 +97,7 @@ define(["dojo/_base/xhr", { var val = formValues[propName]; - if(val === "") + if(val === "" || (lang.isArray(val) && val.length == 0) ) { continue; } @@ -170,20 +176,20 @@ define(["dojo/_base/xhr", registry.byId("formAddPort.wantClientAuth").set("disabled", true); } - var transportSSLPanel = registry.byId("formAddPort:fieldsTransportSSL"); - var transportSSLPanelDisplay = transportSSLPanel.domNode.style.display; + var transportSSLPanelNode = dom.byId("formAddPort:fieldsTransportSSL"); + var transportSSLPanelDisplay = transportSSLPanelNode.style.display; if (transportType == "SSL" || (lang.isArray(transportType) && array.indexOf(transportType, "SSL")>=0)) { - transportSSLPanel.domNode.style.display = "block"; + transportSSLPanelNode.style.display = "block"; registry.byId("formAddPort.keyStore").set("disabled", false); } else { - transportSSLPanel.domNode.style.display = "none"; + transportSSLPanelNode.style.display = "none"; registry.byId("formAddPort.keyStore").set("disabled", true); } - if (transportSSLPanel.domNode.style.display != transportSSLPanelDisplay && transportSSLPanel.domNode.style.display=="block") + if (transportSSLPanelNode.style.display != transportSSLPanelDisplay && transportSSLPanelNode.style.display=="block") { registry.byId("formAddPort.trustStores").resize(); } @@ -216,7 +222,7 @@ define(["dojo/_base/xhr", var store = typeWidget.store; store.data.forEach(function(option){ registry.byId("formAddPort.protocols" + option.value).set("disabled", true); - registry.byId("formAddPort:fields" + option.value).domNode.style.display = "none"; + dom.byId("formAddPort:fields" + option.value).style.display = "none"; }); var isAMQP = ("AMQP" == newValue); @@ -226,7 +232,7 @@ define(["dojo/_base/xhr", registry.byId("formAddPort.needClientAuth").set("enabled", isAMQP || isHTTP); registry.byId("formAddPort.wantClientAuth").set("enabled", isAMQP || isHTTP); - registry.byId("formAddPort:fields" + newValue).domNode.style.display = "block"; + dom.byId("formAddPort:fields" + newValue).style.display = "block"; var defaultsAMQPProtocols = registry.byId("formAddPort.protocolsDefault"); defaultsAMQPProtocols.set("disabled", "AMQP" != newValue) var protocolsWidget = registry.byId("formAddPort.protocols" + newValue); @@ -267,9 +273,9 @@ define(["dojo/_base/xhr", } transportWidget.set("disabled", disableTransportWidget); registry.byId("formAddPort.authenticationProvider").set("disabled", isRMI); - registry.byId("formAddPort:fieldsAuthenticationProvider").domNode.style.display = isRMI? "none" : "block"; - registry.byId("formAddPort:fieldsBindingAddress").domNode.style.display = newValue == "JMX" ? "none" : "block"; - registry.byId("formAddPort:transport").domNode.style.display = isRMI ? "none" : "block"; + dom.byId("formAddPort:fieldsAuthenticationProvider").style.display = isRMI? "none" : "block"; + dom.byId("formAddPort:fieldsBindingAddress").style.display = newValue == "JMX" ? "none" : "block"; + dom.byId("formAddPort:transport").style.display = isRMI ? "none" : "block"; @@ -277,23 +283,6 @@ define(["dojo/_base/xhr", theForm = registry.byId("formAddPort"); - var containers = ["formAddPort:fields", "formAddPort:fieldsTransportSSL", "formAddPort:fieldsAMQP", - "formAddPort:fieldsJMX", "formAddPort:fieldsHTTP", "formAddPort:transport", - "formAddPort:fieldsClientAuthCheckboxes", "formAddPort:fieldsAuthenticationProvider", "formAddPort:fieldsBindingAddress"]; - var labelWidthValue = "200"; - for(var i = 0; i < containers.length; i++) - { - var containerId = containers[i]; - var fields = new dojox.layout.TableContainer( { - cols: 1, - labelWidth: labelWidthValue, - showLabels: true, - orientation: "horiz", - customClass: "formLabel" - }, dom.byId(containerId)); - fields.startup(); - } - registry.byId("formAddPort.protocolsJMX").on("change", function(newValue){ var isRMI = newValue == "RMI"; var transportWidget = registry.byId("formAddPort.transports"); @@ -302,8 +291,8 @@ define(["dojo/_base/xhr", transportWidget.set("value", "TCP"); } transportWidget.set("disabled", isRMI); - registry.byId("formAddPort:transport").domNode.style.display = isRMI ? "none" : "block"; - registry.byId("formAddPort:fieldsAuthenticationProvider").domNode.style.display = isRMI? "none" : "block"; + dom.byId("formAddPort:transport").style.display = isRMI ? "none" : "block"; + dom.byId("formAddPort:fieldsAuthenticationProvider").style.display = isRMI? "none" : "block"; registry.byId("formAddPort.authenticationProvider").set("disabled", isRMI); }); @@ -365,6 +354,7 @@ define(["dojo/_base/xhr", } var keystoreWidget = registry.byId("formAddPort.keyStore"); + if (keystores) { var data = []; @@ -408,7 +398,7 @@ define(["dojo/_base/xhr", var nameWidget = registry.byId("formAddPort.name"); nameWidget.set("value", port.name); nameWidget.set("disabled", true); - nameWidget.set("regExpGen", util.nameOrContextVarRegexp); + dom.byId("formAddPort.id").value=port.id; providerWidget.set("value", port.authenticationProvider ? port.authenticationProvider : ""); keystoreWidget.set("value", port.keyStore ? port.keyStore : ""); @@ -444,7 +434,7 @@ define(["dojo/_base/xhr", var store = typeWidget.store; store.data.forEach(function(option){ registry.byId("formAddPort.protocols" + option.value).set("disabled", true); - registry.byId("formAddPort:fields" + option.value).domNode.style.display = "none"; + dom.byId("formAddPort:fields" + option.value).style.display = "none"; }); // identify the type of port using first protocol specified in protocol field if provided @@ -487,7 +477,7 @@ define(["dojo/_base/xhr", var addressWidget = registry.byId("formAddPort.bindingAddress"); addressWidget.set("value", port.bindingAddress) } - registry.byId("formAddPort:fields" + typeWidget.value).domNode.style.display = "block"; + dom.byId("formAddPort:fields" + typeWidget.value).style.display = "block"; typeWidget.set("disabled", true); keystoreWidget.initialValue = port.keyStore; @@ -496,21 +486,33 @@ define(["dojo/_base/xhr", providerWidget.initialValue = providerWidget.value; registry.byId("addPort").show(); - }); + util.applyMetadataToWidgets(registry.byId("addPort").domNode, "Port", typeWidget.get("value")); + + }); } else { + // Creating new port var typeWidget = registry.byId("formAddPort.type"); if (typeWidget.get("disabled")) { typeWidget.set("disabled", false); } typeWidget.set("value", "AMQP"); - var name = registry.byId("formAddPort.name"); - name.set("disabled", false); + + var nameWidget = registry.byId("formAddPort.name"); + nameWidget.set("disabled", false); + nameWidget.set("regExpGen", util.nameOrContextVarRegexp); + + var portWidget = registry.byId("formAddPort.port"); + portWidget.set("regExpGen", util.numericOrContextVarRegexp); + editWarning.style.display = "none"; registry.byId("addPort").show(); + + util.applyMetadataToWidgets(registry.byId("addPort").domNode, "Port", "AMQP"); } + }; return addPort; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js index 5a1ea48b3e..c66b99ee4c 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addQueue.js @@ -27,6 +27,7 @@ define(["dojo/_base/xhr", "dojo/_base/array", "dojo/_base/event", 'dojo/_base/json', + 'qpid/common/util', "dijit/form/NumberSpinner", // required by the form /* dojox/ validate resources */ "dojox/validate/us", "dojox/validate/web", @@ -41,7 +42,7 @@ define(["dojo/_base/xhr", /* basic dojox classes */ "dojox/form/BusyButton", "dojox/form/CheckedMultiSelect", "dojo/domReady!"], - function (xhr, dom, construct, win, registry, parser, array, event, json) { + function (xhr, dom, construct, win, registry, parser, array, event, json, util) { var addQueue = {}; @@ -147,6 +148,8 @@ define(["dojo/_base/xhr", { dijit.byId('formAddQueue.' + requiredFields[widgetValue]).required = isChecked; } + + util.applyMetadataToWidgets(obj.domNode, "Queue", widgetValue); } }) } @@ -192,9 +195,12 @@ define(["dojo/_base/xhr", addQueue.show = function(data) { addQueue.vhost = data.virtualhost; addQueue.vhostnode = data.virtualhostnode; - registry.byId("formAddQueue").reset(); + var form = registry.byId("formAddQueue"); + form.reset(); registry.byId("addQueue").show(); - }; + util.applyMetadataToWidgets(form.domNode, "Queue", "standard"); + + }; return addQueue; }); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js index 2eac2094e5..ede0c4bc48 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addVirtualHostNodeAndVirtualHost.js @@ -34,6 +34,7 @@ define(["dojo/_base/xhr", "dijit/form/FilteringSelect", "qpid/common/properties", "qpid/common/util", + "qpid/common/metadata", "dojo/text!addVirtualHostNodeAndVirtualHost.html", "dijit/form/Form", "dijit/form/CheckBox", @@ -41,7 +42,7 @@ define(["dojo/_base/xhr", "dojox/validate/us", "dojox/validate/web", "dojo/domReady!"], - function (xhr, event, lang, array, dom, domConstruct, json, parser, Memory, fobject, registry, Dialog, Button, FilteringSelect, properties, util, template) + function (xhr, event, lang, array, dom, domConstruct, json, parser, Memory, fobject, registry, Dialog, Button, FilteringSelect, properties, util, metadata, template) { var addVirtualHostNodeAndVirtualHost = @@ -71,38 +72,26 @@ define(["dojo/_base/xhr", this.virtualHostType = registry.byId("addVirtualHost.type"); this.virtualHostType.set("disabled", true); - xhr.get({sync: properties.useSyncGet, handleAs: "json", url: "api/latest/broker?depth=0", load: function(data){that._onBrokerData(data[0]) }}); - }, - _makeTypeStore: function (types) { - var typeData = []; - for (var i = 0; i < types.length; i++) { - var type = types[i]; - typeData.push({id: type, name: type}); - } - return new Memory({ data: typeData }); - }, - _onBrokerData: function(brokerData) - { - var that=this; - this.supportedVirtualHostNodeTypes = brokerData.supportedVirtualHostNodeTypes; - this.supportedVirtualHostNodeTypes.sort(); - this.supportedVirtualHostTypes = brokerData.supportedVirtualHostTypes; - this.supportedVirtualHostTypes.sort(); + this.supportedVirtualHostNodeTypes = metadata.getTypesForCategory("VirtualHostNode"); + this.supportedVirtualHostNodeTypes.sort(); + this.supportedVirtualHostTypes = metadata.getTypesForCategory("VirtualHost"); + this.supportedVirtualHostTypes.sort(); - //VH Type BDB_HA_REPLICA is not user creatable. This is only needed until we have model meta data available. - this.supportedVirtualHostTypes = array.filter(this.supportedVirtualHostTypes, function(item){ - return item != "BDB_HA_REPLICA" && item != "BDB_HA"; - }); + //VH Type BDB_HA_REPLICA is not user creatable. This is only needed until we have model meta data available. + this.supportedVirtualHostTypes = array.filter(this.supportedVirtualHostTypes, function(item){ + return item != "BDB_HA_REPLICA" && item != "BDB_HA"; + }); - var virtualHostNodeTypeStore = this._makeTypeStore(this.supportedVirtualHostNodeTypes); - this.virtualHostNodeType.set("store", virtualHostNodeTypeStore); - this.virtualHostNodeType.set("disabled", false); - this.virtualHostNodeType.on("change", function(type){that._vhnTypeChanged(type, that.virtualHostNodeTypeFieldsContainer, "qpid/management/virtualhostnode/");}); + var virtualHostNodeTypeStore = util.makeTypeStore(this.supportedVirtualHostNodeTypes); + this.virtualHostNodeType.set("store", virtualHostNodeTypeStore); + this.virtualHostNodeType.set("disabled", false); + this.virtualHostNodeType.on("change", function(type){that._vhnTypeChanged(type, that.virtualHostNodeTypeFieldsContainer, "qpid/management/virtualhostnode/");}); + + this.virtualHostTypeStore = util.makeTypeStore(this.supportedVirtualHostTypes); + this.virtualHostType.set("store", this.virtualHostTypeStore); + this.virtualHostType.set("disabled", false); + this.virtualHostType.on("change", function(type){that._vhTypeChanged(type, that.virtualHostTypeFieldsContainer, "qpid/management/virtualhost/");}); - this.virtualHostTypeStore = this._makeTypeStore(this.supportedVirtualHostTypes); - this.virtualHostType.set("store", this.virtualHostTypeStore); - this.virtualHostType.set("disabled", false); - this.virtualHostType.on("change", function(type){that._vhTypeChanged(type, that.virtualHostTypeFieldsContainer, "qpid/management/virtualhost/");}); }, show: function() { @@ -132,13 +121,14 @@ define(["dojo/_base/xhr", { this._processDropDownsForBdbHa(type); this._processDropDownsForJson(type); - this._typeChanged(type, typeFieldsContainer, urlStem); + + this._typeChanged(type, typeFieldsContainer, urlStem, "VirtualHostNode"); }, _vhTypeChanged: function (type, typeFieldsContainer, urlStem) { - this._typeChanged(type, typeFieldsContainer, urlStem); + this._typeChanged(type, typeFieldsContainer, urlStem, "VirtualHost"); }, - _typeChanged: function (type, typeFieldsContainer, urlStem) + _typeChanged: function (type, typeFieldsContainer, urlStem, category) { var widgets = registry.findWidgets(typeFieldsContainer); array.forEach(widgets, function(item) { item.destroyRecursive();}); @@ -148,11 +138,13 @@ define(["dojo/_base/xhr", { var that = this; require([urlStem + type.toLowerCase() + "/add"], - function(TypeUI) + function(typeUI) { try { - TypeUI.show({containerNode:typeFieldsContainer, parent: that}); + typeUI.show({containerNode:typeFieldsContainer, parent: that}); + + util.applyMetadataToWidgets(typeFieldsContainer,category, type); } catch(e) { diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHost.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHost.js index 1a24e5e770..a959586655 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHost.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHost.js @@ -56,6 +56,7 @@ define(["dojo/_base/xhr", var that=this; this.containerNode = domConstruct.create("div", {innerHTML: template}); parser.parse(this.containerNode); + this.allFieldsContainer = dom.byId("editVirtualHost.allFields"); this.typeFieldsContainer = dom.byId("editVirtualHost.typeFields"); this.dialog = registry.byId("editVirtualHostDialog"); this.saveButton = registry.byId("editVirtualHost.saveButton"); @@ -176,6 +177,8 @@ define(["dojo/_base/xhr", { TypeUI.show({containerNode:that.typeFieldsContainer, parent: that, data: virtualHostData}); that.form.connectChildren(); + + util.applyMetadataToWidgets(that.allFieldsContainer, "VirtualHost", virtualHostData.type); } catch(e) { diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHostNode.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHostNode.js index 704063ae16..3c78eaa29c 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHostNode.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/editVirtualHostNode.js @@ -147,6 +147,8 @@ define(["dojo/_base/xhr", { TypeUI.show({containerNode:that.typeFieldsContainer, parent: that, data: nodeData}); that.form.connectChildren(); + + util.applyMetadataToWidgets(that.allFieldsContainer, "VirtualHostNode", nodeData.type); } catch(e) { diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js index 07c5c25171..69f520bf42 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js @@ -139,7 +139,9 @@ define(["dojo/_base/xhr", widgetFactories, data, "api/latest/plugin/" + encodeURIComponent(data.name), - "Edit plugin - " + data.name); + "Edit plugin - " + data.name, + "Plugin", + "MANAGEMENT-HTTP"); }; function ManagementHttpUpdater(node, pluginObject, controller) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementjmx.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementjmx.js index 78d06da51f..3579d258e9 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementjmx.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementjmx.js @@ -86,7 +86,9 @@ define(["dojo/_base/xhr", widgetFactories, data, "api/latest/plugin/" + encodeURIComponent(data.name), - "Edit plugin - " + data.name); + "Edit plugin - " + data.name, + "Plugin", + "MANAGEMENT-JMX"); }; function ManagementJmxUpdater(node, pluginObject, controller) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/strings.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/strings.html new file mode 100644 index 0000000000..d29ef5c21c --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/strings.html @@ -0,0 +1,21 @@ +<!-- + ~ 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. + --> +<div> + <div id="promptTemplateWithDefault"><i>Optional:</i> ${prompt}.<br/>Defaults to <code>${default}</code></div> +</div> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/providedstore/add.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/providedstore/add.html index 320f056cef..c0cd3f5653 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/providedstore/add.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/providedstore/add.html @@ -28,7 +28,8 @@ name: 'storeOverfullSize', placeHolder: 'size in bytes', required: false, - title: 'Enter ceiling (in bytes) at which store will begin to throttle sessions producing messages'" /> + title: 'Enter ceiling (in bytes) at which store will begin to throttle sessions producing messages', + promptMessage: 'Ceiling (in bytes) at which store will begin to throttle sessions producing messages'" /> </div> </div> <div class="clear"> @@ -40,7 +41,8 @@ name: 'storeUnderfullSize', placeHolder: 'size in bytes', required: false, - title: 'Enter floor (in bytes) at which store will cease to throttle sessions producing messages'" /> + title: 'Enter floor (in bytes) at which store will cease to throttle sessions producing messages', + promptMessage: 'Floor (in bytes) at which store will cease to throttle sessions producing messages'" /> </div> </div> </div> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/providedstore/edit.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/providedstore/edit.html index ec02c67ff4..427a1bab86 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/providedstore/edit.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/providedstore/edit.html @@ -28,7 +28,8 @@ name: 'storeOverfullSize', placeHolder: 'size in bytes', required: false, - title: 'Enter ceiling (in bytes) at which store will begin to throttle sessions producing messages'" + title: 'Enter ceiling (in bytes) at which store will begin to throttle sessions producing messages', + promptMessage: 'Ceiling (in bytes) at which store will begin to throttle sessions producing messages'" /> </div> </div> @@ -41,7 +42,8 @@ name: 'storeUnderfullSize', placeHolder: 'size in bytes', required: false, - title: 'Enter floor (in bytes) at which store will cease to throttle sessions producing messages'" + title: 'Enter floor (in bytes) at which store will cease to throttle sessions producing messages', + promptMessage: 'Floor (in bytes) at which store will cease to throttle sessions producing messages'" /> </div> </div> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/add.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/add.html index 88ca0b3807..484a85b965 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/add.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/add.html @@ -26,7 +26,8 @@ data-dojo-props=" name: 'storePath', placeHolder: 'path/to/store', - title: 'Enter message store path'" /> + title: 'Enter message store path', + promptMessage: 'File system location for the message store'" /> </div> </div> <div class="clear"> @@ -38,7 +39,8 @@ name: 'storeOverfullSize', placeHolder: 'size in bytes', required: false, - title: 'Enter ceiling (in bytes) at which store will begin to throttle sessions producing messages'" /> + title: 'Enter ceiling (in bytes) at which store will begin to throttle sessions producing messages', + promptMessage: 'Ceiling (in bytes) at which store will begin to throttle sessions producing messages'" /> </div> </div> <div class="clear"> @@ -50,7 +52,8 @@ name: 'storeUnderfullSize', placeHolder: 'size in bytes', required: false, - title: 'Enter floor (in bytes) at which store will cease to throttle sessions producing messages'" /> + title: 'Enter floor (in bytes) at which store will cease to throttle sessions producing messages', + promptMessage: 'Floor (in bytes) at which store will cease to throttle sessions producing messages'" /> </div> </div> <div class="clear"></div> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/edit.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/edit.html index 60b8faef56..2486cdcf42 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/edit.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/edit.html @@ -26,7 +26,6 @@ data-dojo-type="dijit/form/ValidationTextBox" data-dojo-props=" name: 'storePath', - placeHolder: 'path/to/store', disabled: true, title: 'Enter message store path'" /> </div> @@ -41,7 +40,8 @@ name: 'storeOverfullSize', placeHolder: 'size in bytes', required: false, - title: 'Enter ceiling (in bytes) at which store will begin to throttle sessions producing messages'" + title: 'Enter ceiling (in bytes) at which store will begin to throttle sessions producing messages', + promptMessage: 'Ceiling (in bytes) at which store will begin to throttle sessions producing messages'" /> </div> </div> @@ -54,7 +54,8 @@ name: 'storeUnderfullSize', placeHolder: 'size in bytes', required: false, - title: 'Enter floor (in bytes) at which store will cease to throttle sessions producing messages'" + title: 'Enter floor (in bytes) at which store will cease to throttle sessions producing messages', + promptMessage: 'Floor (in bytes) at which store will cease to throttle sessions producing messages'" /> </div> </div> diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java index 10f56cef58..61061e6209 100644 --- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java +++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java @@ -32,6 +32,7 @@ import java.util.Set; import javax.management.JMException; import org.apache.log4j.Logger; + import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.jmx.mbeans.LoggingManagementMBean; import org.apache.qpid.server.jmx.mbeans.ServerInformationMBean; diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java index 7d9dfcd600..b64d355f80 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java @@ -20,6 +20,39 @@ */ package org.apache.qpid.client; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.ConnectException; +import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.nio.channels.UnresolvedAddressException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.jms.ConnectionConsumer; +import javax.jms.ConnectionMetaData; +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.IllegalStateException; +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueSession; +import javax.jms.ServerSessionPool; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicSession; +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.naming.Referenceable; +import javax.naming.StringRefAddr; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,38 +82,6 @@ import org.apache.qpid.jms.FailoverPolicy; import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.url.URLSyntaxException; -import javax.jms.ConnectionConsumer; -import javax.jms.ConnectionMetaData; -import javax.jms.Destination; -import javax.jms.ExceptionListener; -import javax.jms.IllegalStateException; -import javax.jms.JMSException; -import javax.jms.Queue; -import javax.jms.QueueConnection; -import javax.jms.QueueSession; -import javax.jms.ServerSessionPool; -import javax.jms.Topic; -import javax.jms.TopicConnection; -import javax.jms.TopicSession; -import javax.naming.NamingException; -import javax.naming.Reference; -import javax.naming.Referenceable; -import javax.naming.StringRefAddr; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.net.ConnectException; -import java.net.SocketAddress; -import java.net.UnknownHostException; -import java.nio.channels.UnresolvedAddressException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - public class AMQConnection extends Closeable implements Connection, QueueConnection, TopicConnection, Referenceable { private static final Logger _logger = LoggerFactory.getLogger(AMQConnection.class); @@ -191,6 +192,9 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect //Address resolution purposes private volatile long _lastFailoverTime = 0; + private boolean _compressMessages; + private int _messageCompressionThresholdSize; + /** * @param broker brokerdetails * @param username username @@ -325,6 +329,31 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect Boolean.parseBoolean(System.getProperty(ClientProperties.VERIFY_QUEUE_ON_SEND, "false")); } + if(connectionURL.getOption(ConnectionURL.OPTIONS_COMPRESS_MESSAGES) != null) + { + _compressMessages = Boolean.parseBoolean(connectionURL.getOption(ConnectionURL.OPTIONS_COMPRESS_MESSAGES)); + } + else + { + _compressMessages = + Boolean.parseBoolean(System.getProperty(ClientProperties.CONNECTION_OPTION_COMPRESS_MESSAGES, + String.valueOf(ClientProperties.DEFAULT_CONNECTION_OPTION_COMPRESS_MESSAGES))); + } + + + if(connectionURL.getOption(ConnectionURL.OPTIONS_MESSAGES_COMPRESSION_THRESHOLD_SIZE) != null) + { + _messageCompressionThresholdSize = Integer.valueOf(connectionURL.getOption(ConnectionURL.OPTIONS_MESSAGES_COMPRESSION_THRESHOLD_SIZE)); + } + else + { + _messageCompressionThresholdSize = Integer.getInteger(ClientProperties.CONNECTION_OPTION_MESSAGE_COMPRESSION_THRESHOLD_SIZE, + ClientProperties.DEFAULT_MESSAGE_COMPRESSION_THRESHOLD_SIZE); + } + if(_messageCompressionThresholdSize <= 0) + { + _messageCompressionThresholdSize = Integer.MAX_VALUE; + } String amqpVersion = System.getProperty((ClientProperties.AMQP_VERSION), "0-10"); if (_logger.isDebugEnabled()) @@ -449,16 +478,13 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } } - if ((message == null) || message.equals("")) + if (message == null) { - if (message == null) - { - message = "Unable to Connect"; - } - else // can only be "" if getMessage() returned it therfore lastException != null - { - message = "Unable to Connect:" + connectionException.getClass(); - } + message = "Unable to Connect"; + } + else if("".equals(message)) + { + message = "Unable to Connect:" + connectionException.getClass(); } for (Throwable th = connectionException; th != null; th = th.getCause()) @@ -1543,6 +1569,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect return _syncPublish; } + public boolean isMessageCompressionDesired() + { + return _compressMessages; + } + public int getNextChannelID() { return _sessions.getNextChannelId(); @@ -1615,4 +1646,9 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { return super.setClosed(); } + + public int getMessageCompressionThresholdSize() + { + return _messageCompressionThresholdSize; + } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java index 0329deee03..74ca1ed74f 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate.java @@ -20,6 +20,11 @@ */ package org.apache.qpid.client; +import java.io.IOException; + +import javax.jms.JMSException; +import javax.jms.XASession; + import org.apache.qpid.AMQException; import org.apache.qpid.client.failover.FailoverException; import org.apache.qpid.client.failover.FailoverProtectedOperation; @@ -27,10 +32,6 @@ import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.jms.BrokerDetails; import org.apache.qpid.jms.Session; -import javax.jms.JMSException; -import javax.jms.XASession; -import java.io.IOException; - public interface AMQConnectionDelegate { ProtocolVersion makeBrokerConnection(BrokerDetails brokerDetail) throws IOException, AMQException; @@ -82,4 +83,6 @@ public interface AMQConnectionDelegate void setHeartbeatListener(HeartbeatListener listener); boolean supportsIsBound(); + + boolean isMessageCompressionSupported(); } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java index 95b1178407..4e9164c3b0 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java @@ -21,6 +21,17 @@ package org.apache.qpid.client; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.XASession; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,7 +40,6 @@ import org.apache.qpid.client.failover.FailoverException; import org.apache.qpid.client.failover.FailoverProtectedOperation; import org.apache.qpid.client.transport.ClientConnectionDelegate; import org.apache.qpid.common.ServerPropertyNames; - import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.jms.BrokerDetails; import org.apache.qpid.jms.ChannelLimitReachedException; @@ -48,16 +58,6 @@ import org.apache.qpid.transport.SessionDetachCode; import org.apache.qpid.transport.SessionException; import org.apache.qpid.transport.TransportException; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.jms.XASession; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; - public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, ConnectionListener { /** @@ -441,7 +441,11 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec try { clientProps.put(ConnectionStartProperties.CLIENT_ID_0_10, _conn.getClientID()); - conSettings.setClientProperties(clientProps); + if(_conn.isMessageCompressionDesired()) + { + clientProps.put(ConnectionStartProperties.QPID_MESSAGE_COMPRESSION_SUPPORTED, Boolean.TRUE.toString()); + } + conSettings.setClientProperties(clientProps); } catch (JMSException e) { @@ -504,4 +508,10 @@ public class AMQConnectionDelegate_0_10 implements AMQConnectionDelegate, Connec //0-10 supports the isBound method return true; } + + @Override + public boolean isMessageCompressionSupported() + { + return _qpidConnection.isMessageCompressionSupported(); + } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java index dfbf7ec60a..5242629a91 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java @@ -20,8 +20,21 @@ */ package org.apache.qpid.client; +import java.io.IOException; +import java.net.ConnectException; +import java.nio.channels.UnresolvedAddressException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.Set; + +import javax.jms.JMSException; +import javax.jms.XASession; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.apache.qpid.AMQException; import org.apache.qpid.client.failover.FailoverException; import org.apache.qpid.client.failover.FailoverProtectedOperation; @@ -49,22 +62,11 @@ import org.apache.qpid.transport.network.Transport; import org.apache.qpid.transport.network.security.SecurityLayer; import org.apache.qpid.transport.network.security.SecurityLayerFactory; -import javax.jms.JMSException; -import javax.jms.XASession; - -import java.io.IOException; -import java.net.ConnectException; -import java.nio.channels.UnresolvedAddressException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.Set; - public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate { private static final Logger _logger = LoggerFactory.getLogger(AMQConnectionDelegate_8_0.class); private final AMQConnection _conn; + private boolean _messageCompressionSupported; public void closeConnection(long timeout) throws JMSException, AMQException { @@ -139,6 +141,7 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate _conn.getFailoverPolicy().attainedConnection(); _conn.setConnected(true); _conn.logConnected(network.getLocalAddress(), network.getRemoteAddress()); + _messageCompressionSupported = checkMessageCompressionSupported(); return null; } else @@ -413,4 +416,17 @@ public class AMQConnectionDelegate_8_0 implements AMQConnectionDelegate return connectedToQpid; } + + private boolean checkMessageCompressionSupported() + { + FieldTable serverProperties = _conn.getProtocolHandler().getProtocolSession().getConnectionStartServerProperties(); + return serverProperties != null + && Boolean.parseBoolean(serverProperties.getString(ConnectionStartProperties.QPID_MESSAGE_COMPRESSION_SUPPORTED)); + + } + + public boolean isMessageCompressionSupported() + { + return _messageCompressionSupported; + } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java index 9efc670e99..eb8104b02c 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_10.java @@ -17,6 +17,19 @@ */ package org.apache.qpid.client; +import static org.apache.qpid.transport.Option.NONE; +import static org.apache.qpid.transport.Option.SYNC; +import static org.apache.qpid.transport.Option.UNRELIABLE; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,25 +49,15 @@ import org.apache.qpid.transport.MessageDeliveryPriority; import org.apache.qpid.transport.MessageProperties; import org.apache.qpid.transport.Option; import org.apache.qpid.transport.TransportException; +import org.apache.qpid.util.GZIPUtils; import org.apache.qpid.util.Strings; -import static org.apache.qpid.transport.Option.NONE; -import static org.apache.qpid.transport.Option.SYNC; -import static org.apache.qpid.transport.Option.UNRELIABLE; - -import javax.jms.DeliveryMode; -import javax.jms.JMSException; -import javax.jms.Message; -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - /** * This is a 0_10 message producer. */ public class BasicMessageProducer_0_10 extends BasicMessageProducer { + private static final Logger _logger = LoggerFactory.getLogger(BasicMessageProducer_0_10.class); private byte[] userIDBytes; @@ -204,6 +207,22 @@ public class BasicMessageProducer_0_10 extends BasicMessageProducer } ByteBuffer data = message.getData(); + + if(data != null + && data.remaining() > getConnection().getMessageCompressionThresholdSize() + && getConnection().getDelegate().isMessageCompressionSupported() + && getConnection().isMessageCompressionDesired() + && messageProps.getContentEncoding() == null) + { + byte[] compressed = GZIPUtils.compressBufferToArray(data); + if(compressed != null) + { + messageProps.setContentEncoding(GZIPUtils.GZIP_CONTENT_ENCODING); + data = ByteBuffer.wrap(compressed); + } + } + + messageProps.setContentLength(data == null ? 0 : data.remaining()); // send the message diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java index b9bb03444f..355c456249 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java @@ -44,6 +44,7 @@ import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.ExchangeDeclareBody; import org.apache.qpid.framing.MethodRegistry; +import org.apache.qpid.util.GZIPUtils; public class BasicMessageProducer_0_8 extends BasicMessageProducer { @@ -147,7 +148,20 @@ public class BasicMessageProducer_0_8 extends BasicMessageProducer contentHeaderProperties.setDeliveryMode((byte) deliveryMode); contentHeaderProperties.setPriority((byte) priority); - final int size = (payload != null) ? payload.limit() : 0; + int size = (payload != null) ? payload.remaining() : 0; + + byte[] compressed; + if(size > getConnection().getMessageCompressionThresholdSize() + && getConnection().getDelegate().isMessageCompressionSupported() + && getConnection().isMessageCompressionDesired() + && contentHeaderProperties.getEncoding() == null + && (compressed = GZIPUtils.compressBufferToArray(payload)) != null) + { + contentHeaderProperties.setEncoding("gzip"); + payload = ByteBuffer.wrap(compressed); + size = compressed.length; + + } final int contentBodyFrameCount = calculateContentBodyFrameCount(payload); final AMQFrame[] frames = new AMQFrame[2 + contentBodyFrameCount]; diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/CloseWhenNoRouteSettingsHelper.java b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/CloseWhenNoRouteSettingsHelper.java index baae072167..e8343fda0a 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/CloseWhenNoRouteSettingsHelper.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/CloseWhenNoRouteSettingsHelper.java @@ -18,11 +18,12 @@ */ package org.apache.qpid.client.handler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.apache.qpid.framing.FieldTable; import org.apache.qpid.jms.ConnectionURL; import org.apache.qpid.properties.ConnectionStartProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Used during connection establishment to optionally set the "close when no route" client property diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java index b0c30f82fa..2e817f2966 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java @@ -20,6 +20,13 @@ */ package org.apache.qpid.client.handler; +import java.io.UnsupportedEncodingException; +import java.util.StringTokenizer; + +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,12 +47,6 @@ import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.jms.ConnectionURL; import org.apache.qpid.properties.ConnectionStartProperties; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslException; -import java.io.UnsupportedEncodingException; -import java.util.StringTokenizer; - public class ConnectionStartMethodHandler implements StateAwareMethodListener<ConnectionStartBody> { private static final Logger _log = LoggerFactory.getLogger(ConnectionStartMethodHandler.class); @@ -173,6 +174,9 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener<Co ConnectionURL url = getConnectionURL(session); _closeWhenNoRouteHelper.setClientProperties(clientProperties, url, serverProperties); + clientProperties.setString(ConnectionStartProperties.QPID_MESSAGE_COMPRESSION_SUPPORTED, + String.valueOf(session.getAMQConnection().isMessageCompressionDesired())); + ConnectionStartOkBody connectionStartOkBody = session.getMethodRegistry().createConnectionStartOkBody(clientProperties,new AMQShortString(mechanism),saslResponse,new AMQShortString(locales)); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. @@ -188,7 +192,7 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener<Co else { _log.error("Broker requested Protocol [" + body.getVersionMajor() + "-" + body.getVersionMinor() - + "] which is not supported by this version of the client library"); + + "] which is not supported by this version of the client library"); session.closeProtocolSession(); } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java index e52ff9acb2..71d07b1fa0 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java @@ -20,6 +20,17 @@ */ package org.apache.qpid.client.message; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.Iterator; +import java.util.List; +import java.util.zip.GZIPInputStream; + +import javax.jms.JMSException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,16 +39,11 @@ import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQSession_0_8; import org.apache.qpid.client.AMQTopic; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentBody; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.transport.DeliveryProperties; import org.apache.qpid.transport.MessageProperties; - -import javax.jms.JMSException; -import java.nio.ByteBuffer; -import java.util.Iterator; -import java.util.List; +import org.apache.qpid.util.GZIPUtils; public abstract class AbstractJMSMessageFactory implements MessageFactory { @@ -52,46 +58,57 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory ByteBuffer data; final boolean debug = _logger.isDebugEnabled(); - // we optimise the non-fragmented case to avoid copying - if ((bodies != null) && (bodies.size() == 1)) - { - if (debug) - { - _logger.debug("Non-fragmented message body (bodySize=" + contentHeader.getBodySize() + ")"); - } + byte[] uncompressed; - data = ByteBuffer.wrap(((ContentBody) bodies.get(0)).getPayload()); + if(GZIPUtils.GZIP_CONTENT_ENCODING.equals(contentHeader.getProperties().getEncodingAsString()) + && (uncompressed = GZIPUtils.uncompressStreamToArray(new BodyInputStream(bodies))) != null ) + { + contentHeader.getProperties().setEncoding((String)null); + data = ByteBuffer.wrap(uncompressed); } - else if (bodies != null) + else { - if (debug) + // we optimise the non-fragmented case to avoid copying + if ((bodies != null) && (bodies.size() == 1)) { - _logger.debug("Fragmented message body (" + bodies - .size() + " frames, bodySize=" + contentHeader.getBodySize() + ")"); - } + if (debug) + { + _logger.debug("Non-fragmented message body (bodySize=" + contentHeader.getBodySize() + ")"); + } - data = ByteBuffer.allocate((int) contentHeader.getBodySize()); // XXX: Is cast a problem? - final Iterator it = bodies.iterator(); - while (it.hasNext()) + data = ByteBuffer.wrap(((ContentBody) bodies.get(0)).getPayload()); + } + else if (bodies != null) { - ContentBody cb = (ContentBody) it.next(); - final ByteBuffer payload = ByteBuffer.wrap(cb.getPayload()); - if(payload.isDirect() || payload.isReadOnly()) + if (debug) { - data.put(payload); + _logger.debug("Fragmented message body (" + bodies + .size() + " frames, bodySize=" + contentHeader.getBodySize() + ")"); } - else + + data = ByteBuffer.allocate((int) contentHeader.getBodySize()); // XXX: Is cast a problem? + final Iterator it = bodies.iterator(); + while (it.hasNext()) { - data.put(payload.array(), payload.arrayOffset(), payload.limit()); + ContentBody cb = (ContentBody) it.next(); + final ByteBuffer payload = ByteBuffer.wrap(cb.getPayload()); + if (payload.isDirect() || payload.isReadOnly()) + { + data.put(payload); + } + else + { + data.put(payload.array(), payload.arrayOffset(), payload.limit()); + } + } + data.flip(); + } + else // bodies == null + { + data = ByteBuffer.allocate(0); } - - data.flip(); - } - else // bodies == null - { - data = ByteBuffer.allocate(0); } if (debug) @@ -132,22 +149,42 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory _logger.debug("Creating message from buffer with position=" + data.position() + " and remaining=" + data .remaining()); } + if(GZIPUtils.GZIP_CONTENT_ENCODING.equals(msgProps.getContentEncoding())) + { + byte[] uncompressed = GZIPUtils.uncompressBufferToArray(data); + if(uncompressed != null) + { + msgProps.setContentEncoding(null); + data = ByteBuffer.wrap(uncompressed); + } + } AMQMessageDelegate delegate = new AMQMessageDelegate_0_10(msgProps, deliveryProps, messageNbr); AbstractJMSMessage message = createMessage(delegate, data); return message; } - private static final String asString(byte[] bytes) + private ByteBuffer uncompressBody(final InputStream bodyInputStream) throws AMQException { - if (bytes == null) + final ByteBuffer data; + try(GZIPInputStream gzipInputStream = new GZIPInputStream(bodyInputStream)) { - return null; + ByteArrayOutputStream uncompressedBuffer = new ByteArrayOutputStream(); + int read; + byte[] buf = new byte[4096]; + while((read = gzipInputStream.read(buf))!=-1) + { + uncompressedBuffer.write(buf,0,read); + } + byte[] uncompressedBytes = uncompressedBuffer.toByteArray(); + data = ByteBuffer.wrap(uncompressedBytes); } - else + catch (IOException e) { - return new String(bytes); + // TODO - shouldn't happen + throw new AMQException("Error uncompressing gzipped message data", e); } + return data; } @@ -174,4 +211,57 @@ public abstract class AbstractJMSMessageFactory implements MessageFactory return msg; } + private class BodyInputStream extends InputStream + { + private final Iterator<ContentBody> _bodiesIter; + private byte[] _currentBuffer; + private int _currentPos; + public BodyInputStream(final List<ContentBody> bodies) + { + _bodiesIter = bodies.iterator(); + _currentBuffer = _bodiesIter.next().getPayload(); + _currentPos = 0; + } + + @Override + public int read() throws IOException + { + byte[] buf = new byte[1]; + int size = read(buf); + if(size == -1) + { + throw new EOFException(); + } + else + { + return ((int)buf[0])&0xff; + } + } + + @Override + public int read(final byte[] dst, final int off, final int len) + { + while(_currentPos == _currentBuffer.length) + { + if(!_bodiesIter.hasNext()) + { + return -1; + } + else + { + _currentBuffer = _bodiesIter.next().getPayload(); + _currentPos = 0; + } + } + int size = Math.min(len, _currentBuffer.length - _currentPos); + System.arraycopy(_currentBuffer,_currentPos, dst,off,size); + _currentPos+=size; + return size; + } + + @Override + public void close() + { + } + } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java b/qpid/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java index 2901a5f983..754b90c372 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/jms/ConnectionURL.java @@ -70,6 +70,11 @@ public interface ConnectionURL */ public static final String OPTIONS_CLOSE_WHEN_NO_ROUTE = "closeWhenNoRoute"; + + public static final String OPTIONS_COMPRESS_MESSAGES = "compressMessages"; + public static final String OPTIONS_MESSAGES_COMPRESSION_THRESHOLD_SIZE = "messageCompressionThresholdSize"; + + public static final String OPTIONS_DEFAULT_TOPIC_EXCHANGE = "defaultTopicExchange"; public static final String OPTIONS_DEFAULT_QUEUE_EXCHANGE = "defaultQueueExchange"; public static final String OPTIONS_TEMPORARY_TOPIC_EXCHANGE = "temporaryTopicExchange"; diff --git a/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java b/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java index f10961c092..24ec496cc9 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java @@ -254,6 +254,19 @@ public class ClientProperties public static final String CONNECTION_OPTION_SSL_VERIFY_HOST_NAME = "qpid.connection_ssl_verify_hostname"; public static final boolean DEFAULT_CONNECTION_OPTION_SSL_VERIFY_HOST_NAME = true; + /** + * System property to set a default value for a connection option 'compress_messages' + */ + public static final String CONNECTION_OPTION_COMPRESS_MESSAGES = "qpid.connection_compress_messages"; + public static final boolean DEFAULT_CONNECTION_OPTION_COMPRESS_MESSAGES = false; + + + /** + * System property to set a default value for a connection option 'message_compression_threshold_size' + */ + public static final String CONNECTION_OPTION_MESSAGE_COMPRESSION_THRESHOLD_SIZE = "qpid.message_compression_threshold_size"; + public static final int DEFAULT_MESSAGE_COMPRESSION_THRESHOLD_SIZE = 102400; + private ClientProperties() { //No instances diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java index fe8c94cee1..b490aee898 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java @@ -20,13 +20,13 @@ */ package org.apache.qpid.framing; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class BasicContentHeaderProperties { //persistent & non-persistent constants, values as per JMS DeliveryMode @@ -83,8 +83,48 @@ public class BasicContentHeaderProperties private byte[] _encodedForm; + public BasicContentHeaderProperties(BasicContentHeaderProperties other) + { + if(other._headers != null) + { + byte[] encodedHeaders = other._headers.getDataAsBytes(); + + _headers = new FieldTable(encodedHeaders,0,encodedHeaders.length); + + } + + _contentType = other._contentType; + + _encoding = other._encoding; + + _deliveryMode = other._deliveryMode; + + _priority = other._priority; + + _correlationId = other._correlationId; + + _replyTo = other._replyTo; + + _expiration = other._expiration; + + _messageId = other._messageId; + + _timestamp = other._timestamp; + + _type = other._type; + + _userId = other._userId; + + _appId = other._appId; + + _clusterId = other._clusterId; + + _propertyFlags = other._propertyFlags; + } + public BasicContentHeaderProperties() - { } + { + } public int getPropertyListSize() { diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java index c4220894a8..9a455ce868 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java @@ -84,7 +84,7 @@ public class FieldTable _encodedSize = length; } - public FieldTable(byte[] encodedForm, int offset, int length) throws IOException + public FieldTable(byte[] encodedForm, int offset, int length) { this(); _encodedForm = encodedForm; @@ -858,7 +858,17 @@ public class FieldTable } } - return _encodedForm.clone(); + else if(_encodedFormOffset == 0 && _encodedSize == _encodedForm.length) + { + return _encodedForm.clone(); + } + else + { + byte[] encodedCopy = new byte[(int) _encodedSize]; + System.arraycopy(_encodedForm,_encodedFormOffset,encodedCopy,0,(int)_encodedSize); + return encodedCopy; + } + } public long getEncodedSize() diff --git a/qpid/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java b/qpid/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java index b2bcc1836e..8f1a1d0be0 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/properties/ConnectionStartProperties.java @@ -41,6 +41,9 @@ public class ConnectionStartProperties */ public static final String QPID_CLOSE_WHEN_NO_ROUTE = "qpid.close_when_no_route"; + public static final String QPID_MESSAGE_COMPRESSION_SUPPORTED = "qpid.message_compression_supported"; + + public static final String CLIENT_ID_0_10 = "clientName"; public static final String CLIENT_ID_0_8 = "instance"; diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java index 44cb30e735..99fc02c959 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java @@ -41,6 +41,7 @@ import javax.security.sasl.SaslClient; import javax.security.sasl.SaslServer; import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.properties.ConnectionStartProperties; import org.apache.qpid.transport.network.Assembler; import org.apache.qpid.transport.network.Disassembler; import org.apache.qpid.transport.network.InputHandler; @@ -78,6 +79,7 @@ public class Connection extends ConnectionInvoker private long _lastReadTime; private NetworkConnection _networkConnection; private FrameSizeObserver _frameSizeObserver; + private boolean _messageCompressionSupported; public enum State { NEW, CLOSED, OPENING, OPEN, CLOSING, CLOSE_RCVD, RESUMING } @@ -699,6 +701,7 @@ public class Connection extends ConnectionInvoker public void setServerProperties(final Map<String, Object> serverProperties) { _serverProperties = serverProperties == null ? Collections.<String, Object>emptyMap() : serverProperties; + _messageCompressionSupported = Boolean.parseBoolean(String.valueOf(_serverProperties.get(ConnectionStartProperties.QPID_MESSAGE_COMPRESSION_SUPPORTED))); } public Map<String, Object> getServerProperties() @@ -848,4 +851,9 @@ public class Connection extends ConnectionInvoker }; } } + + public boolean isMessageCompressionSupported() + { + return _messageCompressionSupported; + } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/util/ByteBufferInputStream.java b/qpid/java/common/src/main/java/org/apache/qpid/util/ByteBufferInputStream.java index b72b342187..14b804f8c0 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/util/ByteBufferInputStream.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/util/ByteBufferInputStream.java @@ -92,4 +92,9 @@ public class ByteBufferInputStream extends InputStream { return _buffer.remaining(); } + + @Override + public void close() + { + } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/util/GZIPUtils.java b/qpid/java/common/src/main/java/org/apache/qpid/util/GZIPUtils.java new file mode 100644 index 0000000000..b5ba0b29af --- /dev/null +++ b/qpid/java/common/src/main/java/org/apache/qpid/util/GZIPUtils.java @@ -0,0 +1,119 @@ +/* + * + * 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.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GZIPUtils +{ + private static final Logger LOGGER = LoggerFactory.getLogger(GZIPUtils.class); + + public static final String GZIP_CONTENT_ENCODING = "gzip"; + + + /** + * Return a new byte array with the compressed contents of the input buffer + * + * @param input byte buffer to compress + * @return a byte array containing the compressed data, or null if the input was null or there was an unexpected + * IOException while compressing + */ + public static byte[] compressBufferToArray(ByteBuffer input) + { + if(input != null) + { + try (ByteArrayOutputStream compressedBuffer = new ByteArrayOutputStream()) + { + try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(compressedBuffer)) + { + if (input.hasArray()) + { + gzipOutputStream.write(input.array(), + input.arrayOffset() + input.position(), + input.remaining()); + } + else + { + + byte[] data = new byte[input.remaining()]; + + input.duplicate().get(data); + + gzipOutputStream.write(data); + } + } + return compressedBuffer.toByteArray(); + } + catch (IOException e) + { + LOGGER.warn("Unexpected IOException when attempting to compress with gzip", e); + } + } + return null; + } + + public static byte[] uncompressBufferToArray(ByteBuffer contentBuffer) + { + if(contentBuffer != null) + { + try (ByteBufferInputStream input = new ByteBufferInputStream(contentBuffer)) + { + return uncompressStreamToArray(input); + } + } + else + { + return null; + } + } + + public static byte[] uncompressStreamToArray(InputStream stream) + { + if(stream != null) + { + try (GZIPInputStream gzipInputStream = new GZIPInputStream(stream)) + { + ByteArrayOutputStream inflatedContent = new ByteArrayOutputStream(); + int read; + byte[] buf = new byte[4096]; + while ((read = gzipInputStream.read(buf)) != -1) + { + inflatedContent.write(buf, 0, read); + } + return inflatedContent.toByteArray(); + } + catch (IOException e) + { + + LOGGER.warn("Unexpected IOException when attempting to uncompress with gzip", e); + } + } + return null; + } +} diff --git a/qpid/java/common/src/test/java/org/apache/qpid/util/GZIPUtilsTest.java b/qpid/java/common/src/test/java/org/apache/qpid/util/GZIPUtilsTest.java new file mode 100644 index 0000000000..60e80da15f --- /dev/null +++ b/qpid/java/common/src/test/java/org/apache/qpid/util/GZIPUtilsTest.java @@ -0,0 +1,102 @@ +/* + * + * 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.util; + + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; + +import junit.framework.TestCase; + +public class GZIPUtilsTest extends TestCase +{ + public void testCompressUncompress() throws Exception + { + byte[] data = new byte[1024]; + Arrays.fill(data, (byte)'a'); + byte[] compressed = GZIPUtils.compressBufferToArray(ByteBuffer.wrap(data)); + assertTrue("Compression didn't compress", compressed.length < data.length); + byte[] uncompressed = GZIPUtils.uncompressBufferToArray(ByteBuffer.wrap(compressed)); + assertTrue("Compression not reversible", Arrays.equals(data,uncompressed)); + } + + public void testUncompressNonZipReturnsNull() throws Exception + { + byte[] data = new byte[1024]; + Arrays.fill(data, (byte)'a'); + assertNull("Non zipped data should not uncompress", GZIPUtils.uncompressBufferToArray(ByteBuffer.wrap(data))); + } + + public void testUncompressStreamWithErrorReturnsNull() throws Exception + { + InputStream is = new InputStream() + { + @Override + public int read() throws IOException + { + throw new IOException(); + } + }; + assertNull("Stream error should return null", GZIPUtils.uncompressStreamToArray(is)); + } + + + public void testUncompressNullStreamReturnsNull() throws Exception + { + assertNull("Null Stream should return null", GZIPUtils.uncompressStreamToArray(null)); + } + public void testUncompressNullBufferReturnsNull() throws Exception + { + assertNull("Null buffer should return null", GZIPUtils.uncompressBufferToArray(null)); + } + + public void testCompressNullArrayReturnsNull() + { + assertNull(GZIPUtils.compressBufferToArray(null)); + } + + public void testNonHeapBuffers() throws Exception + { + + byte[] data = new byte[1024]; + Arrays.fill(data, (byte)'a'); + ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); + directBuffer.put(data); + directBuffer.flip(); + + byte[] compressed = GZIPUtils.compressBufferToArray(directBuffer); + + assertTrue("Compression didn't compress", compressed.length < data.length); + + directBuffer.clear(); + directBuffer.position(1); + directBuffer = directBuffer.slice(); + directBuffer.put(compressed); + directBuffer.flip(); + + byte[] uncompressed = GZIPUtils.uncompressBufferToArray(directBuffer); + + assertTrue("Compression not reversible", Arrays.equals(data,uncompressed)); + + } +} diff --git a/qpid/java/pom.xml b/qpid/java/pom.xml index b30472ce88..1be2ce0f95 100644 --- a/qpid/java/pom.xml +++ b/qpid/java/pom.xml @@ -54,6 +54,7 @@ <qpid.home.qbtc.output>${qpid.home}${file.separator}target${file.separator}qbtc-output</qpid.home.qbtc.output> <!-- override for broker tests --> <qpid.work>${project.build.directory}${file.separator}QPID_WORK</qpid.work> + <argLine /> <profile>java-mms.0-10</profile> <profile.broker.language>java</profile.broker.language> <profile.broker.type>internal</profile.broker.type> diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/MessageCompressionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/MessageCompressionTest.java new file mode 100644 index 0000000000..e1fca306ce --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/MessageCompressionTest.java @@ -0,0 +1,236 @@ +/* + * + * 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.systest; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.NamingException; + +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.systest.rest.RestTestHelper; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.url.URLSyntaxException; + +public class MessageCompressionTest extends QpidBrokerTestCase +{ + private RestTestHelper _restTestHelper = new RestTestHelper(findFreePort()); + + @Override + public void setUp() throws Exception + { + // do nothing - only call setup after props set + } + + public void doActualSetUp() throws Exception + { + // use webadmin account to perform tests + _restTestHelper.setUsernameAndPassword("webadmin", "webadmin"); + + TestBrokerConfiguration config = getBrokerConfiguration(); + config.addHttpManagementConfiguration(); + config.setObjectAttribute(Port.class, + TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, + Port.PORT, + _restTestHelper.getHttpPort()); + + config.setObjectAttribute(AuthenticationProvider.class, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, + "secureOnlyMechanisms", + "{}"); + + // set password authentication provider on http port for the tests + config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + config.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + + super.setUp(); + } + + @Override + protected void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + _restTestHelper.tearDown(); + } + } + + public void testSenderCompressesReceiverUncompresses() throws Exception + { + doTestCompression(true, true, true); + } + + public void testSenderCompressesOnly() throws Exception + { + doTestCompression(true, false, true); + + } + + public void testReceiverUncompressesOnly() throws Exception + { + doTestCompression(false, true, true); + + } + + public void testNoCompression() throws Exception + { + doTestCompression(false, false, true); + + } + + + public void testDisablingCompressionAtBroker() throws Exception + { + doTestCompression(true, true, false); + } + + + private void doTestCompression(final boolean senderCompresses, + final boolean receiverUncompresses, + final boolean brokerCompressionEnabled) throws Exception + { + + setTestSystemProperty(Broker.BROKER_MESSAGE_COMPRESSION_ENABLED, String.valueOf(brokerCompressionEnabled)); + + doActualSetUp(); + + String messageText = createMessageText(); + Connection senderConnection = getConnection(senderCompresses); + String virtualPath = getConnectionFactory().getVirtualPath(); + String testQueueName = getTestQueueName(); + + // create the queue using REST and bind it + assertEquals(201, + _restTestHelper.submitRequest("/api/latest/queue" + + virtualPath + + virtualPath + + "/" + + testQueueName, "PUT", Collections.<String, Object>emptyMap())); + assertEquals(201, + _restTestHelper.submitRequest("/api/latest/binding" + + virtualPath + + virtualPath + + "/amq.direct/" + + testQueueName + + "/" + + testQueueName, "PUT", Collections.<String, Object>emptyMap())); + + Session session = senderConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // send a large message + MessageProducer producer = session.createProducer(getTestQueue()); + TextMessage sentMessage = session.createTextMessage(messageText); + sentMessage.setStringProperty("bar", "foo"); + + producer.send(sentMessage); + ((AMQSession)session).sync(); + + // get the number of bytes received at the broker on the connection + List<Map<String, Object>> connectionRestOutput = _restTestHelper.getJsonAsList("/api/latest/connection"); + assertEquals(1, connectionRestOutput.size()); + Map statistics = (Map) connectionRestOutput.get(0).get("statistics"); + int bytesIn = (Integer) statistics.get("bytesIn"); + + // if sending compressed then the bytesIn statistic for the connection should reflect the compressed size of the + // message + if(senderCompresses && brokerCompressionEnabled) + { + assertTrue("Message was not sent compressed", bytesIn < messageText.length()); + } + else + { + assertFalse("Message was incorrectly sent compressed", bytesIn < messageText.length()); + } + senderConnection.close(); + + // receive the message + Connection consumerConnection = getConnection(receiverUncompresses); + session = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(getTestQueue()); + consumerConnection.start(); + + TextMessage message = (TextMessage) consumer.receive(500l); + assertNotNull("Message was not received", message); + assertEquals("Message was corrupted", messageText, message.getText()); + assertEquals("Header was corrupted", "foo", message.getStringProperty("bar")); + + // get the number of bytes sent by the broker + connectionRestOutput = _restTestHelper.getJsonAsList("/api/latest/connection"); + assertEquals(1, connectionRestOutput.size()); + statistics = (Map) connectionRestOutput.get(0).get("statistics"); + int bytesOut = (Integer) statistics.get("bytesOut"); + + // if receiving compressed the bytes out statistic from the connection should reflect the compressed size of the + // message + if(receiverUncompresses && brokerCompressionEnabled) + { + assertTrue("Message was not received compressed", bytesOut < messageText.length()); + } + else + { + assertFalse("Message was incorrectly received compressed", bytesOut < messageText.length()); + } + + consumerConnection.close(); + } + + private String createMessageText() + { + StringBuilder stringBuilder = new StringBuilder(); + while(stringBuilder.length() < 2048*1024) + { + stringBuilder.append("This should compress easily. "); + } + return stringBuilder.toString(); + } + + private Connection getConnection(final boolean compress) throws URLSyntaxException, NamingException, JMSException + { + AMQConnectionURL url = new AMQConnectionURL(getConnectionFactory().getConnectionURLString()); + + url.setOption(ConnectionURL.OPTIONS_COMPRESS_MESSAGES,String.valueOf(compress)); + url = new AMQConnectionURL(url.toString()); + url.setUsername(GUEST_USERNAME); + url.setPassword(GUEST_PASSWORD); + url.setOption(ConnectionURL.OPTIONS_COMPRESS_MESSAGES,String.valueOf(compress)); + return getConnection(url); + } + +} |