/** (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);
}
}