1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * The contents of this file are subject to the terms of either the Universal Permissive License 7 * v 1.0 as shown at http://oss.oracle.com/licenses/upl 8 * 9 * or the following license: 10 * 11 * Redistribution and use in source and binary forms, with or without modification, are permitted 12 * provided that the following conditions are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions 15 * and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 18 * conditions and the following disclaimer in the documentation and/or other materials provided with 19 * the distribution. 20 * 21 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 22 * endorse or promote products derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 26 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 31 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 package org.openjdk.jmc.rjmx.test.testutil; 34 35 import java.io.IOException; 36 import java.net.DatagramPacket; 37 import java.net.DatagramSocket; 38 import java.security.AccessController; 39 import java.security.PrivilegedAction; 40 41 /** 42 * Simple, small test class to make a JVM stay awake. Takes one optional argument, which is the 43 * time, in seconds, to stay alive. If no argument is specified, the JVM will stay alive 44 * indefinitely. 45 * <p> 46 * It's meant to be used as a simple way to keep a JVM awake while testing the management console. 47 * To start a JVM with the management server, use the following argument: 48 * </p> 49 * Use the system properties -Dkill.port=<port> to specify a port other than 4713 to listen for kill 50 * commands. 51 */ 52 public class JVMKeepAlive { 53 private static int m_aliveTime; 54 private static long m_startTime = System.currentTimeMillis(); 55 public static final int DEFAULT_KILL_PORT = 4713; 56 public static final byte[] KILL_MESSAGE = "KILL".getBytes(); //$NON-NLS-1$ 57 private static final String PROPERTY_KILL_PORT = "jmc.test.kill.port"; //$NON-NLS-1$ 58 59 /** 60 * Small server that listens for datagram packets on the specified port and kills the JVM when 61 * anything is received. 62 */ 63 private static class JVMKeepAliveSlayer implements Runnable { 64 @Override 65 public void run() { 66 String portStr = AccessController.doPrivileged(new PrivilegedAction<String>() { 67 @Override 68 public String run() { 69 return System.getProperty(PROPERTY_KILL_PORT, String.valueOf(DEFAULT_KILL_PORT)); 70 } 71 }); 72 73 int port = 0; 74 try { 75 port = Integer.parseInt(portStr); 76 } catch (NumberFormatException nfe) { 77 port = DEFAULT_KILL_PORT; 78 } 79 System.out.println(buildClassNamePrefix(JVMKeepAliveSlayer.class) + "Send kill command to port " + port //$NON-NLS-1$ 80 + " to kill me."); //$NON-NLS-1$ 81 82 try { 83 try (DatagramSocket s = new DatagramSocket(port)) { 84 DatagramPacket p = new DatagramPacket(new byte[25], 25); 85 s.receive(p); 86 System.exit(0); 87 } 88 89 } catch (IOException e) { 90 System.out.println(buildClassNamePrefix(JVMKeepAliveSlayer.class) + e.getMessage()); 91 System.out.println(buildClassNamePrefix(JVMKeepAliveSlayer.class) 92 + "Proceeding without JRockitKeepAliveSlayer..."); //$NON-NLS-1$ 93 return; 94 } 95 } 96 97 } 98 99 private static String buildClassNamePrefix(Class<?> clazz) { 100 return '[' + clazz.getName() + "] "; //$NON-NLS-1$ 101 } 102 103 /** 104 * Loops for a preset time... 105 * 106 * @param args 107 * none needed 108 */ 109 public static void main(String[] args) { 110 if (args.length == 1) { 111 m_aliveTime = Integer.parseInt(args[0]); 112 } 113 114 // Start the JRockitKeepAliveSlayer that listens for kill commands 115 Thread t = new Thread(new JVMKeepAliveSlayer(), buildClassNamePrefix(JVMKeepAliveSlayer.class)); 116 t.start(); 117 118 System.out.println(buildClassNamePrefix(JVMKeepAlive.class) + "Started..."); //$NON-NLS-1$ 119 120 while (m_aliveTime == 0 || (System.currentTimeMillis() - m_startTime) / 1000 <= m_aliveTime) { 121 try { 122 Thread.sleep(2000); 123 } catch (InterruptedException e) { 124 // ignore 125 } 126 System.gc(); 127 Thread.yield(); 128 } 129 } 130 }