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