A DESCRIPTION OF THE REQUEST :
The ability to specify the class loader used to load the main class would be handy in situations where an applications classes are located in a database, or are encrypted, etc. Currently this would have to be done programmatically by instantiating a class through a class loader, and using reflection.
However, using reflection is not as elegant is specifying this choice on the command line.
JUSTIFICATION :
This feature would allow more dynamic choices of class locations for a Java application, and make the coding of programs that require custom class loaders easier to write. This is because it would remove the custom class loader from the application, and make it a command line (run time) decision.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Java would behave exactly as it currently does. More flexibility in the location of the classes would be the only change.
---------- BEGIN SOURCE ----------
This is actually C source code. This is how it would be executed:
yjava -Djava.class.path=. -LXClassLoader HelloWorld
/* same as java, but loads main from custom class loader */
/* and command line simplified */
#include <dlfcn.h>
#include <stdlib.h>
#include <jni.h>
/* this definition is due to laziness, and shouldn't make any final cut */
/* replace with location of runtime libjvm.so, or specify with -a command */
/* line option. */
#define LIBJVM "/usr/j2se/jre/lib/sparc/client/libjvm.so"
#define MAIN "main"
#define SIG "([Ljava/lang/String;)V"
jclass loadClass (JNIEnv *env, char *loader_name, char *main_class)
{
jclass cls;
jobject jobj;
jmethodID mid;
jstring class_name = NULL;
/* load class loader */
cls = (*env)->FindClass (env, loader_name);
if (cls==NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* get constructor method id for class loader */
mid = (*env)->GetMethodID (env, cls, "<init>", "()V");
if (mid==NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* instantiate class loader */
jobj = (*env)->NewObject (env, cls, mid);
if (jobj == NULL)
{
fprintf (stderr, "class loader NOT instantiated\n");
(*env)->ExceptionDescribe (env);
exit (2);
}
/* load class via classloaders findClass method */
mid = (*env)->GetMethodID (env, cls, "findClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
if (mid==NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
class_name = (*env)->NewStringUTF (env, main_class);
cls = (*env)->CallObjectMethod (env, jobj, mid, class_name);
(*env)->DeleteLocalRef (env, class_name);
if ((*env)->ExceptionCheck (env) == JNI_TRUE)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
return cls;
}
usage ()
{
fprintf (stderr, "usage: %s xxx yyy zzz\n", "xjava");
exit (0);
}
int main (int argc, char **argv)
{
JNIEnv *env = NULL; /* java environment pointer */
JavaVM *vm = NULL; /* Java virtual machine */
jint res = 1; /* 0 if JVM successfully created */
/* indexes for argument processing */
int i;
int y;
int c;
char lib [1024]=LIBJVM; /* default location of JVM shared object */
/* name of class loader */
char loader_name[1024];
/* Object handles for arguement processing */
jclass stringClass = NULL;
jstring jstr = NULL;
jobjectArray args = NULL;
/* Object handles for Class exectution */
jclass cls = NULL;
jmethodID mid = NULL;
jobject jobj = NULL;
jstring class_name = NULL;
/* function pointer for JNI_CreateJVM signature */
jint (*fptr)(JavaVM **, void **, void *);
/* void pointer for dlopen return value */
void *handle = NULL;
/* initialization structure for JNI_CreateJVM */
JavaVMInitArgs vm_args;
/* container for JVM options. Set through command line. */
/* NOTE: command line differs from java command line */
JavaVMOption options[32];
/* set's this initialization specifically for JNI version 1.2 */
vm_args.version = JNI_VERSION_1_2;
/* options initialization */
vm_args.options = options;
vm_args.nOptions = 0;
vm_args.ignoreUnrecognized = JNI_FALSE;
loader_name[0] = 0;
while ( (c = getopt (argc, argv, "L:a:v:D:X:")) != EOF)
{
switch (c)
{
case 'L':
strcpy (loader_name, optarg);
break;
case 'a':
strcpy (lib, optarg);
break;
case 'D':
case 'X':
options[vm_args.nOptions].optionString = argv[optind-1];
vm_args.nOptions++;
break;
case 'v': /* verbose flag */
{
char *s = malloc (strlen ("-verbose:")+
strlen (optarg)+1);
/* check return value */
strcpy (s, "-verbose:");
strcat (s, optarg);
options[vm_args.nOptions].optionString = s;
vm_args.nOptions++;
}
break;
case 'x':
options[vm_args.nOptions].optionString =
argv[optind-1];
vm_args.nOptions++;
break;
default:
usage ();
}
}
/* this could be handled via LD_LIBRARY_PATH, but I think
it is better to specify the JVM explicitly since the
current Java distribution contains at least 3 different
versions
*/
/* load shared library "manually", instead of via LD_LIBRARY_PATH */
handle = dlopen (lib, RTLD_LAZY|RTLD_GLOBAL);
if (handle==NULL)
{
fprintf (stderr, "dlopen: %s\n", dlerror ());
exit (2);
}
/* retrieve symbol from shared library */
/* TODO: use define for cast value */
fptr = (jint (*)(JavaVM **, void **, void *))
dlsym (handle, "JNI_CreateJavaVM");
if (fptr==NULL)
{
fprintf (stderr, "dlsym: %s\n", dlerror ());
exit (2);
}
/* create Java Virtual Machine */
res = fptr (&vm, (void **)&env, &vm_args);
if (res<0)
{
fprintf (stderr, "could not create JVM (res=%d)\n", res);
exit (2);
}
/* Load Class to run. Which class loader is used? */
if (loader_name[0] != 0)
cls = loadClass (env, loader_name, argv[optind]);
else
cls = (*env)->FindClass (env, argv[optind]);
if (cls == NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* Create an array of Strings to pass into main */
stringClass = (*env)->FindClass (env, "java/lang/String");
if (stringClass == NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
args = (*env)->NewObjectArray (env, argc - optind - 1,
stringClass, jstr);
if (args == NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* Process arguments into array of String */
for (i=optind+1,y=0; i<argc; i++,y++)
{
jstring x = (*env)->NewStringUTF (env, argv[i]);
if (x == NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
(*env)->SetObjectArrayElement (env, args, y, x);
if ((*env)->ExceptionCheck (env) == JNI_TRUE)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
}
/* Get method ID entry method */
/* in a real application, it wouldn't have to be main, or static */
mid = (*env)->GetStaticMethodID
(env, cls, MAIN, SIG);
if (mid==NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* execute the entry method (in this thread!) */
(*env)->CallStaticVoidMethod (env, cls, mid, args);
/* process any exceptions that leaked out of main */
if ((*env)->ExceptionCheck (env)==JNI_TRUE)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* clean up of Java */
/* is not yet coded (possible?) */
}
---------- END SOURCE ----------
###@###.### 2005-04-05 11:54:45 GMT
The ability to specify the class loader used to load the main class would be handy in situations where an applications classes are located in a database, or are encrypted, etc. Currently this would have to be done programmatically by instantiating a class through a class loader, and using reflection.
However, using reflection is not as elegant is specifying this choice on the command line.
JUSTIFICATION :
This feature would allow more dynamic choices of class locations for a Java application, and make the coding of programs that require custom class loaders easier to write. This is because it would remove the custom class loader from the application, and make it a command line (run time) decision.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Java would behave exactly as it currently does. More flexibility in the location of the classes would be the only change.
---------- BEGIN SOURCE ----------
This is actually C source code. This is how it would be executed:
yjava -Djava.class.path=. -LXClassLoader HelloWorld
/* same as java, but loads main from custom class loader */
/* and command line simplified */
#include <dlfcn.h>
#include <stdlib.h>
#include <jni.h>
/* this definition is due to laziness, and shouldn't make any final cut */
/* replace with location of runtime libjvm.so, or specify with -a command */
/* line option. */
#define LIBJVM "/usr/j2se/jre/lib/sparc/client/libjvm.so"
#define MAIN "main"
#define SIG "([Ljava/lang/String;)V"
jclass loadClass (JNIEnv *env, char *loader_name, char *main_class)
{
jclass cls;
jobject jobj;
jmethodID mid;
jstring class_name = NULL;
/* load class loader */
cls = (*env)->FindClass (env, loader_name);
if (cls==NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* get constructor method id for class loader */
mid = (*env)->GetMethodID (env, cls, "<init>", "()V");
if (mid==NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* instantiate class loader */
jobj = (*env)->NewObject (env, cls, mid);
if (jobj == NULL)
{
fprintf (stderr, "class loader NOT instantiated\n");
(*env)->ExceptionDescribe (env);
exit (2);
}
/* load class via classloaders findClass method */
mid = (*env)->GetMethodID (env, cls, "findClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
if (mid==NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
class_name = (*env)->NewStringUTF (env, main_class);
cls = (*env)->CallObjectMethod (env, jobj, mid, class_name);
(*env)->DeleteLocalRef (env, class_name);
if ((*env)->ExceptionCheck (env) == JNI_TRUE)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
return cls;
}
usage ()
{
fprintf (stderr, "usage: %s xxx yyy zzz\n", "xjava");
exit (0);
}
int main (int argc, char **argv)
{
JNIEnv *env = NULL; /* java environment pointer */
JavaVM *vm = NULL; /* Java virtual machine */
jint res = 1; /* 0 if JVM successfully created */
/* indexes for argument processing */
int i;
int y;
int c;
char lib [1024]=LIBJVM; /* default location of JVM shared object */
/* name of class loader */
char loader_name[1024];
/* Object handles for arguement processing */
jclass stringClass = NULL;
jstring jstr = NULL;
jobjectArray args = NULL;
/* Object handles for Class exectution */
jclass cls = NULL;
jmethodID mid = NULL;
jobject jobj = NULL;
jstring class_name = NULL;
/* function pointer for JNI_CreateJVM signature */
jint (*fptr)(JavaVM **, void **, void *);
/* void pointer for dlopen return value */
void *handle = NULL;
/* initialization structure for JNI_CreateJVM */
JavaVMInitArgs vm_args;
/* container for JVM options. Set through command line. */
/* NOTE: command line differs from java command line */
JavaVMOption options[32];
/* set's this initialization specifically for JNI version 1.2 */
vm_args.version = JNI_VERSION_1_2;
/* options initialization */
vm_args.options = options;
vm_args.nOptions = 0;
vm_args.ignoreUnrecognized = JNI_FALSE;
loader_name[0] = 0;
while ( (c = getopt (argc, argv, "L:a:v:D:X:")) != EOF)
{
switch (c)
{
case 'L':
strcpy (loader_name, optarg);
break;
case 'a':
strcpy (lib, optarg);
break;
case 'D':
case 'X':
options[vm_args.nOptions].optionString = argv[optind-1];
vm_args.nOptions++;
break;
case 'v': /* verbose flag */
{
char *s = malloc (strlen ("-verbose:")+
strlen (optarg)+1);
/* check return value */
strcpy (s, "-verbose:");
strcat (s, optarg);
options[vm_args.nOptions].optionString = s;
vm_args.nOptions++;
}
break;
case 'x':
options[vm_args.nOptions].optionString =
argv[optind-1];
vm_args.nOptions++;
break;
default:
usage ();
}
}
/* this could be handled via LD_LIBRARY_PATH, but I think
it is better to specify the JVM explicitly since the
current Java distribution contains at least 3 different
versions
*/
/* load shared library "manually", instead of via LD_LIBRARY_PATH */
handle = dlopen (lib, RTLD_LAZY|RTLD_GLOBAL);
if (handle==NULL)
{
fprintf (stderr, "dlopen: %s\n", dlerror ());
exit (2);
}
/* retrieve symbol from shared library */
/* TODO: use define for cast value */
fptr = (jint (*)(JavaVM **, void **, void *))
dlsym (handle, "JNI_CreateJavaVM");
if (fptr==NULL)
{
fprintf (stderr, "dlsym: %s\n", dlerror ());
exit (2);
}
/* create Java Virtual Machine */
res = fptr (&vm, (void **)&env, &vm_args);
if (res<0)
{
fprintf (stderr, "could not create JVM (res=%d)\n", res);
exit (2);
}
/* Load Class to run. Which class loader is used? */
if (loader_name[0] != 0)
cls = loadClass (env, loader_name, argv[optind]);
else
cls = (*env)->FindClass (env, argv[optind]);
if (cls == NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* Create an array of Strings to pass into main */
stringClass = (*env)->FindClass (env, "java/lang/String");
if (stringClass == NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
args = (*env)->NewObjectArray (env, argc - optind - 1,
stringClass, jstr);
if (args == NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* Process arguments into array of String */
for (i=optind+1,y=0; i<argc; i++,y++)
{
jstring x = (*env)->NewStringUTF (env, argv[i]);
if (x == NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
(*env)->SetObjectArrayElement (env, args, y, x);
if ((*env)->ExceptionCheck (env) == JNI_TRUE)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
}
/* Get method ID entry method */
/* in a real application, it wouldn't have to be main, or static */
mid = (*env)->GetStaticMethodID
(env, cls, MAIN, SIG);
if (mid==NULL)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* execute the entry method (in this thread!) */
(*env)->CallStaticVoidMethod (env, cls, mid, args);
/* process any exceptions that leaked out of main */
if ((*env)->ExceptionCheck (env)==JNI_TRUE)
{
(*env)->ExceptionDescribe (env);
exit (2);
}
/* clean up of Java */
/* is not yet coded (possible?) */
}
---------- END SOURCE ----------
###@###.### 2005-04-05 11:54:45 GMT