/** (C) Copyright 2011-2014 Chiral Behaviors, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hellblazer.process; import com.sun.jmx.remote.internal.RMIExporter; import sun.rmi.server.UnicastServerRef; import sun.rmi.server.UnicastServerRef2; import javax.management.MBeanServer; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; import java.io.BufferedReader; import java.io.InputStreamReader; import java.lang.management.ManagementFactory; import java.rmi.NoSuchObjectException; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.UnicastRemoteObject; import java.util.HashMap; import java.util.Map; /** * @author Hal Hildebrand * */ @SuppressWarnings("restriction") public class HelloWorld implements RMIExporter { public static final String STARTUP_MSG = "HelloWorld startup successful"; public static final String JMX_CONNECTION_NAME = "com.chiralbehaviors.helloworld.jmx"; static void bindJmx() throws Exception { JMXConnectorServer server; // Ensure cryptographically strong random number generater used // to choose the object number - see java.rmi.server.ObjID System.setProperty("java.rmi.server.randomIDs", "true"); // Ensure that the rmi server socket binds to the localhost, rather than the translated IP address System.setProperty("java.rmi.server.hostname", "127.0.0.1"); // This RMI server should not keep the VM alive Map<String, RMIExporter> env = new HashMap<String, RMIExporter>(); env.put(RMIExporter.EXPORTER_ATTRIBUTE, new HelloWorld()); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); JMXServiceURL url = new JMXServiceURL("rmi", "127.0.0.1", 11645); server = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); server.start(); System.setProperty(JMX_CONNECTION_NAME, server.getAddress().toString()); } public static void main(String[] argv) throws Exception { System.out.println(STARTUP_MSG); if (argv[0].equals("-echo")) { for (int i = 1; i < argv.length; i++) { System.out.println(argv[i]); System.err.println(argv[i]); } } else if (argv[0].equals("-loglines")) { for (int i = 0; i < 5000; i++) { String msg = String.format("Line #%d", i); System.out.println(msg); System.err.println(msg); } } else if (argv[0].equals("-jmx")) { bindJmx(); Thread.sleep(Integer.parseInt(argv[1])); System.out.println("finished"); } else if (argv[0].equals("-sleep")) { Thread.sleep(Integer.parseInt(argv[1])); System.out.println("finished"); } else if (argv[0].equals("-errno")) { System.exit(Integer.parseInt(argv[1])); } else if (argv[0].equals("-readln")) { BufferedReader reader = new BufferedReader( new InputStreamReader( System.in)); String line = null; int i = 0; while (line == null && i++ < 100) { Thread.sleep(100); line = reader.readLine(); } if (line == null) { System.exit(1); } else { System.out.println(line); } } else { System.err.println("Unknown option: " + argv[0]); System.exit(-1); } } Remote firstExported; /** * <p> * Prevents our RMI server objects from keeping the JVM alive. * </p> * * <p> * We use a private interface in Sun's JMX Remote API implementation that * allows us to specify how to export RMI objects. We do so using * UnicastServerRef, a class in Sun's RMI implementation. This is all * non-portable, of course, so this is only valid because we are inside * Sun's JRE. * </p> * * <p> * Objects are exported using * {@link UnicastServerRef#exportObject(Remote, Object, boolean)}. The * boolean parameter is called <code>permanent</code> and means both that * the object is not eligible for Distributed Garbage Collection, and that * its continued existence will not prevent the JVM from exiting. It is the * latter semantics we want (we already have the former because of the way * the JMX Remote API works). Hence the somewhat misleading name of this * class. * </p> */ @Override public Remote exportObject(Remote obj, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException { synchronized (this) { if (firstExported == null) { firstExported = obj; } } final UnicastServerRef ref; if (csf == null && ssf == null) { ref = new UnicastServerRef(port); } else { ref = new UnicastServerRef2(port, csf, ssf); } return ref.exportObject(obj, null, true); } // Nothing special to be done for this case @Override public boolean unexportObject(Remote obj, boolean force) throws NoSuchObjectException { return UnicastRemoteObject.unexportObject(obj, force); } }