jdk/src/java.management/share/classes/sun/management/DiagnosticCommandImpl.java
changeset 30365 551470085a1d
parent 30073 989253a902c3
parent 30364 429945d7189c
child 30366 74651100cf08
child 30664 337397328b72
equal deleted inserted replaced
30073:989253a902c3 30365:551470085a1d
     1 /*
       
     2  * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.management;
       
    27 
       
    28 import com.sun.management.DiagnosticCommandMBean;
       
    29 import java.lang.reflect.Constructor;
       
    30 import java.lang.reflect.InvocationTargetException;
       
    31 import java.security.Permission;
       
    32 import java.util.*;
       
    33 import javax.management.*;
       
    34 
       
    35 /**
       
    36  * Implementation class for the diagnostic commands subsystem.
       
    37  *
       
    38  * @since 1.8
       
    39  */
       
    40 class DiagnosticCommandImpl extends NotificationEmitterSupport
       
    41     implements DiagnosticCommandMBean {
       
    42 
       
    43     private final VMManagement jvm;
       
    44     private volatile Map<String, Wrapper> wrappers = null;
       
    45     private static final String strClassName = "".getClass().getName();
       
    46     private static final String strArrayClassName = String[].class.getName();
       
    47     private final boolean isSupported;
       
    48 
       
    49     @Override
       
    50     public Object getAttribute(String attribute) throws AttributeNotFoundException,
       
    51         MBeanException, ReflectionException {
       
    52         throw new AttributeNotFoundException(attribute);
       
    53     }
       
    54 
       
    55     @Override
       
    56     public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
       
    57         InvalidAttributeValueException, MBeanException, ReflectionException {
       
    58         throw new AttributeNotFoundException(attribute.getName());
       
    59     }
       
    60 
       
    61     @Override
       
    62     public AttributeList getAttributes(String[] attributes) {
       
    63         return new AttributeList();
       
    64     }
       
    65 
       
    66     @Override
       
    67     public AttributeList setAttributes(AttributeList attributes) {
       
    68         return new AttributeList();
       
    69     }
       
    70 
       
    71     private class Wrapper {
       
    72 
       
    73         String name;
       
    74         String cmd;
       
    75         DiagnosticCommandInfo info;
       
    76         Permission permission;
       
    77 
       
    78         Wrapper(String name, String cmd, DiagnosticCommandInfo info)
       
    79                 throws InstantiationException {
       
    80             this.name = name;
       
    81             this.cmd = cmd;
       
    82             this.info = info;
       
    83             this.permission = null;
       
    84             Exception cause = null;
       
    85             if (info.getPermissionClass() != null) {
       
    86                 try {
       
    87                     Class<?> c = Class.forName(info.getPermissionClass());
       
    88                     if (info.getPermissionAction() == null) {
       
    89                         try {
       
    90                             Constructor<?> constructor = c.getConstructor(String.class);
       
    91                             permission = (Permission) constructor.newInstance(info.getPermissionName());
       
    92 
       
    93                         } catch (InstantiationException | IllegalAccessException
       
    94                                 | IllegalArgumentException | InvocationTargetException
       
    95                                 | NoSuchMethodException | SecurityException ex) {
       
    96                             cause = ex;
       
    97                         }
       
    98                     }
       
    99                     if (permission == null) {
       
   100                         try {
       
   101                             Constructor<?> constructor = c.getConstructor(String.class, String.class);
       
   102                             permission = (Permission) constructor.newInstance(
       
   103                                     info.getPermissionName(),
       
   104                                     info.getPermissionAction());
       
   105                         } catch (InstantiationException | IllegalAccessException
       
   106                                 | IllegalArgumentException | InvocationTargetException
       
   107                                 | NoSuchMethodException | SecurityException ex) {
       
   108                             cause = ex;
       
   109                         }
       
   110                     }
       
   111                 } catch (ClassNotFoundException ex) { }
       
   112                 if (permission == null) {
       
   113                     InstantiationException iex =
       
   114                             new InstantiationException("Unable to instantiate required permission");
       
   115                     iex.initCause(cause);
       
   116                 }
       
   117             }
       
   118         }
       
   119 
       
   120         public String execute(String[] args) {
       
   121             if (permission != null) {
       
   122                 SecurityManager sm = System.getSecurityManager();
       
   123                 if (sm != null) {
       
   124                     sm.checkPermission(permission);
       
   125                 }
       
   126             }
       
   127             if(args == null) {
       
   128                 return executeDiagnosticCommand(cmd);
       
   129             } else {
       
   130                 StringBuilder sb = new StringBuilder();
       
   131                 sb.append(cmd);
       
   132                 for(int i=0; i<args.length; i++) {
       
   133                     if(args[i] == null) {
       
   134                         throw new IllegalArgumentException("Invalid null argument");
       
   135                     }
       
   136                     sb.append(" ");
       
   137                     sb.append(args[i]);
       
   138                 }
       
   139                 return executeDiagnosticCommand(sb.toString());
       
   140             }
       
   141         }
       
   142     }
       
   143 
       
   144     DiagnosticCommandImpl(VMManagement jvm) {
       
   145         this.jvm = jvm;
       
   146         isSupported = jvm.isRemoteDiagnosticCommandsSupported();
       
   147     }
       
   148 
       
   149     private static class OperationInfoComparator implements Comparator<MBeanOperationInfo> {
       
   150         @Override
       
   151         public int compare(MBeanOperationInfo o1, MBeanOperationInfo o2) {
       
   152             return o1.getName().compareTo(o2.getName());
       
   153         }
       
   154     }
       
   155 
       
   156     @Override
       
   157     public MBeanInfo getMBeanInfo() {
       
   158         SortedSet<MBeanOperationInfo> operations = new TreeSet<>(new OperationInfoComparator());
       
   159         Map<String, Wrapper> wrappersmap;
       
   160         if (!isSupported) {
       
   161             wrappersmap = Collections.emptyMap();
       
   162         } else {
       
   163             try {
       
   164                 String[] command = getDiagnosticCommands();
       
   165                 DiagnosticCommandInfo[] info = getDiagnosticCommandInfo(command);
       
   166                 MBeanParameterInfo stringArgInfo[] = new MBeanParameterInfo[]{
       
   167                     new MBeanParameterInfo("arguments", strArrayClassName,
       
   168                     "Array of Diagnostic Commands Arguments and Options")
       
   169                 };
       
   170                 wrappersmap = new HashMap<>();
       
   171                 for (int i = 0; i < command.length; i++) {
       
   172                     String name = transform(command[i]);
       
   173                     try {
       
   174                         Wrapper w = new Wrapper(name, command[i], info[i]);
       
   175                         wrappersmap.put(name, w);
       
   176                         operations.add(new MBeanOperationInfo(
       
   177                                 w.name,
       
   178                                 w.info.getDescription(),
       
   179                                 (w.info.getArgumentsInfo() == null
       
   180                                     || w.info.getArgumentsInfo().isEmpty())
       
   181                                     ? null : stringArgInfo,
       
   182                                 strClassName,
       
   183                                 MBeanOperationInfo.ACTION_INFO,
       
   184                                 commandDescriptor(w)));
       
   185                     } catch (InstantiationException ex) {
       
   186                         // If for some reasons the creation of a diagnostic command
       
   187                         // wrappers fails, the diagnostic command is just ignored
       
   188                         // and won't appear in the DynamicMBean
       
   189                     }
       
   190                 }
       
   191             } catch (IllegalArgumentException | UnsupportedOperationException e) {
       
   192                 wrappersmap = Collections.emptyMap();
       
   193             }
       
   194         }
       
   195         wrappers =  Collections.unmodifiableMap(wrappersmap);
       
   196         HashMap<String, Object> map = new HashMap<>();
       
   197         map.put("immutableInfo", "false");
       
   198         map.put("interfaceClassName","com.sun.management.DiagnosticCommandMBean");
       
   199         map.put("mxbean", "false");
       
   200         Descriptor desc = new ImmutableDescriptor(map);
       
   201         return new MBeanInfo(
       
   202                 this.getClass().getName(),
       
   203                 "Diagnostic Commands",
       
   204                 null, // attributes
       
   205                 null, // constructors
       
   206                 operations.toArray(new MBeanOperationInfo[operations.size()]), // operations
       
   207                 getNotificationInfo(), // notifications
       
   208                 desc);
       
   209     }
       
   210 
       
   211     @Override
       
   212     public Object invoke(String actionName, Object[] params, String[] signature)
       
   213             throws MBeanException, ReflectionException {
       
   214         if (!isSupported) {
       
   215             throw new UnsupportedOperationException();
       
   216         }
       
   217         if (wrappers == null) {
       
   218             getMBeanInfo();
       
   219         }
       
   220         Wrapper w = wrappers.get(actionName);
       
   221         if (w != null) {
       
   222             if (w.info.getArgumentsInfo().isEmpty()
       
   223                     && (params == null || params.length == 0)
       
   224                     && (signature == null || signature.length == 0)) {
       
   225                 return w.execute(null);
       
   226             } else if((params != null && params.length == 1)
       
   227                     && (signature != null && signature.length == 1
       
   228                     && signature[0] != null
       
   229                     && signature[0].compareTo(strArrayClassName) == 0)) {
       
   230                 return w.execute((String[]) params[0]);
       
   231             }
       
   232         }
       
   233         throw new ReflectionException(new NoSuchMethodException(actionName));
       
   234     }
       
   235 
       
   236     private static String transform(String name) {
       
   237         StringBuilder sb = new StringBuilder();
       
   238         boolean toLower = true;
       
   239         boolean toUpper = false;
       
   240         for (int i = 0; i < name.length(); i++) {
       
   241             char c = name.charAt(i);
       
   242             if (c == '.' || c == '_') {
       
   243                 toLower = false;
       
   244                 toUpper = true;
       
   245             } else {
       
   246                 if (toUpper) {
       
   247                     toUpper = false;
       
   248                     sb.append(Character.toUpperCase(c));
       
   249                 } else if(toLower) {
       
   250                     sb.append(Character.toLowerCase(c));
       
   251                 } else {
       
   252                     sb.append(c);
       
   253                 }
       
   254             }
       
   255         }
       
   256         return sb.toString();
       
   257     }
       
   258 
       
   259     private Descriptor commandDescriptor(Wrapper w) throws IllegalArgumentException {
       
   260         HashMap<String, Object> map = new HashMap<>();
       
   261         map.put("dcmd.name", w.info.getName());
       
   262         map.put("dcmd.description", w.info.getDescription());
       
   263         map.put("dcmd.vmImpact", w.info.getImpact());
       
   264         map.put("dcmd.permissionClass", w.info.getPermissionClass());
       
   265         map.put("dcmd.permissionName", w.info.getPermissionName());
       
   266         map.put("dcmd.permissionAction", w.info.getPermissionAction());
       
   267         map.put("dcmd.enabled", w.info.isEnabled());
       
   268         StringBuilder sb = new StringBuilder();
       
   269         sb.append("help ");
       
   270         sb.append(w.info.getName());
       
   271         map.put("dcmd.help", executeDiagnosticCommand(sb.toString()));
       
   272         if (w.info.getArgumentsInfo() != null && !w.info.getArgumentsInfo().isEmpty()) {
       
   273             HashMap<String, Object> allargmap = new HashMap<>();
       
   274             for (DiagnosticCommandArgumentInfo arginfo : w.info.getArgumentsInfo()) {
       
   275                 HashMap<String, Object> argmap = new HashMap<>();
       
   276                 argmap.put("dcmd.arg.name", arginfo.getName());
       
   277                 argmap.put("dcmd.arg.type", arginfo.getType());
       
   278                 argmap.put("dcmd.arg.description", arginfo.getDescription());
       
   279                 argmap.put("dcmd.arg.isMandatory", arginfo.isMandatory());
       
   280                 argmap.put("dcmd.arg.isMultiple", arginfo.isMultiple());
       
   281                 boolean isOption = arginfo.isOption();
       
   282                 argmap.put("dcmd.arg.isOption", isOption);
       
   283                 if(!isOption) {
       
   284                     argmap.put("dcmd.arg.position", arginfo.getPosition());
       
   285                 } else {
       
   286                     argmap.put("dcmd.arg.position", -1);
       
   287                 }
       
   288                 allargmap.put(arginfo.getName(), new ImmutableDescriptor(argmap));
       
   289             }
       
   290             map.put("dcmd.arguments", new ImmutableDescriptor(allargmap));
       
   291         }
       
   292         return new ImmutableDescriptor(map);
       
   293     }
       
   294 
       
   295     private final static String notifName =
       
   296         "javax.management.Notification";
       
   297 
       
   298     private final static String[] diagFramNotifTypes = {
       
   299         "jmx.mbean.info.changed"
       
   300     };
       
   301 
       
   302     private MBeanNotificationInfo[] notifInfo = null;
       
   303 
       
   304     @Override
       
   305     public MBeanNotificationInfo[] getNotificationInfo() {
       
   306         synchronized (this) {
       
   307             if (notifInfo == null) {
       
   308                  notifInfo = new MBeanNotificationInfo[1];
       
   309                  notifInfo[0] =
       
   310                          new MBeanNotificationInfo(diagFramNotifTypes,
       
   311                                                    notifName,
       
   312                                                    "Diagnostic Framework Notification");
       
   313             }
       
   314         }
       
   315         return notifInfo;
       
   316     }
       
   317 
       
   318     private static long seqNumber = 0;
       
   319     private static long getNextSeqNumber() {
       
   320         return ++seqNumber;
       
   321     }
       
   322 
       
   323     private void createDiagnosticFrameworkNotification() {
       
   324 
       
   325         if (!hasListeners()) {
       
   326             return;
       
   327         }
       
   328         ObjectName on = null;
       
   329         try {
       
   330             on = ObjectName.getInstance(ManagementFactoryHelper.HOTSPOT_DIAGNOSTIC_COMMAND_MBEAN_NAME);
       
   331         } catch (MalformedObjectNameException e) { }
       
   332         Notification notif = new Notification("jmx.mbean.info.changed",
       
   333                                               on,
       
   334                                               getNextSeqNumber());
       
   335         notif.setUserData(getMBeanInfo());
       
   336         sendNotification(notif);
       
   337     }
       
   338 
       
   339     @Override
       
   340     public synchronized void addNotificationListener(NotificationListener listener,
       
   341             NotificationFilter filter,
       
   342             Object handback) {
       
   343         boolean before = hasListeners();
       
   344         super.addNotificationListener(listener, filter, handback);
       
   345         boolean after = hasListeners();
       
   346         if (!before && after) {
       
   347             setNotificationEnabled(true);
       
   348         }
       
   349     }
       
   350 
       
   351     @Override
       
   352     public synchronized void removeNotificationListener(NotificationListener listener)
       
   353             throws ListenerNotFoundException {
       
   354         boolean before = hasListeners();
       
   355         super.removeNotificationListener(listener);
       
   356         boolean after = hasListeners();
       
   357         if (before && !after) {
       
   358             setNotificationEnabled(false);
       
   359         }
       
   360     }
       
   361 
       
   362     @Override
       
   363     public synchronized void removeNotificationListener(NotificationListener listener,
       
   364             NotificationFilter filter,
       
   365             Object handback)
       
   366             throws ListenerNotFoundException {
       
   367         boolean before = hasListeners();
       
   368         super.removeNotificationListener(listener, filter, handback);
       
   369         boolean after = hasListeners();
       
   370         if (before && !after) {
       
   371             setNotificationEnabled(false);
       
   372         }
       
   373     }
       
   374 
       
   375     private native void setNotificationEnabled(boolean enabled);
       
   376     private native String[] getDiagnosticCommands();
       
   377     private native DiagnosticCommandInfo[] getDiagnosticCommandInfo(String[] commands);
       
   378     private native String executeDiagnosticCommand(String command);
       
   379 
       
   380 }