jdk/src/java.management/share/classes/sun/management/jdp/JdpController.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) 2013, 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.jdp;
       
    26 
       
    27 import java.io.IOException;
       
    28 import java.net.InetAddress;
       
    29 import java.net.UnknownHostException;
       
    30 import java.util.UUID;
       
    31 
       
    32 import java.lang.management.ManagementFactory;
       
    33 import java.lang.management.RuntimeMXBean;
       
    34 import java.lang.reflect.Field;
       
    35 import java.lang.reflect.Method;
       
    36 import sun.management.VMManagement;
       
    37 
       
    38 /**
       
    39  * JdpController is responsible to create and manage a broadcast loop.
       
    40  *
       
    41  * <p> Other part of code has no access to broadcast loop and have to use
       
    42  * provided static methods
       
    43  * {@link #startDiscoveryService(InetAddress,int,String,String) startDiscoveryService}
       
    44  * and {@link #stopDiscoveryService() stopDiscoveryService}
       
    45  * <p>{@link #startDiscoveryService(InetAddress,int,String,String) startDiscoveryService} could be called multiple
       
    46  * times as it stops the running service if it is necessary.
       
    47  * Call to {@link #stopDiscoveryService() stopDiscoveryService}
       
    48  * ignored if service isn't run.
       
    49  *
       
    50  *
       
    51  * <p> System properties below could be used to control broadcast loop behavior.
       
    52  * Property below have to be set explicitly in command line. It's not possible to
       
    53  * set it in management.config file.  Careless changes of these properties could
       
    54  * lead to security or network issues.
       
    55  * <ul>
       
    56  *     <li>com.sun.management.jdp.ttl         - set ttl for broadcast packet</li>
       
    57  *     <li>com.sun.management.jdp.pause       - set broadcast interval in seconds</li>
       
    58  *     <li>com.sun.management.jdp.source_addr - an address of interface to use for broadcast</li>
       
    59  * </ul>
       
    60  *
       
    61  * <p>null parameters values are filtered out on {@link JdpPacketWriter} level and
       
    62  * corresponding keys are not placed to packet.
       
    63  */
       
    64 public final class JdpController {
       
    65 
       
    66     private static class JDPControllerRunner implements Runnable {
       
    67 
       
    68         private final JdpJmxPacket packet;
       
    69         private final JdpBroadcaster bcast;
       
    70         private final int pause;
       
    71         private volatile boolean shutdown = false;
       
    72 
       
    73         private JDPControllerRunner(JdpBroadcaster bcast, JdpJmxPacket packet, int pause) {
       
    74             this.bcast = bcast;
       
    75             this.packet = packet;
       
    76             this.pause = pause;
       
    77         }
       
    78 
       
    79         @Override
       
    80         public void run() {
       
    81             try {
       
    82                 while (!shutdown) {
       
    83                     bcast.sendPacket(packet);
       
    84                     try {
       
    85                         Thread.sleep(this.pause);
       
    86                     } catch (InterruptedException e) {
       
    87                         // pass
       
    88                     }
       
    89                 }
       
    90 
       
    91             } catch (IOException e) {
       
    92               // pass;
       
    93             }
       
    94 
       
    95             // It's not possible to re-use controller,
       
    96             // nevertheless reset shutdown variable
       
    97             try {
       
    98                 stop();
       
    99                 bcast.shutdown();
       
   100             } catch (IOException ex) {
       
   101                 // pass - ignore IOException during shutdown
       
   102             }
       
   103         }
       
   104 
       
   105         public void stop() {
       
   106             shutdown = true;
       
   107         }
       
   108     }
       
   109     private static JDPControllerRunner controller = null;
       
   110 
       
   111     private JdpController(){
       
   112         // Don't allow to instantiate this class.
       
   113     }
       
   114 
       
   115     // Utility to handle optional system properties
       
   116     // Parse an integer from string or return default if provided string is null
       
   117     private static int getInteger(String val, int dflt, String msg) throws JdpException {
       
   118         try {
       
   119             return (val == null) ? dflt : Integer.parseInt(val);
       
   120         } catch (NumberFormatException ex) {
       
   121             throw new JdpException(msg);
       
   122         }
       
   123     }
       
   124 
       
   125     // Parse an inet address from string or return default if provided string is null
       
   126     private static InetAddress getInetAddress(String val, InetAddress dflt, String msg) throws JdpException {
       
   127         try {
       
   128             return (val == null) ? dflt : InetAddress.getByName(val);
       
   129         } catch (UnknownHostException ex) {
       
   130             throw new JdpException(msg);
       
   131         }
       
   132     }
       
   133 
       
   134     // Get the process id of the current running Java process
       
   135     private static Integer getProcessId() {
       
   136         try {
       
   137             // Get the current process id using a reflection hack
       
   138             RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
       
   139             Field jvm = runtime.getClass().getDeclaredField("jvm");
       
   140             jvm.setAccessible(true);
       
   141 
       
   142             VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime);
       
   143             Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId");
       
   144             pid_method.setAccessible(true);
       
   145             Integer pid = (Integer) pid_method.invoke(mgmt);
       
   146             return pid;
       
   147         } catch(Exception ex) {
       
   148             return null;
       
   149         }
       
   150     }
       
   151 
       
   152 
       
   153     /**
       
   154      * Starts discovery service
       
   155      *
       
   156      * @param address - multicast group address
       
   157      * @param port - udp port to use
       
   158      * @param instanceName - name of running JVM instance
       
   159      * @param url - JMX service url
       
   160      * @throws IOException
       
   161      */
       
   162     public static synchronized void startDiscoveryService(InetAddress address, int port, String instanceName, String url)
       
   163             throws IOException, JdpException {
       
   164 
       
   165         // Limit packet to local subnet by default
       
   166         int ttl = getInteger(
       
   167                 System.getProperty("com.sun.management.jdp.ttl"), 1,
       
   168                 "Invalid jdp packet ttl");
       
   169 
       
   170         // Broadcast once a 5 seconds by default
       
   171         int pause = getInteger(
       
   172                 System.getProperty("com.sun.management.jdp.pause"), 5,
       
   173                 "Invalid jdp pause");
       
   174 
       
   175         // Converting seconds to milliseconds
       
   176         pause = pause * 1000;
       
   177 
       
   178         // Allow OS to choose broadcast source
       
   179         InetAddress sourceAddress = getInetAddress(
       
   180                 System.getProperty("com.sun.management.jdp.source_addr"), null,
       
   181                 "Invalid source address provided");
       
   182 
       
   183         // Generate session id
       
   184         UUID id = UUID.randomUUID();
       
   185 
       
   186         JdpJmxPacket packet = new JdpJmxPacket(id, url);
       
   187 
       
   188         // Don't broadcast whole command line for security reason.
       
   189         // Strip everything after first space
       
   190         String javaCommand = System.getProperty("sun.java.command");
       
   191         if (javaCommand != null) {
       
   192             String[] arr = javaCommand.split(" ", 2);
       
   193             packet.setMainClass(arr[0]);
       
   194         }
       
   195 
       
   196         // Put optional explicit java instance name to packet, if user doesn't specify
       
   197         // it the key is skipped. PacketWriter is responsible to skip keys having null value.
       
   198         packet.setInstanceName(instanceName);
       
   199 
       
   200         // Set rmi server hostname if it explicitly specified by user with
       
   201         // java.rmi.server.hostname
       
   202         String rmiHostname = System.getProperty("java.rmi.server.hostname");
       
   203         packet.setRmiHostname(rmiHostname);
       
   204 
       
   205         // Set broadcast interval
       
   206         packet.setBroadcastInterval(Integer.toString(pause));
       
   207 
       
   208         // Set process id
       
   209         Integer pid = getProcessId();
       
   210         if (pid != null) {
       
   211            packet.setProcessId(pid.toString());
       
   212         }
       
   213 
       
   214         JdpBroadcaster bcast = new JdpBroadcaster(address, sourceAddress, port, ttl);
       
   215 
       
   216         // Stop discovery service if it's already running
       
   217         stopDiscoveryService();
       
   218 
       
   219         controller = new JDPControllerRunner(bcast, packet, pause);
       
   220 
       
   221         Thread t = new Thread(null, controller, "JDP broadcaster", 0, false);
       
   222         t.setDaemon(true);
       
   223         t.start();
       
   224     }
       
   225 
       
   226     /**
       
   227      * Stop running discovery service,
       
   228      * it's safe to attempt to stop not started service
       
   229      */
       
   230     public static synchronized void stopDiscoveryService() {
       
   231         if ( controller != null ){
       
   232              controller.stop();
       
   233              controller = null;
       
   234         }
       
   235     }
       
   236 }