feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.ProtocolFamily;
import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.UnsupportedAddressTypeException;
/**
* JdpBroadcaster is responsible for sending pre-built JDP packet across a Net
*
* <p> Multicast group address, port number and ttl have to be chosen on upper
* level and passed to broadcaster constructor. Also it's possible to specify
* source address to broadcast from. </p>
*
* <p>JdpBradcaster doesn't perform any validation on a supplied {@code port} and {@code ttl} because
* the allowed values depend on an operating system setup</p>
*
*/
public final class JdpBroadcaster {
private final InetAddress addr;
private final int port;
private final DatagramChannel channel;
/**
* Create a new broadcaster
*
* @param address - multicast group address
* @param srcAddress - address of interface we should use to broadcast.
* @param port - udp port to use
* @param ttl - packet ttl
* @throws IOException
*/
public JdpBroadcaster(InetAddress address, InetAddress srcAddress, int port, int ttl)
throws IOException, JdpException {
this.addr = address;
this.port = port;
ProtocolFamily family = (address instanceof Inet6Address)
? StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
channel = DatagramChannel.open(family);
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
channel.setOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl);
// with srcAddress equal to null, this constructor do exactly the same as
// if srcAddress is not passed
if (srcAddress != null) {
// User requests particular interface to bind to
NetworkInterface interf = NetworkInterface.getByInetAddress(srcAddress);
try {
channel.bind(new InetSocketAddress(srcAddress, 0));
} catch (UnsupportedAddressTypeException ex) {
throw new JdpException("Unable to bind to source address");
}
channel.setOption(StandardSocketOptions.IP_MULTICAST_IF, interf);
}
}
/**
* Create a new broadcaster
*
* @param address - multicast group address
* @param port - udp port to use
* @param ttl - packet ttl
* @throws IOException
*/
public JdpBroadcaster(InetAddress address, int port, int ttl)
throws IOException, JdpException {
this(address, null, port, ttl);
}
/**
* Broadcast pre-built packet
*
* @param packet - instance of JdpPacket
* @throws IOException
*/
public void sendPacket(JdpPacket packet)
throws IOException {
byte[] data = packet.getPacketData();
// Unlike allocate/put wrap don't need a flip afterward
ByteBuffer b = ByteBuffer.wrap(data);
channel.send(b, new InetSocketAddress(addr, port));
}
/**
* Shutdown broadcaster and close underlying socket channel
*
* @throws IOException
*/
public void shutdown() throws IOException {
channel.close();
}
}

View File

@@ -0,0 +1,237 @@
/*
* Copyright (c) 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import sun.management.VMManagement;
/**
* 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);
}
}
// Get the process id of the current running Java process
private static Integer getProcessId() {
try {
// Get the current process id using a reflection hack
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
Field jvm = runtime.getClass().getDeclaredField("jvm");
jvm.setAccessible(true);
VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime);
Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId");
pid_method.setAccessible(true);
Integer pid = (Integer) pid_method.invoke(mgmt);
return pid;
} catch(Exception ex) {
return null;
}
}
/**
* 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);
// Set rmi server hostname if it explicitly specified by user with
// java.rmi.server.hostname
String rmiHostname = System.getProperty("java.rmi.server.hostname");
packet.setRmiHostname(rmiHostname);
// Set broadcast interval
packet.setBroadcastInterval(new Integer(pause).toString());
// Set process id
Integer pid = getProcessId();
if (pid != null) {
packet.setProcessId(pid.toString());
}
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;
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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;
/**
* An Exception thrown if a JDP implementation encounters a problem.
*/
public final class JdpException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Construct a new JDP exception with a meaningful message
*
* @param msg - message
*/
public JdpException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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;
/**
* JdpGenericPacket responsible to provide fields
* common for all Jdp packets
*/
public abstract class JdpGenericPacket implements JdpPacket {
/**
* JDP protocol magic. Magic allows a reader to quickly select
* JDP packets from a bunch of broadcast packets addressed to the same port
* and broadcast group. Any packet intended to be parsed by JDP client
* has to start from this magic.
*/
private static final int MAGIC = 0xC0FFEE42;
/**
* Current version of protocol. Any implementation of this protocol has to
* conform with the packet structure and the flow described in JEP-168
*/
private static final short PROTOCOL_VERSION = 1;
/**
* Default do-nothing constructor
*/
protected JdpGenericPacket(){
// do nothing
}
/**
* Validate protocol header magic field
*
* @param magic - value to validate
* @throws JdpException
*/
public static void checkMagic(int magic)
throws JdpException {
if (magic != MAGIC) {
throw new JdpException("Invalid JDP magic header: " + magic);
}
}
/**
* Validate protocol header version field
*
* @param version - value to validate
* @throws JdpException
*/
public static void checkVersion(short version)
throws JdpException {
if (version > PROTOCOL_VERSION) {
throw new JdpException("Unsupported protocol version: " + version);
}
}
/**
*
* @return protocol magic
*/
public static int getMagic() {
return MAGIC;
}
/**
*
* @return current protocol version
*/
public static short getVersion() {
return PROTOCOL_VERSION;
}
}

View File

@@ -0,0 +1,245 @@
/*
* Copyright (c) 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
/**
* A packet to broadcasts JMX URL
*
* Fields:
*
* <ul>
* <li>UUID - broadcast session ID, changed every time when we start/stop
* discovery service</li>
* <li>JMX_URL - URL to connect to JMX service</li>
* <li>MAIN_CLASS - optional name of main class, filled from sun.java.command stripped for
* security reason to first space</li>
* <li>INSTANCE_NAME - optional custom name of particular instance as provided by customer</li>
* </ul>
*/
public final class JdpJmxPacket
extends JdpGenericPacket
implements JdpPacket {
/**
* Session ID
*/
public final static String UUID_KEY = "DISCOVERABLE_SESSION_UUID";
/**
* Name of main class
*/
public final static String MAIN_CLASS_KEY = "MAIN_CLASS";
/**
* JMX service URL
*/
public final static String JMX_SERVICE_URL_KEY = "JMX_SERVICE_URL";
/**
* Name of Java instance
*/
public final static String INSTANCE_NAME_KEY = "INSTANCE_NAME";
/**
* PID of java process, optional presented if it could be obtained
*/
public final static String PROCESS_ID_KEY = "PROCESS_ID";
/**
* Hostname of rmi server, optional presented if user overrides rmi server
* hostname by java.rmi.server.hostname property
*/
public final static String RMI_HOSTNAME_KEY = "RMI_HOSTNAME";
/**
* Configured broadcast interval, optional
*/
public final static String BROADCAST_INTERVAL_KEY = "BROADCAST_INTERVAL";
private UUID id;
private String mainClass;
private String jmxServiceUrl;
private String instanceName;
private String processId;
private String rmiHostname;
private String broadcastInterval;
/**
* Create new instance from user provided data. Set mandatory fields
*
* @param id - java instance id
* @param jmxServiceUrl - JMX service url
*/
public JdpJmxPacket(UUID id, String jmxServiceUrl) {
this.id = id;
this.jmxServiceUrl = jmxServiceUrl;
}
/**
* Create new instance from network data Parse packet and set fields.
*
* @param data - raw packet data as it came from a Net
* @throws JdpException
*/
public JdpJmxPacket(byte[] data)
throws JdpException {
JdpPacketReader reader;
reader = new JdpPacketReader(data);
Map<String, String> p = reader.getDiscoveryDataAsMap();
String sId = p.get(UUID_KEY);
this.id = (sId == null) ? null : UUID.fromString(sId);
this.jmxServiceUrl = p.get(JMX_SERVICE_URL_KEY);
this.mainClass = p.get(MAIN_CLASS_KEY);
this.instanceName = p.get(INSTANCE_NAME_KEY);
this.processId = p.get(PROCESS_ID_KEY);
this.rmiHostname = p.get(RMI_HOSTNAME_KEY);
this.broadcastInterval = p.get(BROADCAST_INTERVAL_KEY);
}
/**
* Set main class field
*
* @param mainClass - main class of running app
*/
public void setMainClass(String mainClass) {
this.mainClass = mainClass;
}
/**
* Set instance name field
*
* @param instanceName - name of instance as provided by customer
*/
public void setInstanceName(String instanceName) {
this.instanceName = instanceName;
}
/**
* @return id of discovery session
*/
public UUID getId() {
return id;
}
/**
*
* @return main class field
*/
public String getMainClass() {
return mainClass;
}
/**
*
* @return JMX service URL
*/
public String getJmxServiceUrl() {
return jmxServiceUrl;
}
/**
*
* @return instance name
*/
public String getInstanceName() {
return instanceName;
}
public String getProcessId() {
return processId;
}
public void setProcessId(String processId) {
this.processId = processId;
}
public String getRmiHostname() {
return rmiHostname;
}
public void setRmiHostname(String rmiHostname) {
this.rmiHostname = rmiHostname;
}
public String getBroadcastInterval() {
return broadcastInterval;
}
public void setBroadcastInterval(String broadcastInterval) {
this.broadcastInterval = broadcastInterval;
}
/**
*
* @return assembled packet ready to be sent across a Net
* @throws IOException
*/
@Override
public byte[] getPacketData() throws IOException {
// Assemble packet from fields to byte array
JdpPacketWriter writer;
writer = new JdpPacketWriter();
writer.addEntry(UUID_KEY, (id == null) ? null : id.toString());
writer.addEntry(MAIN_CLASS_KEY, mainClass);
writer.addEntry(JMX_SERVICE_URL_KEY, jmxServiceUrl);
writer.addEntry(INSTANCE_NAME_KEY, instanceName);
writer.addEntry(PROCESS_ID_KEY, processId);
writer.addEntry(RMI_HOSTNAME_KEY, rmiHostname);
writer.addEntry(BROADCAST_INTERVAL_KEY, broadcastInterval);
return writer.getPacketBytes();
}
/**
*
* @return packet hash code
*/
@Override
public int hashCode() {
int hash = 1;
hash = hash * 31 + id.hashCode();
hash = hash * 31 + jmxServiceUrl.hashCode();
return hash;
}
/**
* Compare two packets
*
* @param o - packet to compare
* @return either packet equals or not
*/
@Override
public boolean equals(Object o) {
if (o == null || ! (o instanceof JdpJmxPacket) ){
return false;
}
JdpJmxPacket p = (JdpJmxPacket) o;
return Objects.equals(id, p.getId()) && Objects.equals(jmxServiceUrl, p.getJmxServiceUrl());
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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;
/**
* Packet to broadcast
*
* <p>Each packet have to contain MAGIC and PROTOCOL_VERSION in order to be
* recognized as a valid JDP packet.</p>
*
* <p>Default implementation build packet as a set of UTF-8 encoded Key/Value pairs
* are stored as an ordered list of values, and are sent to the server
* in that order.</p>
*
* <p>
* Packet structure:
*
* 4 bytes JDP magic (0xC0FFE42)
* 2 bytes JDP protocol version (01)
*
* 2 bytes size of key
* x bytes key (UTF-8 encoded)
* 2 bytes size of value
* x bytes value (UTF-8 encoded)
*
* repeat as many times as necessary ...
* </p>
*/
public interface JdpPacket {
/**
* This method responsible to assemble packet and return a byte array
* ready to be sent across a Net.
*
* @return assembled packet as an array of bytes
* @throws IOException
*/
public byte[] getPacketData() throws IOException;
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* JdpPacketReader responsible for reading a packet <p>This class gets a byte
* array as it came from a Net, validates it and breaks a part </p>
*/
public final class JdpPacketReader {
private final DataInputStream pkt;
private Map<String, String> pmap = null;
/**
* Create packet reader, extract and check magic and version
*
* @param packet - packet received from a Net
* @throws JdpException
*/
public JdpPacketReader(byte[] packet)
throws JdpException {
ByteArrayInputStream bais = new ByteArrayInputStream(packet);
pkt = new DataInputStream(bais);
try {
int magic = pkt.readInt();
JdpGenericPacket.checkMagic(magic);
} catch (IOException e) {
throw new JdpException("Invalid JDP packet received, bad magic");
}
try {
short version = pkt.readShort();
JdpGenericPacket.checkVersion(version);
} catch (IOException e) {
throw new JdpException("Invalid JDP packet received, bad protocol version");
}
}
/**
* Get next entry from packet
*
* @return the entry
* @throws EOFException
* @throws JdpException
*/
public String getEntry()
throws EOFException, JdpException {
try {
short len = pkt.readShort();
// Artificial setting the "len" field to Short.MAX_VALUE may cause a reader to allocate
// to much memory. Prevent this possible DOS attack.
if (len < 1 && len > pkt.available()) {
throw new JdpException("Broken JDP packet. Invalid entry length field.");
}
byte[] b = new byte[len];
if (pkt.read(b) != len) {
throw new JdpException("Broken JDP packet. Unable to read entry.");
}
return new String(b, "UTF-8");
} catch (EOFException e) {
throw e;
} catch (UnsupportedEncodingException ex) {
throw new JdpException("Broken JDP packet. Unable to decode entry.");
} catch (IOException e) {
throw new JdpException("Broken JDP packet. Unable to read entry.");
}
}
/**
* return packet content as a key/value map
*
* @return map containing packet entries pair of entries treated as
* key,value
* @throws IOException
* @throws JdpException
*/
public Map<String, String> getDiscoveryDataAsMap()
throws JdpException {
// return cached map if possible
if (pmap != null) {
return pmap;
}
String key = null, value = null;
final Map<String, String> tmpMap = new HashMap<>();
try {
while (true) {
key = getEntry();
value = getEntry();
tmpMap.put(key, value);
}
} catch (EOFException e) {
// EOF reached on reading value, report broken packet
// otherwise ignore it.
if (value == null) {
throw new JdpException("Broken JDP packet. Key without value." + key);
}
}
pmap = Collections.unmodifiableMap(tmpMap);
return pmap;
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* JdpPacketWriter responsible for writing a packet
* <p>This class assembles a set of key/value pairs to valid JDP packet,
* ready to be sent across a Net</p>
*/
public final class JdpPacketWriter {
private final ByteArrayOutputStream baos;
private final DataOutputStream pkt;
/**
* Create a JDP packet, add mandatory magic and version headers
*
* @throws IOException
*/
public JdpPacketWriter()
throws IOException {
baos = new ByteArrayOutputStream();
pkt = new DataOutputStream(baos);
pkt.writeInt(JdpGenericPacket.getMagic());
pkt.writeShort(JdpGenericPacket.getVersion());
}
/**
* Put string entry to packet
*
* @param entry - string to put (utf-8 encoded)
* @throws IOException
*/
public void addEntry(String entry)
throws IOException {
/* DataOutputStream.writeUTF() do essentially
* the same as:
* pkt.writeShort(entry.getBytes("UTF-8").length);
* pkt.write(entry.getBytes("UTF-8"));
*/
pkt.writeUTF(entry);
}
/**
* Put key/value pair to packet
*
* @param key - key to put (utf-8 encoded)
* @param val - value to put (utf-8 encoded)
* @throws IOException
*/
public void addEntry(String key, String val)
throws IOException {
/* Silently skip key if value is null.
* We don't need to distinguish between key missing
* and key has no value cases
*/
if (val != null) {
addEntry(key);
addEntry(val);
}
}
/**
* Return assembled packet as a byte array
*
* @return packet bytes
*/
public byte[] getPacketBytes() {
return baos.toByteArray();
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 2013, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
/**
* Summary
* -------
*
* Define a lightweight network protocol for discovering running and
* manageable Java processes within a network subnet.
*
*
* Description
* -----------
*
* The protocol is lightweight multicast based, and works like a beacon,
* broadcasting the JMXService URL needed to connect to the external JMX
* agent if an application is started with appropriate parameters.
*
* The payload is structured like this:
*
* 4 bytes JDP magic (0xC0FFEE42)
* 2 bytes JDP protocol version (1)
* 2 bytes size of the next entry
* x bytes next entry (UTF-8 encoded)
* 2 bytes size of next entry
* ... Rinse and repeat...
*
* The payload will be parsed as even entries being keys, odd entries being
* values.
*
* The standard JDP packet contains four entries:
*
* - `DISCOVERABLE_SESSION_UUID` -- Unique id of the instance; this id changes every time
* the discovery protocol starts and stops
*
* - `MAIN_CLASS` -- The value of the `sun.java.command` property
*
* - `JMX_SERVICE_URL` -- The URL to connect to the JMX agent
*
* - `INSTANCE_NAME` -- The user-provided name of the running instance
*
* The protocol sends packets to 224.0.23.178:7095 by default.
*
* The protocol uses system properties to control it's behaviour:
* - `com.sun.management.jdp.port` -- override default port
*
* - `com.sun.management.jdp.address` -- override default address
*
* - `com.sun.management.jmxremote.autodiscovery` -- whether we should start autodiscovery or
* not. Autodiscovery starts if and only if following conditions are met: (autodiscovery is
* true OR (autodiscovery is not set AND jdp.port is set))
*
* - `com.sun.management.jdp.ttl` -- set ttl for broadcast packet, default is 1
* - `com.sun.management.jdp.pause` -- set broadcast interval in seconds default is 5
* - `com.sun.management.jdp.source_addr` -- an address of interface to use for broadcast
*/
package sun.management.jdp;