jdk/src/java.management/share/classes/sun/management/Agent.java
changeset 43662 6b16a26de895
parent 43661 c3f1a529d829
parent 43593 06bce0388880
child 43663 4416065868c1
equal deleted inserted replaced
43661:c3f1a529d829 43662:6b16a26de895
     1 /*
       
     2  * Copyright (c) 2003, 2016, 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 package sun.management;
       
    26 
       
    27 import java.io.BufferedInputStream;
       
    28 import java.io.File;
       
    29 import java.io.FileInputStream;
       
    30 import java.io.FileNotFoundException;
       
    31 import java.io.IOException;
       
    32 import java.io.InputStream;
       
    33 import java.lang.management.ManagementFactory;
       
    34 import java.lang.reflect.Method;
       
    35 import java.net.InetAddress;
       
    36 import java.net.MalformedURLException;
       
    37 import java.net.UnknownHostException;
       
    38 import java.security.AccessController;
       
    39 import java.security.PrivilegedAction;
       
    40 import java.text.MessageFormat;
       
    41 import java.util.HashMap;
       
    42 import java.util.Map;
       
    43 import java.util.MissingResourceException;
       
    44 import java.util.Properties;
       
    45 import java.util.ResourceBundle;
       
    46 import java.util.ServiceLoader;
       
    47 import java.util.function.Function;
       
    48 import java.util.function.Predicate;
       
    49 
       
    50 import javax.management.remote.JMXConnectorServer;
       
    51 import javax.management.remote.JMXServiceURL;
       
    52 
       
    53 import static sun.management.AgentConfigurationError.*;
       
    54 import sun.management.jmxremote.ConnectorBootstrap;
       
    55 import sun.management.jdp.JdpController;
       
    56 import sun.management.jdp.JdpException;
       
    57 import jdk.internal.vm.VMSupport;
       
    58 import sun.management.spi.AgentProvider;
       
    59 
       
    60 /**
       
    61  * This Agent is started by the VM when -Dcom.sun.management.snmp or
       
    62  * -Dcom.sun.management.jmxremote is set. This class will be loaded by the
       
    63  * system class loader. Also jmx framework could be started by jcmd
       
    64  */
       
    65 public class Agent {
       
    66     /**
       
    67      * Agent status collector strategy class
       
    68      */
       
    69     private static abstract class StatusCollector {
       
    70         protected static final Map<String, String> DEFAULT_PROPS = new HashMap<>();
       
    71 
       
    72         static {
       
    73             DEFAULT_PROPS.put(ConnectorBootstrap.PropertyNames.PORT,
       
    74                               ConnectorBootstrap.DefaultValues.PORT);
       
    75             DEFAULT_PROPS.put(ConnectorBootstrap.PropertyNames.USE_LOCAL_ONLY,
       
    76                               ConnectorBootstrap.DefaultValues.USE_LOCAL_ONLY);
       
    77             DEFAULT_PROPS.put(ConnectorBootstrap.PropertyNames.USE_AUTHENTICATION,
       
    78                               ConnectorBootstrap.DefaultValues.USE_AUTHENTICATION);
       
    79             DEFAULT_PROPS.put(ConnectorBootstrap.PropertyNames.USE_SSL,
       
    80                               ConnectorBootstrap.DefaultValues.USE_SSL);
       
    81             DEFAULT_PROPS.put(ConnectorBootstrap.PropertyNames.USE_REGISTRY_SSL,
       
    82                               ConnectorBootstrap.DefaultValues.USE_REGISTRY_SSL);
       
    83             DEFAULT_PROPS.put(ConnectorBootstrap.PropertyNames.SSL_NEED_CLIENT_AUTH,
       
    84                               ConnectorBootstrap.DefaultValues.SSL_NEED_CLIENT_AUTH);
       
    85             DEFAULT_PROPS.put(ConnectorBootstrap.PropertyNames.CONFIG_FILE_NAME,
       
    86                               ConnectorBootstrap.DefaultValues.CONFIG_FILE_NAME);
       
    87             DEFAULT_PROPS.put(ConnectorBootstrap.PropertyNames.PASSWORD_FILE_NAME,
       
    88                               ConnectorBootstrap.DefaultValues.PASSWORD_FILE_NAME);
       
    89             DEFAULT_PROPS.put(ConnectorBootstrap.PropertyNames.ACCESS_FILE_NAME,
       
    90                               ConnectorBootstrap.DefaultValues.ACCESS_FILE_NAME);
       
    91 
       
    92         }
       
    93 
       
    94         final protected StringBuilder sb = new StringBuilder();
       
    95         final public String collect() {
       
    96             Properties agentProps = VMSupport.getAgentProperties();
       
    97             String localConnAddr = (String)agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP);
       
    98             if (localConnAddr != null || jmxServer != null) {
       
    99                 addAgentStatus(true);
       
   100                 appendConnections(localConnAddr);
       
   101             } else {
       
   102                 addAgentStatus(false);
       
   103             }
       
   104             return sb.toString();
       
   105         }
       
   106 
       
   107         private void appendConnections(String localConnAddr) {
       
   108             appendConnectionsHeader();
       
   109             if (localConnAddr != null) {
       
   110                 try {
       
   111                     JMXServiceURL u = new JMXServiceURL(localConnAddr);
       
   112                     addConnection(false, u);
       
   113                 } catch (MalformedURLException e) {
       
   114                     // will never happen
       
   115                 }
       
   116 
       
   117             }
       
   118             if (jmxServer != null) {
       
   119                 addConnection(true, jmxServer.getAddress());
       
   120             }
       
   121             appendConnectionsFooter();
       
   122         }
       
   123 
       
   124         private void addConnection(boolean remote, JMXServiceURL u) {
       
   125             appendConnectionHeader(remote);
       
   126             addConnectionDetails(u);
       
   127             addConfigProperties();
       
   128             appendConnectionFooter(remote);
       
   129         }
       
   130 
       
   131         private void addConfigProperties() {
       
   132             appendConfigPropsHeader();
       
   133 
       
   134             Properties remoteProps = configProps != null ?
       
   135                                         configProps : getManagementProperties();
       
   136             Map<Object, Object> props = new HashMap<>(DEFAULT_PROPS);
       
   137 
       
   138             if (remoteProps == null) {
       
   139                 // local connector only
       
   140                 String loc_only = System.getProperty(
       
   141                     ConnectorBootstrap.PropertyNames.USE_LOCAL_ONLY
       
   142                 );
       
   143 
       
   144                 if (loc_only != null &&
       
   145                     !ConnectorBootstrap.DefaultValues.USE_LOCAL_ONLY.equals(loc_only)) {
       
   146                     props.put(
       
   147                         ConnectorBootstrap.PropertyNames.USE_LOCAL_ONLY,
       
   148                         loc_only
       
   149                     );
       
   150                 }
       
   151             } else {
       
   152                 props.putAll(remoteProps);
       
   153             }
       
   154 
       
   155             props.entrySet().stream()
       
   156                 .filter(preprocess(Map.Entry::getKey, StatusCollector::isManagementProp))
       
   157                 .forEach(this::addConfigProp);
       
   158 
       
   159             appendConfigPropsFooter();
       
   160         }
       
   161 
       
   162         private static boolean isManagementProp(Object pName) {
       
   163             return pName != null && pName.toString().startsWith("com.sun.management.");
       
   164         }
       
   165 
       
   166         private static <T, V> Predicate<T> preprocess(Function<T, V> f, Predicate<V> p) {
       
   167             return (T t) -> p.test(f.apply(t));
       
   168         }
       
   169 
       
   170         abstract protected void addAgentStatus(boolean enabled);
       
   171         abstract protected void appendConnectionsHeader();
       
   172         abstract protected void appendConnectionsFooter();
       
   173         abstract protected void addConnectionDetails(JMXServiceURL u);
       
   174         abstract protected void appendConnectionHeader(boolean remote);
       
   175         abstract protected void appendConnectionFooter(boolean remote);
       
   176         abstract protected void appendConfigPropsHeader();
       
   177         abstract protected void appendConfigPropsFooter();
       
   178         abstract protected void addConfigProp(Map.Entry<?, ?> prop);
       
   179     }
       
   180 
       
   181     /**
       
   182      * Free-text status collector strategy implementation
       
   183      */
       
   184     final private static class TextStatusCollector extends StatusCollector {
       
   185 
       
   186         @Override
       
   187         protected void addAgentStatus(boolean enabled) {
       
   188             sb.append("Agent: ").append(enabled ? "enabled" : "disabled").append('\n');
       
   189         }
       
   190 
       
   191         @Override
       
   192         protected void appendConnectionsHeader() {
       
   193             sb.append('\n');
       
   194         }
       
   195 
       
   196         @Override
       
   197         protected void addConnectionDetails(JMXServiceURL u) {
       
   198             sb.append("Protocol       : ").append(u.getProtocol()).append('\n')
       
   199               .append("Host           : ").append(u.getHost()).append('\n')
       
   200               .append("URL            : ").append(u).append('\n');
       
   201         }
       
   202 
       
   203         @Override
       
   204         protected void appendConnectionHeader(boolean remote) {
       
   205             sb.append("Connection Type: ").append(remote ? "remote" : "local").append('\n');
       
   206         }
       
   207 
       
   208         @Override
       
   209         protected void appendConfigPropsHeader() {
       
   210             sb.append("Properties     :\n");
       
   211         }
       
   212 
       
   213         @Override
       
   214         protected void addConfigProp(Map.Entry<?, ?> prop) {
       
   215             sb.append("  ").append(prop.getKey()).append(" = ")
       
   216               .append(prop.getValue());
       
   217             Object defVal = DEFAULT_PROPS.get(prop.getKey());
       
   218             if (defVal != null && defVal.equals(prop.getValue())) {
       
   219                 sb.append(" [default]");
       
   220             }
       
   221             sb.append("\n");
       
   222         }
       
   223 
       
   224         @Override
       
   225         protected void appendConnectionsFooter() {}
       
   226 
       
   227         @Override
       
   228         protected void appendConnectionFooter(boolean remote) {
       
   229             sb.append('\n');
       
   230         }
       
   231 
       
   232         @Override
       
   233         protected void appendConfigPropsFooter() {}
       
   234     }
       
   235 
       
   236     // management properties
       
   237 
       
   238     private static Properties mgmtProps;
       
   239     private static ResourceBundle messageRB;
       
   240     private static final String CONFIG_FILE =
       
   241             "com.sun.management.config.file";
       
   242     private static final String SNMP_PORT =
       
   243             "com.sun.management.snmp.port";
       
   244     private static final String JMXREMOTE =
       
   245             "com.sun.management.jmxremote";
       
   246     private static final String JMXREMOTE_PORT =
       
   247             "com.sun.management.jmxremote.port";
       
   248     private static final String RMI_PORT =
       
   249             "com.sun.management.jmxremote.rmi.port";
       
   250     private static final String ENABLE_THREAD_CONTENTION_MONITORING =
       
   251             "com.sun.management.enableThreadContentionMonitoring";
       
   252     private static final String LOCAL_CONNECTOR_ADDRESS_PROP =
       
   253             "com.sun.management.jmxremote.localConnectorAddress";
       
   254     private static final String SNMP_AGENT_NAME =
       
   255             "SnmpAgent";
       
   256 
       
   257     private static final String JDP_DEFAULT_ADDRESS = "224.0.23.178";
       
   258     private static final int JDP_DEFAULT_PORT = 7095;
       
   259 
       
   260     // The only active agent allowed
       
   261     private static JMXConnectorServer jmxServer = null;
       
   262     // The properties used to configure the server
       
   263     private static Properties configProps = null;
       
   264 
       
   265     // Parse string com.sun.management.prop=xxx,com.sun.management.prop=yyyy
       
   266     // and return property set if args is null or empty
       
   267     // return empty property set
       
   268     private static Properties parseString(String args) {
       
   269         Properties argProps = new Properties();
       
   270         if (args != null && !args.trim().equals("")) {
       
   271             for (String option : args.split(",")) {
       
   272                 String s[] = option.split("=", 2);
       
   273                 String name = s[0].trim();
       
   274                 String value = (s.length > 1) ? s[1].trim() : "";
       
   275 
       
   276                 if (!name.startsWith("com.sun.management.")) {
       
   277                     error(INVALID_OPTION, name);
       
   278                 }
       
   279 
       
   280                 argProps.setProperty(name, value);
       
   281             }
       
   282         }
       
   283 
       
   284         return argProps;
       
   285     }
       
   286 
       
   287     // invoked by -javaagent or -Dcom.sun.management.agent.class
       
   288     public static void premain(String args) throws Exception {
       
   289         agentmain(args);
       
   290     }
       
   291 
       
   292     // invoked by attach mechanism
       
   293     public static void agentmain(String args) throws Exception {
       
   294         if (args == null || args.length() == 0) {
       
   295             args = JMXREMOTE;           // default to local management
       
   296         }
       
   297 
       
   298         Properties arg_props = parseString(args);
       
   299 
       
   300         // Read properties from the config file
       
   301         Properties config_props = new Properties();
       
   302         String fname = arg_props.getProperty(CONFIG_FILE);
       
   303         readConfiguration(fname, config_props);
       
   304 
       
   305         // Arguments override config file
       
   306         config_props.putAll(arg_props);
       
   307         startAgent(config_props);
       
   308     }
       
   309 
       
   310     // jcmd ManagementAgent.start_local entry point
       
   311     // Also called due to command-line via startAgent()
       
   312     private static synchronized void startLocalManagementAgent() {
       
   313         Properties agentProps = VMSupport.getAgentProperties();
       
   314 
       
   315         // start local connector if not started
       
   316         if (agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP) == null) {
       
   317             JMXConnectorServer cs = ConnectorBootstrap.startLocalConnectorServer();
       
   318             String address = cs.getAddress().toString();
       
   319             // Add the local connector address to the agent properties
       
   320             agentProps.put(LOCAL_CONNECTOR_ADDRESS_PROP, address);
       
   321 
       
   322             try {
       
   323                 // export the address to the instrumentation buffer
       
   324                 ConnectorAddressLink.export(address);
       
   325             } catch (Exception x) {
       
   326                 // Connector server started but unable to export address
       
   327                 // to instrumentation buffer - non-fatal error.
       
   328                 warning(EXPORT_ADDRESS_FAILED, x.getMessage());
       
   329             }
       
   330         }
       
   331     }
       
   332 
       
   333     // jcmd ManagementAgent.start entry point
       
   334     // This method starts the remote JMX agent and starts neither
       
   335     // the local JMX agent nor the SNMP agent
       
   336     // @see #startLocalManagementAgent and also @see #startAgent.
       
   337     private static synchronized void startRemoteManagementAgent(String args) throws Exception {
       
   338         if (jmxServer != null) {
       
   339             throw new RuntimeException(getText(INVALID_STATE, "Agent already started"));
       
   340         }
       
   341 
       
   342         try {
       
   343             Properties argProps = parseString(args);
       
   344             configProps = new Properties();
       
   345 
       
   346             // Load the management properties from the config file
       
   347             // if config file is not specified readConfiguration implicitly
       
   348             // reads <java.home>/conf/management/management.properties
       
   349 
       
   350             String fname = System.getProperty(CONFIG_FILE);
       
   351             readConfiguration(fname, configProps);
       
   352 
       
   353             // management properties can be overridden by system properties
       
   354             // which take precedence
       
   355             Properties sysProps = System.getProperties();
       
   356             synchronized (sysProps) {
       
   357                 configProps.putAll(sysProps);
       
   358             }
       
   359 
       
   360             // if user specifies config file into command line for either
       
   361             // jcmd utilities or attach command it overrides properties set in
       
   362             // command line at the time of VM start
       
   363             String fnameUser = argProps.getProperty(CONFIG_FILE);
       
   364             if (fnameUser != null) {
       
   365                 readConfiguration(fnameUser, configProps);
       
   366             }
       
   367 
       
   368             // arguments specified in command line of jcmd utilities
       
   369             // override both system properties and one set by config file
       
   370             // specified in jcmd command line
       
   371             configProps.putAll(argProps);
       
   372 
       
   373             // jcmd doesn't allow to change ThreadContentionMonitoring, but user
       
   374             // can specify this property inside config file, so enable optional
       
   375             // monitoring functionality if this property is set
       
   376             final String enableThreadContentionMonitoring =
       
   377                     configProps.getProperty(ENABLE_THREAD_CONTENTION_MONITORING);
       
   378 
       
   379             if (enableThreadContentionMonitoring != null) {
       
   380                 ManagementFactory.getThreadMXBean().
       
   381                         setThreadContentionMonitoringEnabled(true);
       
   382             }
       
   383 
       
   384             String jmxremotePort = configProps.getProperty(JMXREMOTE_PORT);
       
   385             if (jmxremotePort != null) {
       
   386                 jmxServer = ConnectorBootstrap.
       
   387                         startRemoteConnectorServer(jmxremotePort, configProps);
       
   388 
       
   389                 startDiscoveryService(configProps);
       
   390             } else {
       
   391                 throw new AgentConfigurationError(INVALID_JMXREMOTE_PORT, "No port specified");
       
   392             }
       
   393         } catch (JdpException e) {
       
   394             error(e);
       
   395         } catch (AgentConfigurationError err) {
       
   396             error(err.getError(), err.getParams());
       
   397         }
       
   398     }
       
   399 
       
   400     private static synchronized void stopRemoteManagementAgent() throws Exception {
       
   401 
       
   402         JdpController.stopDiscoveryService();
       
   403 
       
   404         if (jmxServer != null) {
       
   405             ConnectorBootstrap.unexportRegistry();
       
   406             ConnectorAddressLink.unexportRemote();
       
   407 
       
   408             // Attempt to stop already stopped agent
       
   409             // Don't cause any errors.
       
   410             jmxServer.stop();
       
   411             jmxServer = null;
       
   412             configProps = null;
       
   413         }
       
   414     }
       
   415 
       
   416     private static synchronized String getManagementAgentStatus() throws Exception {
       
   417         return new TextStatusCollector().collect();
       
   418     }
       
   419 
       
   420     private static void startAgent(Properties props) throws Exception {
       
   421         String snmpPort = props.getProperty(SNMP_PORT);
       
   422         String jmxremote = props.getProperty(JMXREMOTE);
       
   423         String jmxremotePort = props.getProperty(JMXREMOTE_PORT);
       
   424 
       
   425         // Enable optional monitoring functionality if requested
       
   426         final String enableThreadContentionMonitoring =
       
   427                 props.getProperty(ENABLE_THREAD_CONTENTION_MONITORING);
       
   428         if (enableThreadContentionMonitoring != null) {
       
   429             ManagementFactory.getThreadMXBean().
       
   430                     setThreadContentionMonitoringEnabled(true);
       
   431         }
       
   432 
       
   433         try {
       
   434             if (snmpPort != null) {
       
   435                 loadSnmpAgent(props);
       
   436             }
       
   437 
       
   438             /*
       
   439              * If the jmxremote.port property is set then we start the
       
   440              * RMIConnectorServer for remote M&M.
       
   441              *
       
   442              * If the jmxremote or jmxremote.port properties are set then
       
   443              * we start a RMIConnectorServer for local M&M. The address
       
   444              * of this "local" server is exported as a counter to the jstat
       
   445              * instrumentation buffer.
       
   446              */
       
   447             if (jmxremote != null || jmxremotePort != null) {
       
   448                 if (jmxremotePort != null) {
       
   449                     jmxServer = ConnectorBootstrap.
       
   450                             startRemoteConnectorServer(jmxremotePort, props);
       
   451                     startDiscoveryService(props);
       
   452                 }
       
   453                 startLocalManagementAgent();
       
   454             }
       
   455 
       
   456         } catch (AgentConfigurationError e) {
       
   457             error(e.getError(), e.getParams());
       
   458         } catch (Exception e) {
       
   459             error(e);
       
   460         }
       
   461     }
       
   462 
       
   463     private static void startDiscoveryService(Properties props)
       
   464             throws IOException, JdpException {
       
   465         // Start discovery service if requested
       
   466         String discoveryPort = props.getProperty("com.sun.management.jdp.port");
       
   467         String discoveryAddress = props.getProperty("com.sun.management.jdp.address");
       
   468         String discoveryShouldStart = props.getProperty("com.sun.management.jmxremote.autodiscovery");
       
   469 
       
   470         // Decide whether we should start autodicovery service.
       
   471         // To start autodiscovery following conditions should be met:
       
   472         // autodiscovery==true OR (autodicovery==null AND jdp.port != NULL)
       
   473 
       
   474         boolean shouldStart = false;
       
   475         if (discoveryShouldStart == null){
       
   476             shouldStart = (discoveryPort != null);
       
   477         }
       
   478         else{
       
   479             try{
       
   480                shouldStart = Boolean.parseBoolean(discoveryShouldStart);
       
   481             } catch (NumberFormatException e) {
       
   482                 throw new AgentConfigurationError(AGENT_EXCEPTION, "Couldn't parse autodiscovery argument");
       
   483             }
       
   484         }
       
   485 
       
   486         if (shouldStart) {
       
   487             // port and address are required arguments and have no default values
       
   488             InetAddress address;
       
   489             try {
       
   490                 address = (discoveryAddress == null) ?
       
   491                         InetAddress.getByName(JDP_DEFAULT_ADDRESS) : InetAddress.getByName(discoveryAddress);
       
   492             } catch (UnknownHostException e) {
       
   493                 throw new AgentConfigurationError(AGENT_EXCEPTION, e, "Unable to broadcast to requested address");
       
   494             }
       
   495 
       
   496             int port = JDP_DEFAULT_PORT;
       
   497             if (discoveryPort != null) {
       
   498                try {
       
   499                   port = Integer.parseInt(discoveryPort);
       
   500                } catch (NumberFormatException e) {
       
   501                  throw new AgentConfigurationError(AGENT_EXCEPTION, "Couldn't parse JDP port argument");
       
   502                }
       
   503             }
       
   504 
       
   505             // Rebuilding service URL to broadcast it
       
   506             String jmxremotePort = props.getProperty(JMXREMOTE_PORT);
       
   507             String rmiPort = props.getProperty(RMI_PORT);
       
   508 
       
   509             JMXServiceURL url = jmxServer.getAddress();
       
   510             String hostname = url.getHost();
       
   511 
       
   512             String jmxUrlStr = (rmiPort != null)
       
   513                     ? String.format(
       
   514                     "service:jmx:rmi://%s:%s/jndi/rmi://%s:%s/jmxrmi",
       
   515                     hostname, rmiPort, hostname, jmxremotePort)
       
   516                     : String.format(
       
   517                     "service:jmx:rmi:///jndi/rmi://%s:%s/jmxrmi", hostname, jmxremotePort);
       
   518 
       
   519             String instanceName = props.getProperty("com.sun.management.jdp.name");
       
   520 
       
   521             JdpController.startDiscoveryService(address, port, instanceName, jmxUrlStr);
       
   522         }
       
   523     }
       
   524 
       
   525     public static Properties loadManagementProperties() {
       
   526         Properties props = new Properties();
       
   527 
       
   528         // Load the management properties from the config file
       
   529 
       
   530         String fname = System.getProperty(CONFIG_FILE);
       
   531         readConfiguration(fname, props);
       
   532 
       
   533         // management properties can be overridden by system properties
       
   534         // which take precedence
       
   535         Properties sysProps = System.getProperties();
       
   536         synchronized (sysProps) {
       
   537             props.putAll(sysProps);
       
   538         }
       
   539 
       
   540         return props;
       
   541     }
       
   542 
       
   543     public static synchronized Properties getManagementProperties() {
       
   544         if (mgmtProps == null) {
       
   545             String configFile = System.getProperty(CONFIG_FILE);
       
   546             String snmpPort = System.getProperty(SNMP_PORT);
       
   547             String jmxremote = System.getProperty(JMXREMOTE);
       
   548             String jmxremotePort = System.getProperty(JMXREMOTE_PORT);
       
   549 
       
   550             if (configFile == null && snmpPort == null
       
   551                     && jmxremote == null && jmxremotePort == null) {
       
   552                 // return if out-of-the-management option is not specified
       
   553                 return null;
       
   554             }
       
   555             mgmtProps = loadManagementProperties();
       
   556         }
       
   557         return mgmtProps;
       
   558     }
       
   559 
       
   560     private static void loadSnmpAgent(Properties props) {
       
   561         /*
       
   562          * Load the jdk.snmp service
       
   563          */
       
   564         AgentProvider provider = AccessController.doPrivileged(
       
   565             (PrivilegedAction<AgentProvider>) () -> {
       
   566                 for(AgentProvider aProvider : ServiceLoader.loadInstalled(AgentProvider.class)) {
       
   567                     if(aProvider.getName().equals(SNMP_AGENT_NAME))
       
   568                         return aProvider;
       
   569                 }
       
   570                 return null;
       
   571             },  null
       
   572         );
       
   573 
       
   574         if (provider != null) {
       
   575             provider.startAgent(props);
       
   576          } else { // snmp runtime doesn't exist - initialization fails
       
   577             throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT);
       
   578         }
       
   579     }
       
   580 
       
   581     // read config file and initialize the properties
       
   582     private static void readConfiguration(String fname, Properties p) {
       
   583         if (fname == null) {
       
   584             String home = System.getProperty("java.home");
       
   585             if (home == null) {
       
   586                 throw new Error("Can't find java.home ??");
       
   587             }
       
   588             StringBuilder defaultFileName = new StringBuilder(home);
       
   589             defaultFileName.append(File.separator).append("conf");
       
   590             defaultFileName.append(File.separator).append("management");
       
   591             defaultFileName.append(File.separator).append("management.properties");
       
   592             // Set file name
       
   593             fname = defaultFileName.toString();
       
   594         }
       
   595         final File configFile = new File(fname);
       
   596         if (!configFile.exists()) {
       
   597             error(CONFIG_FILE_NOT_FOUND, fname);
       
   598         }
       
   599 
       
   600         InputStream in = null;
       
   601         try {
       
   602             in = new FileInputStream(configFile);
       
   603             BufferedInputStream bin = new BufferedInputStream(in);
       
   604             p.load(bin);
       
   605         } catch (FileNotFoundException e) {
       
   606             error(CONFIG_FILE_OPEN_FAILED, e.getMessage());
       
   607         } catch (IOException e) {
       
   608             error(CONFIG_FILE_OPEN_FAILED, e.getMessage());
       
   609         } catch (SecurityException e) {
       
   610             error(CONFIG_FILE_ACCESS_DENIED, fname);
       
   611         } finally {
       
   612             if (in != null) {
       
   613                 try {
       
   614                     in.close();
       
   615                 } catch (IOException e) {
       
   616                     error(CONFIG_FILE_CLOSE_FAILED, fname);
       
   617                 }
       
   618             }
       
   619         }
       
   620     }
       
   621 
       
   622     public static void startAgent() throws Exception {
       
   623         String prop = System.getProperty("com.sun.management.agent.class");
       
   624 
       
   625         // -Dcom.sun.management.agent.class not set so read management
       
   626         // properties and start agent
       
   627         if (prop == null) {
       
   628             // initialize management properties
       
   629             Properties props = getManagementProperties();
       
   630             if (props != null) {
       
   631                 startAgent(props);
       
   632             }
       
   633             return;
       
   634         }
       
   635 
       
   636         // -Dcom.sun.management.agent.class=<agent classname>:<agent args>
       
   637         String[] values = prop.split(":");
       
   638         if (values.length < 1 || values.length > 2) {
       
   639             error(AGENT_CLASS_INVALID, "\"" + prop + "\"");
       
   640         }
       
   641         String cname = values[0];
       
   642         String args = (values.length == 2 ? values[1] : null);
       
   643 
       
   644         if (cname == null || cname.length() == 0) {
       
   645             error(AGENT_CLASS_INVALID, "\"" + prop + "\"");
       
   646         }
       
   647 
       
   648         if (cname != null) {
       
   649             try {
       
   650                 // Instantiate the named class.
       
   651                 // invoke the premain(String args) method
       
   652                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
       
   653                 Method premain = clz.getMethod("premain",
       
   654                         new Class<?>[]{String.class});
       
   655                 premain.invoke(null, /* static */
       
   656                         new Object[]{args});
       
   657             } catch (ClassNotFoundException ex) {
       
   658                 error(AGENT_CLASS_NOT_FOUND, "\"" + cname + "\"");
       
   659             } catch (NoSuchMethodException ex) {
       
   660                 error(AGENT_CLASS_PREMAIN_NOT_FOUND, "\"" + cname + "\"");
       
   661             } catch (SecurityException ex) {
       
   662                 error(AGENT_CLASS_ACCESS_DENIED);
       
   663             } catch (Exception ex) {
       
   664                 String msg = (ex.getCause() == null
       
   665                         ? ex.getMessage()
       
   666                         : ex.getCause().getMessage());
       
   667                 error(AGENT_CLASS_FAILED, msg);
       
   668             }
       
   669         }
       
   670     }
       
   671 
       
   672     public static void error(String key) {
       
   673         String keyText = getText(key);
       
   674         System.err.print(getText("agent.err.error") + ": " + keyText);
       
   675         throw new RuntimeException(keyText);
       
   676     }
       
   677 
       
   678     public static void error(String key, String[] params) {
       
   679         if (params == null || params.length == 0) {
       
   680             error(key);
       
   681         } else {
       
   682             StringBuilder message = new StringBuilder(params[0]);
       
   683             for (int i = 1; i < params.length; i++) {
       
   684                 message.append(' ').append(params[i]);
       
   685             }
       
   686             error(key, message.toString());
       
   687         }
       
   688     }
       
   689 
       
   690     public static void error(String key, String message) {
       
   691         String keyText = getText(key);
       
   692         System.err.print(getText("agent.err.error") + ": " + keyText);
       
   693         System.err.println(": " + message);
       
   694         throw new RuntimeException(keyText + ": " + message);
       
   695     }
       
   696 
       
   697     public static void error(Exception e) {
       
   698         e.printStackTrace();
       
   699         System.err.println(getText(AGENT_EXCEPTION) + ": " + e.toString());
       
   700         throw new RuntimeException(e);
       
   701     }
       
   702 
       
   703     public static void warning(String key, String message) {
       
   704         System.err.print(getText("agent.err.warning") + ": " + getText(key));
       
   705         System.err.println(": " + message);
       
   706     }
       
   707 
       
   708     private static void initResource() {
       
   709         try {
       
   710             messageRB =
       
   711                     ResourceBundle.getBundle("sun.management.resources.agent");
       
   712         } catch (MissingResourceException e) {
       
   713             throw new Error("Fatal: Resource for management agent is missing");
       
   714         }
       
   715     }
       
   716 
       
   717     public static String getText(String key) {
       
   718         if (messageRB == null) {
       
   719             initResource();
       
   720         }
       
   721         try {
       
   722             return messageRB.getString(key);
       
   723         } catch (MissingResourceException e) {
       
   724             return "Missing management agent resource bundle: key = \"" + key + "\"";
       
   725         }
       
   726     }
       
   727 
       
   728     public static String getText(String key, String... args) {
       
   729         if (messageRB == null) {
       
   730             initResource();
       
   731         }
       
   732         String format = messageRB.getString(key);
       
   733         if (format == null) {
       
   734             format = "missing resource key: key = \"" + key + "\", "
       
   735                     + "arguments = \"{0}\", \"{1}\", \"{2}\"";
       
   736         }
       
   737         return MessageFormat.format(format, (Object[]) args);
       
   738     }
       
   739 }