|
using Java™ 1.1 JNI on HP-UX
The Java™ Native Interface, typically referred to as JNI, is a standard native method interface that allows Java™ to call up native libraries written in other languages. (Java™ is a 32-bit language, so you can't use 64-bit libraries with JNI.) It also allows you to load the JVM into native applications to integrate Java™ functionality into native applications. JNI offers a JVM-independent programming interface to native programs that enables developers to write a single native method library version
that will be binary compatible with all JVMs on a given platform.
The HP-UX implementation of JNI does not differ significantly from that of the JavaSoft implementation on Solaris. The online JavaSoft documentation tree for JNI is located at
java.sun.com/products/jdk1.1/docs/guide/jni/index.html. The examples below detail the differences that you need to be aware of when using native methods on Java™ 1.1 for HP-UX. Information on "Using Java™ 2 JNI on HP-UX" is available here.
In the HP-UX implementation, JNI provides for two different capabilities:
Java™ calling a native method
The first capability that JNI provides is to allow Java™ code running under the Java™ Virtual Machine (JVM) to make native method calls. This allows the Java™ programmer to supply a native implementation instead of a Java™ implementation for any method in any user defined class. The Java™ keyword native is used in the declaration of the method and no body or definition is supplied in the Java™ source code.
native void sample(int x, int y);
The above declares a non-static native method named "sample" which returns a void and it accepts two integers as parameters.
The native method must be implemented in C or C++. When using C++ native methods special care must be taken to properly initialize the C++ runtime before transferring control to any C++ native method. For the HP C++ compiler this means that the routine _main must be called before transferring control to any C++ method. The examples below detail a mechanism for ensuring that the C++ runtime is properly initialized.
All Java™ native methods must reside in a shared library. This implies that the native methods must be built using the +z or +Z compiler options. These options cause the compiler to generate PIC (Position-Independent-Code). The shared library containing the native method implementation is dynamically loaded during execution of the Java™ program using the Java™ method: System.loadLibrary(). The implementation of this function with the JVM on HP-UX relies upon the HP-UX runtime routine shl_load.
The alignment requirements for Java™ data structures allocated in the JVM are not the same as those found in the standard PA-RISC calling conventions. The JVM requires that class instance data members
64-bits in size (longs and doubles) be allocated at the next available 4-byte boundary. The standard PA-RISC calling conventions normally require that such objects be aligned on the next 8-byte boundary. If a C or C++ native method were to access such a Java™ class instance data member that was not properly aligned on a 8-byte boundary, a SIGBUS signal would be delivered to the program and this would terminate the JVM. To prevent this situation, use the +u4 option to the C and aCC compilers when compiling native code that will directly access Java™ data members. This command-line option instructs the compiler to use special code when dereferencing pointers to the 64-bit types. The special sequence correctly handles the cases in which a 64-bit type is misaligned.
For JDK 1.1.5 and later releases on both HP-UX 10.20 and 11.0, the command line option -D_HPUX is required.
When building native method implementations to be used with the kernel-threaded JVM (for HP-UX 11.0), sources must be compiled with the following additional command-line options: -DNATIVE -D_POSIX_C_SOURCE=199506L. Additionally developers that produce hybrid applications where the application entry point is a language other than Java™, for example a C language main(), must link with the p-thread library using -lpthread on the link line in order to use the kernel-threaded JVM.
Failing to link with libpthread.sl will result in a runtime failure when the JVM is loaded. Since the libpthread library was not available in releases prior to HP-UX 11.0, developers who wish to support 10.20 and also wish to take advantage of the kernel-threaded JVM on HP-UX 11.0 and later versions need to release multiple versions of their applications (one for 10.20 and one for 11.0).
Implementers of native methods called by Java™ main programs should take care to insure that their code does not dereference null pointers. The JVM is linked using the -z option, which is discussed in the man page for the C compiler. If a native method does deference a null pointer a SIGSEGV will be delivered to the JVM and this will cause the JVM to terminate.
HP provides the following three examples on how to call C and C++ code from Java™ code using the standard JNI calling mechanism.
sample native method implementation in C
Here is the sample Java™ program that calls a native method, which has a C implementation:
//
// File TestJavaCallingNative.java
//
class TestJavaCallingNative {
native static void sayHelloWorld();
public static void main(String args[])
{
String libname = "cImpl";
try {
System.loadLibrary(libname);
System.out.println("Library " +
libname + " successfully loaded");
}
catch (UnsatisfiedLinkError Err) {
System.out.println("error: " + Err);
return;
}
System.out.println("Calling sayHelloWorld");
sayHelloWorld();
System.out.println("All done");
}
}
Compile this class:
$ javac TestJavaCallingNative.java
Output:
TestJavaCallingNative.class
Generate the JNI header file for this class. You must have the current
directory in your CLASSPATH for the javah command to find your newly compiled
class file.
$ javah -jni TestJavaCallingNative
Output:
TestJavaCallingNative.h
Here is the sample C native method implementation for sayHelloWorld:
/*
* File cImpl.c
*/
#include "TestJavaCallingNative.h"
#include <stdio.h>
JNIEXPORT void JNICALL
Java_TestJavaCallingNative_sayHelloWorld(JNIEnv *env, jclass class)
{
printf("C says HelloWorld via stdio\n");
}
To compile this C source file for the green-threaded JVM:
$ cc -Ae +u4 +z -c -D_HPUX \
-I/opt/java/include -I/opt/java/include/hp-ux \
cImpl.c
Output:
cImpl.o
To compile this C source file for the kernel-threaded JVM:
$ cc -Ae +u4 +z -c -D_HPUX -DNATIVE -D_POSIX_C_SOURCE=199506L \
-I/opt/java/include -I/opt/java/include/hp-ux \
cImpl.c
Output:
cImpl.o
Note that you are required to supply either -Aa or -Ae as
a command line option to the C compiler. The Java™ header files that you must include require support for ANSI C prototypes.
Create the shared library containing the native method implementation:
$ ld -b -o libcImpl.sl cImpl.o
Output:
libcImpl.sl
executing the Java™ program
You must set the SHLIB_PATH environment variable to contain the
location of the directory that contains libcImpl.sl. SHLIB_PATH
is the HP-UX name for LD_LIBRARY_PATH and can contain a list of
directories each separated by colons.
$ export SHLIB_PATH=$(/bin/pwd):$SHLIB_PATH
$ java TestJavaCallingNative
Library cImpl successfully loaded
Calling sayHelloWorld
C says HelloWorld via stdio
All done
sample native method implementation in C++ (cfront)
Here is a sample Java™ program that calls a native method which has a C++ implementation. This C++ example uses the cfront based C++ compiler. HP has two different C++ compilers, an older cfront based product and a newer aC++ compiler. You can tell which C++ compiler you are using by the name of the driver. The older cfront based product uses CC as the driver, while the newer aC++ compiler uses aCC as the name of the driver. The official HP product names for these two C++ compilers are HP C++ for the cfront based product and HP aC++ for the new C++ compiler.
//
// File TestJavaCallingNative.java
//
class TestJavaCallingNative {
native static void initialize();
native static void sayHelloWorld();
public static void main(String args[])
{
String libname = "CCImpl";
try {
System.loadLibrary(libname);
System.out.println("Library " + libname +
" successfully loaded");
}
catch (UnsatisfiedLinkError Err) {
System.out.println("error: " + Err);
return;
}
System.out.println("initialize C++ runtime");
initialize();
System.out.println("Calling sayHelloWorld");
sayHelloWorld();
System.out.println("All done");
}
}
The above example is very similar to the C example, but for the C++ examples you need to initialize the C++ runtime data structures before transferring control to any C++ code. We accomplish this by adding a second native method called initialize() which will perform the necessary initialization step.
Compile this class:
$ javac TestJavaCallingNative.java
Output:
TestJavaCallingNative.class
Generate the JNI header file for this class. You must have the current directory in your CLASSPATH for the javah command to find your newly compiled class file.
$ javah -jni TestJavaCallingNative
Output:
TestJavaCallingNative.h
Here is the sample C++ native method implementation for
sayHelloWorld:
//
// File CCImpl.C
//
#include "TestJavaCallingNative.h"
#include <iostream.h>
extern "C" {
void _main();
}
JNIEXPORT void JNICALL
Java_TestJavaCallingNative_initialize(JNIEnv *, jclass)
{
_main();
}
JNIEXPORT void JNICALL
Java_TestJavaCallingNative_sayHelloWorld(JNIEnv *, jclass)
{
cout << "C++ (cfront) says HelloWorld via iostreams"
<< endl;
}
In the above example you can see the additional native method initialize() simply calls the
routine _main(). Since the Java™ Native interface does allow us to call a routine name _main directly we have to write this wrapper function to allow us to call _main
indirectly. Also note that we need to use extern "C" to direct the C++ compiler not to perform name mangling on this routine. The entry point for _main is found in the C++ runtime support library libC.sl.
To compile this C++ source file for the green-threaded
JVM:
$ CC -ext +z -c -D_HPUX \
-I/opt/java/include -I/opt/java/include/hp-ux \
CCImpl.C
Output:
CCImpl.o
To compile this C++ source file for the kernel-threaded JVM:
$ CC -ext +z -c -D_HPUX -DNATIVE -D_POSIX_C_SOURCE=199506L \
-I/opt/java/include -I/opt/java/include/hp-ux \
CCImpl.C
Output:
CCImpl.o
Above, the ––ext flag directs the C++ compiler to allow extensions. The Java™ JNI interface requires support for 64-bit integer types. In C++ 64-bit integers are declared using a new type: "long long". This C++ compiler requires that you add ––ext to the command line to enable support for this feature. If you have ––ext on your command line and you still get the warning two long declarators (162) then you will require an update to the C++ compiler (PHSS_10767). You can ignore the warning about "signed" not implemented, as signed is the default behavior for data types in C++.
Create the shared library containing the native method implementation:
$ CC -b -o libCCImpl.sl CCImpl.o -lC
Output:
libCCImpl.sl
Note that the C++ driver program CC must be used to create the shared library. Also note that an explicit dependency on libC.sl needs to be specified via -lC. This will cause the linker to record the fact that whenever libCCImpl.sl is loaded into memory the dependent library libC.sl also must be loaded. This is necessary since libC.sl contains the entry-point _main as well as all the other necessary runtime support routines required by every C++ method.
executing the Java™ program
You must set the SHLIB_PATH environment variable to contain the location of the directory that contains libCCImpl.sl. SHLIB_PATH is the HP-UX name for LD_LIBRARY_PATH and can contain a list of directories each separated by colons.
$ export SHLIB_PATH=$(/bin/pwd):$SHLIB_PATH
$ java TestJavaCallingNative
Library CCImpl successfully loaded
initialize C++ runtime
Calling sayHelloWorld
C++ (cfront) says HelloWorld via iostreams
All done
sample native method implementation in HP aC++
Here is a sample Java™ program that calls a native method which has a C++ implementation. This C++ example will use the aC++ compiler. HP has two different C++ compilers, and older cfront based product and a newer aC++ compiler. You can tell which C++ compiler you are using by the name of the driver. The older cfront based product uses CC as the driver, while the newer aC++ compiler uses aCC as the name of the driver. The official HP product names for these two C++ compilers are HP C++ for the cfront based product and HP aC++ for the new C++ compiler.
//
// File TestJavaCallingNative.java
//
class TestJavaCallingNative {
native static void initialize();
native static void sayHelloWorld();
public static void main(String args[])
{
String libname = "aCCImpl";
try {
System.loadLibrary(libname);
System.out.println("Library " + libname +
" successfully loaded");
}
catch (UnsatisfiedLinkError Err) {
System.out.println("error: " + Err);
return;
}
System.out.println("initialize C++ runtime");
initialize();
System.out.println("Calling sayHelloWorld");
sayHelloWorld();
System.out.println("All done");
}
}
The above example is very similar to the C example, but for the C++ examples you need to initialize the C++ runtime data structures before transferring control to any C++ code. We accomplish this by adding a second native method called initialize() which will perform the necessary initialization step.
Compile this class:
$ javac TestJavaCallingNative.java
Output:
TestJavaCallingNative.class
Generate the JNI header file for this class. You must have the current directory in your CLASSPATH for the javah command to find your newly compiled class file.
$ javah -jni TestJavaCallingNative
Output:
TestJavaCallingNative.h
Here is the sample C++ native method implementation for sayHelloWorld:
//
// File aCCImpl.C
//
#include "TestJavaCallingNative.h"
#include <iostream.h>
extern "C" {
void _main();
}
JNIEXPORT void JNICALL
Java_TestJavaCallingNative_initialize(JNIEnv *, jclass)
{
_main();
}
JNIEXPORT void JNICALL
Java_TestJavaCallingNative_sayHelloWorld(JNIEnv *, jclass)
{
cout << "aC++ says HelloWorld via iostreams"
<<endl;
}
In the above example you can see the additional native method initialize() simply calls the routine _main(). Since the Java™ Native interface does not allow us to call a routine name _main directly we have to write this wrapper function to allow us to call _main indirectly. Also note that we need to use extern "C" to direct the C++ compiler not to perform name mangling on this routine. The entry point for _mainis found in the C++ runtime support library libCsup.sl.
Compile this C++ source file for the green-threaded JVM:
$ aCC +z +u4 -c -D_HPUX \
-I/opt/java/include -I/opt/java/include/hp-ux \
aCCImpl.C
Output:
aCCImpl.o
Compile this C++ source file for the kernel-threaded JVM:
$ aCC +z +u4 -c -D_HPUX -DNATIVE -D_POSIX_C_SOURCE=199506L \
-I/opt/java/include -I/opt/java/include/hp-ux \
aCCImpl.C
Output:
aCCImpl.o
The aC++ compiler has built-in support for 64-bit integers. In C++ 64-bit integers are declared using a new type: long long .
Create the shared library containing the native method implementation:
$ aCC -b -o libaCCImpl.sl aCCImpl.o \
-lCsup -lstream -lstd
Output:
libaCCImpl.sl
Note that the C++ driver program aCC must be used to create the shared library. Also note that an explicit dependency on three C++ runtime libraries need to be specified. The HP aC++ compiler has split the runtime support libraries into three separate shared libraries: libCsup.sl, libstream.sl
and libstd.sl. All HP aC++ programs require libCsup.sl. The other two libraries are required by a subset of C++ programs. In this example, we could omit libstd.sl since we are not using the Standard Template Library functionality. However it is usually best to link your native method shared library against all three of these libraries. Linking a shared library against these other shared libraries will cause the linker to record the fact that whenever libaCCImpl.sl is loaded into memory the dependent libraries libCsup.sl, libstream.sl and libstd.sl also must be loaded. This is necessary since libCsup.sl contains the entry-point _main as well as all the other necessary runtime support routines required by every C++ method.
executing the Java™ program
You must set the SHLIB_PATH environment variable to contain the location of the directory that includes libaCCImpl.sl. SHLIB_PATH is the HP-UX name for LD_LIBRARY_PATH and can contain a list of directories each separated by colons.
$ export SHLIB_PATH=$(/bin/pwd):$SHLIB_PATH
$ java TestJavaCallingNative
Library aCCImpl successfully loaded
initialize C++ runtime
Calling sayHelloWorld
ANSI C++ says HelloWorld via iostreams
All done
non-Java™ code calling Java™ methods
The second capability that JNI provides is to allow non-Java™ code to make calls into Java™ bytecode. This capability is provide via the C and C++ header file jni.h. Using this capability C and C++ programs can make calls into Java™ bytecode.
In JDK 1.1, the Java™ Virtual Machine (JVM) is shipped as a shared library. To utilize the JVM in a native application you must link the application against libjava.sl. The JNI supports an Invocation API that allows you to create and initialize a new JVM. Using this newly created JVM you can invoke various Java™ methods, create new Java™ objects or access Java™ objects created by the JVM.
The Invocation API is provided by the C/C++ header file jni.h. It actually provides two different interfaces. It provides a standard C interface and an object based C++ interface.
Here is the sample Java™ class that we will call from C and C++ programs:
//
// File TestNonJavaCallingJava.java
//
public class TestNonJavaCallingJava {
public static void printInt(int arg)
{
System.out.println("TestNonJavaCallingJava.
printInt received: "
+ arg);
}
}
Compile the above Java™ file into bytecode:
$ javac TestNonJavaCallingJava.java
Output:
TestNonCallingJava.class
HP provides the following three examples on how to call C and C++ code from Java™ code using the standard JNI calling mechanism.
sample implementation in C
Here is the sample C program. This program will use the JVM Invocation Interface to create a new JVM, find a class named TestNonJavaCallingJava, and find a Java™ method named printInt, and invoke the method with an argument of 10.
/*
* File: c_main.c
*
* Example 1: C Source File as the Main
* create a new Java Virtual Machine
* and locate the class TestNonJavaCallingJava
* and invoke the static method printInt
*/
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
main()
{
JavaVM *jvm;
JNIEnv *env;
JDK1_1InitArgs vm_args;
const struct JNINativeInterface_ *jni;
const struct JNIInvokeInterface_ *vmi;
jclass cls;
jmethodID mid;
printf("beginning execution...\n");
vm_args.version = 0x00010001;
/*
* Get the default initialization args and
* set the class path
*/
JNI_GetDefaultJavaVMInitArgs(&vm_args);
/*
* Note if you have not set and exported the
* environment variable CLASSPATH you may also
* need to add this:
* vm_args.classpath = ".:/opt/java/lib/classes.zip";
*/
/*
* load and initialize a java vm,
* return a JNI interface ptr in env
*/
JNI_CreateJavaVM(&jvm,&env,&vm_args);
jni = *env;
vmi = *jvm;
/* Find the class */
cls = jni->FindClass(env, "TestNonJavaCallingJava");
if (cls == 0) {
fprintf(stderr,
"Could not locate class
TestNonJavaCallingJava"
" in your CLASSPATH.\n");
exit(1);
}
/* Find the method */
mid = jni->GetStaticMethodID(env, cls, "printInt",
"(I)V");
if (mid == 0) {
fprintf(stderr,
"Could not locate method printInt with
signature (I)V"
" in the class TestNonJavaCallingJava.\n");
exit(1);
}
/* Invoke the method */
jni->CallStaticVoidMethod(env, cls, mid, 100);
/* we are done */
vmi->DestroyJavaVM(jvm);
}
For the green-threaded JVM:
Compile this C source file:
$ cc -g -c -Ae -D_HPUX \
-I/opt/java/include -I/opt/java/include/hp-ux \
c_main.c
Output:
c_main.o
Create the main program and link against libjava.sl
$ cc -g -o c_main c_main.o \
-L/opt/java/lib/PA_RISC/green_threads \
-ljava
Output:
c_main
For the kernel-threaded JVM:
Compile this C source file:
$ cc -g -c -Ae -D_HPUX -DNATIVE -D_POSIX_C_SOURCE=199506L \
-I/opt/java/include -I/opt/java/include/hp-ux \
c_main.c
Output:
c_main.o
Create the main program and link against libjava.sl
$ cc -g -o c_main c_main.o \
-L/opt/java/lib/PA_RISC/native_threads \
-ljava -lpthread -llwp
Output:
c_main
executing the C main program:
$ ./c_main
TestNonJavaCallingJava.printInt received: 100
sample implementation in C++ (cfront)
Here is the sample C++ program. This program will use the C++ object-oriented interface provided in the JVM Invocation Interface to create a new JVM, find a class named TestNonJavaCallingJava,
and find a Java™ method named printInt, and invoke the method with an argument of 10.
// File: CC_main.C
//
//Example 2: Cfront (C++) Source File as the Main
//create a new Java Virtual Machine
//and locate the class TestNonJavaCallingJava
//and invoke the static method printInt
//
#include <jni.h>
#include <iostream.h>
#include <stdlib.h>
int main() {
JNIEnv *env;
JavaVM *jvm;
JNIEnv jni;
JavaVM vmi;
JDK1_1InitArgs vm_args;
cout << "beginning execution..." << endl;
vm_args.version = 0x00010001;
// Get the default initialization args and set the class path
JNI_GetDefaultJavaVMInitArgs(&vm_args);
// vm_args.classpath = ".:/opt/java/lib/classes.zip";
// load and init. a java vm, return a JNI interface ptr in env
JNI_CreateJavaVM(&jvm,&env,&vm_args);
jni = *env;
vmi = *jvm;
// Find the class
jclass cls=env->FindClass("TestNonJavaCallingJava");
if (cls == 0) {
cerr << "Could not locate class
TestNonJavaCallingJava"
" in your CLASSPATH." << endl;
exit(1);
}
// Find the method
jmethodID mid=env->GetStaticMethodID(cls, "printInt",
"(I)V");
if (mid == 0) {
cerr << "Could not locate method printInt with
signature (I)V"
" in the class TestNonJavaCallingJava."
<< endl;
exit(1);
}
// Invoke the method
env->CallStaticVoidMethod(cls, mid, 100);
//we are done
jvm->DestroyJavaVM();
}
For the green-threaded JVM:
Compile this C++ source file:
$ CC -g -c -ext -D_HPUX \
-I/opt/java/include -I/opt/java/include/hp-ux \
CC_main.C
You can ignore the warning about "signed" not implemented, as signed is
the default behavior for data types in C++.
Output:
CC_main.o
Create the main program and link against libjava.sl
$ CC -g -o CC_main CC_main.o \
-L/opt/java/lib/PA_RISC/green_threads \
-ljava
Output:
CC_main
For the kernel-threaded JVM:
Compile this C++ source file:
$ CC -g -c -ext -D_HPUX -DNATIVE -D_POSIX_C_SOURCE=199506L \
-I/opt/java/include -I/opt/java/include/hp-ux \
CC_main.C
You can ignore the warning about "signed" not implemented, as signed is
the default behavior for data types in C++.
Output:
CC_main.o
Create the main program and link against libjava.sl
$ CC -g -o CC_main CC_main.o \
-L/opt/java/lib/PA_RISC/native_threads \
-ljava -lpthread -llwp
Output:
CC_main
executing the CC main program
$ ./CC_main
beginning execution...
TestNonJavaCallingJava.printInt received: 100
sample implementation in HP aC++
Here is the sample HP aC++ program. This program will use the C++ object-oriented interface provided in the JVM Invocation Interface to create a new JVM, find a class named TestNonJavaCallingJava,
and find a Java method named printInt, and invoke the method with an argument of 10.
//File: aCC_main.C
//
//Example 3: aC++ Source File as the Main
//create a new Java Virtual Machine
//and locate the class TestNonJavaCallingJava
//and invoke the static method printInt
#include <jni.h>
#include <iostream.h>
#include <stdlib.h>
int main() {
JNIEnv *env;
JavaVM *jvm;
JNIEnv jni;
JavaVM vmi;
JDK1_1InitArgs vm_args;
cout << "beginning execution..." << endl;
vm_args.version = 0x00010001;
// Get the default initialization args and set the class path
JNI_GetDefaultJavaVMInitArgs(&vm_args);
// vm_args.classpath = ".:/opt/java/lib/classes.zip";
// load and init. a java vm, return a JNI interface ptr
in env
JNI_CreateJavaVM(&jvm,&env,&vm_args);
jni = *env;
vmi = *jvm;
// Find the class
jclass cls=env->FindClass("TestNonJavaCallingJava");
if (cls == 0) {
cerr << "Could not locate class
TestNonJavaCallingJava"
" in your CLASSPATH." << endl;
exit(1);
}
// Find the method
jmethodID mid=env->GetStaticMethodID(cls, "printInt", "(I)V");
if (mid == 0) {
cerr << "Could not locate method printInt with
signature (I)V"
" in the class TestNonJavaCallingJava."
<< endl;
exit(1);
}
// Invoke the method
env->CallStaticVoidMethod(cls, mid, 100);
//we are done
jvm->DestroyJavaVM();
}
For the green-threaded JVM:
Compile this aC++ source file:
$ aCC -g -c -ext -D_HPUX \
-I/opt/java/include -I/opt/java/include/hp-ux \
aCC_main.C
Output:
aCC_main.o
Create the main program and link against libjava.sl
$ aCC -g -o aCC_main aCC_main.o \
-L/opt/java/lib/PA_RISC/green_threads \
-ljava
Output:
aCC_main
For the kernel-threaded JVM:
Compile this aC++ source file:
$ aCC -g -c -ext -D_HPUX -DNATIVE -D_POSIX_C_SOURCE=199506L \
-I/opt/java/include -I/opt/java/include/hp-ux \
aCC_main.C
Output:
aCC_main.o
Create the main program and link against libjava.sl
$ aCC -g -o aCC_main aCC_main.o \
-L/opt/java/lib/PA_RISC/native_threads/ \
-ljava -lpthread -llwp
Output:
aCC_main
executing the aCC main program:
$ ./aCC_main
beginning execution...
TestNonJavaCallingJava.printInt received: 100
Java™ and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries. Hewlett-Packard is independent of Sun Microsystems, Inc.
|