001: /*
002: * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.management;
027:
028: import java.io.File;
029: import java.io.InputStream;
030: import java.io.FileInputStream;
031: import java.io.BufferedInputStream;
032: import java.io.FileNotFoundException;
033: import java.io.IOException;
034: import java.text.MessageFormat;
035: import java.util.Properties;
036: import java.util.Enumeration;
037: import java.util.ResourceBundle;
038: import java.util.MissingResourceException;
039: import java.lang.management.ManagementFactory;
040: import java.lang.reflect.Method;
041:
042: import javax.management.remote.JMXConnectorServer;
043:
044: import sun.management.snmp.AdaptorBootstrap;
045: import sun.management.jmxremote.ConnectorBootstrap;
046: import static sun.management.AgentConfigurationError.*;
047: import sun.misc.VMSupport;
048:
049: /**
050: * This Agent is started by the VM when -Dcom.sun.management.snmp
051: * or -Dcom.sun.management.jmxremote is set. This class will be
052: * loaded by the system class loader.
053: */
054: public class Agent {
055: // management properties
056: private static Properties mgmtProps;
057: private static ResourceBundle messageRB;
058:
059: private static final String CONFIG_FILE = "com.sun.management.config.file";
060: private static final String SNMP_PORT = "com.sun.management.snmp.port";
061: private static final String JMXREMOTE = "com.sun.management.jmxremote";
062: private static final String JMXREMOTE_PORT = "com.sun.management.jmxremote.port";
063: private static final String ENABLE_THREAD_CONTENTION_MONITORING = "com.sun.management.enableThreadContentionMonitoring";
064: private static final String LOCAL_CONNECTOR_ADDRESS_PROP = "com.sun.management.jmxremote.localConnectorAddress";
065:
066: // invoked by -javaagent or -Dcom.sun.management.agent.class
067: public static void premain(String args) throws Exception {
068: agentmain(args);
069: }
070:
071: // invoked by attach mechanism
072: public static void agentmain(String args) throws Exception {
073: if (args == null || args.length() == 0) {
074: args = JMXREMOTE; // default to local management
075: }
076:
077: // Parse agent options into properties
078:
079: Properties arg_props = new Properties();
080: if (args != null) {
081: String[] options = args.split(",");
082: for (int i = 0; i < options.length; i++) {
083: String[] option = options[i].split("=");
084: if (option.length >= 1 && option.length <= 2) {
085: String name = option[0];
086: String value = (option.length == 1) ? ""
087: : option[1];
088: if (name != null && name.length() > 0) {
089:
090: // Assume that any com.sun.management.* options are okay
091: if (name.startsWith("com.sun.management.")) {
092: arg_props.setProperty(name, value);
093: } else {
094: error(INVALID_OPTION, name);
095: }
096: }
097: }
098: }
099: }
100:
101: // Read properties from the config file
102: Properties config_props = new Properties();
103: String fname = arg_props.getProperty(CONFIG_FILE);
104: readConfiguration(fname, config_props);
105:
106: // Arguments override config file
107: config_props.putAll(arg_props);
108: startAgent(config_props);
109: }
110:
111: private static void startAgent(Properties props) throws Exception {
112: String snmpPort = props.getProperty(SNMP_PORT);
113: String jmxremote = props.getProperty(JMXREMOTE);
114: String jmxremotePort = props.getProperty(JMXREMOTE_PORT);
115:
116: // Enable optional monitoring functionality if requested
117: final String enableThreadContentionMonitoring = props
118: .getProperty(ENABLE_THREAD_CONTENTION_MONITORING);
119: if (enableThreadContentionMonitoring != null) {
120: ManagementFactory.getThreadMXBean()
121: .setThreadContentionMonitoringEnabled(true);
122: }
123:
124: try {
125: if (snmpPort != null) {
126: AdaptorBootstrap.initialize(snmpPort, props);
127: }
128:
129: /*
130: * If the jmxremote.port property is set then we start the
131: * RMIConnectorServer for remote M&M.
132: *
133: * If the jmxremote or jmxremote.port properties are set then
134: * we start a RMIConnectorServer for local M&M. The address
135: * of this "local" server is exported as a counter to the jstat
136: * instrumentation buffer.
137: */
138: if (jmxremote != null || jmxremotePort != null) {
139: if (jmxremotePort != null) {
140: ConnectorBootstrap.initialize(jmxremotePort, props);
141: }
142:
143: Properties agentProps = VMSupport.getAgentProperties();
144: // start local connector if not started
145: // System.out.println("local address : " +
146: // agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP));
147: if (agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP) == null) {
148: JMXConnectorServer cs = ConnectorBootstrap
149: .startLocalConnectorServer();
150: String address = cs.getAddress().toString();
151: // Add the local connector address to the agent properties
152: agentProps.put(LOCAL_CONNECTOR_ADDRESS_PROP,
153: address);
154:
155: try {
156: // export the address to the instrumentation buffer
157: ConnectorAddressLink.export(address);
158: } catch (Exception x) {
159: // Connector server started but unable to export address
160: // to instrumentation buffer - non-fatal error.
161: warning(EXPORT_ADDRESS_FAILED, x.getMessage());
162: }
163: }
164: }
165: } catch (AgentConfigurationError e) {
166: error(e.getError(), e.getParams());
167: } catch (Exception e) {
168: error(e);
169: }
170: }
171:
172: public static Properties loadManagementProperties() {
173: Properties props = new Properties();
174:
175: // Load the management properties from the config file
176:
177: String fname = System.getProperty(CONFIG_FILE);
178: readConfiguration(fname, props);
179:
180: // management properties can be overridden by system properties
181: // which take precedence
182: props.putAll(System.getProperties());
183:
184: return props;
185: }
186:
187: public static synchronized Properties getManagementProperties() {
188: if (mgmtProps == null) {
189: String configFile = System.getProperty(CONFIG_FILE);
190: String snmpPort = System.getProperty(SNMP_PORT);
191: String jmxremote = System.getProperty(JMXREMOTE);
192: String jmxremotePort = System.getProperty(JMXREMOTE_PORT);
193:
194: if (configFile == null && snmpPort == null
195: && jmxremote == null && jmxremotePort == null) {
196: // return if out-of-the-management option is not specified
197: return null;
198: }
199: mgmtProps = loadManagementProperties();
200: }
201: return mgmtProps;
202: }
203:
204: // read config file and initialize the properties
205: private static void readConfiguration(String fname, Properties p) {
206: if (fname == null) {
207: String home = System.getProperty("java.home");
208: if (home == null) {
209: throw new Error("Can't find java.home ??");
210: }
211: StringBuffer defaultFileName = new StringBuffer(home);
212: defaultFileName.append(File.separator).append("lib");
213: defaultFileName.append(File.separator).append("management");
214: defaultFileName.append(File.separator).append(
215: "management.properties");
216: // Set file name
217: fname = defaultFileName.toString();
218: }
219: final File configFile = new File(fname);
220: if (!configFile.exists()) {
221: error(CONFIG_FILE_NOT_FOUND, fname);
222: }
223:
224: InputStream in = null;
225: try {
226: in = new FileInputStream(configFile);
227: BufferedInputStream bin = new BufferedInputStream(in);
228: p.load(bin);
229: } catch (FileNotFoundException e) {
230: error(CONFIG_FILE_OPEN_FAILED, e.getMessage());
231: } catch (IOException e) {
232: error(CONFIG_FILE_OPEN_FAILED, e.getMessage());
233: } catch (SecurityException e) {
234: error(CONFIG_FILE_ACCESS_DENIED, fname);
235: } finally {
236: if (in != null) {
237: try {
238: in.close();
239: } catch (IOException e) {
240: error(CONFIG_FILE_CLOSE_FAILED, fname);
241: }
242: }
243: }
244: }
245:
246: public static void startAgent() throws Exception {
247: String prop = System
248: .getProperty("com.sun.management.agent.class");
249:
250: // -Dcom.sun.management.agent.class not set so read management
251: // properties and start agent
252: if (prop == null) {
253: // initialize management properties
254: Properties props = getManagementProperties();
255: if (props != null) {
256: startAgent(props);
257: }
258: return;
259: }
260:
261: // -Dcom.sun.management.agent.class=<agent classname>:<agent args>
262: String[] values = prop.split(":");
263: if (values.length < 1 || values.length > 2) {
264: error(AGENT_CLASS_INVALID, "\"" + prop + "\"");
265: }
266: String cname = values[0];
267: String args = (values.length == 2 ? values[1] : null);
268:
269: if (cname == null || cname.length() == 0) {
270: error(AGENT_CLASS_INVALID, "\"" + prop + "\"");
271: }
272:
273: if (cname != null) {
274: try {
275: // Instantiate the named class.
276: // invoke the premain(String args) method
277: Class<?> clz = ClassLoader.getSystemClassLoader()
278: .loadClass(cname);
279: Method premain = clz.getMethod("premain",
280: new Class[] { String.class });
281: premain.invoke(null, /* static */
282: new Object[] { args });
283: } catch (ClassNotFoundException ex) {
284: error(AGENT_CLASS_NOT_FOUND, "\"" + cname + "\"");
285: } catch (NoSuchMethodException ex) {
286: error(AGENT_CLASS_PREMAIN_NOT_FOUND, "\"" + cname
287: + "\"");
288: } catch (SecurityException ex) {
289: error(AGENT_CLASS_ACCESS_DENIED);
290: } catch (Exception ex) {
291: String msg = (ex.getCause() == null ? ex.getMessage()
292: : ex.getCause().getMessage());
293: error(AGENT_CLASS_FAILED, msg);
294: }
295: }
296: }
297:
298: public static void error(String key) {
299: String keyText = getText(key);
300: System.err.print(getText("agent.err.error") + ": " + keyText);
301: throw new RuntimeException(keyText);
302: }
303:
304: public static void error(String key, String[] params) {
305: if (params == null || params.length == 0) {
306: error(key);
307: } else {
308: StringBuffer message = new StringBuffer(params[0]);
309: for (int i = 1; i < params.length; i++) {
310: message.append(" " + params[i]);
311: }
312: error(key, message.toString());
313: }
314: }
315:
316: public static void error(String key, String message) {
317: String keyText = getText(key);
318: System.err.print(getText("agent.err.error") + ": " + keyText);
319: System.err.println(": " + message);
320: throw new RuntimeException(keyText);
321: }
322:
323: public static void error(Exception e) {
324: e.printStackTrace();
325: System.err.println(getText(AGENT_EXCEPTION) + ": "
326: + e.toString());
327: throw new RuntimeException(e);
328: }
329:
330: public static void warning(String key, String message) {
331: System.err.print(getText("agent.err.warning") + ": "
332: + getText(key));
333: System.err.println(": " + message);
334: }
335:
336: private static void initResource() {
337: try {
338: messageRB = ResourceBundle
339: .getBundle("sun.management.resources.agent");
340: } catch (MissingResourceException e) {
341: throw new Error(
342: "Fatal: Resource for management agent is missing");
343: }
344: }
345:
346: public static String getText(String key) {
347: if (messageRB == null) {
348: initResource();
349: }
350: try {
351: return messageRB.getString(key);
352: } catch (MissingResourceException e) {
353: return "Missing management agent resource bundle: key = \""
354: + key + "\"";
355: }
356: }
357:
358: public static String getText(String key, String... args) {
359: if (messageRB == null) {
360: initResource();
361: }
362: String format = messageRB.getString(key);
363: if (format == null) {
364: format = "missing resource key: key = \"" + key + "\", "
365: + "arguments = \"{0}\", \"{1}\", \"{2}\"";
366: }
367: return MessageFormat.format(format, (Object[]) args);
368: }
369:
370: }
|