/* * Copyright (c) 2007, 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 com.sun.tools.visualvm.jmx.impl; import com.sun.tools.attach.AgentInitializationException; import com.sun.tools.attach.AgentLoadException; import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.visualvm.application.Application; import com.sun.tools.visualvm.application.jvm.HeapHistogram; import com.sun.tools.visualvm.application.type.ApplicationType; import com.sun.tools.visualvm.core.datasource.Storage; import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptor; import com.sun.tools.visualvm.core.datasupport.DataRemovedListener; import com.sun.tools.visualvm.core.datasupport.Stateful; import com.sun.tools.visualvm.host.Host; import com.sun.tools.visualvm.jmx.EnvironmentProvider; import com.sun.tools.visualvm.tools.attach.AttachModelFactory; import com.sun.tools.visualvm.tools.jmx.CachedMBeanServerConnection; import com.sun.tools.visualvm.tools.jmx.CachedMBeanServerConnectionFactory; import com.sun.tools.visualvm.tools.jmx.JmxModel; import com.sun.tools.visualvm.tools.jmx.JmxModelFactory; import com.sun.tools.visualvm.tools.jvmstat.JvmJvmstatModel; import com.sun.tools.visualvm.tools.jvmstat.JvmJvmstatModelFactory; import com.sun.tools.visualvm.tools.jvmstat.JvmstatModel; import java.awt.BorderLayout; import java.awt.EventQueue; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.lang.management.ManagementFactory; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; import javax.management.ListenerNotFoundException; import javax.management.MBeanServerConnection; import javax.management.Notification; import javax.management.NotificationListener; import javax.management.remote.JMXConnectionNotification; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import javax.rmi.ssl.SslRMIClientSocketFactory; import javax.security.sasl.SaslException; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.awt.Mnemonics; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; import sun.tools.attach.HotSpotVirtualMachine; /** * This class encapsulates the JMX functionality of the target Java application. * * Call {@link JmxModelFactory#getJmxModelFor()} to get an instance of the * {@link JmxModel} class. * * Usually this class will be used as follows: * * <pre> * JmxModel jmx = JmxModelFactory.getJmxModelFor(application); * MBeanServerConnection mbsc = jmx.getMBeanServerConnection(); * if (mbsc != null) { * // Invoke JMX operations... * } * </pre> * * Several factory methods are available in {@link CachedMBeanServerConnectionFactory} * that can be used to work with a {@link CachedMBeanServerConnection} instead of a * plain {@link MBeanServerConnection}. * * In case the JMX connection is not established yet, you could register * a listener on the {@code JmxModel} for ConnectionState property changes. * The JmxModel notifies any PropertyChangeListeners about the ConnectionState * property change to CONNECTED and DISCONNECTED. The JmxModel instance will * be the source for any generated events. * * Polling for the ConnectionState is also possible by calling * {@link JmxModel#getConnectionState()}. * * @author Luis-Miguel Alventosa * @author Jiri Sedlacek * @author Tomas Hurka */ class JmxModelImpl extends JmxModel { // private static final String PROPERTY_USERNAME = "prop_username"; // NOI18N // private static final String PROPERTY_PASSWORD = "prop_password"; // NOI18N private final static Logger LOGGER = Logger.getLogger(JmxModelImpl.class.getName()); private ProxyClient client; private ApplicationRemovedListener removedListener; private ApplicationAvailabilityListener availabilityListener; private JmxSupport jmxSupport; private final Object jmxSupportLock = new Object(); /** * Creates an instance of {@code JmxModel} for a {@link JvmstatApplication}. * * @param application the {@link JvmstatApplication}. */ public JmxModelImpl(Application application, JvmstatModel jvmstat) { try { JvmJvmstatModel jvmstatModel = JvmJvmstatModelFactory.getJvmstatModelFor(application); // Create ProxyClient (i.e. create the JMX connection to the JMX agent) ProxyClient proxyClient = null; if (Application.CURRENT_APPLICATION.equals(application)) { // Monitor self proxyClient = new ProxyClient(this); } else if (application.isLocalApplication()) { // Create a ProxyClient from local pid String connectorAddress = jvmstat.findByName("sun.management.JMXConnectorServer.address"); // NOI18N String javaHome = jvmstat.findByName("java.property.java.home"); // NOI18N LocalVirtualMachine lvm = new LocalVirtualMachine(application.getPid(), AttachModelFactory.getAttachFor(application) != null, connectorAddress, javaHome); if (!lvm.isManageable()) { if (lvm.isAttachable()) { proxyClient = new ProxyClient(this, lvm); } else { if (LOGGER.isLoggable(Level.WARNING)) { LOGGER.warning("The JMX management agent " + // NOI18N "cannot be enabled in this application (pid " + // NOI18N application.getPid() + ")"); // NOI18N } } } else { proxyClient = new ProxyClient(this, lvm); } } if (proxyClient == null) { // Create a ProxyClient for the remote out-of-the-box // JMX management agent using the port and security // related information retrieved through jvmstat. List<String> urls = jvmstat.findByPattern("sun.management.JMXConnectorServer.[0-9]+.remoteAddress"); // NOI18N if (urls.size() != 0) { List<String> auths = jvmstat.findByPattern("sun.management.JMXConnectorServer.[0-9]+.authenticate"); // NOI18N proxyClient = new ProxyClient(this, urls.get(0)); if ("true".equals(auths.get(0))) { // NOI18N supplyCredentials(application, proxyClient); } } else { // Create a ProxyClient for the remote out-of-the-box // JMX management agent using the port specified in // the -Dcom.sun.management.jmxremote.port=<port> // system property String jvmArgs = jvmstatModel.getJvmArgs(); StringTokenizer st = new StringTokenizer(jvmArgs); int port = -1; boolean authenticate = false; while (st.hasMoreTokens()) { String token = st.nextToken(); if (token.startsWith("-Dcom.sun.management.jmxremote.port=")) { // NOI18N port = Integer.parseInt(token.substring(token.indexOf("=") + 1)); // NOI18N } else if (token.equals("-Dcom.sun.management.jmxremote.authenticate=true")) { // NOI18N authenticate = true; } } if (port != -1) { proxyClient = new ProxyClient(this, application.getHost(), port); if (authenticate) { supplyCredentials(application, proxyClient); } } } } if (proxyClient != null) { client = proxyClient; removedListener = new ApplicationRemovedListener(); availabilityListener = new ApplicationAvailabilityListener(); connect(application, proxyClient, removedListener, availabilityListener); } } catch (Exception e) { LOGGER.throwing(JmxModelImpl.class.getName(), "<init>", e); // NOI18N client = null; } } /** * Creates an instance of {@code JmxModel} for a {@link JmxApplication}. * * @param application the {@link JmxApplication}. */ public JmxModelImpl(JmxApplication application) { try { final ProxyClient proxyClient = new ProxyClient(this, application); client = proxyClient; removedListener = new ApplicationRemovedListener(); availabilityListener = new ApplicationAvailabilityListener(); connect(application, proxyClient, removedListener, availabilityListener); } catch (Exception e) { LOGGER.throwing(JmxModelImpl.class.getName(), "<init>", e); // NOI18N client = null; } } private void connect(Application application, ProxyClient proxyClient, ApplicationRemovedListener listener, ApplicationAvailabilityListener aListener) { while (true) { try { proxyClient.connect(); application.notifyWhenRemoved(listener); application.addPropertyChangeListener(Stateful.PROPERTY_STATE, aListener); break; } catch (SecurityException e) { LOGGER.log(Level.INFO, "connect", e); // NOI18N if (proxyClient.hasSSLStubCheck()) { Storage storage = application.getStorage(); String noSSLProp = JmxApplicationProvider.PROPERTY_RETRY_WITHOUT_SSL; String noSSL = storage.getCustomProperty(noSSLProp); if (noSSL != null && Boolean.parseBoolean(noSSL)) { // NOI18N proxyClient.setInsecure(); continue; } else { String conn = storage.getCustomProperty(DataSourceDescriptor.PROPERTY_NAME); if (conn == null) conn = storage.getCustomProperty(ApplicationType.PROPERTY_SUGGESTED_NAME); if (conn == null) conn = proxyClient.getUrl().toString(); String msg = NbBundle.getMessage(JmxModelImpl.class, "MSG_Insecure_SSL", conn); // NOI18N String title = NbBundle.getMessage(JmxModelImpl.class, "Title_Insecure_SSL"); // NOI18N String retry = NbBundle.getMessage(JmxModelImpl.class, "Retry_Insecure_SSL"); // NOI18N JLabel l = new JLabel(msg); JCheckBox c = new JCheckBox(); Mnemonics.setLocalizedText(c, retry); c.setSelected(noSSL == null); JPanel p = new JPanel(new BorderLayout(0, 20)); p.add(l, BorderLayout.CENTER); p.add(c, BorderLayout.SOUTH); NotifyDescriptor dd = new NotifyDescriptor.Confirmation(p, title, NotifyDescriptor.YES_NO_OPTION); if (DialogDisplayer.getDefault().notify(dd) == NotifyDescriptor.YES_OPTION) { storage.setCustomProperty(noSSLProp, Boolean.toString(c.isSelected())); proxyClient.setInsecure(); continue; } else { break; } } } if (supplyCredentials(application, proxyClient) == null) { break; } } } } /** * Ask for security credentials. */ private CredentialsConfigurator supplyCredentials( Application application, ProxyClient proxyClient) { String displayName = application.getStorage().getCustomProperty(DataSourceDescriptor.PROPERTY_NAME); if (displayName == null) displayName = proxyClient.getUrl().toString(); CredentialsConfigurator jsc = CredentialsConfigurator.supplyCredentials(displayName); if (jsc != null) proxyClient.setCredentials(jsc.getUsername(), jsc.getPassword()); return jsc; } /** * Returns the current connection state. * * @return the current connection state. */ public ConnectionState getConnectionState() { if (client != null) { return client.getConnectionState(); } return ConnectionState.DISCONNECTED; } /** * Returns the {@link MBeanServerConnection} for the connection to * an application. The returned {@code MBeanServerConnection} object * becomes invalid when the connection state is changed to the * {@link ConnectionState#DISCONNECTED DISCONNECTED} state. * * @return the {@code MBeanServerConnection} for the * connection to an application. It returns {@code null} * if the JMX connection couldn't be established. */ public MBeanServerConnection getMBeanServerConnection() { if (client != null) { return client.getMBeanServerConnection(); } return null; } /** * Returns the {@link JMXServiceURL} associated to this (@code JmxModel}. * * @return the {@link JMXServiceURL} associated to this (@code JmxModel}. */ public JMXServiceURL getJMXServiceURL() { if (client != null) { return client.getUrl(); } return null; } public Properties getSystemProperties() { return getJmxSupport().getSystemProperties(); } public boolean takeHeapDump(String fileName) { return getJmxSupport().takeHeapDump(fileName); } public String takeThreadDump() { return getJmxSupport().takeThreadDump(); } public String takeThreadDump(long[] threadIds) { return getJmxSupport().takeThreadDump(threadIds); } public HeapHistogram takeHeapHistogram() { return getJmxSupport().takeHeapHistogram(); } public String getFlagValue(String name) { return getJmxSupport().getFlagValue(name); } public void setFlagValue(String name, String value) { getJmxSupport().setFlagValue(name,value); } public boolean isTakeHeapDumpSupported() { JmxSupport support = getJmxSupport(); return support.getHotSpotDiagnostic() != null && !support.isReadOnlyConnection(); } public boolean isTakeThreadDumpSupported() { JmxSupport support = getJmxSupport(); return support.getThreadBean() != null && !support.isReadOnlyConnection(); } private JmxSupport getJmxSupport() { synchronized (jmxSupportLock) { if (jmxSupport == null) { jmxSupport = new JmxSupport(this); } return jmxSupport; } } /** * Disconnect from JMX agent when the application is removed. */ private class ApplicationRemovedListener implements DataRemovedListener<Application> { public void dataRemoved(Application application) { RequestProcessor.getDefault().post(new Runnable() { public void run() { client.markAsDead(); removedListener = null; } }); } } private class ApplicationAvailabilityListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { if (!evt.getNewValue().equals(Stateful.STATE_AVAILABLE)) { ((Application)evt.getSource()).removePropertyChangeListener( Stateful.PROPERTY_STATE, this); client.disconnectImpl(false); availabilityListener = null; } } } private static class ProxyClient implements NotificationListener { private static final int MODE_SELF = 0; private static final int MODE_LOCAL = 1; private static final int MODE_GENERIC = 2; private final int mode; private ConnectionState connectionState = ConnectionState.DISCONNECTED; private volatile boolean isDead = true; private String userName = null; private String password = null; private LocalVirtualMachine lvm; private JMXServiceURL jmxUrl = null; private Application app; private EnvironmentProvider envProvider = null; private MBeanServerConnection conn = null; private JMXConnector jmxc = null; private static final SslRMIClientSocketFactory sslRMIClientSocketFactory = new SslRMIClientSocketFactory(); private final JmxModelImpl model; private boolean insecure; // do not check for SSL-protected RMI registry private boolean checkSSLStub; // Self attach public ProxyClient(JmxModelImpl model) throws IOException { this.mode = MODE_SELF; this.model = model; } // Local attach public ProxyClient(JmxModelImpl model, LocalVirtualMachine lvm) throws IOException { this.mode = MODE_LOCAL; this.model = model; this.lvm = lvm; } // Generic attach - host/port public ProxyClient(JmxModelImpl model, Host host, int port) throws IOException { this(model, new JMXServiceURL("rmi", "", 0, createUrl(host.getHostName(), // NOI18N port)), null, null); } // Generic attach - connection string public ProxyClient(JmxModelImpl model, String url) throws IOException { this(model, new JMXServiceURL(url), null, null); } // Generic attach - JmxApplication public ProxyClient(JmxModelImpl model, JmxApplication jmxApp) throws IOException { this(model, jmxApp.getJMXServiceURL(), jmxApp, jmxApp.getEnvironmentProvider()); } // Generic attach - JMXServiceURL private ProxyClient(JmxModelImpl model, JMXServiceURL url, Application app, EnvironmentProvider envProvider) throws IOException { this.mode = MODE_GENERIC; this.model = model; this.jmxUrl = url; this.app = app; this.envProvider = envProvider; } public void setCredentials(String userName, String password) { this.userName = userName; this.password = password; } boolean hasSSLStubCheck() { return checkSSLStub; } void setInsecure() { insecure = true; } boolean isInsecure() { return insecure; } private static String createUrl(String hostName, int port) { return "/jndi/rmi://" + hostName + ":" + port + "/jmxrmi"; // NOI18N } private void setConnectionState(ConnectionState state) { ConnectionState oldState = connectionState; connectionState = state; model.propertyChangeSupport.firePropertyChange( JmxModelImpl.CONNECTION_STATE_PROPERTY, oldState, state); } public ConnectionState getConnectionState() { return connectionState; } void connect() { setConnectionState(ConnectionState.CONNECTING); try { tryConnect(); setConnectionState(ConnectionState.CONNECTED); } catch (SecurityException e) { setConnectionState(ConnectionState.DISCONNECTED); throw e; } catch (SaslException e) { // Workaround for JBoss/WildFly authentication failed exception throw new SecurityException(e); } catch (Exception e) { setConnectionState(ConnectionState.DISCONNECTED); // Workaround for GlassFish's LoginException class not found if (e.toString().contains("com.sun.enterprise.security.LoginException")) { // NOI18N throw new SecurityException("Authentication failed! Invalid username or password"); // NOI18N } if (LOGGER.isLoggable(Level.INFO)) { // Try to provide info on the target // Use PID when attach was used to connect, // Use JMXServiceURL otherwise... final String param = (lvm != null) ? String.valueOf(lvm.vmid()) : ((jmxUrl != null) ? jmxUrl.toString() : ""); // NOI18N LOGGER.log(Level.INFO, "connect(" + param + ")", e); // NOI18N } } } private void tryConnect() throws IOException { if (mode == MODE_SELF) { jmxc = null; conn = ManagementFactory.getPlatformMBeanServer(); } else { if (mode == MODE_LOCAL) { if (!lvm.isManageable()) { lvm.startManagementAgent(); if (!lvm.isManageable()) { // FIXME: what to throw throw new IOException(lvm + " not manageable"); // NOI18N } } if (jmxUrl == null) { jmxUrl = new JMXServiceURL(lvm.connectorAddress()); } } Map<String, Object> env = new HashMap(); if (envProvider != null) env.putAll(envProvider.getEnvironment(app, app.getStorage())); if (userName != null || password != null) env.put(JMXConnector.CREDENTIALS, new String[] { userName, password }); if (!insecure && mode != MODE_LOCAL && env.get(JMXConnector.CREDENTIALS) != null) { env.put("jmx.remote.x.check.stub", "true"); // NOI18N checkSSLStub = true; } else { checkSSLStub = false; } jmxc = JMXConnectorFactory.newJMXConnector(jmxUrl, env); jmxc.addConnectionNotificationListener(this, null, null); try { jmxc.connect(env); } catch (java.io.IOException e) { // Likely a SSL-protected RMI registry if ("rmi".equals(jmxUrl.getProtocol())) { // NOI18N env.put("com.sun.jndi.rmi.factory.socket", sslRMIClientSocketFactory); // NOI18N jmxc.connect(env); } else { throw e; } } MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); conn = Checker.newChecker(this, mbsc); } isDead = false; } public MBeanServerConnection getMBeanServerConnection() { return conn; } public JMXServiceURL getUrl() { return jmxUrl; } public void disconnect() { disconnectImpl(true); } private synchronized void disconnectImpl(boolean sendClose) { // Close MBeanServer connection if (jmxc != null) { try { jmxc.removeConnectionNotificationListener(this); if (sendClose) jmxc.close(); } catch (IOException e) { // Ignore... } catch (ListenerNotFoundException e) { LOGGER.log(Level.INFO, "disconnectImpl", e); // NOI18N } jmxc = null; } // Set connection state to DISCONNECTED if (!isDead) { isDead = true; setConnectionState(ConnectionState.DISCONNECTED); } } public synchronized void markAsDead() { disconnect(); } public boolean isDead() { return isDead; } boolean isConnected() { return !isDead(); } public void handleNotification(Notification n, Object hb) { if (n instanceof JMXConnectionNotification) { if (JMXConnectionNotification.FAILED.equals(n.getType()) || JMXConnectionNotification.CLOSED.equals(n.getType())) { markAsDead(); } } } } private static class Checker { private Checker() { } public static MBeanServerConnection newChecker( ProxyClient client, MBeanServerConnection mbsc) { final InvocationHandler ih = new CheckerInvocationHandler(mbsc); return (MBeanServerConnection) Proxy.newProxyInstance( Checker.class.getClassLoader(), new Class[]{MBeanServerConnection.class}, ih); } } private static class CheckerInvocationHandler implements InvocationHandler { private final MBeanServerConnection conn; CheckerInvocationHandler(MBeanServerConnection conn) { this.conn = conn; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (LOGGER.isLoggable(Level.FINE)) { // Check if MBeanServerConnection call is performed on EDT if (EventQueue.isDispatchThread()) { Throwable thrwbl = new Throwable(); LOGGER.log(Level.FINE, createTracedMessage("MBeanServerConnection call " + // NOI18N "performed on Event Dispatch Thread!", thrwbl)); // NOI18N } } // Invoke MBeanServerConnection call try { return method.invoke(conn, args); } catch (InvocationTargetException e) { throw e.getCause(); } } private String createTracedMessage(String message, Throwable thrwbl) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintWriter pw = new PrintWriter(baos); pw.println(message); thrwbl.printStackTrace(pw); pw.flush(); return baos.toString(); } } private static class LocalVirtualMachine { private static final String ENABLE_LOCAL_AGENT_JCMD = "ManagementAgent.start_local"; // NOI18N private int vmid; private boolean isAttachSupported; private String javaHome; // @GuardedBy this volatile private String address; public LocalVirtualMachine(int vmid, boolean canAttach, String connectorAddress, String home) { this.vmid = vmid; this.address = connectorAddress; this.isAttachSupported = canAttach; this.javaHome = home; } public int vmid() { return vmid; } public synchronized boolean isManageable() { return (address != null); } public boolean isAttachable() { return isAttachSupported; } public synchronized void startManagementAgent() throws IOException { if (address != null) { // already started return; } if (!isAttachable()) { throw new IOException("This virtual machine \"" + vmid + // NOI18N "\" does not support dynamic attach."); // NOI18N } loadManagementAgent(); // fails to load or start the management agent if (address == null) { // should never reach here throw new IOException("Fails to find connector address"); // NOI18N } } public synchronized String connectorAddress() { // return null if not available or no JMX agent return address; } private static final String LOCAL_CONNECTOR_ADDRESS_PROP = "com.sun.management.jmxremote.localConnectorAddress"; // NOI18N private synchronized void loadManagementAgent() throws IOException { VirtualMachine vm = null; String name = String.valueOf(vmid); try { vm = VirtualMachine.attach(name); } catch (AttachNotSupportedException x) { throw new IOException(x); } // try to enable local JMX via jcmd command if (!loadManagementAgentViaJcmd(vm)) { // load the management agent into the target VM loadManagementAgentViaJar(vm); } // get the connector address Properties agentProps = vm.getAgentProperties(); address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); vm.detach(); } private void loadManagementAgentViaJar(VirtualMachine vm) throws IOException { // Normally in ${java.home}/jre/lib/management-agent.jar but might // be in ${java.home}/lib in build environments. String agent = javaHome + File.separator + "jre" + File.separator + // NOI18N "lib" + File.separator + "management-agent.jar"; // NOI18N File f = new File(agent); if (!f.exists()) { agent = javaHome + File.separator + "lib" + File.separator + // NOI18N "management-agent.jar"; // NOI18N f = new File(agent); if (!f.exists()) { throw new IOException("Management agent not found"); // NOI18N } } agent = f.getCanonicalPath(); try { vm.loadAgent(agent, "com.sun.management.jmxremote"); // NOI18N } catch (AgentLoadException x) { throw new IOException(x); } catch (AgentInitializationException x) { throw new IOException(x); } } private boolean loadManagementAgentViaJcmd(VirtualMachine vm) throws IOException { if (vm instanceof HotSpotVirtualMachine) { HotSpotVirtualMachine hsvm = (HotSpotVirtualMachine) vm; InputStream in = null; try { byte b[] = new byte[256]; int n; in = hsvm.executeJCmd(ENABLE_LOCAL_AGENT_JCMD); do { n = in.read(b); if (n > 0) { String s = new String(b, 0, n, "UTF-8"); // NOI18N System.out.print(s); } } while (n > 0); return true; } catch (IOException ex) { LOGGER.log(Level.INFO, "jcmd command \""+ENABLE_LOCAL_AGENT_JCMD+"\" for PID "+vmid+" failed", ex); // NOI18N } finally { if (in != null) { in.close(); } } } return false; } } }