blob: c779acd6ff69b7627f3979c73db0cc374ba8c83e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.oodt.commons;
import org.apache.oodt.commons.io.Base64EncodingOutputStream;
import org.apache.oodt.commons.util.LogInit;
import org.apache.oodt.commons.util.XML;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import javax.naming.Context;
import javax.naming.NamingException;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteRef;
import java.rmi.server.RemoteStub;
import java.util.Date;
import java.util.Iterator;
public class AvroExecServer {
/** The configuration. */
private static Configuration configuration;
/** The servant. */
private Object servant;
/** Current binder, if any. */
private static Binder binder;
/** Object key name. */
protected String name;
/** Server's status document. */
private Document statusDocument;
/** The <log> element within the status document. */
private Element logElement;
/** Status DTD Document Type Definition formal public identifier. */
public static final String STATUS_FPI = "-//JPL//DTD EDA Server Status 1.0";
/** Status DTD system identifier. */
public static final String STATUS_URL = "http://oodt.jpl.nasa.gov/edm-commons/xml/serverStatus.dtd";
/** Name of the property that prints the server's IOR or RMI handle. */
public static final String PRINT_IOR_PROPERTY = "org.apache.oodt.commons.ExecServer.printIOR";
/** Name of the property that prevents binding of this object with the naming service. */
public static final String DISABLE_BINDING = "org.apache.oodt.commons.ExecServer.disableBinding";
/** How long to wait before bind attempts, in ms. */
private static final long REBIND_PERIOD = Long.getLong("org.apache.oodt.commons.ExecServer.rebindPeriod", 30*60*1000).longValue();
protected AvroExecServer(String name) {
this.name = name;
}
/** Create a new executable server.
*
* @param name Name of the server
* @param className Name of class that implements the server.
* @throws ClassNotFoundException If the class for <var>className</var> can't be found.
* @throws NoSuchMethodException If the constructor for <var>className</var> taking a single <code>ExecServer</code>
* can't be found.
* @throws InstantiationException If the class for <var>className</var> is abstract or is an interface.
* @throws IllegalAccessException If the class for <var>className</var> isn't public.
* @throws InvocationTargetException If an exception occurs in the constructor for <var>className</var>.
* @throws DOMException If the server's status document can't be created.
* @throws UnknownHostException If the local host name can't be determined.
*/
public AvroExecServer(String name, String className) throws ClassNotFoundException, NoSuchMethodException,
InstantiationException, IllegalAccessException, InvocationTargetException, DOMException, UnknownHostException {
this.name = name;
// Find the class and the required constructor.
Class clazz = Class.forName(className);
Constructor ctor = clazz.getConstructor(new Class[]{ExecServer.class});
// Invoke the constructor to create the servant.
servant = ctor.newInstance(new Object[]{this});
Date startDate = new Date();
// Create the XML-RPC interface to this server.
// I should create avro interface to this server
/*Responder responder = new GenericResponder() {
@Override
public Object respond(Protocol.Message message, Object o) throws Exception {
return null;
}
}*/
/* server =new HttpServer();
server.*/
// xmlrpcServer = new XmlRpcServer();
// xmlrpcServer.addHandler("server", this);
// Create the server status document.
DocumentType docType = XML.getDOMImplementation().createDocumentType("server", STATUS_FPI, STATUS_URL);
statusDocument = XML.getDOMImplementation().createDocument(/*namespaceURI*/null, "server", docType);
Element serverElement = statusDocument.getDocumentElement();
XML.add(serverElement, "name", name);
XML.add(serverElement, "class", className);
XML.add(serverElement, "state", "up");
Element startElement = statusDocument.createElement("start");
serverElement.appendChild(startElement);
Element userElement = statusDocument.createElement("user");
startElement.appendChild(userElement);
XML.add(userElement, "name", System.getProperty("user.name", "UNKNOWN"));
XML.add(userElement, "cwd", System.getProperty("user.dir", "UNKNOWN"));
XML.add(userElement, "home", System.getProperty("user.home", "UNKNOWN"));
Element dateElement = statusDocument.createElement("date");
startElement.appendChild(dateElement);
dateElement.setAttribute("ms", String.valueOf(startDate.getTime()));
dateElement.appendChild(statusDocument.createTextNode(startDate.toString()));
XML.add(startElement, "config", System.getProperty("org.apache.oodt.commons.Configuration.url", "UNKNOWN"));
Element hostElement = statusDocument.createElement("host");
serverElement.appendChild(hostElement);
XML.add(hostElement, "name", InetAddress.getLocalHost().getHostName());
Element osElement = statusDocument.createElement("os");
hostElement.appendChild(osElement);
XML.add(osElement, "name", System.getProperty("os.name", "UNKNOWN"));
XML.add(osElement, "version", System.getProperty("os.version", "UNKNOWN"));
XML.add(osElement, "arch", System.getProperty("os.arch", "UNKNOWN"));
Element vmElement = statusDocument.createElement("vm");
serverElement.appendChild(vmElement);
XML.add(vmElement, "name", System.getProperty("java.vm.name", "UNKNOWN"));
XML.add(vmElement, "version", System.getProperty("java.version", "UNKNOWN"));
XML.add(vmElement, "classpath", System.getProperty("java.class.path", "UNKNOWN"));
XML.add(vmElement, "extdirs", System.getProperty("java.ext.dirs", "UNKNOWN"));
logElement = statusDocument.createElement("log");
serverElement.appendChild(logElement);
}
public static void runInitializers() throws EDAException {
String initList = System.getProperty("org.apache.oodt.commons.initializers",
System.getProperty("org.apache.oodt.commons.ExecServer.initializers", System.getProperty("initializers", "")));
for (Iterator i = org.apache.oodt.commons.util.Utility.parseCommaList(initList); i.hasNext();) {
String iname = (String) i.next();
try {
Class initClass = Class.forName(iname);
Initializer init = (Initializer) initClass.newInstance();
init.initialize();
} catch (ClassNotFoundException ex) {
System.err.println("Initializer \"" + iname + "\" not found; aborting");
throw new EDAException(ex);
} catch (InstantiationException ex) {
System.err.println("Initializer \"" + iname + "\" is abstract; aborting");
throw new EDAException(ex);
} catch (IllegalAccessException ex) {
System.err.println("Initializer \"" + iname + "\" isn't public; aborting");
throw new EDAException(ex);
}
}
}
public static void main(String[] argv) {
if (argv.length < 2) {
System.err.println("Usage: class-name-of-server object-name");
System.exit(1);
}
String className = argv[0];
String name = argv[1];
// Enable support of our special URLs, like stdin:
System.setProperty("java.protocol.handler.pkgs", "org.apache.oodt.commons.net.protocol");
try {
// Get the configuration.
configuration = Configuration.getConfiguration();
configuration.mergeProperties(System.getProperties());
// Set up the logger.
LogInit.init(System.getProperties(), name);
// Run initializers
try {
runInitializers();
} catch (EDAException ex) {
ex.printStackTrace();
System.exit(1);
}
// Create it.
final AvroExecServer server = new AvroExecServer(name, className);
// Print it.
if (Boolean.getBoolean(PRINT_IOR_PROPERTY)) {
if (server.getServant() instanceof RemoteObject) {
RemoteObject remoteObject = (RemoteObject) server.getServant();
RemoteStub remoteStub = (RemoteStub) RemoteObject.toStub(remoteObject);
RemoteRef ref = remoteStub.getRef();
System.out.print("RMI:");
System.out.flush();
ObjectOutputStream objOut
= new ObjectOutputStream(new Base64EncodingOutputStream(System.out));
objOut.writeObject(ref);
objOut.flush();
System.out.println();
} else {
org.omg.PortableServer.Servant servant=(org.omg.PortableServer.Servant)server.getServant();
org.omg.CORBA.ORB orb = servant._orb();
System.out.println(orb.object_to_string(servant._this_object(orb)));
}
System.out.flush();
}
// Bind it.
if (!Boolean.getBoolean(DISABLE_BINDING)) {
binder = new Binder(name, server);
binder.start();
}
// Prepare for the inevitable
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
server.shutdown0();
}
});
// We're done here.
for (;;) try {
Thread.currentThread().join();
} catch (InterruptedException ignore) {}
} catch (IOException ex) {
System.err.println("I/O error during initialization: " + ex.getMessage());
ex.printStackTrace();
} catch (SAXParseException ex) {
System.err.println("Error in the configuration file at line " + ex.getLineNumber() + ", column "
+ ex.getColumnNumber() + ": " + ex.getMessage());
} catch (SAXException ex) {
System.err.println("Error " + ex.getClass().getName() + " while attempting to parse the configuration"
+ " file: " + ex.getMessage());
} catch (java.lang.reflect.InvocationTargetException ex) {
Throwable target = ex.getTargetException();
System.err.println("Constructor for \"" + className + "\" threw " + target.getClass().getName() + ": "
+ ex.getMessage());
target.printStackTrace();
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
System.err.println("Exception " + ex.getClass().getName() + " initializing server \"" + name
+ "\" with class \"" + className + "\": " + ex.getMessage());
ex.printStackTrace();
}
System.exit(1);
}
/**
* Binding thread.
*/
private static class Binder extends Thread {
private boolean keepBinding;
private String name;
private AvroExecServer server;
public Binder(String name, AvroExecServer server) {
super("Binder for " + name);
setDaemon(true);
this.name = name;
this.server = server;
keepBinding = true;
}
public void run() {
while (shouldKeepBinding()) try {
Context objectContext = configuration.getObjectContext();
objectContext.rebind(name, server.getServant());
objectContext.close();
} catch (Throwable ex) {
System.err.println("Exception binding at " + new Date() + "; will keep trying...");
ex.printStackTrace();
} finally {
try {
Thread.sleep(REBIND_PERIOD);
} catch (InterruptedException ignore) {}
}
}
public synchronized void stopBinding() {
keepBinding = false;
}
private synchronized boolean shouldKeepBinding() {
return keepBinding;
}
}
/** Return the servant for this executable server.
*
* @return The servant.
*/
public Object getServant() {
return servant;
}
private void shutdown0() {
// Unbind.
if (!Boolean.getBoolean(DISABLE_BINDING)) try {
binder.stopBinding();
Context objectContext = configuration.getObjectContext();
objectContext.unbind(getName());
objectContext.close();
} catch (NamingException ignore) {}
// Kill the ORB. YEAH! KILL IT, KILL IT, KIIIIIIIIIIIIIIL IIIIIIIIT!!!!!!!1
try {
if (servant instanceof org.omg.PortableServer.Servant) {
org.omg.PortableServer.Servant s = (org.omg.PortableServer.Servant) servant;
org.omg.CORBA.ORB orb = s._orb();
orb.shutdown(false/*=>terminate without waiting for reqs to complete*/);
}
} catch (Throwable ignore) {}
}
/** Get my name.
*
* @return The name under which I'm registered in teh naming context.
*/
public String getName() {
return name;
}
}