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.Iterator; 021 import java.util.List; 022 import java.util.StringTokenizer; 023 024 import javax.management.MBeanServerConnection; 025 import javax.management.ObjectInstance; 026 import javax.management.ObjectName; 027 import javax.management.openmbean.CompositeData; 028 import javax.management.remote.JMXConnector; 029 030 import org.apache.activemq.console.util.JmxMBeansUtil; 031 032 public class PurgeCommand extends AbstractJmxCommand { 033 034 protected String[] helpFile = new String[] { 035 "Task Usage: Main purge [browse-options] <destinations>", 036 "Description: Delete selected destination's messages that matches the message selector.", 037 "", 038 "Browse Options:", 039 " --msgsel <msgsel1,msglsel2> Add to the search list messages matched by the query similar to", 040 " the messages selector format.", 041 " --jmxurl <url> Set the JMX URL to connect to.", 042 " --jmxuser <user> Set the JMX user used for authenticating.", 043 " --jmxpassword <password> Set the JMX password used for authenticating.", 044 " --jmxlocal Use the local JMX server instead of a remote one.", 045 " --version Display the version information.", 046 " -h,-?,--help Display the browse broker help information.", 047 "", 048 "Examples:", 049 " Main purge FOO.BAR", 050 " - Delete all the messages in queue FOO.BAR", 051 052 " Main purge --msgsel JMSMessageID='*:10',JMSPriority>5 FOO.*", 053 " - Delete all the messages in the destinations that matches FOO.* and has a JMSMessageID in", 054 " the header field that matches the wildcard *:10, and has a JMSPriority field > 5 in the", 055 " queue FOO.BAR", 056 " * To use wildcard queries, the field must be a string and the query enclosed in ''", 057 "", 058 }; 059 060 private final List<String> queryAddObjects = new ArrayList<String>(10); 061 private final List<String> querySubObjects = new ArrayList<String>(10); 062 063 /** 064 * Execute the purge command, which allows you to purge the messages in a 065 * given JMS destination 066 * 067 * @param tokens - command arguments 068 * @throws Exception 069 */ 070 protected void runTask(List<String> tokens) throws Exception { 071 try { 072 // If there is no queue name specified, let's select all 073 if (tokens.isEmpty()) { 074 tokens.add("*"); 075 } 076 077 // Iterate through the queue names 078 for (Iterator<String> i = tokens.iterator(); i.hasNext();) { 079 List queueList = JmxMBeansUtil.queryMBeans(createJmxConnection(), "Type=Queue,Destination=" + i.next() + ",*"); 080 081 for (Iterator j = queueList.iterator(); j.hasNext();) { 082 ObjectName queueName = ((ObjectInstance)j.next()).getObjectName(); 083 if (queryAddObjects.isEmpty()) { 084 purgeQueue(queueName); 085 } else { 086 List messages = JmxMBeansUtil.createMessageQueryFilter(createJmxConnection(), queueName).query(queryAddObjects); 087 purgeMessages(queueName, messages); 088 } 089 } 090 } 091 } catch (Exception e) { 092 context.printException(new RuntimeException("Failed to execute purge task. Reason: " + e)); 093 throw new Exception(e); 094 } 095 } 096 097 /** 098 * Purge all the messages in the queue 099 * 100 * @param queue - ObjectName of the queue to purge 101 * @throws Exception 102 */ 103 public void purgeQueue(ObjectName queue) throws Exception { 104 context.printInfo("Purging all messages in queue: " + queue.getKeyProperty("Destination")); 105 createJmxConnection().invoke(queue, "purge", new Object[] {}, new String[] {}); 106 } 107 108 /** 109 * Purge selected messages in the queue 110 * 111 * @param queue - ObjectName of the queue to purge the messages from 112 * @param messages - List of messages to purge 113 * @throws Exception 114 */ 115 public void purgeMessages(ObjectName queue, List messages) throws Exception { 116 Object[] param = new Object[1]; 117 for (Iterator i = messages.iterator(); i.hasNext();) { 118 CompositeData msg = (CompositeData)i.next(); 119 param[0] = "" + msg.get("JMSMessageID"); 120 context.printInfo("Removing message: " + param[0] + " from queue: " + queue.getKeyProperty("Destination")); 121 createJmxConnection().invoke(queue, "removeMessage", param, new String[] { 122 "java.lang.String" 123 }); 124 } 125 } 126 127 /** 128 * Handle the --msgsel, --xmsgsel. 129 * 130 * @param token - option token to handle 131 * @param tokens - succeeding command arguments 132 * @throws Exception 133 */ 134 protected void handleOption(String token, List<String> tokens) throws Exception { 135 // If token is an additive message selector option 136 if (token.startsWith("--msgsel")) { 137 138 // If no message selector is specified, or next token is a new 139 // option 140 if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) { 141 context.printException(new IllegalArgumentException("Message selector not specified")); 142 return; 143 } 144 145 StringTokenizer queryTokens = new StringTokenizer((String)tokens.remove(0), COMMAND_OPTION_DELIMETER); 146 while (queryTokens.hasMoreTokens()) { 147 queryAddObjects.add(queryTokens.nextToken()); 148 } 149 } else if (token.startsWith("--xmsgsel")) { 150 // If token is a substractive message selector option 151 152 // If no message selector is specified, or next token is a new 153 // option 154 if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) { 155 context.printException(new IllegalArgumentException("Message selector not specified")); 156 return; 157 } 158 159 StringTokenizer queryTokens = new StringTokenizer((String)tokens.remove(0), COMMAND_OPTION_DELIMETER); 160 while (queryTokens.hasMoreTokens()) { 161 querySubObjects.add(queryTokens.nextToken()); 162 } 163 164 } else { 165 // Let super class handle unknown option 166 super.handleOption(token, tokens); 167 } 168 } 169 170 /** 171 * Print the help messages for the browse command 172 */ 173 protected void printHelp() { 174 context.printHelp(helpFile); 175 } 176 177 }