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 }