In bash, at least, there's an environment variable that holds the
PID of the last process.  So you can start jBoss and then echo the PID to
a file.  I'm not sure how standard this is across shells.
        We should also implement a "quit" command like the "stop" command,
which would solve the problem quite nicely.  However, I'm waiting for
Rickard's input on how to stop the JVM from within...  This would make it
quite easy too.  Don't kill yourself with ClassLoaders and JNI!

Aaron

On Wed, 20 Sep 2000, Ken Jenks wrote:
> I'm trying to get jBoss to run every time Linux starts, and it's been quite 
> an adventure.
> 
> We've worked out a script for use in /etc/rc.d/init.d/jboss, but launching 
> a Java application this way has a big problem: you can't shut it down 
> because you can't keep track of the PID.
> 
> So I wrote a C program wrapper that uses JNI to call jBoss, with the idea 
> that killing the C program will kill the JVM it creates and hence kill off 
> jBoss. It didn't work right away because JNI creates a null ClassLoader, 
> and jBoss uses the ClassLoader to locate its resources.
> 
> So I had the C program use JNI to call another Java application, 
> jbossd.java, which creates a ClassLoader then uses the new 
> JbossdClassLoader to launch jBoss. But it doesn't work, it doesn't return 
> an error message, and I'm stuck in ClassLoader Hell.
> 
> 
> Here are the three parts, the startup script, the C program, and the Java 
> program.
> 
> First, the startup script, /etc/rc.d/init.d/jboss:
> 
> #!/bin/sh
> #
> # chkconfig: 4 85 15
> # description: jbossd is the Jboss daemon
> # processname: jbossd
> # pidfile: /var/run/jbossd.pid
> 
> # Source function library.
> . /etc/rc.d/init.d/functions
> 
> # See how we were called.
> case "$1" in
>   start)
>         # Start daemons.
>         echo "jbossd"
>         PATH=$PATH:/usr/java/jdk1.3/bin
>         export PATH
> 
>         
>CLASSPATH=/usr/java/jdk1.3/lib:/usr/local/jboss/bin:/usr/local/jboss/bin/run.jar
>         export CLASSPATH
>         /usr/local/jboss/bin/jbossd &
>         pidof jbossd > /var/run/jbossd.pid
>         touch /var/lock/subsys/jbossd
>         ;;
>   stop)
>         # Stop daemons.
>         echo -n "Shutting down jbossd: "
>         kill -USR1 `cat /var/run/jbossd.pid`
>         rm -f /var/lock/subsys/jbossd
>         ;;
>   status)
>          status jbossd
>          ;;
>   restart|reload)
>          $0 stop
>          $0 start
>          ;;
>   *)
>         echo "Usage: jbossd {start|stop|restart|reload|status}"
>         exit 1
> esac
> 
> 
> 
> Here's the JNI wrapper, /usr/local/jboss/bin/jbossd.c:
> 
> #include <jni.h>
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <sys/wait.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <syslog.h>
> #include <unistd.h>
> 
> /* The jbossd daemon launches jBoss, a Java application. When the daemon is
>   * killed, jBoss is shut down as well.
>   *
>   * Based on invoke.c from
>   * <http://java.sun.com/docs/books/tutorial/native1.1/invoking/invo.html>
>   *
>   * Compile with:
>   *  gcc -lpthread \
> -I /usr/java/jdk1.3/include \
> -I /usr/java/jdk1.3/include/linux \
> -o jbossd \
> jbossd.c \
> /usr/java/jdk1.3/jre/lib/i386/classic/libjvm.so \
> /usr/java/jdk1.3/jre/lib/i386/libjava.so \
> /usr/java/jdk1.3/jre/lib/i386/libverify.so \
> /usr/java/jdk1.3/jre/lib/i386/native_threads/libhpi.so
>   *
>   * Then to run the daemon, edit the file "/etc/ld.so.conf" and add the
>   * following lines:
> 
> /usr/java/jdk1.3/jre/lib/i386/classic
> /usr/java/jdk1.3/jre/lib/i386
> /usr/java/jdk1.3/jre/lib/i386/native_threads
> 
>   * Then run the command "ldconfig".
>   *
>   */
> 
> #ifdef _WIN32
> #define PATH_SEPARATOR ';'
> #else /* UNIX */
> #define PATH_SEPARATOR ':'
> #endif
> 
> #define USER_CLASSPATH "/usr/local/jboss/bin:/usr/local/jboss/bin/run.jar" 
> /* wh
> ere jbossd.class is */
> 
> JavaVM *jvm;
> 
> int check_cla(int argc, char* argv[])
> {
>    if (argc != 1) {
>      return -1;
>    }
> 
>    return 0;
> }
> 
> /*
> int daemon_init(void)
> {
>    pid_t pid;
> 
>    pid = fork();
>    if (pid < 0) {
>      return -1;
>    } else if (pid != 0) {
>      exit(0); // parent exits
>    }
> 
>    setsid();
>    chdir("/");
>    umask(0);
> 
>    return 0;
> }
> */
> 
> int main(int argc, char* argv[]) {
> 
>    JNIEnv *env;
>    JDK1_1InitArgs vm_args;
>    jint res;
>    jclass cls;
>    jmethodID mid;
>    jstring jstr;
>    jobjectArray args;
>    char classpath[4096];
> 
>    if (check_cla(argc, argv)) {
>      fprintf(stderr, "%s: Usage error\n", argv[0]);
>      return -1;
>    }
> 
> /*
>    if (daemon_init()) {
>      fprintf(stderr, "%s: Error initializing jBoss daemon\n", argv[0]);
>      return -1;
>    }
> */
> 
>    vm_args.version = 0x00010001;
> 
>    JNI_GetDefaultJavaVMInitArgs(&vm_args);
> 
>    /* Append USER_CLASSPATH to the end of default system class path */
>    sprintf(classpath, "%s%c%s",
>      vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH);
>    vm_args.classpath = classpath;
> 
>    /* Create the Java VM */
>    res = JNI_CreateJavaVM(&jvm,(void**)&env,&vm_args);
>    if (res < 0) {
>      fprintf(stderr, "%s: Can't create Java VM\n", argv[0]);
>      exit(1);
>    }
> 
>    if (env == 0) {
>      fprintf(stderr, "%s: Can't find Java environment\n", argv[0]);
>      exit(3);
>    }
> 
>    cls = (*env)->FindClass(env,"jbossd");
> 
>    if (cls == 0) {
>      fprintf(stderr, "%s: Can't find class jbossd\n", argv[0]);
>      exit(4);
>    }
> 
>    mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V");
>    if (mid == 0) {
>      fprintf(stderr, "%s: Can't find static method jbossd.main\n", argv[0]);
>      exit(5);
>    }
> 
>    jstr = (*env)->NewStringUTF(env, "");
>    if (jstr == 0) {
>      fprintf(stderr, "%s: Can't create jstr\n",argv[0]);
>      exit(6);
>    }
> 
>    args = (*env)->NewObjectArray(env, 1,
>      (*env)->FindClass(env, "java/lang/String"), jstr);
>    if (args == 0) {
>      fprintf(stderr, "%s: Can't create args array\n",argv[0]);
>      exit(7);
>    }
> 
>    // Finally, call the main method of class jbossd
> 
>    (*env)->CallStaticVoidMethod(env, cls, mid, args);
> 
>    //(*jvm)->DestroyJavaVM(jvm);
> 
>    return 0;
> }
> 
> 
> 
> Here's the Java application that creates a ClassLoader and launches jBoss, 
> /usr/local/jboss/bin/jbossd.java:
> 
> // jbossd.java
> //
> // Launches jBoss. Called using JNI from jbossd.c.
> //
> // Compile with:
> //  javac -classpath run.jar jbossd.java
> //
> 
> import java.util.Hashtable;
> 
> public class jbossd {
>    jbossd() {
> 
>      // The args passed in from JNI are screwy. We don't need them
>      // anyway, so we'll invent our own set of blank args and send
>      // them along.
> 
>      String newArgs[] = new String[1];
>      newArgs[0] = new String("");
> 
>      try {
>        System.err.println("jbossd: Starting");
> 
>        // This didn't work:
>        //   org.jboss.Main m = new org.jboss.Main();
>        // When I tried it, jBoss started, but it died when org.jboss.Main
>        // tried to use its ClassLoader. It turns out that JNI has a null
>        // ClassLoader. So here's my attempt to create a classloader.
> 
>        JbossdClassLoader loader = new JbossdClassLoader();
>        org.jboss.Main m = 
> (org.jboss.Main)loader.findClass("org.jboss.Main").newI
> nstance();
> 
>        m.main(newArgs);
>        System.err.println("jbossd: Launched.");
>      } catch (java.lang.Exception e) {
>        System.err.println("jbossd: Exception: " + e);
>        e.printStackTrace();
>      }
>    }
> 
>    public static void main(String[] args) {
>      jbossd j = new jbossd();
>    }
> 
>    class JbossdClassLoader extends ClassLoader {
>      public JbossdClassLoader() {
>        super();
>      }
> 
>      public Class findClass(String name) throws ClassNotFoundException {
>        return loadClass(name, true );
>      }
> 
>      protected Class loadClass(String name, boolean resolve)
>        throws ClassNotFoundException {
> 
>        Object o = cache.get(name);
>        if (o != null) {
>          if (o instanceof Class) {
>            return (Class) o;
>          }
>        }
> 
>        Class c = findSystemClass(name);
>        cache.put(name, c);
>        if (resolve) {
>          resolveClass(c);
>        }
>        return c;
>      }
> 
>      private Hashtable cache = new Hashtable();
>    }
> }
> 
> Help!
> 
> -- Ken Jenks, http://abiblion.com/
> 
>     Tools for reading.
> 
> 


Reply via email to