You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2016/09/08 17:27:56 UTC

svn commit: r1759867 - in /qpid/java/trunk: broker-core/src/main/java/org/apache/qpid/server/model/ broker-core/src/main/java/org/apache/qpid/server/queue/ broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ broker-pl...

Author: orudyy
Date: Thu Sep  8 17:27:55 2016
New Revision: 1759867

URL: http://svn.apache.org/viewvc?rev=1759867&view=rev
Log:
QPID-7409: [Java Broker, WMC] Add support to preview content of map and list messages in JSON format

Added:
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/JsonMessageContent.java
Modified:
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java
    qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_v0_10_to_Internal.java
    qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_v0_8_to_Internal.java
    qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/css/common.css
    qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js
    qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/showMessage.html
    qpid/java/trunk/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java
    qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/MessageCompressionTest.java
    qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java?rev=1759867&r1=1759866&r2=1759867&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java Thu Sep  8 17:27:55 2016
@@ -296,7 +296,8 @@ public interface Queue<X extends Queue<X
 
     @ManagedOperation(nonModifying = true, secure = true)
     Content getMessageContent(@Param(name = "messageId") long messageId,
-                              @Param(name = "limit", defaultValue = "-1", description = "Number of bytes to return") long limit);
+                              @Param(name = "limit", defaultValue = "-1", description = "Number of bytes to return") long limit,
+                              @Param(name = "returnJson", defaultValue = "true", description = "if true (default), converts message into json format") boolean returnJson);
 
     @ManagedOperation(nonModifying = true, paramRequiringSecure = "includeHeaders")
     List<MessageInfo> getMessageInfo(@Param(name = "first", defaultValue = "-1") int first,

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java?rev=1759867&r1=1759866&r2=1759867&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java Thu Sep  8 17:27:55 2016
@@ -83,11 +83,14 @@ import org.apache.qpid.server.message.Me
 import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.message.MessageReference;
 import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.message.internal.InternalMessage;
 import org.apache.qpid.server.model.*;
 import org.apache.qpid.server.model.preferences.GenericPrincipal;
+import org.apache.qpid.server.plugin.MessageConverter;
 import org.apache.qpid.server.plugin.MessageFilterFactory;
 import org.apache.qpid.server.plugin.QpidServiceLoader;
 import org.apache.qpid.server.protocol.AMQSessionModel;
+import org.apache.qpid.server.protocol.MessageConverterRegistry;
 import org.apache.qpid.server.security.access.Operation;
 import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
 import org.apache.qpid.server.store.MessageDurability;
@@ -3562,13 +3565,13 @@ public abstract class AbstractQueue<X ex
     }
 
     @Override
-    public Content getMessageContent(final long messageId, final long limit)
+    public Content getMessageContent(final long messageId, final long limit, boolean returnJson)
     {
         final MessageContentFinder messageFinder = new MessageContentFinder(messageId);
         visit(messageFinder);
         if(messageFinder.isFound())
         {
-            return new MessageContent(messageFinder.getMessageReference(), limit);
+            return createMessageContent((MessageReference) messageFinder.getMessageReference(), limit);
         }
         else
         {
@@ -3576,6 +3579,34 @@ public abstract class AbstractQueue<X ex
         }
     }
 
+    private Content createMessageContent(final MessageReference messageReference, final long limit)
+    {
+        String mimeType = messageReference.getMessage().getMessageHeader().getMimeType();
+        if (("amqp/list".equalsIgnoreCase(mimeType)
+             || "amqp/map".equalsIgnoreCase(mimeType)
+             || "jms/map-message".equalsIgnoreCase(mimeType)))
+        {
+            ServerMessage message = messageReference.getMessage();
+            if (message instanceof InternalMessage)
+            {
+                return new JsonMessageContent(getName(), messageReference, (InternalMessage) message, limit);
+            }
+            else
+            {
+                MessageConverter messageConverter =
+                        MessageConverterRegistry.getConverter(message.getClass(), InternalMessage.class);
+                if (messageConverter != null)
+                {
+                    return new JsonMessageContent(getName(),
+                                                  messageReference,
+                                                  (InternalMessage) messageConverter.convert(message, getVirtualHost()),
+                                                  limit);
+                }
+            }
+        }
+        return new MessageContent(messageReference, limit);
+    }
+
     @Override
     public List<MessageInfo> getMessageInfo(int first, int last, boolean includeHeaders)
     {

Added: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/JsonMessageContent.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/JsonMessageContent.java?rev=1759867&view=auto
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/JsonMessageContent.java (added)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/JsonMessageContent.java Thu Sep  8 17:27:55 2016
@@ -0,0 +1,259 @@
+/*
+ * 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.queue;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Array;
+import java.net.URLEncoder;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.google.common.base.CharMatcher;
+
+import org.apache.qpid.server.message.MessageReference;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.message.internal.InternalMessage;
+import org.apache.qpid.server.model.Content;
+import org.apache.qpid.server.model.CustomRestHeaders;
+import org.apache.qpid.server.model.RestContentHeader;
+
+class JsonMessageContent implements Content, CustomRestHeaders
+{
+    private static final int BRACKETS_COUNT = 2;
+    private static final int NULL_LENGTH = 4;
+    private static final String DOTS = "...";
+
+    private final InternalMessage _internalMessage;
+    private final MessageReference<?> _messageReference;
+    private final ObjectMapper _objectMapper;
+    private final String _queueName;
+    private final long _limit;
+    private long _remaining;
+
+    JsonMessageContent(String queueName, MessageReference<?> messageReference, InternalMessage message, long limit)
+    {
+        _queueName = queueName;
+        _messageReference = messageReference;
+        _internalMessage = message;
+        _objectMapper = new ObjectMapper();
+        _limit = limit;
+        _remaining = limit;
+    }
+
+    @Override
+    public void write(final OutputStream outputStream) throws IOException
+    {
+        Object messageBody = _internalMessage.getMessageBody();
+        if (_limit == -1 || _messageReference.getMessage().getSize() <= _limit)
+        {
+            _objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
+        }
+        else
+        {
+            messageBody= copyObject(messageBody);
+        }
+        _objectMapper.writeValue(outputStream, messageBody);
+    }
+
+    @Override
+    public void release()
+    {
+        _messageReference.release();
+    }
+
+    @SuppressWarnings("unused")
+    @RestContentHeader("Content-Type")
+    public String getContentType()
+    {
+        return "application/json";
+    }
+
+    @SuppressWarnings("unused")
+    @RestContentHeader("Content-Disposition")
+    public String getContentDisposition()
+    {
+        String queueName = _queueName;
+        boolean isAscii = CharMatcher.ASCII.matchesAllOf(queueName);
+        String asciiQueueName = isAscii ? queueName : queueName.replaceAll("\\P{InBasic_Latin}", "_");
+        String disposition = String.format("attachment; filename=\"%s\"",
+                                           getDispositionFileName(asciiQueueName, _internalMessage));
+        if (!isAscii)
+        {
+            try
+            {
+                disposition += "; filename*=UTF-8''"
+                               + URLEncoder.encode(getDispositionFileName(queueName, _internalMessage), "UTF-8");
+            }
+            catch (UnsupportedEncodingException e)
+            {
+                throw new RuntimeException("JVM does not support UTF8", e);
+            }
+        }
+        return disposition;
+    }
+
+    private String getDispositionFileName(String queueName, ServerMessage message)
+    {
+        return String.format("%s.message.%s", queueName, message.getMessageNumber())
+               + (message.getMessageHeader().getMimeType().startsWith("text") ? ".txt" : "");
+    }
+
+    private Object copyObject(final Object source) throws IOException
+    {
+        if (_remaining > 0)
+        {
+            if (source == null)
+            {
+                return null;
+            }
+            else if (source instanceof String || source instanceof Character)
+            {
+                return copyString(String.valueOf(source));
+            }
+            else if (source instanceof Number || source instanceof Boolean || source.getClass().isPrimitive())
+            {
+                String value = _objectMapper.writeValueAsString(source);
+                _remaining = _remaining - value.length();
+                return source;
+            }
+            else if (source instanceof Map)
+            {
+                return copyMap((Map)source);
+            }
+            else if (source instanceof Collection)
+            {
+                return copyCollection((Collection) source);
+            }
+            else if (source instanceof UUID)
+            {
+                return copyString(source.toString());
+            }
+            else if (source.getClass().isArray())
+            {
+                return copyArray(source);
+            }
+            else
+            {
+                // other types are not supported by map and list messages
+                // the code execution should not really reach this point
+                // to play safe returning them as string
+                return copyString(String.valueOf(source));
+            }
+        }
+        return null;
+    }
+
+    private Object copyString(final String source) throws IOException
+    {
+        String value = _objectMapper.writeValueAsString(source);
+        if (_remaining >= value.length())
+        {
+            _remaining = _remaining - value.length();
+            return source;
+        }
+        else if (_remaining > 0)
+        {
+            int limit = Math.min((int) _remaining, source.length()) ;
+            _remaining = 0;
+            return source.substring(0, limit);
+        }
+        else
+        {
+            return DOTS;
+        }
+    }
+
+    private Object copyCollection(final Collection source) throws IOException
+    {
+        _remaining = _remaining - BRACKETS_COUNT;
+        List copy = new LinkedList();
+        for (Object key : source)
+        {
+            if (_remaining > 0)
+            {
+                Object copiedKey = copyObject(key);
+                if (copiedKey == null)
+                {
+                    _remaining = _remaining - NULL_LENGTH;
+                }
+                copy.add(copiedKey);
+                if (copy.size() > 0 && _remaining > 0)
+                {
+                    _remaining = _remaining - 1; // comma character
+                }
+            }
+            else
+            {
+                break;
+            }
+        }
+        return copy;
+    }
+
+    private Object copyMap(final Map source) throws IOException
+    {
+        _remaining = _remaining - BRACKETS_COUNT;
+        Map copy = new LinkedHashMap();
+        for (Object key : source.keySet())
+        {
+            if (_remaining > 0)
+            {
+                Object copiedValue = copyObject(source.get(key));
+                if (copiedValue != null && _remaining > 0)
+                {
+                    Object copiedKey = copyObject(key);
+                    copy.put(copiedKey, copiedValue);
+                    _remaining = _remaining - 1; // colon character
+                    if (copy.size() > 0 && _remaining > 0)
+                    {
+                        _remaining = _remaining - 1; // comma character
+                    }
+                }
+            }
+            else
+            {
+                break;
+            }
+        }
+        return copy;
+    }
+
+    private Object copyArray(final Object source) throws IOException
+    {
+        List copy = new LinkedList();
+        int length = Array.getLength(source);
+        for (int i = 0; i < length; i++)
+        {
+            Object value = Array.get(source, i);
+            copy.add(copyObject(value));
+        }
+        return copyCollection(copy);
+    }
+
+}

Modified: qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_v0_10_to_Internal.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_v0_10_to_Internal.java?rev=1759867&r1=1759866&r2=1759867&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_v0_10_to_Internal.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageConverter_v0_10_to_Internal.java Thu Sep  8 17:27:55 2016
@@ -41,6 +41,7 @@ import org.apache.qpid.transport.ReplyTo
 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;
 
 @PluggableService
 public class MessageConverter_v0_10_to_Internal implements MessageConverter<MessageTransferMessage, InternalMessage>
@@ -71,9 +72,18 @@ public class MessageConverter_v0_10_to_I
             total += len;
         }
 
+        String encoding = serverMessage.getMessageHeader().getEncoding();
+        byte[] uncompressed;
+        if (GZIPUtils.GZIP_CONTENT_ENCODING.equals(encoding)
+            && (uncompressed = GZIPUtils.uncompressBufferToArray(ByteBuffer.wrap(data))) != null)
+        {
+            data = uncompressed;
+            encoding =  null;
+        }
+
         Object body = convertMessageBody(mimeType, data);
         MessageProperties messageProps = serverMessage.getHeader().getMessageProperties();
-        AMQMessageHeader fixedHeader = new DelegatingMessageHeader(serverMessage.getMessageHeader(), messageProps == null ? null : messageProps.getReplyTo());
+        AMQMessageHeader fixedHeader = new DelegatingMessageHeader(serverMessage.getMessageHeader(), messageProps == null ? null : messageProps.getReplyTo(), encoding);
         return InternalMessage.convert(serverMessage.getMessageNumber(), serverMessage.isPersistent(), fixedHeader, body);
     }
 
@@ -81,12 +91,14 @@ public class MessageConverter_v0_10_to_I
     {
         private final AMQMessageHeader _delegate;
         private final ReplyTo _replyTo;
+        private final String _encoding;
 
 
-        private DelegatingMessageHeader(final AMQMessageHeader delegate, final ReplyTo replyTo)
+        private DelegatingMessageHeader(final AMQMessageHeader delegate, final ReplyTo replyTo, final String encoding)
         {
             _delegate = delegate;
             _replyTo = replyTo;
+            _encoding = encoding;
         }
 
         @Override
@@ -128,7 +140,7 @@ public class MessageConverter_v0_10_to_I
         @Override
         public String getEncoding()
         {
-            return _delegate.getEncoding();
+            return _encoding;
         }
 
         @Override

Modified: qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_v0_8_to_Internal.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_v0_8_to_Internal.java?rev=1759867&r1=1759866&r2=1759867&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_v0_8_to_Internal.java (original)
+++ qpid/java/trunk/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageConverter_v0_8_to_Internal.java Thu Sep  8 17:27:55 2016
@@ -20,7 +20,9 @@
  */
 package org.apache.qpid.server.protocol.v0_8;
 
+import java.io.ByteArrayOutputStream;
 import java.io.EOFException;
+import java.io.IOException;
 import java.net.URISyntaxException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -41,6 +43,7 @@ import org.apache.qpid.transport.codec.B
 import org.apache.qpid.typedmessage.TypedBytesContentReader;
 import org.apache.qpid.typedmessage.TypedBytesFormatException;
 import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.util.GZIPUtils;
 
 @PluggableService
 public class MessageConverter_v0_8_to_Internal implements MessageConverter<AMQMessage, InternalMessage>
@@ -71,10 +74,19 @@ public class MessageConverter_v0_8_to_In
             total += len;
         }
 
+        String encoding = serverMessage.getMessageHeader().getEncoding();
+        byte[] uncompressed;
+        if (GZIPUtils.GZIP_CONTENT_ENCODING.equals(encoding)
+            && (uncompressed = GZIPUtils.uncompressBufferToArray(ByteBuffer.wrap(data))) != null)
+        {
+            data = uncompressed;
+            encoding =  null;
+        }
+
         Object body = convertMessageBody(mimeType, data);
 
         return InternalMessage.convert(serverMessage.getMessageNumber(), serverMessage.isPersistent(),
-                new DelegatingMessageHeader(serverMessage.getMessageHeader()), body);
+                new DelegatingMessageHeader(serverMessage.getMessageHeader(), encoding), body);
     }
 
     private static class ReplyToComponents
@@ -132,10 +144,12 @@ public class MessageConverter_v0_8_to_In
     private static class DelegatingMessageHeader implements AMQMessageHeader
     {
         private final AMQMessageHeader _delegate;
+        private final String _encoding;
 
-        private DelegatingMessageHeader(final AMQMessageHeader delegate)
+        private DelegatingMessageHeader(final AMQMessageHeader delegate, String encoding)
         {
             _delegate = delegate;
+            _encoding = encoding;
         }
 
         @Override
@@ -177,7 +191,7 @@ public class MessageConverter_v0_8_to_In
         @Override
         public String getEncoding()
         {
-            return _delegate.getEncoding();
+            return _encoding;
         }
 
         @Override

Modified: qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/css/common.css
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/css/common.css?rev=1759867&r1=1759866&r2=1759867&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/css/common.css (original)
+++ qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/css/common.css Thu Sep  8 17:27:55 2016
@@ -458,6 +458,7 @@ td.advancedSearchField, col.autoWidth {
     width: auto;
 }
 
+.claro.qpid #message-content-preview textarea,
 .claro.qpid .formLabel-controlCell textarea,
 .claro.qpid .advancedSearchField textarea {
     width: 100%;
@@ -653,3 +654,13 @@ td.advancedSearchField, col.autoWidth {
     background-size: 1em;
 }
 
+#message-content-preview{
+    width: 100%;
+    height: 10.2em;
+}
+
+#message-content-preview .dgrid,
+#message-content-preview textarea
+{
+    height: 10em;
+}

Modified: qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js?rev=1759867&r1=1759866&r2=1759867&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js (original)
+++ qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/js/qpid/management/showMessage.js Thu Sep  8 17:27:55 2016
@@ -24,13 +24,19 @@ define(["dojo/dom",
         "dojo/_base/lang",
         "dojo/_base/array",
         "dojo/_base/event",
-        'dojo/_base/json',
+        'dojo/json',
         "dojo/query",
         "dojo/_base/connect",
         "qpid/common/properties",
         "dojox/html/entities",
         "qpid/common/util",
         "dojo/text!showMessage.html",
+        'dojo/_base/declare',
+        'dstore/Memory',
+        'dstore/Trackable',
+        "dgrid/OnDemandGrid",
+        "dgrid/extensions/DijitRegistry",
+        "dijit/form/SimpleTextarea",
         "dojo/domReady!"],
     function (dom,
               construct,
@@ -47,7 +53,12 @@ define(["dojo/dom",
               properties,
               entities,
               util,
-              template)
+              template,
+              declare,
+              Memory,
+              Trackable,
+              OnDemandGrid,
+              DijitRegistry)
     {
 
         function encode(val)
@@ -161,7 +172,7 @@ define(["dojo/dom",
                     parent: modelObj,
                     type: modelObj.type
                 };
-                var parameters = {messageId: data.id};
+                var parameters = {messageId: data.id, returnJson: true};
                 var url = management.buildObjectURL(contentModelObj, parameters);
 
                 var href = query('a#message-download', this.dialogNode)[0];
@@ -171,7 +182,10 @@ define(["dojo/dom",
                     management.download(contentModelObj, parameters);
                 });
 
-                if (data.mimeType && data.mimeType.match(/text\/.*/))
+                if (data.mimeType && (data.mimeType.match(/text\/.*/)
+                                      || data.mimeType === "amqp/list"
+                                      || data.mimeType === "amqp/map"
+                                      || data.mimeType === "jms/map-message"))
                 {
                     var limit = 1024;
                     preview.style.display = "block";
@@ -187,7 +201,65 @@ define(["dojo/dom",
                         })
                         .then(function (content)
                         {
-                            previewContent.innerHTML = encode(content);
+                            if (showMessage.previewWidget)
+                            {
+                                showMessage.previewWidget.destroyRecursive();
+                            }
+                            var widgetDiv = construct.create("div", null, previewContent, "last");
+                            var contentWidget = null;
+                            if (data.mimeType === "amqp/list"
+                                || data.mimeType === "amqp/map"
+                                || data.mimeType === "jms/map-message")
+                            {
+                                var contentData = json.parse(content);
+                                var columns, items = [];
+                                if (data.mimeType === "amqp/list")
+                                {
+                                    columns = {
+                                        value: {
+                                            label: 'Item'
+                                        }
+                                    };
+                                    for (var i = 0; i < contentData.length; i++)
+                                    {
+                                        items.push({id: i, value: json.stringify(contentData[i])});
+                                    }
+                                }
+                                else
+                                {
+                                    columns = {
+                                        id: {
+                                            label: 'Key'
+                                        },
+                                        value: {
+                                            label: 'Value'
+                                        }
+                                    };
+
+                                    for (var i in contentData)
+                                    {
+                                        items.push({id: i, value: json.stringify(contentData[i])});
+                                    }
+                                }
+                                var store = new (declare([Memory, Trackable]))({
+                                    data: items
+                                });
+                                 contentWidget = new (declare([OnDemandGrid,DijitRegistry]))({
+                                    collection: store,
+                                    columns: columns
+                                }, widgetDiv);
+
+                            }
+                            else
+                            {
+                                contentWidget = new dijit.form.SimpleTextarea({
+                                    value: content,
+                                    rows: 4,
+                                    readOnly: true
+                                }, widgetDiv);
+                            }
+                            showMessage.previewWidget = contentWidget;
+                            contentWidget.startup();
                             registry.byId("showMessage") .show();
                         });
                 }

Modified: qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/showMessage.html
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/showMessage.html?rev=1759867&r1=1759866&r2=1759867&view=diff
==============================================================================
--- qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/showMessage.html (original)
+++ qpid/java/trunk/broker-plugins/management-http/src/main/java/resources/showMessage.html Thu Sep  8 17:27:55 2016
@@ -89,9 +89,9 @@
                 <div class="confidential">
                     <a href="#" id="message-download">Download</a>
                     <br/>
-                    <div id="preview" class="fillRemaining">
+                    <div id="preview">
                         Preview (<span id="preview-detail"></span>):<br/>
-                        <textarea id="message-content-preview" readonly rows="5" style="width: 100%"></textarea>
+                        <div id="message-content-preview"></div>
                     </div>
                 </div>
                 <div class="confidentialPlaceholder highlightedText">Not available</div>

Modified: qpid/java/trunk/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java?rev=1759867&r1=1759866&r2=1759867&view=diff
==============================================================================
--- qpid/java/trunk/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java (original)
+++ qpid/java/trunk/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java Thu Sep  8 17:27:55 2016
@@ -371,6 +371,18 @@ public class RestTestHelper
         return response;
     }
 
+    public List<Object> getJsonAsSimpleList(String path) throws IOException
+    {
+        HttpURLConnection connection = openManagementConnection(path, "GET");
+        connection.connect();
+        byte[] data = readConnectionInputStream(connection);
+        ObjectMapper mapper = new ObjectMapper();
+        List<Object> providedObject = mapper.readValue(new ByteArrayInputStream(data), new TypeReference<List<Object>>()
+        {
+        });
+        return providedObject;
+    }
+
     public Map<String, Object> getJsonAsMap(String path) throws IOException
     {
         HttpURLConnection connection = openManagementConnection(path, "GET");

Modified: qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/MessageCompressionTest.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/MessageCompressionTest.java?rev=1759867&r1=1759866&r2=1759867&view=diff
==============================================================================
--- qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/MessageCompressionTest.java (original)
+++ qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/MessageCompressionTest.java Thu Sep  8 17:27:55 2016
@@ -26,18 +26,23 @@ import java.io.InputStream;
 import java.net.HttpURLConnection;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.zip.GZIPInputStream;
 
 import javax.jms.Connection;
 import javax.jms.JMSException;
+import javax.jms.MapMessage;
 import javax.jms.MessageConsumer;
 import javax.jms.MessageProducer;
 import javax.jms.Session;
 import javax.jms.TextMessage;
 import javax.naming.NamingException;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Maps;
+
 import org.apache.qpid.client.AMQConnectionURL;
 import org.apache.qpid.client.AMQSession;
 import org.apache.qpid.jms.ConnectionURL;
@@ -244,6 +249,85 @@ public class MessageCompressionTest exte
         return decompressInputStream(connection);
     }
 
+    public void testGetContentViaRestForCompressedMapMessageWithAgentNotSupportingCompression() throws Exception
+    {
+        setTestSystemProperty(Broker.BROKER_MESSAGE_COMPRESSION_ENABLED, String.valueOf(true));
+
+        doActualSetUp();
+
+        Connection senderConnection = getConnection(true);
+        String virtualPath = getConnectionFactory().getVirtualPath();
+        String testQueueName = getTestQueueName();
+        createAndBindQueue(virtualPath, testQueueName);
+
+        Map<String, Object> mapToSend = createMapToSend();
+        publishMapMessage(senderConnection, mapToSend);
+
+        String queueRelativePath = "queue" + virtualPath + virtualPath + "/" + testQueueName;
+
+        List<Map<String, Object>> messages = _restTestHelper.getJsonAsList(queueRelativePath + "/getMessageInfo");
+        assertEquals("Unexpected number of messages", 1, messages.size());
+        long id = ((Number) messages.get(0).get("id")).longValue();
+
+        Map<String, Object> content =
+                _restTestHelper.getJsonAsMap(queueRelativePath + "/getMessageContent?returnJson=true&messageId=" + id);
+        assertEquals("Unexpected message content: difference " + Maps.difference(mapToSend, content),
+                     new HashMap<>(mapToSend),
+                     new HashMap<>(content));
+    }
+
+    public void testGetContentViaRestForCompressedMapMessageWithAgentSupportingCompression() throws Exception
+    {
+        setTestSystemProperty(Broker.BROKER_MESSAGE_COMPRESSION_ENABLED, String.valueOf(true));
+
+        doActualSetUp();
+
+        Connection senderConnection = getConnection(true);
+        String virtualPath = getConnectionFactory().getVirtualPath();
+        String testQueueName = getTestQueueName();
+        createAndBindQueue(virtualPath, testQueueName);
+
+        Map<String, Object> mapToSend = createMapToSend();
+        publishMapMessage(senderConnection, mapToSend);
+
+        String queueRelativePath = "queue" + virtualPath + virtualPath + "/" + testQueueName;
+
+        List<Map<String, Object>> messages = _restTestHelper.getJsonAsList(queueRelativePath + "/getMessageInfo");
+        assertEquals("Unexpected number of messages", 1, messages.size());
+        long id = ((Number) messages.get(0).get("id")).longValue();
+
+        _restTestHelper.setAcceptEncoding("gzip, deflate, br");
+        HttpURLConnection connection =
+                _restTestHelper.openManagementConnection(queueRelativePath
+                                                         + "/getMessageContent?returnJson=true&messageId="
+                                                         + id,
+                                                         "GET");
+        connection.connect();
+
+        String content = decompressInputStream(connection);
+        Map<String, Object> mapContent = new ObjectMapper().readValue(content, Map.class);
+        assertEquals("Unexpected message content: difference " + Maps.difference(mapToSend, mapContent),
+                     new HashMap<>(mapToSend),
+                     new HashMap<>(mapContent));
+    }
+
+    private Map<String, Object> createMapToSend()
+    {
+        Map<String, Object> mapToSend = new HashMap<>();
+
+        String message = "This is a sample message";
+        int i = 0, l = message.length();
+        do
+        {
+            mapToSend.put("text" + i, message);
+            i++;
+        }
+        while (i * l < 2048 * 1024);
+
+        mapToSend.put("int", 1);
+        return mapToSend;
+    }
+
     private String decompressInputStream(final HttpURLConnection connection) throws IOException
     {
         String content;
@@ -261,12 +345,41 @@ public class MessageCompressionTest exte
         return content;
     }
 
+    private void publishMapMessage(final Connection senderConnection, final Map<String, Object> mapData)
+            throws JMSException, org.apache.qpid.QpidException
+    {
+        Session session = senderConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+        MessageProducer producer = session.createProducer(getTestQueue());
+        MapMessage sentMessage = session.createMapMessage();
+        sentMessage.setStringProperty("bar", "foo");
+        for(Map.Entry<String,Object> entry: mapData.entrySet())
+        {
+            String key =  entry.getKey();
+            Object value =  entry.getValue();
+            if (value instanceof String)
+            {
+                sentMessage.setString(key, (String) value);
+            }
+            else if (value instanceof Integer)
+            {
+                sentMessage.setInt(key, (Integer) value);
+            }
+            else
+            {
+                throw new RuntimeException("Setting value of type " + value.getClass() + " is not implemented yet");
+            }
+        }
+
+        producer.send(sentMessage);
+        ((AMQSession) session).sync();
+    }
+
     private void publishMessage(final Connection senderConnection, final String messageText)
             throws JMSException, org.apache.qpid.QpidException
     {
         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");

Modified: qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java?rev=1759867&r1=1759866&r2=1759867&view=diff
==============================================================================
--- qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java (original)
+++ qpid/java/trunk/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java Thu Sep  8 17:27:55 2016
@@ -33,11 +33,13 @@ import java.util.concurrent.TimeUnit;
 import javax.jms.Connection;
 import javax.jms.DeliveryMode;
 import javax.jms.Destination;
+import javax.jms.MapMessage;
 import javax.jms.Message;
 import javax.jms.MessageProducer;
 import javax.jms.Session;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.qpid.jms.ListMessage;
 import org.apache.qpid.server.model.Port;
 import org.apache.qpid.server.model.port.HttpPort;
 import org.apache.qpid.test.utils.TestBrokerConfiguration;
@@ -123,34 +125,60 @@ public class MessagesRestTest extends Qp
         _session.commit();
 
         // get message IDs
-        List<Long> ids = getMesssageIds(queueName);
-
-        List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("queue/test/test/" + queueName + "/getMessageInfo?first=0&last=0");
-        assertEquals("Unexpected message number returned", 1, messages.size());
-        Map<String, Object> message = messages.get(0);
-        assertMessageAttributes(message);
-        assertMessageAttributeValues(message, true);
-
-        int lastMessageId = ids.size() - 1;
-        messages = getRestTestHelper().getJsonAsList("queue/test/test/" + queueName + "/getMessageInfo?first=" + lastMessageId + "&last=" + lastMessageId);
-        assertEquals("Unexpected message number returned", 1, messages.size());
-        message = messages.get(0);
-        assertMessageAttributes(message);
-        assertEquals("Unexpected message attribute mimeType", "text/plain", message.get("mimeType"));
-        assertEquals("Unexpected message attribute size", STRING_VALUE.getBytes(StandardCharsets.UTF_8).length, message.get("size"));
+        Long lastMessageId = getLastMessageIdAndVerifyMimeType(queueName, "text/plain");
 
-        message = getRestTestHelper().getJsonAsMap("queue/test/test/" + queueName + "/getMessageInfoById?messageId=" + ids.get(lastMessageId));
+        Map<String, Object> message = getRestTestHelper().getJsonAsMap("queue/test/test/" + queueName + "/getMessageInfoById?messageId=" + lastMessageId);
         @SuppressWarnings("unchecked")
         Map<String, Object> messageHeader = (Map<String, Object>) message.get("headers");
         assertNotNull("Message headers are not found", messageHeader);
         assertEquals("Unexpected message header value", STRING_VALUE, messageHeader.get(STRING_PROP));
 
         // get content
-        byte[] data = getRestTestHelper().getBytes("queue/test/test/" + queueName + "/getMessageContent?messageId=" + ids.get(lastMessageId));
+        byte[] data = getRestTestHelper().getBytes("queue/test/test/" + queueName + "/getMessageContent?messageId=" + lastMessageId);
         assertTrue("Unexpected message for id " + lastMessageId + ":" + data.length, Arrays.equals(STRING_VALUE.getBytes(StandardCharsets.UTF_8), data));
 
     }
 
+    public void testGetMapMessageContentAsJson() throws Exception
+    {
+        String queueName = getTestQueueName();
+        MapMessage mapMessage = _session.createMapMessage();
+        mapMessage.setString("testStringProperty", "My String");
+        mapMessage.setInt("testIntProperty", 999999);
+        _producer.send(mapMessage);
+        _session.commit();
+
+        Long lastMessageId = getLastMessageIdAndVerifyMimeType(queueName, "amqp/map");
+
+        Map<String, Object> jsonMessageData = getRestTestHelper().getJsonAsMap("queue/test/test/"
+                                                                               + queueName
+                                                                               + "/getMessageContent?returnJson=true&messageId="
+                                                                               + lastMessageId);
+        assertEquals("Unexpected map content size", 2, jsonMessageData.size());
+        assertEquals("Unexpected testStringProperty", "My String", jsonMessageData.get("testStringProperty"));
+        assertEquals("Unexpected testIntProperty", 999999, jsonMessageData.get("testIntProperty"));
+    }
+
+    public void testGetListMessageContentAsJson() throws Exception
+    {
+        String queueName = getTestQueueName();
+        ListMessage listMessage = ((org.apache.qpid.jms.Session) _session).createListMessage();
+        listMessage.add(999999);
+        listMessage.add("My String");
+        _producer.send(listMessage);
+        _session.commit();
+
+        Long lastMessageId = getLastMessageIdAndVerifyMimeType(queueName, "amqp/list");
+
+        List<Object> jsonMessageData = getRestTestHelper().getJsonAsSimpleList("queue/test/test/"
+                                                                               + queueName
+                                                                               + "/getMessageContent?returnJson=true&messageId="
+                                                                               + lastMessageId);
+        assertEquals("Unexpected map content size", 2, jsonMessageData.size());
+        assertEquals("Unexpected value at index 1", "My String", jsonMessageData.get(1));
+        assertEquals("Unexpected value at index 0", 999999, jsonMessageData.get(0));
+    }
+
     public void testPostMoveMessages() throws Exception
     {
         String queueName = getTestQueueName();
@@ -509,4 +537,23 @@ public class MessagesRestTest extends Qp
         assertNotNull("Message priority cannot be null", message.get("priority"));
         assertNotNull("Message persistent cannot be null", message.get("persistent"));
     }
+
+
+    private Long getLastMessageIdAndVerifyMimeType(final String queueName, final String mimeType) throws IOException
+    {
+        List<Long> ids = getMesssageIds(queueName);
+        int lastMessageIndex = ids.size() - 1;
+        List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("queue/test/test/"
+                                                                               + queueName
+                                                                               + "/getMessageInfo?first="
+                                                                               + lastMessageIndex
+                                                                               + "&last="
+                                                                               + lastMessageIndex);
+        assertEquals("Unexpected message number returned", 1, messages.size());
+        Map<String, Object> message = messages.get(0);
+        assertEquals("Unexpected message attribute mimeType", mimeType, message.get("mimeType"));
+        assertMessageAttributes(message);
+
+        return ids.get(lastMessageIndex);
+    }
 }




---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org