001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.activemq.console.command; 018 019 import java.util.ArrayList; 020 import java.util.HashSet; 021 import java.util.Iterator; 022 import java.util.List; 023 import java.util.Set; 024 import java.util.StringTokenizer; 025 026 import javax.jms.Destination; 027 028 import org.apache.activemq.command.ActiveMQQueue; 029 import org.apache.activemq.command.ActiveMQTopic; 030 import org.apache.activemq.console.util.AmqMessagesUtil; 031 032 public class AmqBrowseCommand extends AbstractAmqCommand { 033 public static final String QUEUE_PREFIX = "queue:"; 034 public static final String TOPIC_PREFIX = "topic:"; 035 036 public static final String VIEW_GROUP_HEADER = "header:"; 037 public static final String VIEW_GROUP_CUSTOM = "custom:"; 038 public static final String VIEW_GROUP_BODY = "body:"; 039 040 protected String[] helpFile = new String[] { 041 "Task Usage: Main browse --amqurl <broker url> [browse-options] <destinations>", 042 "Description: Display selected destination's messages.", 043 "", 044 "Browse Options:", 045 " --amqurl <url> Set the broker URL to connect to.", 046 " --msgsel <msgsel1,msglsel2> Add to the search list messages matched by the query similar to", 047 " the messages selector format.", 048 " -V<header|custom|body> Predefined view that allows you to view the message header, custom", 049 " message header, or the message body.", 050 " --view <attr1>,<attr2>,... Select the specific attribute of the message to view.", 051 " --version Display the version information.", 052 " -h,-?,--help Display the browse broker help information.", 053 "", 054 "Examples:", 055 " Main browse --amqurl tcp://localhost:61616 FOO.BAR", 056 " - Print the message header, custom message header, and message body of all messages in the", 057 " queue FOO.BAR", 058 "", 059 " Main browse --amqurl tcp://localhost:61616 -Vheader,body queue:FOO.BAR", 060 " - Print only the message header and message body of all messages in the queue FOO.BAR", 061 "", 062 " Main browse --amqurl tcp://localhost:61616 -Vheader --view custom:MyField queue:FOO.BAR", 063 " - Print the message header and the custom field 'MyField' of all messages in the queue FOO.BAR", 064 "", 065 " Main browse --amqurl tcp://localhost:61616 --msgsel JMSMessageID='*:10',JMSPriority>5 FOO.BAR", 066 " - Print all the message fields that has a JMSMessageID in the header field that matches the", 067 " wildcard *:10, and has a JMSPriority field > 5 in the queue FOO.BAR", 068 " * To use wildcard queries, the field must be a string and the query enclosed in ''", 069 "", 070 }; 071 072 private final List<String> queryAddObjects = new ArrayList<String>(10); 073 private final List<String> querySubObjects = new ArrayList<String>(10); 074 private final Set<String> groupViews = new HashSet<String>(10); 075 private final Set queryViews = new HashSet(10); 076 077 /** 078 * Execute the browse command, which allows you to browse the messages in a 079 * given JMS destination 080 * 081 * @param tokens - command arguments 082 * @throws Exception 083 */ 084 protected void runTask(List tokens) throws Exception { 085 try { 086 // If no destination specified 087 if (tokens.isEmpty()) { 088 context.printException(new IllegalArgumentException("No JMS destination specified.")); 089 return; 090 } 091 092 // If no broker url specified 093 if (getBrokerUrl() == null) { 094 context.printException(new IllegalStateException("No broker url specified. Use the --amqurl option to specify a broker url.")); 095 return; 096 } 097 098 // Display the messages for each destination 099 for (Iterator i = tokens.iterator(); i.hasNext();) { 100 String destName = (String)i.next(); 101 Destination dest; 102 103 // If destination has been explicitly specified as a queue 104 if (destName.startsWith(QUEUE_PREFIX)) { 105 dest = new ActiveMQQueue(destName.substring(QUEUE_PREFIX.length())); 106 107 // If destination has been explicitly specified as a topic 108 } else if (destName.startsWith(TOPIC_PREFIX)) { 109 dest = new ActiveMQTopic(destName.substring(TOPIC_PREFIX.length())); 110 111 // By default destination is assumed to be a queue 112 } else { 113 dest = new ActiveMQQueue(destName); 114 } 115 116 // Query for the messages to view 117 List addMsgs = AmqMessagesUtil.getMessages(getBrokerUrl(), dest, queryAddObjects); 118 119 // Query for the messages to remove from view 120 if (querySubObjects.size() > 0) { 121 List subMsgs = AmqMessagesUtil.getMessages(getBrokerUrl(), dest, querySubObjects); 122 addMsgs.removeAll(subMsgs); 123 } 124 125 // Display the messages 126 context.printMessage(AmqMessagesUtil.filterMessagesView(addMsgs, groupViews, queryViews)); 127 } 128 129 } catch (Exception e) { 130 context.printException(new RuntimeException("Failed to execute browse task. Reason: " + e)); 131 throw new Exception(e); 132 } 133 } 134 135 /** 136 * Handle the --msgsel, --xmsgsel, --view, -V options. 137 * 138 * @param token - option token to handle 139 * @param tokens - succeeding command arguments 140 * @throws Exception 141 */ 142 protected void handleOption(String token, List tokens) throws Exception { 143 144 // If token is an additive message selector option 145 if (token.startsWith("--msgsel")) { 146 147 // If no message selector is specified, or next token is a new 148 // option 149 if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) { 150 context.printException(new IllegalArgumentException("Message selector not specified")); 151 return; 152 } 153 154 StringTokenizer queryTokens = new StringTokenizer((String)tokens.remove(0), COMMAND_OPTION_DELIMETER); 155 while (queryTokens.hasMoreTokens()) { 156 queryAddObjects.add(queryTokens.nextToken()); 157 } 158 } else if (token.startsWith("--xmsgsel")) { 159 // If token is a substractive message selector option 160 161 // If no message selector is specified, or next token is a new 162 // option 163 if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) { 164 context.printException(new IllegalArgumentException("Message selector not specified")); 165 return; 166 } 167 168 StringTokenizer queryTokens = new StringTokenizer((String)tokens.remove(0), COMMAND_OPTION_DELIMETER); 169 while (queryTokens.hasMoreTokens()) { 170 querySubObjects.add(queryTokens.nextToken()); 171 } 172 173 } else if (token.startsWith("--view")) { 174 // If token is a view option 175 176 // If no view specified, or next token is a new option 177 if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) { 178 context.printException(new IllegalArgumentException("Attributes to view not specified")); 179 return; 180 } 181 182 // Add the attributes to view 183 StringTokenizer viewTokens = new StringTokenizer((String)tokens.remove(0), COMMAND_OPTION_DELIMETER); 184 while (viewTokens.hasMoreTokens()) { 185 String viewToken = viewTokens.nextToken(); 186 187 // If view is explicitly specified to belong to the JMS header 188 if (viewToken.equals(VIEW_GROUP_HEADER)) { 189 queryViews.add(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + viewToken.substring(VIEW_GROUP_HEADER.length())); 190 191 // If view is explicitly specified to belong to the JMS 192 // custom header 193 } else if (viewToken.equals(VIEW_GROUP_CUSTOM)) { 194 queryViews.add(AmqMessagesUtil.JMS_MESSAGE_CUSTOM_PREFIX + viewToken.substring(VIEW_GROUP_CUSTOM.length())); 195 196 // If view is explicitly specified to belong to the JMS body 197 } else if (viewToken.equals(VIEW_GROUP_BODY)) { 198 queryViews.add(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + viewToken.substring(VIEW_GROUP_BODY.length())); 199 200 // If no view explicitly specified, let's check the view for 201 // each group 202 } else { 203 queryViews.add(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX + viewToken); 204 queryViews.add(AmqMessagesUtil.JMS_MESSAGE_CUSTOM_PREFIX + viewToken); 205 queryViews.add(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX + viewToken); 206 } 207 } 208 } else if (token.startsWith("-V")) { 209 // If token is a predefined group view option 210 String viewGroup = token.substring(2); 211 // If option is a header group view 212 if (viewGroup.equals("header")) { 213 groupViews.add(AmqMessagesUtil.JMS_MESSAGE_HEADER_PREFIX); 214 215 // If option is a custom header group view 216 } else if (viewGroup.equals("custom")) { 217 groupViews.add(AmqMessagesUtil.JMS_MESSAGE_CUSTOM_PREFIX); 218 219 // If option is a body group view 220 } else if (viewGroup.equals("body")) { 221 groupViews.add(AmqMessagesUtil.JMS_MESSAGE_BODY_PREFIX); 222 223 // Unknown group view 224 } else { 225 context.printInfo("Unknown group view: " + viewGroup + ". Ignoring group view option."); 226 } 227 } else { 228 // Let super class handle unknown option 229 super.handleOption(token, tokens); 230 } 231 } 232 233 /** 234 * Print the help messages for the browse command 235 */ 236 protected void printHelp() { 237 context.printHelp(helpFile); 238 } 239 240 }