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 */
017package org.apache.activemq.console.command;
018
019import org.apache.activemq.console.util.JmxMBeansUtil;
020
021import java.util.*;
022
023public class QueryCommand extends AbstractJmxCommand {
024    // Predefined type=identifier query
025    private static final Properties PREDEFINED_OBJNAME_QUERY = new Properties();
026
027    static {
028        PREDEFINED_OBJNAME_QUERY.setProperty("Broker", "type=Broker,brokerName=%1");
029        PREDEFINED_OBJNAME_QUERY.setProperty("Connection", "type=Broker,connector=clientConnectors,connectionName=%1,*");
030        PREDEFINED_OBJNAME_QUERY.setProperty("Connector", "type=Broker,brokerName=*,connector=clientConnectors,connectorName=%1");
031        PREDEFINED_OBJNAME_QUERY.setProperty("NetworkConnector", "type=Broker,brokerName=%1,connector=networkConnectors,networkConnectorName=*");
032        PREDEFINED_OBJNAME_QUERY.setProperty("Queue", "type=Broker,brokerName=*,destinationType=Queue,destinationName=%1");
033        PREDEFINED_OBJNAME_QUERY.setProperty("Topic", "type=Broker,brokerName=*,destinationType=Topic,destinationName=%1,*");
034    };
035
036    protected String[] helpFile = new String[] {
037        "Task Usage: Main query [query-options]",
038        "Description: Display selected broker component's attributes and statistics.",
039        "",
040        "Query Options:",
041        "    -Q<type>=<name>               Add to the search list the specific object type matched",
042        "                                  by the defined object identifier.",
043        "    -xQ<type>=<name>              Remove from the search list the specific object type",
044        "                                  matched by the object identifier.",
045        "    --objname <query>             Add to the search list objects matched by the query similar",
046        "                                  to the JMX object name format.",
047        "    --xobjname <query>            Remove from the search list objects matched by the query",
048        "                                  similar to the JMX object name format.",
049        "    --view <attr1>,<attr2>,...    Select the specific attribute of the object to view.",
050        "                                  By default all attributes will be displayed.",
051        "    --jmxurl <url>                Set the JMX URL to connect to.",
052        "    --pid <pid>                   Set the pid to connect to (only on Sun JVM).",            
053        "    --jmxuser <user>              Set the JMX user used for authenticating.",
054        "    --jmxpassword <password>      Set the JMX password used for authenticating.",
055        "    --jmxlocal                    Use the local JMX server instead of a remote one.",
056        "    --version                     Display the version information.",
057        "    -h,-?,--help                  Display the query broker help information.",
058        "", "Examples:",
059        "    query",
060        "        - Print all the attributes of all registered objects queues, topics, connections, etc).",
061        "",
062        "    query -QQueue=TEST.FOO",
063        "        - Print all the attributes of the queue with destination name TEST.FOO.",
064        "",
065        "    query -QTopic=*",
066        "        - Print all the attributes of all registered topics.",
067        "",
068        "    query --view EnqueueCount,DequeueCount", 
069        "        - Print the attributes EnqueueCount and DequeueCount of all registered objects.",
070        "",
071        "    query -QTopic=* --view EnqueueCount,DequeueCount",
072        "        - Print the attributes EnqueueCount and DequeueCount of all registered topics.",
073        "",
074        "    query -QTopic=* -QQueue=* --view EnqueueCount,DequeueCount",
075        "        - Print the attributes EnqueueCount and DequeueCount of all registered topics and",
076        "          queues.",
077        "",
078        "    query -QTopic=* -xQTopic=ActiveMQ.Advisory.*", 
079        "        - Print all attributes of all topics except those that has a name that begins",
080        "          with \"ActiveMQ.Advisory\".",
081        "",
082        "    query --objname Type=*Connect*,BrokerName=local* -xQNetworkConnector=*",
083        "        - Print all attributes of all connectors, connections excluding network connectors",
084        "          that belongs to the broker that begins with local.", 
085        "", 
086        "    query -QQueue=* -xQQueue=????", 
087        "        - Print all attributes of all queues except those that are 4 letters long.",
088        "",
089    };
090
091    private final List<String> queryAddObjects = new ArrayList<String>(10);
092    private final List<String> querySubObjects = new ArrayList<String>(10);
093    private final Set queryViews = new LinkedHashSet();
094
095    @Override
096    public String getName() {
097        return "query";
098    }
099
100    @Override
101    public String getOneLineDescription() {
102        return "Display selected broker component's attributes and statistics.";
103    }
104
105    /**
106     * Queries the mbeans registered in the specified JMX context
107     * 
108     * @param tokens - command arguments
109     * @throws Exception
110     */
111    protected void runTask(List<String> tokens) throws Exception {
112        try {
113            // Query for the mbeans to add
114            Map<String,List> addMBeans = JmxMBeansUtil.queryMBeansAsMap(createJmxConnection(), queryAddObjects, queryViews);
115            // Query for the mbeans to sub
116            if (querySubObjects.size() > 0) {
117                Map<String,List> subMBeans = JmxMBeansUtil.queryMBeansAsMap(createJmxConnection(), querySubObjects, queryViews);
118                addMBeans.keySet().removeAll(subMBeans.keySet());
119            }
120            context.printMBean(JmxMBeansUtil.filterMBeansView(new ArrayList(addMBeans.values()), queryViews));
121        } catch (Exception e) {
122            context.printException(new RuntimeException("Failed to execute query task. Reason: " + e));
123            throw new Exception(e);
124        }
125    }
126
127    /**
128     * Handle the -Q, -xQ, --objname, --xobjname, --view options.
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 a additive predefined query define option
136        if (token.startsWith("-Q")) {
137            String key = token.substring(2);
138            String value = "";
139            int pos = key.indexOf("=");
140            if (pos >= 0) {
141                value = key.substring(pos + 1);
142                key = key.substring(0, pos);
143            }
144
145            // If additive query
146            String predefQuery = PREDEFINED_OBJNAME_QUERY.getProperty(key);
147            if (predefQuery == null) {
148                context.printException(new IllegalArgumentException("Unknown query object type: " + key));
149                return;
150            }
151            String queryStr = JmxMBeansUtil.createQueryString(predefQuery, value);
152            StringTokenizer queryTokens = new StringTokenizer(queryStr, COMMAND_OPTION_DELIMETER);
153            while (queryTokens.hasMoreTokens()) {
154                queryAddObjects.add(queryTokens.nextToken());
155            }
156        } else if (token.startsWith("-xQ")) {
157            // If token is a substractive predefined query define option
158            String key = token.substring(3);
159            String value = "";
160            int pos = key.indexOf("=");
161            if (pos >= 0) {
162                value = key.substring(pos + 1);
163                key = key.substring(0, pos);
164            }
165
166            // If subtractive query
167            String predefQuery = PREDEFINED_OBJNAME_QUERY.getProperty(key);
168            if (predefQuery == null) {
169                context.printException(new IllegalArgumentException("Unknown query object type: " + key));
170                return;
171            }
172            String queryStr = JmxMBeansUtil.createQueryString(predefQuery, value);
173            StringTokenizer queryTokens = new StringTokenizer(queryStr, COMMAND_OPTION_DELIMETER);
174            while (queryTokens.hasMoreTokens()) {
175                querySubObjects.add(queryTokens.nextToken());
176            }
177        } else if (token.startsWith("--objname")) {
178            // If token is an additive object name query option
179
180            // If no object name query is specified, or next token is a new
181            // option
182            if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) {
183                context.printException(new IllegalArgumentException("Object name query not specified"));
184                return;
185            }
186
187            StringTokenizer queryTokens = new StringTokenizer((String)tokens.remove(0), COMMAND_OPTION_DELIMETER);
188            while (queryTokens.hasMoreTokens()) {
189                queryAddObjects.add(queryTokens.nextToken());
190            }
191        } else if (token.startsWith("--xobjname")) {
192            // If token is a substractive object name query option
193
194            // If no object name query is specified, or next token is a new
195            // option
196            if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) {
197                context.printException(new IllegalArgumentException("Object name query not specified"));
198                return;
199            }
200
201            StringTokenizer queryTokens = new StringTokenizer((String)tokens.remove(0), COMMAND_OPTION_DELIMETER);
202            while (queryTokens.hasMoreTokens()) {
203                querySubObjects.add(queryTokens.nextToken());
204            }
205        } else if (token.startsWith("--view")) {
206            // If token is a view option
207
208            // If no view specified, or next token is a new option
209            if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) {
210                context.printException(new IllegalArgumentException("Attributes to view not specified"));
211                return;
212            }
213
214            // Add the attributes to view
215            Enumeration viewTokens = new StringTokenizer((String)tokens.remove(0), COMMAND_OPTION_DELIMETER);
216            while (viewTokens.hasMoreElements()) {
217                queryViews.add(viewTokens.nextElement());
218            }
219        } else {
220            // Let super class handle unknown option
221            super.handleOption(token, tokens);
222        }
223    }
224
225    /**
226     * Print the help messages for the browse command
227     */
228    protected void printHelp() {
229        context.printHelp(helpFile);
230    }
231
232}