5652N/A/*
5744N/A * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
5652N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5652N/A *
5652N/A * This code is free software; you can redistribute it and/or modify it
5652N/A * under the terms of the GNU General Public License version 2 only, as
5744N/A * published by the Free Software Foundation. Oracle designates this
5744N/A * particular file as subject to the "Classpath" exception as provided
5744N/A * by Oracle in the LICENSE file that accompanied this code.
5652N/A *
5652N/A * This code is distributed in the hope that it will be useful, but WITHOUT
5652N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5652N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5652N/A * version 2 for more details (a copy is included in the LICENSE file that
5652N/A * accompanied this code).
5652N/A *
5652N/A * You should have received a copy of the GNU General Public License version
5652N/A * 2 along with this work; if not, write to the Free Software Foundation,
5652N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5652N/A *
5652N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
5652N/A * or visit www.oracle.com if you need additional information or have any
5652N/A * questions.
5652N/A */
5652N/Apackage sun.management.jdp;
5652N/A
5652N/Aimport java.io.IOException;
5652N/Aimport java.net.InetAddress;
5652N/Aimport java.net.UnknownHostException;
5652N/Aimport java.util.UUID;
5652N/A
5652N/A/**
5652N/A * JdpController is responsible to create and manage a broadcast loop
5652N/A *
5652N/A * <p> Other part of code has no access to broadcast loop and have to use
5652N/A * provided static methods
5652N/A * {@link #startDiscoveryService(InetAddress,int,String,String) startDiscoveryService}
5652N/A * and {@link #stopDiscoveryService() stopDiscoveryService}</p>
5652N/A * <p>{@link #startDiscoveryService(InetAddress,int,String,String) startDiscoveryService} could be called multiple
5652N/A * times as it stops the running service if it is necessary. Call to {@link #stopDiscoveryService() stopDiscoveryService}
5652N/A * ignored if service isn't run</p>
5652N/A *
5652N/A *
5652N/A * </p>
5652N/A *
5652N/A * <p> System properties below could be used to control broadcast loop behavior.
5652N/A * Property below have to be set explicitly in command line. It's not possible to
5652N/A * set it in management.config file. Careless changes of these properties could
5652N/A * lead to security or network issues.
5652N/A * <ul>
5652N/A * <li>com.sun.management.jdp.ttl - set ttl for broadcast packet</li>
5652N/A * <li>com.sun.management.jdp.pause - set broadcast interval in seconds</li>
5652N/A * <li>com.sun.management.jdp.source_addr - an address of interface to use for broadcast</li>
5652N/A * </ul>
5652N/A </p>
5652N/A * <p>null parameters values are filtered out on {@link JdpPacketWriter} level and
5652N/A * corresponding keys are not placed to packet.</p>
5652N/A */
5652N/Apublic final class JdpController {
5652N/A
5652N/A private static class JDPControllerRunner implements Runnable {
5652N/A
5652N/A private final JdpJmxPacket packet;
5652N/A private final JdpBroadcaster bcast;
5652N/A private final int pause;
5652N/A private volatile boolean shutdown = false;
5652N/A
5652N/A private JDPControllerRunner(JdpBroadcaster bcast, JdpJmxPacket packet, int pause) {
5652N/A this.bcast = bcast;
5652N/A this.packet = packet;
5652N/A this.pause = pause;
5652N/A }
5652N/A
5652N/A @Override
5652N/A public void run() {
5652N/A try {
5652N/A while (!shutdown) {
5652N/A bcast.sendPacket(packet);
5652N/A try {
5652N/A Thread.sleep(this.pause);
5652N/A } catch (InterruptedException e) {
5652N/A // pass
5652N/A }
5652N/A }
5652N/A
5652N/A } catch (IOException e) {
5652N/A // pass;
5652N/A }
5652N/A
5652N/A // It's not possible to re-use controller,
5652N/A // nevertheless reset shutdown variable
5652N/A try {
5652N/A stop();
5652N/A bcast.shutdown();
5652N/A } catch (IOException ex) {
5652N/A // pass - ignore IOException during shutdown
5652N/A }
5652N/A }
5652N/A
5652N/A public void stop() {
5652N/A shutdown = true;
5652N/A }
5652N/A }
5652N/A private static JDPControllerRunner controller = null;
5652N/A
5652N/A private JdpController(){
5652N/A // Don't allow to instantiate this class.
5652N/A }
5652N/A
5652N/A // Utility to handle optional system properties
5652N/A // Parse an integer from string or return default if provided string is null
5652N/A private static int getInteger(String val, int dflt, String msg) throws JdpException {
5652N/A try {
5652N/A return (val == null) ? dflt : Integer.parseInt(val);
5652N/A } catch (NumberFormatException ex) {
5652N/A throw new JdpException(msg);
5652N/A }
5652N/A }
5652N/A
5652N/A // Parse an inet address from string or return default if provided string is null
5652N/A private static InetAddress getInetAddress(String val, InetAddress dflt, String msg) throws JdpException {
5652N/A try {
5652N/A return (val == null) ? dflt : InetAddress.getByName(val);
5652N/A } catch (UnknownHostException ex) {
5652N/A throw new JdpException(msg);
5652N/A }
5652N/A }
5652N/A
5652N/A /**
5652N/A * Starts discovery service
5652N/A *
5652N/A * @param address - multicast group address
5652N/A * @param port - udp port to use
5652N/A * @param instanceName - name of running JVM instance
5652N/A * @param url - JMX service url
5652N/A * @throws IOException
5652N/A */
5652N/A public static synchronized void startDiscoveryService(InetAddress address, int port, String instanceName, String url)
5652N/A throws IOException, JdpException {
5652N/A
5652N/A // Limit packet to local subnet by default
5652N/A int ttl = getInteger(
5652N/A System.getProperty("com.sun.management.jdp.ttl"), 1,
5652N/A "Invalid jdp packet ttl");
5652N/A
5652N/A // Broadcast once a 5 seconds by default
5652N/A int pause = getInteger(
5652N/A System.getProperty("com.sun.management.jdp.pause"), 5,
5652N/A "Invalid jdp pause");
5652N/A
5652N/A // Converting seconds to milliseconds
5652N/A pause = pause * 1000;
5652N/A
5652N/A // Allow OS to choose broadcast source
5652N/A InetAddress sourceAddress = getInetAddress(
5652N/A System.getProperty("com.sun.management.jdp.source_addr"), null,
5652N/A "Invalid source address provided");
5652N/A
5652N/A // Generate session id
5652N/A UUID id = UUID.randomUUID();
5652N/A
5652N/A JdpJmxPacket packet = new JdpJmxPacket(id, url);
5652N/A
5652N/A // Don't broadcast whole command line for security reason.
5652N/A // Strip everything after first space
5652N/A String javaCommand = System.getProperty("sun.java.command");
5652N/A if (javaCommand != null) {
5652N/A String[] arr = javaCommand.split(" ", 2);
5652N/A packet.setMainClass(arr[0]);
5652N/A }
5652N/A
5652N/A // Put optional explicit java instance name to packet, if user doesn't specify
5652N/A // it the key is skipped. PacketWriter is responsible to skip keys having null value.
5652N/A packet.setInstanceName(instanceName);
5652N/A
5652N/A JdpBroadcaster bcast = new JdpBroadcaster(address, sourceAddress, port, ttl);
5652N/A
5652N/A // Stop discovery service if it's already running
5652N/A stopDiscoveryService();
5652N/A
5652N/A controller = new JDPControllerRunner(bcast, packet, pause);
5652N/A
5652N/A Thread t = new Thread(controller, "JDP broadcaster");
5652N/A t.setDaemon(true);
5652N/A t.start();
5652N/A }
5652N/A
5652N/A /**
5652N/A * Stop running discovery service,
5652N/A * it's safe to attempt to stop not started service
5652N/A */
5652N/A public static synchronized void stopDiscoveryService() {
5652N/A if ( controller != null ){
5652N/A controller.stop();
5652N/A controller = null;
5652N/A }
5652N/A }
5652N/A}