1 /*
   2  * Copyright (c) 2003, 2008, 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 
  25 /*
  26  * @test
  27  * @bug 6760712
  28  * @summary test the connector server option that causes it not to prevent the
  29  * VM from exiting
  30  * @author Shanliang JIANG, Eamonn McManus
  31  * @run main/othervm DaemonRMIExporterTest
  32  */
  33 import java.util.Arrays;
  34 import java.util.Collections;
  35 import java.util.HashSet;
  36 import java.util.Map;
  37 import java.util.Set;
  38 
  39 import javax.management.MBeanServerFactory;
  40 import javax.management.remote.JMXConnector;
  41 import javax.management.remote.JMXConnectorFactory;
  42 import javax.management.remote.JMXServiceURL;
  43 import javax.management.remote.JMXConnectorServer;
  44 import javax.management.remote.JMXConnectorServerFactory;
  45 
  46 // Test the connector server option that causes it not to prevent the VM
  47 // from exiting.  It's tricky to test exactly that, though possible.  If
  48 // we're being run from within jtreg, then jtreg has threads of its own
  49 // that will prevent the VM from exiting.  What's more it will kill all
  50 // threads that the test created as soon as the main method returns,
  51 // including the ones that would prevent the VM from exiting without the
  52 // special option.
  53 // Here we check that the test code does not create
  54 // any permanent non-daemon threads, by recording the initial set of
  55 // non-daemon threads (including at least one from jtreg), doing our stuff,
  56 // then waiting for there to be no non-daemon threads that were not in
  57 // the initial set.
  58 public class DaemonRMIExporterTest {
  59     public static void main(String[] args) throws Exception {
  60         Set<Thread> initialNonDaemonThreads = getNonDaemonThreads();
  61 
  62         JMXServiceURL addr = new JMXServiceURL("rmi", null, 0);
  63         System.out.println("DaemonRMIExporterTest: Creating a RMIConnectorServer on " + addr);
  64         Map<String, ?> env =
  65             Collections.singletonMap("jmx.remote.x.daemon", "true");
  66         JMXConnectorServer server =
  67                 JMXConnectorServerFactory.newJMXConnectorServer(addr,
  68                 env,
  69                 MBeanServerFactory.createMBeanServer());
  70         server.start();
  71         System.out.println("DaemonRMIExporterTest: Started the server on " + server.getAddress());
  72 
  73         System.out.println("DaemonRMIExporterTest: Connecting a client to the server ...");
  74         final JMXConnector conn = JMXConnectorFactory.connect(server.getAddress());
  75         conn.getMBeanServerConnection().getDefaultDomain();
  76 
  77         System.out.println("DaemonRMIExporterTest: Closing the client ...");
  78         conn.close();
  79 
  80         System.out.println("DaemonRMIExporterTest No more user code to execute, the VM should " +
  81                 "exit normally, otherwise will be blocked forever if the bug is not fixed.");
  82 
  83         long deadline = System.currentTimeMillis() + 10000;
  84         ok: {
  85             while (System.currentTimeMillis() < deadline) {
  86                 Set<Thread> nonDaemonThreads = getNonDaemonThreads();
  87                 nonDaemonThreads.removeAll(initialNonDaemonThreads);
  88                 if (nonDaemonThreads.isEmpty())
  89                     break ok;
  90                 System.out.println("Non-daemon threads: " + nonDaemonThreads);
  91                 try {
  92                     Thread.sleep(500);
  93                 } catch (InterruptedException e) {
  94                     throw new AssertionError(e);
  95                 }
  96             }
  97             throw new Exception("TEST FAILED: non-daemon threads remain");
  98         }
  99 
 100         System.out.println("TEST PASSED");
 101     }
 102 
 103     private static Set<Thread> getNonDaemonThreads() {
 104         ThreadGroup tg = Thread.currentThread().getThreadGroup();
 105         while (tg.getParent() != null)
 106             tg = tg.getParent();
 107         Thread[] threads = null;
 108         for (int size = 10; size < 10000; size *= 2) {
 109             threads = new Thread[size];
 110             int n = tg.enumerate(threads, true);
 111             if (n < size) {
 112                 threads = Arrays.copyOf(threads, n);
 113                 break;
 114             }
 115         }
 116         Set<Thread> ndThreads = new HashSet<Thread>();
 117         for (Thread t : threads) {
 118             if (!t.isDaemon())
 119                 ndThreads.add(t);
 120         }
 121         return ndThreads;
 122     }
 123 }