1 /* 2 * Copyright (c) 2014 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.testlibrary.ProcessThread; 37 import jdk.testlibrary.Utils; 38 39 /* 40 * @test 41 * @summary Test for VirtualMachine.startManagementAgent and VirtualMachine.startLocalManagementAgent 42 * @library /lib/testlibrary 43 * @run build Application SimpleProvider jdk.testlibrary.* 44 * @run main/timeout=300 StartManagementAgent 45 */ 46 47 /* 48 * This test is not meant to test all possible configuration parameters to 49 * the JMX agent, there are other tests for that. This test makes sure it is 50 * possible to start the agent via attach. 51 */ 52 public class StartManagementAgent { 53 public static void main(String[] args) throws Throwable { 54 ProcessThread processThread = null; 55 try { 56 System.out.println("Starting test application"); 57 processThread = RunnerUtil.startApplication(); 58 System.out.println("Application started"); 59 runTests(processThread.getPid()); 60 } catch (Throwable t) { 61 System.out.println("StartManagementAgent got unexpected exception: " + t); 62 t.printStackTrace(); 63 throw t; 64 } finally { 65 // Make sure the Application process is stopped. 66 RunnerUtil.stopApplication(processThread); 67 } 68 } 69 70 private static void basicTests(VirtualMachine vm) throws Exception { 71 72 // Try calling with null argument 73 boolean exception = false; 74 try { 75 System.out.println("Starting management agent with null"); 76 vm.startManagementAgent(null); 77 } catch (NullPointerException e) { 78 exception = true; 79 } 80 if (!exception) { 81 throw new Exception("startManagementAgent(null) should throw NPE"); 82 } 83 84 // Try calling with a property value with a space in it 85 Properties p = new Properties(); 86 File f = new File("file with space"); 87 try (FileWriter fw = new FileWriter(f)) { 88 fw.write("com.sun.management.jmxremote.port=apa"); 89 } 90 p.put("com.sun.management.config.file", f.getAbsolutePath()); 91 try { 92 System.out.println("Starting management agent with bogus port"); 93 vm.startManagementAgent(p); 94 } catch(AttachOperationFailedException ex) { 95 // We expect parsing of "apa" above to fail, but if the file path 96 // can't be read we get a different exception message 97 if (!ex.getMessage().contains("Invalid com.sun.management.jmxremote.port number")) { 98 throw ex; 99 } 100 ex.printStackTrace(System.err); 101 } catch (Throwable t) { 102 t.printStackTrace(System.err); 103 throw t; 104 } 105 } 106 107 private static final String LOCAL_CONNECTOR_ADDRESS_PROP = 108 "com.sun.management.jmxremote.localConnectorAddress"; 109 110 private static final int MAX_RETRIES = 10; 111 112 public static void runTests(long pid) throws Exception { 113 VirtualMachine vm = VirtualMachine.attach(""+pid); 114 try { 115 116 basicTests(vm); 117 118 testLocalAgent(vm); 119 120 // we retry the remote case several times in case the error 121 // was caused by a port conflict 122 int i = 0; 123 boolean success = false; 124 do { 125 try { 126 System.err.println("Trying remote agent. Try #" + i); 127 testRemoteAgent(vm); 128 System.err.println("Successfully connected to remote agent"); 129 success = true; 130 } catch(Exception ex) { 131 System.err.println("testRemoteAgent failed with exception:"); 132 ex.printStackTrace(); 133 System.err.println("Retrying."); 134 } 135 i++; 136 } while(!success && i < MAX_RETRIES); 137 if (!success) { 138 throw new Exception("testRemoteAgent failed after " + MAX_RETRIES + " tries"); 139 } 140 } finally { 141 System.err.println("Detaching from VM ..."); 142 vm.detach(); 143 System.err.println("Detached"); 144 } 145 } 146 147 public static void testLocalAgent(VirtualMachine vm) throws Exception { 148 System.out.println("Getting VM properties"); 149 Properties agentProps = vm.getAgentProperties(); 150 String address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); 151 if (address != null) { 152 throw new Exception("Local management agent already started"); 153 } 154 155 System.out.println("Starting local agent"); 156 157 String result = vm.startLocalManagementAgent(); 158 159 System.out.println("Agent started"); 160 161 // try to parse the return value as a JMXServiceURL 162 new JMXServiceURL(result); 163 164 agentProps = vm.getAgentProperties(); 165 address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); 166 if (address == null) { 167 throw new Exception("Local management agent could not be started"); 168 } 169 } 170 171 public static void testRemoteAgent(VirtualMachine vm) throws Exception { 172 int port = Utils.getFreePort(); 173 174 // try to connect - should fail 175 tryConnect(port, false); 176 177 // start agent 178 System.out.println("Starting agent on port: " + port); 179 Properties mgmtProps = new Properties(); 180 mgmtProps.put("com.sun.management.jmxremote.port", port); 181 mgmtProps.put("com.sun.management.jmxremote.authenticate", "false"); 182 mgmtProps.put("com.sun.management.jmxremote.ssl", "false"); 183 184 System.err.println("Starting management agent ..."); 185 vm.startManagementAgent(mgmtProps); 186 System.err.println("Started"); 187 188 // try to connect - should work 189 tryConnect(port, true); 190 191 // try to start again - should fail 192 boolean exception = false; 193 try { 194 System.err.println("Starting management agent second time ..."); 195 vm.startManagementAgent(mgmtProps); 196 System.err.println("Started"); 197 } catch(AttachOperationFailedException ex) { 198 // expected 199 System.err.println("Got expected exception: " + ex.getMessage()); 200 exception = true; 201 } 202 if (!exception) { 203 throw new Exception("Expected the second call to vm.startManagementAgent() to fail"); 204 } 205 } 206 207 private static void tryConnect(int port, boolean shouldSucceed) throws Exception { 208 String jmxUrlStr = 209 String.format( 210 "service:jmx:rmi:///jndi/rmi://localhost:%d/jmxrmi", 211 port); 212 JMXServiceURL url = new JMXServiceURL(jmxUrlStr); 213 HashMap<String, ?> env = new HashMap<>(); 214 215 boolean succeeded; 216 try { 217 System.err.println("Trying to connect to " + jmxUrlStr); 218 JMXConnector c = JMXConnectorFactory.connect(url, env); 219 System.err.println("Connected, getting MBeanServerConnection"); 220 c.getMBeanServerConnection(); 221 System.err.println("Success"); 222 succeeded = true; 223 } catch(Exception ex) { 224 ex.printStackTrace(System.err); 225 succeeded = false; 226 } 227 if (succeeded && !shouldSucceed) { 228 throw new Exception("Could connect to agent, but should not have been possible"); 229 } 230 if (!succeeded && shouldSucceed) { 231 throw new Exception("Could not connect to agent"); 232 } 233 } 234 }