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/16 09:57:13 UTC

svn commit: r1761017 - 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/management-http/src/main/java/resources/js/qpid/management/

Author: orudyy
Date: Fri Sep 16 09:57:13 2016
New Revision: 1761017

URL: http://svn.apache.org/viewvc?rev=1761017&view=rev
Log:
QPID-7409: [Java Broker, WMC] Address review comments

Added:
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/MessageContentJsonConverter.java
Removed:
    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/management-http/src/main/java/resources/js/qpid/management/showMessage.js

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=1761017&r1=1761016&r2=1761017&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 Fri Sep 16 09:57:13 2016
@@ -306,8 +306,12 @@ 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 = "returnJson", defaultValue = "true", description = "if true (default), converts message into json format") boolean returnJson);
+                              @Param(name = "limit", defaultValue = "-1",
+                                      description = "Number of bytes to return") long limit,
+                              @Param(name = "returnJson", defaultValue = "false",
+                                      description = "If true, converts message content into json format"
+                                                    + " if message mime-type is either amqp/map or amqp/list"
+                                                    + " or jms/map-message. Default is false.") 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=1761017&r1=1761016&r2=1761017&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 Fri Sep 16 09:57:13 2016
@@ -2691,19 +2691,105 @@ public abstract class AbstractQueue<X ex
         }
     }
 
-    class MessageContent implements Content, CustomRestHeaders, StreamingContent
+    abstract class BaseMessageContent implements Content
     {
-        private static final int UNLIMITED = -1;
-        private final MessageReference<?> _messageReference;
-        private final long _limit;
+        public static final int UNLIMITED = -1;
+        protected final MessageReference<?> _messageReference;
+        protected final long _limit;
 
-        MessageContent(MessageReference<?> messageReference, long limit)
+        BaseMessageContent(MessageReference<?> messageReference, long limit)
         {
             _messageReference = messageReference;
             _limit = limit;
         }
 
         @Override
+        public void release()
+        {
+            _messageReference.release();
+        }
+
+        public abstract String getContentType();
+
+        public String getContentDisposition()
+        {
+            try
+            {
+                String queueName = getName();
+                // replace all non-ascii and non-printable characters and all backslashes and percent encoded characters
+                // as suggested by rfc6266 Appendix D
+                String asciiQueueName = queueName.replaceAll("[^\\x20-\\x7E]", "?")
+                                                 .replace('\\', '?')
+                                                 .replaceAll("%[0-9a-fA-F]{2}", "?");
+                long messageNumber = _messageReference.getMessage().getMessageNumber();
+                String filenameExtension = _mimeTypeToFileExtension.get(getContentType());
+                filenameExtension = (filenameExtension == null ? "" : filenameExtension);
+                String disposition = String.format("attachment; filename=\"%s_msg%09d%s\"; filename*=\"UTF-8''%s_msg%09d%s\"",
+                                                   asciiQueueName,
+                                                   messageNumber,
+                                                   filenameExtension,
+                                                   URLEncoder.encode(queueName, UTF8),
+                                                   messageNumber,
+                                                   filenameExtension);
+                return disposition;
+            }
+            catch (UnsupportedEncodingException e)
+            {
+                throw new RuntimeException("JVM does not support UTF8", e);
+            }
+        }
+    }
+
+    class JsonMessageContent extends BaseMessageContent implements CustomRestHeaders
+    {
+        private final InternalMessage _internalMessage;
+        private boolean _truncate = false;
+
+        JsonMessageContent(MessageReference<?> messageReference, InternalMessage message, long limit)
+        {
+            super(messageReference, limit);
+            _internalMessage = message;
+            _truncate = limit >= 0 && _messageReference.getMessage().getSize() > limit;
+        }
+
+        @Override
+        public void write(final OutputStream outputStream) throws IOException
+        {
+            Object messageBody = _internalMessage.getMessageBody();
+            new MessageContentJsonConverter(messageBody, _truncate ? _limit : UNLIMITED).convertAndWrite(outputStream);
+        }
+
+        @SuppressWarnings("unused")
+        @RestContentHeader("X-Content-Truncated")
+        public String getContentTruncated()
+        {
+            return String.valueOf(_truncate);
+        }
+
+        @SuppressWarnings("unused")
+        @RestContentHeader("Content-Type")
+        public String getContentType()
+        {
+            return "application/json";
+        }
+
+        @SuppressWarnings("unused")
+        @RestContentHeader("Content-Disposition")
+        public String getContentDisposition()
+        {
+            return super.getContentDisposition();
+        }
+    }
+
+    class MessageContent extends BaseMessageContent implements CustomRestHeaders, StreamingContent
+    {
+
+        MessageContent(MessageReference<?> messageReference, long limit)
+        {
+            super(messageReference, limit);
+        }
+
+        @Override
         public void write(OutputStream outputStream) throws IOException
         {
             ServerMessage message = _messageReference.getMessage();
@@ -2754,30 +2840,7 @@ public abstract class AbstractQueue<X ex
         @RestContentHeader("Content-Disposition")
         public String getContentDisposition()
         {
-            try
-            {
-                String queueName = getName();
-                // replace all non-ascii and non-printable characters and all backslashes and percent encoded characters
-                // as suggested by rfc6266 Appendix D
-                String asciiQueueName = queueName.replaceAll("[^\\x20-\\x7E]", "?")
-                                                 .replace('\\', '?')
-                                                 .replaceAll("%[0-9a-fA-F]{2}", "?");
-                long messageNumber = _messageReference.getMessage().getMessageNumber();
-                String filenameExtension = _mimeTypeToFileExtension.get(getContentType());
-                filenameExtension = (filenameExtension == null ? "" : filenameExtension);
-                String disposition = String.format("attachment; filename=\"%s_msg%09d%s\"; filename*=\"UTF-8''%s_msg%09d%s\"",
-                                                   asciiQueueName,
-                                                   messageNumber,
-                                                   filenameExtension,
-                                                   URLEncoder.encode(queueName, UTF8),
-                                                   messageNumber,
-                                                   filenameExtension);
-                return disposition;
-            }
-            catch (UnsupportedEncodingException e)
-            {
-                throw new RuntimeException("JVM does not support UTF8", e);
-            }
+            return super.getContentDisposition();
         }
 
         @Override
@@ -3585,9 +3648,9 @@ public abstract class AbstractQueue<X ex
     {
         final MessageContentFinder messageFinder = new MessageContentFinder(messageId);
         visit(messageFinder);
-        if(messageFinder.isFound())
+        if (messageFinder.isFound())
         {
-            return createMessageContent((MessageReference) messageFinder.getMessageReference(), limit);
+            return createMessageContent(messageFinder.getMessageReference(), returnJson, limit);
         }
         else
         {
@@ -3595,17 +3658,19 @@ public abstract class AbstractQueue<X ex
         }
     }
 
-    private Content createMessageContent(final MessageReference messageReference, final long limit)
+    private Content createMessageContent(final MessageReference<?> messageReference,
+                                         final boolean returnJson,
+                                         final long limit)
     {
         String mimeType = messageReference.getMessage().getMessageHeader().getMimeType();
-        if (("amqp/list".equalsIgnoreCase(mimeType)
-             || "amqp/map".equalsIgnoreCase(mimeType)
-             || "jms/map-message".equalsIgnoreCase(mimeType)))
+        if (returnJson && ("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);
+                return new JsonMessageContent(messageReference, (InternalMessage) message, limit);
             }
             else
             {
@@ -3613,8 +3678,7 @@ public abstract class AbstractQueue<X ex
                         MessageConverterRegistry.getConverter(message.getClass(), InternalMessage.class);
                 if (messageConverter != null)
                 {
-                    return new JsonMessageContent(getName(),
-                                                  messageReference,
+                    return new JsonMessageContent(messageReference,
                                                   (InternalMessage) messageConverter.convert(message, getVirtualHost()),
                                                   limit);
                 }

Added: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/MessageContentJsonConverter.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/MessageContentJsonConverter.java?rev=1761017&view=auto
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/MessageContentJsonConverter.java (added)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/MessageContentJsonConverter.java Fri Sep 16 09:57:13 2016
@@ -0,0 +1,183 @@
+/*
+ * 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.lang.reflect.Array;
+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;
+
+class MessageContentJsonConverter
+{
+    private static final int BRACKETS_COUNT = 2;
+    private static final int NULL_LENGTH = 4;
+    private static final String DOTS = "...";
+
+    private final ObjectMapper _objectMapper;
+    private final Object _messageBody;
+    private long _remaining;
+
+    MessageContentJsonConverter(Object messageBody, long limit)
+    {
+        _messageBody = messageBody;
+        _objectMapper = new ObjectMapper();
+        _remaining = limit;
+    }
+
+    public void convertAndWrite(OutputStream outputStream) throws IOException
+    {
+        Object messageBody = _messageBody;
+        if (_remaining >= 0)
+        {
+            messageBody = convertAndTruncate(_messageBody);
+        }
+        _objectMapper.writeValue(outputStream, messageBody);
+    }
+
+    private Object convertAndTruncate(final Object source) throws IOException
+    {
+        if (source == null)
+        {
+            _remaining = _remaining - NULL_LENGTH;
+            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())
+        {
+            _remaining = _remaining - _objectMapper.writeValueAsString(source).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));
+        }
+    }
+
+    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()) ;
+            String truncated =  source.substring(0, limit) + DOTS;
+            _remaining = _remaining - truncated.length();
+            return truncated;
+        }
+        else
+        {
+            return DOTS;
+        }
+    }
+
+    private Object copyCollection(final Collection source) throws IOException
+    {
+        _remaining = _remaining - BRACKETS_COUNT;
+        List copy = new LinkedList();
+        for (Object item : source)
+        {
+            if (_remaining > 0)
+            {
+                Object copiedItem = convertAndTruncate(item);
+                copy.add(copiedItem);
+                if (copy.size() > 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 copiedKey = convertAndTruncate(key);
+                Object copiedValue = convertAndTruncate(source.get(key));
+                copy.put(copiedKey, copiedValue);
+                _remaining = _remaining - 1; // colon character
+                if (copy.size() > 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++)
+        {
+            copy.add(Array.get(source, i));
+        }
+        return copyCollection(copy);
+    }
+
+}

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=1761017&r1=1761016&r2=1761017&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 Fri Sep 16 09:57:13 2016
@@ -172,7 +172,7 @@ define(["dojo/dom",
                     parent: modelObj,
                     type: modelObj.type
                 };
-                var parameters = {messageId: data.id, returnJson: true};
+                var parameters = {messageId: data.id};
                 var url = management.buildObjectURL(contentModelObj, parameters);
 
                 var href = query('a#message-download', this.dialogNode)[0];
@@ -194,7 +194,7 @@ define(["dojo/dom",
                         ? 'showing the first ' + limit + ' of ' + data.size + ' bytes'
                         : 'showing all ' + data.size + ' bytes');
                     var previewContent = query("#message-content-preview", preview)[0];
-                    var previewParameters = lang.mixin({limit: limit}, parameters);
+                    var previewParameters = lang.mixin({limit: limit, returnJson: true}, parameters);
                     management.load(contentModelObj, previewParameters, {
                             handleAs: "text",
                             headers: {"Content-Type": data.mimeType}



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