1 /* 2 * Copyright (c) 2014, 2018, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import com.sun.tools.attach.AttachOperationFailedException; 25 import com.sun.tools.attach.VirtualMachine; 26 27 import java.io.File; 28 import java.io.FileWriter; 29 import java.util.Properties; 30 import java.util.HashMap; 31 32 import javax.management.remote.JMXServiceURL; 33 import javax.management.remote.JMXConnector; 34 import javax.management.remote.JMXConnectorFactory; 35 36 import jdk.test.lib.thread.ProcessThread; 37 import jdk.test.lib.Utils; 38 39 /* 40 * @test 41 * @summary Test for VirtualMachine.startManagementAgent and VirtualMachine.startLocalManagementAgent 42 * 43 * @library /test/lib 44 * @modules java.management 45 * jdk.attach 46 * jdk.jartool/sun.tools.jar 47 * 48 * @run build Application SimpleProvider 49 * @run main/timeout=300 StartManagementAgent 50 */ 51 52 /* 53 * This test is not meant to test all possible configuration parameters to 54 * the JMX agent, there are other tests for that. This test makes sure it is 55 * possible to start the agent via attach. 56 */ 57 public class StartManagementAgent { 58 public static void main(String[] args) throws Throwable { 59 ProcessThread processThread = null; 60 try { 61 System.out.println("Starting test application"); 62 processThread = RunnerUtil.startApplication(); 63 System.out.println("Application started"); 64 runTests(processThread.getPid()); 65 } catch (Throwable t) { 66 System.out.println("StartManagementAgent got unexpected exception: " + t); 67 t.printStackTrace(); 68 throw t; 69 } finally { 70 // Make sure the Application process is stopped. 71 RunnerUtil.stopApplication(processThread); 72 } 73 } 74 75 private static void basicTests(VirtualMachine vm) throws Exception { 76 77 // Try calling with null argument 78 boolean exception = false; 79 try { 80 System.out.println("Starting management agent with null"); 81 vm.startManagementAgent(null); 82 } catch (NullPointerException e) { 83 exception = true; 84 } 85 if (!exception) { 86 throw new Exception("startManagementAgent(null) should throw NPE"); 87 } 88 89 // Try calling with a property value with a space in it 90 Properties p = new Properties(); 91 File f = new File("file with space"); 92 try (FileWriter fw = new FileWriter(f)) { 93 fw.write("com.sun.management.jmxremote.port=apa"); 94 } 95 p.put("com.sun.management.config.file", f.getAbsolutePath()); 96 try { 97 System.out.println("Starting management agent with bogus port"); 98 vm.startManagementAgent(p); 99 } catch(AttachOperationFailedException ex) { 100 // We expect parsing of "apa" above to fail, but if the file path 101 // can't be read we get a different exception message 102 if (!ex.getMessage().contains("NumberFormatException: For input string: \"apa\"")) { 103 throw ex; 104 } 105 ex.printStackTrace(System.err); 106 } catch (Throwable t) { 107 t.printStackTrace(System.err); 108 throw t; 109 } 110 } 111 112 private static final String LOCAL_CONNECTOR_ADDRESS_PROP = 113 "com.sun.management.jmxremote.localConnectorAddress"; 114 115 private static final int MAX_RETRIES = 10; 116 117 public static void runTests(long pid) throws Exception { 118 VirtualMachine vm = VirtualMachine.attach(""+pid); 119 try { 120 121 basicTests(vm); 122 123 testLocalAgent(vm); 124 125 // we retry the remote case several times in case the error 126 // was caused by a port conflict 127 int i = 0; 128 boolean success = false; 129 do { 130 try { 131 System.err.println("Trying remote agent. Try #" + i); 132 testRemoteAgent(vm); 133 System.err.println("Successfully connected to remote agent"); 134 success = true; 135 } catch(Exception ex) { 136 System.err.println("testRemoteAgent failed with exception:"); 137 ex.printStackTrace(); 138 System.err.println("Retrying."); 139 } 140 i++; 141 } while(!success && i < MAX_RETRIES); 142 if (!success) { 143 throw new Exception("testRemoteAgent failed after " + MAX_RETRIES + " tries"); 144 } 145 } finally { 146 System.err.println("Detaching from VM ..."); 147 vm.detach(); 148 System.err.println("Detached"); 149 } 150 } 151 152 public static void testLocalAgent(VirtualMachine vm) throws Exception { 153 System.out.println("Getting VM properties"); 154 Properties agentProps = vm.getAgentProperties(); 155 String address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); 156 if (address != null) { 157 throw new Exception("Local management agent already started"); 158 } 159 160 System.out.println("Starting local agent"); 161 162 String result = vm.startLocalManagementAgent(); 163 164 System.out.println("Agent started"); 165 166 // try to parse the return value as a JMXServiceURL 167 new JMXServiceURL(result); 168 169 agentProps = vm.getAgentProperties(); 170 address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); 171 if (address == null) { 172 throw new Exception("Local management agent could not be started"); 173 } 174 } 175 176 public static void testRemoteAgent(VirtualMachine vm) throws Exception { 177 int port = Utils.getFreePort(); 178 179 // try to connect - should fail 180 tryConnect(port, false); 181 182 // start agent 183 System.out.println("Starting agent on port: " + port); 184 Properties mgmtProps = new Properties(); 185 mgmtProps.put("com.sun.management.jmxremote.port", port); 186 mgmtProps.put("com.sun.management.jmxremote.authenticate", "false"); 187 mgmtProps.put("com.sun.management.jmxremote.ssl", "false"); 188 189 System.err.println("Starting management agent ..."); 190 vm.startManagementAgent(mgmtProps); 191 System.err.println("Started"); 192 193 // try to connect - should work 194 tryConnect(port, true); 195 196 // try to start again - should fail 197 boolean exception = false; 198 try { 199 System.err.println("Starting management agent second time ..."); 200 vm.startManagementAgent(mgmtProps); 201 System.err.println("Started"); 202 } catch(AttachOperationFailedException ex) { 203 // expected 204 System.err.println("Got expected exception: " + ex.getMessage()); 205 exception = true; 206 } 207 if (!exception) { 208 throw new Exception("Expected the second call to vm.startManagementAgent() to fail"); 209 } 210 } 211 212 private static void tryConnect(int port, boolean shouldSucceed) throws Exception { 213 String jmxUrlStr = 214 String.format( 215 "service:jmx:rmi:///jndi/rmi://localhost:%d/jmxrmi", 216 port); 217 JMXServiceURL url = new JMXServiceURL(jmxUrlStr); 218 HashMap<String, ?> env = new HashMap<>(); 219 220 boolean succeeded; 221 try { 222 System.err.println("Trying to connect to " + jmxUrlStr); 223 JMXConnector c = JMXConnectorFactory.connect(url, env); 224 System.err.println("Connected, getting MBeanServerConnection"); 225 c.getMBeanServerConnection(); 226 System.err.println("Success"); 227 succeeded = true; 228 } catch(Exception ex) { 229 ex.printStackTrace(System.err); 230 succeeded = false; 231 } 232 if (succeeded && !shouldSucceed) { 233 throw new Exception("Could connect to agent, but should not have been possible"); 234 } 235 if (!succeeded && shouldSucceed) { 236 throw new Exception("Could not connect to agent"); 237 } 238 } 239 }