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