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.Enumeration;
021    import java.util.HashSet;
022    import java.util.List;
023    import java.util.Properties;
024    import java.util.Set;
025    import java.util.StringTokenizer;
026    
027    import org.apache.activemq.console.util.JmxMBeansUtil;
028    
029    public 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=Broker,connector=clientConnectors,connectionName=%1,*");
036            PREDEFINED_OBJNAME_QUERY.setProperty("Connector", "type=Broker,brokerName=*,connector=clientConnectors,connectorName=%1");
037            PREDEFINED_OBJNAME_QUERY.setProperty("NetworkConnector", "type=Broker,brokerName=%1,connector=networkConnectors,networkConnectorName=*");
038            PREDEFINED_OBJNAME_QUERY.setProperty("Queue", "type=Broker,brokerName=*,destinationType=Queue,destinationName=%1");
039            PREDEFINED_OBJNAME_QUERY.setProperty("Topic", "type=Broker,brokerName=*,destinationType=Topic,destinationName=%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        @Override
102        public String getName() {
103            return "query";
104        }
105    
106        @Override
107        public String getOneLineDescription() {
108            return "Display selected broker component's attributes and statistics.";
109        }
110    
111        /**
112         * Queries the mbeans registered in the specified JMX context
113         * 
114         * @param tokens - command arguments
115         * @throws Exception
116         */
117        protected void runTask(List<String> tokens) throws Exception {
118            try {
119                // Query for the mbeans to add
120                List addMBeans = JmxMBeansUtil.queryMBeans(createJmxConnection(), queryAddObjects, queryViews);
121    
122                // Query for the mbeans to sub
123                if (querySubObjects.size() > 0) {
124                    List subMBeans = JmxMBeansUtil.queryMBeans(createJmxConnection(), querySubObjects, queryViews);
125                    addMBeans.removeAll(subMBeans);
126                }
127    
128                context.printMBean(JmxMBeansUtil.filterMBeansView(addMBeans, queryViews));
129    
130            } catch (Exception e) {
131                context.printException(new RuntimeException("Failed to execute query task. Reason: " + e));
132                throw new Exception(e);
133            }
134        }
135    
136        /**
137         * Handle the -Q, -xQ, --objname, --xobjname, --view options.
138         * 
139         * @param token - option token to handle
140         * @param tokens - succeeding command arguments
141         * @throws Exception
142         */
143        protected void handleOption(String token, List<String> tokens) throws Exception {
144            // If token is a additive predefined query define option
145            if (token.startsWith("-Q")) {
146                String key = token.substring(2);
147                String value = "";
148                int pos = key.indexOf("=");
149                if (pos >= 0) {
150                    value = key.substring(pos + 1);
151                    key = key.substring(0, pos);
152                }
153    
154                // If additive query
155                String predefQuery = PREDEFINED_OBJNAME_QUERY.getProperty(key);
156                if (predefQuery == null) {
157                    context.printException(new IllegalArgumentException("Unknown query object type: " + key));
158                    return;
159                }
160                String queryStr = JmxMBeansUtil.createQueryString(predefQuery, value);
161                StringTokenizer queryTokens = new StringTokenizer(queryStr, COMMAND_OPTION_DELIMETER);
162                while (queryTokens.hasMoreTokens()) {
163                    queryAddObjects.add(queryTokens.nextToken());
164                }
165            } else if (token.startsWith("-xQ")) {
166                // If token is a substractive predefined query define option
167                String key = token.substring(3);
168                String value = "";
169                int pos = key.indexOf("=");
170                if (pos >= 0) {
171                    value = key.substring(pos + 1);
172                    key = key.substring(0, pos);
173                }
174    
175                // If subtractive query
176                String predefQuery = PREDEFINED_OBJNAME_QUERY.getProperty(key);
177                if (predefQuery == null) {
178                    context.printException(new IllegalArgumentException("Unknown query object type: " + key));
179                    return;
180                }
181                String queryStr = JmxMBeansUtil.createQueryString(predefQuery, value);
182                StringTokenizer queryTokens = new StringTokenizer(queryStr, COMMAND_OPTION_DELIMETER);
183                while (queryTokens.hasMoreTokens()) {
184                    querySubObjects.add(queryTokens.nextToken());
185                }
186            } else if (token.startsWith("--objname")) {
187                // If token is an additive object name query option
188    
189                // If no object name query is specified, or next token is a new
190                // option
191                if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) {
192                    context.printException(new IllegalArgumentException("Object name query not specified"));
193                    return;
194                }
195    
196                StringTokenizer queryTokens = new StringTokenizer((String)tokens.remove(0), COMMAND_OPTION_DELIMETER);
197                while (queryTokens.hasMoreTokens()) {
198                    queryAddObjects.add(queryTokens.nextToken());
199                }
200            } else if (token.startsWith("--xobjname")) {
201                // If token is a substractive object name query option
202    
203                // If no object name query is specified, or next token is a new
204                // option
205                if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) {
206                    context.printException(new IllegalArgumentException("Object name query not specified"));
207                    return;
208                }
209    
210                StringTokenizer queryTokens = new StringTokenizer((String)tokens.remove(0), COMMAND_OPTION_DELIMETER);
211                while (queryTokens.hasMoreTokens()) {
212                    querySubObjects.add(queryTokens.nextToken());
213                }
214            } else if (token.startsWith("--view")) {
215                // If token is a view option
216    
217                // If no view specified, or next token is a new option
218                if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) {
219                    context.printException(new IllegalArgumentException("Attributes to view not specified"));
220                    return;
221                }
222    
223                // Add the attributes to view
224                Enumeration viewTokens = new StringTokenizer((String)tokens.remove(0), COMMAND_OPTION_DELIMETER);
225                while (viewTokens.hasMoreElements()) {
226                    queryViews.add(viewTokens.nextElement());
227                }
228            } else {
229                // Let super class handle unknown option
230                super.handleOption(token, tokens);
231            }
232        }
233    
234        /**
235         * Print the help messages for the browse command
236         */
237        protected void printHelp() {
238            context.printHelp(helpFile);
239        }
240    
241    }