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