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