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