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    
018    package org.apache.geronimo.console.jmxmanager;
019    
020    import java.net.URI;
021    import java.net.URL;
022    import java.text.DateFormat;
023    import java.util.ArrayList;
024    import java.util.Arrays;
025    import java.util.Collection;
026    import java.util.Collections;
027    import java.util.Date;
028    import java.util.HashMap;
029    import java.util.Iterator;
030    import java.util.Map;
031    import java.util.Set;
032    import java.util.TreeMap;
033    
034    import javax.management.ObjectName;
035    import javax.management.j2ee.statistics.BoundaryStatistic;
036    import javax.management.j2ee.statistics.BoundedRangeStatistic;
037    import javax.management.j2ee.statistics.CountStatistic;
038    import javax.management.j2ee.statistics.RangeStatistic;
039    import javax.management.j2ee.statistics.Statistic;
040    import javax.management.j2ee.statistics.Stats;
041    import javax.management.j2ee.statistics.TimeStatistic;
042    
043    import org.apache.geronimo.console.util.TimeUtils;
044    import org.apache.geronimo.gbean.AbstractName;
045    import org.apache.geronimo.gbean.AbstractNameQuery;
046    import org.apache.geronimo.gbean.GAttributeInfo;
047    import org.apache.geronimo.gbean.GBeanInfo;
048    import org.apache.geronimo.gbean.GOperationInfo;
049    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
050    import org.apache.geronimo.kernel.GBeanNotFoundException;
051    import org.apache.geronimo.kernel.Kernel;
052    import org.apache.geronimo.kernel.KernelRegistry;
053    import org.directwebremoting.annotations.RemoteMethod;
054    import org.directwebremoting.annotations.RemoteProxy;
055    
056    /**
057     * The JMX manager helper
058     */
059    @RemoteProxy(name="JMXHelper")
060    public class JMXManagerHelper {
061        /** Used to return all MBeans */
062        private static final String ALL_MBEANS = "AllMBeans";
063        private static final String SERVICEMODULE_KEY = "ServiceModule";
064        private static final String GBEANINFO_ATTRIB = "GBeanInfo";
065        private static final String STATSPROVIDER_ATTRIB = "statisticsProvider";
066        private static final String STATS_ATTRIB = "stats";
067        
068    
069        private final Kernel kernel;
070    
071        /**
072         * Construct an JMX manager helper (default)
073         */
074        public JMXManagerHelper() {
075            kernel = KernelRegistry.getSingleKernel();
076        }
077    
078        /**
079         * List MBeans using a domain
080         */
081        public Collection listByDomain(String domain) {
082            Collection result = new ArrayList();
083            if ((domain == null) || (domain.trim().length() == 0)) {
084                return result;
085            }
086    
087            return listByPattern(domain + ":*");
088        }
089    
090        /**
091         * List MBeans containing a substring in its object name
092         */
093        @RemoteMethod
094        public Collection listBySubstring(String substring) {
095            Collection result = new ArrayList();
096            if ((substring == null) || (substring.trim().length() == 0)) {
097                return result;
098            }
099            
100            Collection abstractNames = getAbstractNames(substring);
101            for (Iterator it = abstractNames.iterator(); it.hasNext();) {
102                AbstractName aname = (AbstractName) it.next();
103                ObjectName oname = aname.getObjectName();
104                String[] pair = { aname.toString(), oname.toString() };
105                result.add(pair);
106            }
107            
108            return result;
109        }
110        
111        /**
112         * List MBeans using a pattern (ObjectName)
113         */
114        @RemoteMethod
115        public Collection listByPattern(String pattern) {
116            Collection result = new ArrayList();
117            if ((pattern == null) || (pattern.trim().length() == 0)) {
118                return result;
119            }
120    
121            try {
122                // TODO: Use AbstractNameQuery
123                // Uses Object names for query pattern to support
124                // domain searches. Can't find a way to do it using
125                // AbstractNameQuery.
126                Map abstractNames = getAbstractNames();
127                ObjectName onamePattern = new ObjectName(pattern);
128                Set beans = kernel.listGBeans(onamePattern);
129                for (Iterator it = beans.iterator(); it.hasNext();) {
130                    ObjectName oname = (ObjectName) it.next();
131                    AbstractName aname = (AbstractName) abstractNames.get(oname);
132                    String[] pair = { aname.toString(), oname.toString() };
133                    result.add(pair);
134                }
135            } catch (Exception e) {
136                // Malformed object name, just return what you have
137            }
138    
139            return result;
140        }
141    
142        /**
143         * List MBeans using J2EE type
144         */
145        @RemoteMethod
146        public Collection listByJ2EEType(String type) {
147            Collection result = new ArrayList();
148            Map m = null;
149    
150            if ((type == null) || (type.trim().length() == 0)) {
151                return result;
152            } else {
153                if (ALL_MBEANS.equalsIgnoreCase(type)) {
154                    m = Collections.EMPTY_MAP;
155                } else {
156                    m = Collections.singletonMap(NameFactory.J2EE_TYPE, type);
157                }
158            }
159    
160            AbstractNameQuery query = new AbstractNameQuery(null, m,
161                    Collections.EMPTY_SET);
162            Set beans = kernel.listGBeans(query);
163            for (Iterator it = beans.iterator(); it.hasNext();) {
164                AbstractName abstractName = (AbstractName) it.next();
165                ObjectName objectName = abstractName.getObjectName();
166                String[] pair = { abstractName.toString(), objectName.toString() };
167                result.add(pair);
168            }
169    
170            return result;
171        }
172    
173        /**
174         * Return all service modules
175         */
176        public Collection getServiceModules() {
177            Map svcModules = new TreeMap();
178            Collection svcModuleMBeans = getAbstractNames(SERVICEMODULE_KEY + '=');
179            for (Iterator it = svcModuleMBeans.iterator(); it.hasNext();) {
180                AbstractName aname = (AbstractName) it.next();
181                String svcModule = aname.getNameProperty(SERVICEMODULE_KEY);
182                if (!svcModules.containsKey(svcModule)) {
183                    svcModules.put(svcModule, null);
184                }
185            }
186    
187            return svcModules.keySet();
188        }
189    
190        /**
191         * Return abstract names containing a substring
192         */
193        private Collection getAbstractNames(String substring) {
194            Collection result = new ArrayList();
195            if ((substring == null) || (substring.trim().length() == 0)) {
196                return result;
197            }
198    
199            Map abstractNames = getAbstractNames();
200            for (Iterator it = abstractNames.keySet().iterator(); it.hasNext();) {
201                ObjectName oname = (ObjectName) it.next();
202                if (oname.toString().indexOf(substring) > 0) {
203                    AbstractName aname = (AbstractName) abstractNames.get(oname);
204                    result.add(aname);
205                }
206            }
207            
208            return result;
209        }
210    
211        /**
212         * Return all abstract names as a map
213         */
214        private Map getAbstractNames() {
215            Map abstractNames = new HashMap();
216            // Create Map (Key = ObjectName, Value = AbstractName)
217            AbstractNameQuery query = new AbstractNameQuery(null,
218                    Collections.EMPTY_MAP, Collections.EMPTY_SET);
219            Set allBeans = kernel.listGBeans(query);
220            for (Iterator it = allBeans.iterator(); it.hasNext();) {
221                AbstractName abstractName = (AbstractName) it.next();
222                ObjectName objectName = abstractName.getObjectName();
223                abstractNames.put(objectName, abstractName);
224            }
225    
226            return abstractNames;
227        }
228    
229        /**
230         * Return MBean attributes
231         */
232        @RemoteMethod
233        public Collection getAttributes(String abstractName) {
234            Map attributes = new TreeMap();
235            try {
236                AbstractName aname = new AbstractName(URI.create(abstractName));
237                GBeanInfo info = kernel.getGBeanInfo(aname);
238                Set attribs = info.getAttributes();
239                for (Iterator i = attribs.iterator(); i.hasNext();) {
240                    GAttributeInfo attribInfo = (GAttributeInfo) i.next();
241                    // Don't include 'GBeanInfo' attributes
242                    String attribName = attribInfo.getName();
243                    if (!GBEANINFO_ATTRIB.equals(attribName)) {
244                        Map attribInfoMap = getAttribInfoAsMap(aname, attribInfo);
245                        attributes.put(attribName, attribInfoMap);
246                    }
247                }
248            } catch (GBeanNotFoundException e) {
249                // GBean not found, just ignore
250            }
251    
252            return attributes.values();
253        }
254    
255        /**
256         * Return attribute info as map
257         */
258        private Map getAttribInfoAsMap(AbstractName abstractName,
259                GAttributeInfo attribInfo) {
260            Map map = new TreeMap();
261            String attribName = attribInfo.getName();
262            map.put("name", attribName);
263            map.put("getterName", attribInfo.getGetterName());
264            map.put("setterName", attribInfo.getSetterName());
265            map.put("type", attribInfo.getType());
266            map.put("manageable", String.valueOf(attribInfo.isManageable()));
267            map.put("persistent", String.valueOf(attribInfo.isPersistent()));
268            map.put("readable", String.valueOf(attribInfo.isReadable()));
269            map.put("writable", String.valueOf(attribInfo.isWritable()));
270            if (attribInfo.isReadable()) {
271                String attribValue = "";
272                try {
273                    Object value = kernel.getAttribute(abstractName, attribName);
274                    if (value != null) {
275                        if (value instanceof String[]) {
276                            attribValue = Arrays.asList((String[]) value)
277                                    .toString();
278                        } else {
279                            attribValue = value.toString();
280                        }
281                    }
282                } catch (Exception e) {
283                    // GBean or attribute not found, just ignore
284                    attribValue = "** EXCEPTION: " + e;
285                }
286                map.put("value", attribValue);
287            }
288            return map;
289        }
290    
291        /**
292         * Return MBean operations
293         */
294        @RemoteMethod
295        public Collection getOperations(String abstractName) {
296            Map operations = new TreeMap();
297            try {
298                AbstractName aname = new AbstractName(URI.create(abstractName));
299                GBeanInfo info = kernel.getGBeanInfo(aname);
300                Set opers = info.getOperations();
301                for (Iterator i = opers.iterator(); i.hasNext();) {
302                    GOperationInfo operInfo = (GOperationInfo) i.next();
303                    Map operInfoMap = getOperInfoAsMap(operInfo);
304                    String operName = (String) operInfoMap.get("name");
305                    operations.put(operName, operInfoMap);
306                }
307            } catch (Exception e) {
308                // GBean not found, just ignore
309            }
310    
311            return operations.values();
312        }
313    
314        /**
315         * Return operation info as map
316         */
317        private Map getOperInfoAsMap(GOperationInfo operInfo) {
318            Map map = new TreeMap();
319            map.put("methodName", operInfo.getMethodName());
320            map.put("name", operInfo.getName());
321            map.put("parameterList", operInfo.getParameterList());
322            return map;
323        }
324    
325        /**
326         * Return MBean basic info
327         */
328        @RemoteMethod
329        public Collection getMBeanInfo(String abstractName) {
330            Collection info = new ArrayList();
331            try {
332                AbstractName aname = new AbstractName(URI.create(abstractName));
333                info.add(new String[] { "abstractName", aname.toString() });
334                ObjectName oname = aname.getObjectName();
335                info.add(new String[] { "objectName", oname.toString() });
336                GBeanInfo beanInfo = kernel.getGBeanInfo(aname);
337                String className = beanInfo.getClassName();
338                info.add(new String[] { "className", className });
339                String domain = oname.getDomain();
340                info.add(new String[] { "domain", domain });
341                String j2eeType = beanInfo.getJ2eeType();
342                info.add(new String[] { "j2eeType", j2eeType });
343                // String sourceClass = beanInfo.getSourceClass();
344                // info.add(new String[] { "sourceClass", sourceClass });
345            } catch (Exception e) {
346                // GBean not found, just ignore
347            }
348    
349            return info;
350        }
351    
352        /**
353         * Return all MBeans that provide stats
354         */
355        @RemoteMethod
356        public Collection getStatsProvidersMBeans() {
357            Collection result = new ArrayList();
358    
359            Object[] allMBeans = listByPattern("*:*").toArray();
360            for (int i = 0; i < allMBeans.length; i++) {
361                try {
362                    String[] mbean = (String[]) allMBeans[i];
363                    AbstractName abstractName = new AbstractName(URI
364                            .create(mbean[0]));
365                    Boolean statisticsProvider = (Boolean) kernel.getAttribute(
366                            abstractName, "statisticsProvider");
367                    if (Boolean.TRUE.equals(statisticsProvider)) {
368                        result.add(mbean);
369                    }
370                } catch (Exception e) {
371                    // ignore
372                }
373            }
374    
375            return result;
376        }
377    
378        /**
379         * Return MBean stats
380         */
381        @RemoteMethod
382        public Collection getMBeanStats(String abstractName) {
383            Map mbeanStats = new TreeMap();
384            try {
385                AbstractName aname = new AbstractName(URI.create(abstractName));
386                Boolean statisticsProvider = (Boolean) kernel.getAttribute(aname,
387                        STATSPROVIDER_ATTRIB);
388                Stats stats = (Stats) kernel.getAttribute(aname, STATS_ATTRIB);
389                if (statisticsProvider.booleanValue() == true && (stats != null)) {
390                    String[] statisticNames = stats.getStatisticNames();
391                    for (int i = 0; i < statisticNames.length; i++) {
392                        Statistic statistic = stats.getStatistic(statisticNames[i]);
393    
394                        Collection mbeanStat = new ArrayList();
395                        String name = statistic.getName();
396                        mbeanStat.add(new String[] { "Name", name });
397                        String className = statistic.getClass().getName();
398                        // mbeanStat.add(new String[] { "Type", className });
399                        mbeanStat.add(new String[] { "Description",
400                                statistic.getDescription() });
401                        mbeanStat.add(new String[] { "Unit", statistic.getUnit() });
402                        Date startTime = new Date(statistic.getStartTime());
403                        mbeanStat.add(new String[] { "Start Time",
404                                startTime.toString() });
405                        Date lastSampleTime = new Date(statistic
406                                .getLastSampleTime());
407                        mbeanStat.add(new String[] { "Last Sample Time",
408                                lastSampleTime.toString() });
409    
410                        if (statistic instanceof CountStatistic) {
411                            CountStatistic cStat = (CountStatistic) statistic;
412                            long count = cStat.getCount();
413                            mbeanStat.add(new String[] { "Count",
414                                    Long.toString(count) });
415                        } else if (statistic instanceof TimeStatistic) {
416                            TimeStatistic tStat = (TimeStatistic) statistic;
417                            long count = tStat.getCount();
418                            mbeanStat.add(new String[] { "Count",
419                                    Long.toString(count) });
420                            String maxTime = TimeUtils.formatDuration(tStat.getMaxTime());
421                            mbeanStat.add(new String[] { "Max Time",
422                                    maxTime });
423                            String minTime = TimeUtils.formatDuration(tStat.getMinTime());
424                            mbeanStat.add(new String[] { "Min Time",
425                                    minTime });
426                            long totalTime = tStat.getTotalTime();
427                            mbeanStat.add(new String[] { "Total Time",
428                                    Long.toString(totalTime) });
429                        } else if (statistic instanceof BoundedRangeStatistic) {
430                            BoundedRangeStatistic brStat = (BoundedRangeStatistic) statistic;
431                            long upperBound = brStat.getUpperBound();
432                            mbeanStat.add(new String[] { "Upper Bound",
433                                    Long.toString(upperBound) });
434                            long lowerBound = brStat.getLowerBound();
435                            mbeanStat.add(new String[] { "Lower Bound",
436                                    Long.toString(lowerBound) });
437                            long highWaterMark = brStat.getHighWaterMark();
438                            mbeanStat.add(new String[] { "High Water Mark",
439                                    Long.toString(highWaterMark) });
440                            long lowWaterMark = brStat.getLowWaterMark();
441                            mbeanStat.add(new String[] { "Low Water Mark",
442                                    Long.toString(lowWaterMark) });
443                            long current = brStat.getCurrent();
444                            mbeanStat.add(new String[] { "Current",
445                                    Long.toString(current) });
446                        } else if (statistic instanceof BoundaryStatistic) {
447                            BoundaryStatistic bStat = (BoundaryStatistic) statistic;
448                            long upperBound = bStat.getUpperBound();
449                            mbeanStat.add(new String[] { "Upper Bound",
450                                    Long.toString(upperBound) });
451                            long lowerBound = bStat.getLowerBound();
452                            mbeanStat.add(new String[] { "Lower Bound",
453                                    Long.toString(lowerBound) });
454                        } else if (statistic instanceof RangeStatistic) {
455                            RangeStatistic rStat = (RangeStatistic) statistic;
456                            long highWaterMark = rStat.getHighWaterMark();
457                            mbeanStat.add(new String[] { "High Water Mark",
458                                    Long.toString(highWaterMark) });
459                            long lowWaterMark = rStat.getLowWaterMark();
460                            mbeanStat.add(new String[] { "Low Water Mark",
461                                    Long.toString(lowWaterMark) });
462                            long current = rStat.getCurrent();
463                            mbeanStat.add(new String[] { "Current",
464                                    Long.toString(current) });
465                        }
466    
467                        mbeanStats.put(name, mbeanStat);
468                    }
469                }
470            } catch (Exception e) {
471                // GBean not found, just ignore
472            }
473    
474            return mbeanStats.values();
475        }
476    
477        /**
478         * Invoke MBean operation with arguments
479         */
480        @RemoteMethod
481        public String[] invokeOperWithArgs(String abstractName, String methodName,
482                String[] args, String[] types) {
483            String[] result = new String[2]; // return method name & result
484            result[0] = methodName + "(...)";
485    
486            try {
487                Object[] newArgs = processOperArgs(args, types);
488                AbstractName aname = new AbstractName(URI.create(abstractName));
489                Object res = kernel.invoke(aname, methodName, newArgs, types);
490                if (res != null) {
491                    result[1] = res.toString();
492                } else {
493                    result[1] = "<null>";
494                }
495            } catch (Exception e) {
496                result[1] = e.toString();
497            }
498    
499            return result;
500        }
501    
502        /**
503         * Invoke MBean operation without arguments
504         */
505        @RemoteMethod
506        public String[] invokeOperNoArgs(String abstractName, String methodName) {
507            String[] result = new String[2]; // return method name & result
508            result[0] = methodName + "()";
509    
510            try {
511                AbstractName aname = new AbstractName(URI.create(abstractName));
512                Object res = kernel.invoke(aname, methodName);
513                if (res != null) {
514                    result[1] = res.toString();
515                } else {
516                    result[1] = "<null>";
517                }
518            } catch (Exception e) {
519                result[1] = e.toString();
520            }
521    
522            return result;
523        }
524    
525        /**
526         * Process MBean operation arguments
527         */
528        private Object[] processOperArgs(String[] args, String[] types)
529                throws Exception {
530            // TODO: Modify this algorithm and add other classes
531            Object[] newArgs = new Object[args.length];
532            for (int i = 0; i < args.length; i++) {
533                String type = types[i];
534                String arg = args[i];
535                newArgs[i] = createObject(arg, type);
536            }
537    
538            return newArgs;
539        }
540    
541        /**
542         * Create MBean operation argument
543         */
544        private Object createObject(String arg, String type) throws Exception {
545            Object newArg = new Object();
546            if ("byte".equals(type) || "java.lang.Byte".equals(type)) {
547                newArg = new Byte(arg);
548            } else if ("short".equals(type) || "java.lang.Short".equals(type)) {
549                newArg = new Short(arg);
550            } else if ("int".equals(type) || "java.lang.Integer".equals(type)) {
551                newArg = new Integer(arg);
552            } else if ("long".equals(type) || "java.lang.Long".equals(type)) {
553                newArg = new Long(arg);
554            } else if ("float".equals(type) || "java.lang.Float".equals(type)) {
555                newArg = new Float(arg);
556            } else if ("double".equals(type) || "java.lang.Double".equals(type)) {
557                newArg = new Double(arg);
558            } else if ("char".equals(type) || "java.lang.Character".equals(type)) {
559                newArg = new Character(arg.charAt(0));
560            } else if ("boolean".equals(type) || "java.lang.Boolean".equals(type)) {
561                newArg = new Boolean(arg);
562            } else if ("java.lang.String".equals(type)) {
563                newArg = arg;
564            } else if ("java.lang.Object".equals(type)) {
565                newArg = arg;
566            } else if ("java.util.Date".equals(type)) {
567                newArg = DateFormat.getInstance().parse(arg);
568            } else if ("java.net.URL".equals(type)) {
569                newArg = new URL(arg);
570            } else if ("java.net.URI".equals(type)) {
571                newArg = new URI(arg);
572            } else if ("javax.management.ObjectName".equals(type)) {
573                newArg = new ObjectName(arg);
574            } else if ("org.apache.geronimo.gbean.AbstractName".equals(type)) {
575                newArg = new AbstractName(URI.create(arg));
576            } else {
577                // Unknown type, throw exception
578                String errorMsg = "Can't create instance of '" + type + "' using '"
579                        + arg + "'.";
580                throw new IllegalArgumentException(errorMsg);
581            }
582    
583            return newArg;
584        }
585    
586        /**
587         * Set MBean attribute value
588         */
589        public String[] setAttribute(String abstractName, String attribName,
590                String attribValue, String attribType) {
591            String[] result = new String[2]; // return attribute name & result
592            result[0] = attribName;
593            result[1] = "<SUCCESS>"; 
594            
595            try {
596                AbstractName aname = new AbstractName(URI.create(abstractName));
597                Object newAttribValue = createObject(attribValue, attribType);
598                kernel.setAttribute(aname, attribName, newAttribValue);
599            } catch (Exception e) {
600                result[1] = e.toString();
601            }
602    
603            return result;
604        }
605    
606    }