/* * 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.tools.messagestore.commands; import org.apache.commons.codec.binary.Hex; import org.apache.qpid.server.queue.QueueEntryImpl; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.tools.messagestore.MessageStoreTool; import org.apache.qpid.tools.utils.Console; import java.io.UnsupportedEncodingException; import java.util.LinkedList; import java.util.List; public class Dump extends Show { private static final int LINE_SIZE = 8; private static final String DEFAULT_ENCODING = "utf-8"; private static final boolean SPACE_BYTES = true; private static final String BYTE_SPACER = " "; private static final String NON_PRINTING_ASCII_CHAR = "?"; protected boolean _content = true; public Dump(MessageStoreTool tool) { super(tool); } public String help() { return "Dump selected message content. Default: show=content"; } public String usage() { return getCommand() + " [show=[all],[msgheaders],[_amqHeaders],[routing],[content]] [id=]"; } public String getCommand() { return "dump"; } public void execute(String... args) { assert args.length > 0; assert args[0].equals(getCommand()); if (args.length >= 2) { for (String arg : args) { if (arg.startsWith("show=")) { _content = arg.contains("content") || arg.contains("all"); } } parseArgs(args); } performShow(); } protected List createMessageData(java.util.List msgids, List messages, boolean showHeaders, boolean showRouting, boolean showMessageHeaders) { List display = new LinkedList(); List hex = new LinkedList(); List ascii = new LinkedList(); display.add(hex); display.add(ascii); for (QueueEntry entry : messages) { ServerMessage msg = entry.getMessage(); if (!includeMsg(msg, msgids)) { continue; } //Add divider between messages hex.add(Console.ROW_DIVIDER); ascii.add(Console.ROW_DIVIDER); // Show general message information hex.add(Show.Columns.ID.name()); ascii.add(msg.getMessageNumber().toString()); hex.add(Console.ROW_DIVIDER); ascii.add(Console.ROW_DIVIDER); if (showRouting) { addShowInformation(hex, ascii, msg, "Routing Details", true, false, false); } if (showHeaders) { addShowInformation(hex, ascii, msg, "Headers", false, true, false); } if (showMessageHeaders) { addShowInformation(hex, ascii, msg, null, false, false, true); } // Add Content Body section hex.add("Content Body"); ascii.add(""); hex.add(Console.ROW_DIVIDER); ascii.add(Console.ROW_DIVIDER); final int messageSize = (int) msg.getSize(); if (messageSize != 0) { hex.add("Hex"); hex.add(Console.ROW_DIVIDER); ascii.add("ASCII"); ascii.add(Console.ROW_DIVIDER); java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(64 * 1024); int position = 0; while(position < messageSize) { position += msg.getContent(buf, position); buf.flip(); //Duplicate so we don't destroy original data :) java.nio.ByteBuffer hexBuffer = buf; java.nio.ByteBuffer charBuffer = hexBuffer.duplicate(); Hex hexencoder = new Hex(); while (hexBuffer.hasRemaining()) { byte[] line = new byte[LINE_SIZE]; int bufsize = hexBuffer.remaining(); if (bufsize < LINE_SIZE) { hexBuffer.get(line, 0, bufsize); } else { bufsize = line.length; hexBuffer.get(line); } byte[] encoded = hexencoder.encode(line); try { String encStr = new String(encoded, 0, bufsize * 2, DEFAULT_ENCODING); String hexLine = ""; int strLength = encStr.length(); for (int c = 0; c < strLength; c++) { hexLine += encStr.charAt(c); if ((c & 1) == 1 && SPACE_BYTES) { hexLine += BYTE_SPACER; } } hex.add(hexLine); } catch (UnsupportedEncodingException e) { _console.println(e.getMessage()); return null; } } while (charBuffer.hasRemaining()) { String asciiLine = ""; for (int pos = 0; pos < LINE_SIZE; pos++) { if (charBuffer.hasRemaining()) { byte ch = charBuffer.get(); if (isPrintable(ch)) { asciiLine += (char) ch; } else { asciiLine += NON_PRINTING_ASCII_CHAR; } if (SPACE_BYTES) { asciiLine += BYTE_SPACER; } } else { break; } } ascii.add(asciiLine); } buf.clear(); } } else { List result = new LinkedList(); display.add(result); result.add("No ContentBodies"); } } // if hex is empty then we have no data to display if (hex.size() == 0) { return null; } return display; } private void addShowInformation(List column1, List column2, ServerMessage msg, String title, boolean routing, boolean headers, boolean messageHeaders) { List single = new LinkedList(); single.add(new QueueEntryImpl(null,msg, Long.MIN_VALUE)); List routingData = super.createMessageData(null, single, headers, routing, messageHeaders); //Reformat data if (title != null) { column1.add(title); column2.add(""); column1.add(Console.ROW_DIVIDER); column2.add(Console.ROW_DIVIDER); } // look at all columns in the routing Data for (List item : routingData) { // the item should be: // Title // *divider // value // otherwise we can't reason about the correct value if (item.size() == 3) { //Filter out the columns we are not interested in. String columnName = item.get(0).toString(); if (!(columnName.equals(Show.Columns.ID.name()) || columnName.equals(Show.Columns.Size.name()))) { column1.add(columnName); column2.add(item.get(2).toString()); } } } column1.add(Console.ROW_DIVIDER); column2.add(Console.ROW_DIVIDER); } private boolean isPrintable(byte c) { return c > 31 && c < 127; } }