1 /* 2 * Copyright (c) 2004, 2015, 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 26 package sun.management; 27 28 import java.io.IOException; 29 import java.nio.ByteBuffer; 30 import java.nio.ByteOrder; 31 import java.util.HashMap; 32 import java.util.Iterator; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.concurrent.atomic.AtomicInteger; 36 37 import jdk.internal.perf.Perf; 38 import sun.management.counter.Units; 39 import sun.management.counter.Counter; 40 import sun.management.counter.perf.PerfInstrumentation; 41 42 /** 43 * A utility class to support the exporting and importing of the address 44 * of a connector server using the instrumentation buffer. 45 * 46 * @since 1.5 47 */ 48 public class ConnectorAddressLink { 49 /** 50 * A simple wrapper for the perf-counter backing {@linkplain ByteBuffer} 51 */ 52 private static final class PerfHandle { 53 private ByteBuffer bb; 54 55 private PerfHandle(ByteBuffer bb) { 56 this.bb = bb.order(ByteOrder.nativeOrder()); 57 } 58 59 private void putLong(long l) { 60 this.bb = bb.clear(); 61 this.bb.asLongBuffer().put(l); 62 } 63 } 64 65 private static final String CONNECTOR_ADDRESS_COUNTER = 66 "sun.management.JMXConnectorServer.address"; 67 private static final String REMOTE_CONNECTOR_STATE_COUNTER = 68 "sun.management.JMXConnectorServer.remote.enabled"; 69 70 /* 71 * The format of the jvmstat counters representing the properties of 72 * a given out-of-the-box JMX remote connector will be as follows: 73 * 74 * sun.management.JMXConnectorServer.<counter>.<key>=<value> 75 * 76 * where: 77 * 78 * counter = index computed by this class which uniquely identifies 79 * an out-of-the-box JMX remote connector running in this 80 * Java virtual machine. 81 * key/value = a given key/value pair in the map supplied to the 82 * exportRemote() method. 83 * 84 * For example, 85 * 86 * sun.management.JMXConnectorServer.0.remoteAddress=service:jmx:rmi:///jndi/rmi://myhost:5000/jmxrmi 87 * sun.management.JMXConnectorServer.0.authenticate=false 88 * sun.management.JMXConnectorServer.0.ssl=false 89 * sun.management.JMXConnectorServer.0.sslRegistry=false 90 * sun.management.JMXConnectorServer.0.sslNeedClientAuth=false 91 */ 92 private static final String REMOTE_CONNECTOR_COUNTER_PREFIX = 93 "sun.management.JMXConnectorServer."; 94 95 /* 96 * JMX remote connector counter (it will be incremented every 97 * time a new out-of-the-box JMX remote connector is created). 98 */ 99 private static final AtomicInteger counter = new AtomicInteger(); 100 101 private static PerfHandle remotePerfHandle = null; 102 103 /** 104 * Exports the specified connector address to the instrumentation buffer 105 * so that it can be read by this or other Java virtual machines running 106 * on the same system. 107 * 108 * @param address The connector address. 109 */ 110 public static void export(String address) { 111 if (address == null || address.length() == 0) { 112 throw new IllegalArgumentException("address not specified"); 113 } 114 Perf perf = Perf.getPerf(); 115 perf.createString( 116 CONNECTOR_ADDRESS_COUNTER, 1, Units.STRING.intValue(), address); 117 } 118 119 public static void unexportRemote() { 120 unexport(remotePerfHandle); 121 } 122 123 private static void unexport(PerfHandle ph) { 124 if (ph != null) { 125 ph.putLong(-1L); 126 } 127 } 128 129 /** 130 * Imports the connector address from the instrument buffer 131 * of the specified Java virtual machine. 132 * 133 * @param vmid an identifier that uniquely identifies a local Java virtual 134 * machine, or <code>0</code> to indicate the current Java virtual machine. 135 * 136 * @return the value of the connector address, or <code>null</code> if the 137 * target VM has not exported a connector address. 138 * 139 * @throws IOException An I/O error occurred while trying to acquire the 140 * instrumentation buffer. 141 */ 142 public static String importFrom(int vmid) throws IOException { 143 Perf perf = Perf.getPerf(); 144 ByteBuffer bb; 145 try { 146 bb = perf.attach(vmid, "r"); 147 } catch (IllegalArgumentException iae) { 148 throw new IOException(iae.getMessage()); 149 } 150 List<Counter> counters = 151 new PerfInstrumentation(bb).findByPattern(CONNECTOR_ADDRESS_COUNTER); 152 Iterator<Counter> i = counters.iterator(); 153 if (i.hasNext()) { 154 Counter c = i.next(); 155 return (String) c.getValue(); 156 } else { 157 return null; 158 } 159 } 160 161 /** 162 * Exports the specified remote connector address and associated 163 * configuration properties to the instrumentation buffer so that 164 * it can be read by this or other Java virtual machines running 165 * on the same system. 166 * 167 * @param properties The remote connector address properties. 168 */ 169 public static void exportRemote(Map<String, String> properties) { 170 final int index = counter.getAndIncrement(); 171 Perf perf = Perf.getPerf(); 172 for (Map.Entry<String, String> entry : properties.entrySet()) { 173 perf.createString(REMOTE_CONNECTOR_COUNTER_PREFIX + index + "." + 174 entry.getKey(), 1, Units.STRING.intValue(), entry.getValue()); 175 } 176 if (remotePerfHandle != null) { 177 remotePerfHandle.putLong(index); 178 } else { 179 remotePerfHandle = new PerfHandle( 180 perf.createLong(REMOTE_CONNECTOR_STATE_COUNTER, 1, Units.NONE.intValue(), (long)index) 181 ); 182 } 183 } 184 185 /** 186 * Imports the remote connector address and associated 187 * configuration properties from the instrument buffer 188 * of the specified Java virtual machine. 189 * 190 * @param vmid an identifier that uniquely identifies a local Java virtual 191 * machine, or <code>0</code> to indicate the current Java virtual machine. 192 * 193 * @return a map containing the remote connector's properties, or an empty 194 * map if the target VM has not exported the remote connector's properties. 195 * 196 * @throws IOException An I/O error occurred while trying to acquire the 197 * instrumentation buffer. 198 */ 199 public static Map<String, String> importRemoteFrom(int vmid) throws IOException { 200 Perf perf = Perf.getPerf(); 201 ByteBuffer bb; 202 try { 203 bb = perf.attach(vmid, "r"); 204 } catch (IllegalArgumentException iae) { 205 throw new IOException(iae.getMessage()); 206 } 207 List<Counter> counters = new PerfInstrumentation(bb).getAllCounters(); 208 Map<String, String> properties = new HashMap<>(); 209 for (Counter c : counters) { 210 String name = c.getName(); 211 if (name.startsWith(REMOTE_CONNECTOR_COUNTER_PREFIX) && 212 !name.equals(CONNECTOR_ADDRESS_COUNTER)) { 213 properties.put(name, c.getValue().toString()); 214 } 215 } 216 return properties; 217 } 218 }