Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 
Search the JavaFAQ.nu
1000 Java Tips ebook

1000 Java Tips - Click here for the high resolution copy!1000 Java Tips - Click here for the high resolution copy!

Java Screensaver, take it here

Free "1000 Java Tips" eBook is here! It is huge collection of big and small Java programming articles and tips. Please take your copy here.

Take your copy of free "Java Technology Screensaver"!.

Native From Java: Java code example

JavaFAQ Home » Java Code Examples Go to all tips in Java Code Examples


Bookmark and Share

Native call from Java: These samples working illustrate how to call a native library from within Java.

It also includes a sample that attempts a simple performance (speed) comparison between the pure native, pure Java and JNI implementation.

You can find two versions:
- Native call from Java program to C program and
- Native call from Java program to C++ program

C version:

JNISamples.c

Code:

#include <jni.h>
#include "JNISamples.h"
#include <stdio.h>

static void printString(JNIEnv *env, jstring jstr);

JNIEXPORT void JNICALL Java_JNISamples_syncNativeMethod (JNIEnv *env, jobject obj, jobject syncObj)
{
   printf("Inside synchronized native method\n");
   (*env)->MonitorEnter(env, syncObj);
   printf("After synchronizing syncObj\n");
   (*env)->MonitorExit(env, syncObj);
   printf("After releasing syncObj\n");
   /*
   The functions Object.wait, Object.notify, and Object.notifyAll provide
   another useful thread synchronization mechanism. While the JNI does not
   directly support these functions, a native method can always follow the
   JNI method call mechanism to invoke them.
   */
}

JNIEXPORT void JNICALL Java_JNISamples_nativeCatchThrow (JNIEnv *env, jobject obj)
{
   jclass cls = (*env)->GetObjectClass(env, obj);
   jmethodID mid = (*env)->GetMethodID(env, cls, "javaCatchThrow", "()V");
   jthrowable exc;
   jclass newException;

   if(0 == mid)
   {
      printf("Error obtaining method id\n");
      return;
   }

   (*env)->CallVoidMethod(env, obj, mid);
   exc = (*env)->ExceptionOccurred(env);

   if(exc)
   {
      /*
      We don't do much with the exception, except that we print a debug message
      using ExceptionDescribe, clear it, and throw a new exception.
      */
      /*
      It is extremely important to check, handle, and clear the pending exception
      before calling subsequent JNI functions. Calling arbitrary JNI functions with
      a pending exception may lead to unexpected results. You can safely call only
      a small number of JNI functions when there is a pending exception. These
      functions are ExceptionOccurred, ExceptionDescribe, and ExceptionClear.
      */

      (*env)->ExceptionDescribe(env);
       (*env)->ExceptionClear(env);
   }

   newException = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
   if (newException == 0)
   {
      /* Unable to find the new exception class, give up. */
      printf("Error finding the new exception class\n");
       return;
   }

   (*env)->ThrowNew(env, newException, "IllegalArgumentException thrown from C code");
}

JNIEXPORT void JNICALL Java_JNISamples_fieldAccess (JNIEnv *env, jobject obj)
{
   jfieldID fid;
   jstring jstr;
   const char *str;
   jint iStaticIntValue;
   jclass cls = (*env)->GetObjectClass(env, obj);

   fid = (*env)->GetStaticFieldID(env, cls, "iStaticIntFld", "I");
   if(0 == fid)
   {
      printf("Error getting fid for iStaticIntFld\n");
      return;
   }
   iStaticIntValue = (*env)->GetStaticIntField(env, cls, fid);
   printf("iStaticIntValue=%d\n", iStaticIntValue);
   (*env)->SetStaticIntField(env, cls, fid, 200);

   fid = (*env)->GetFieldID(env, cls, "sStringFld", "Ljava/lang/String;");
   if(0 == fid)
   {
      printf("Error getting fid for sStringFld\n");
      return;
   }
   jstr = (*env)->GetObjectField(env, obj, fid);
   printString(env, jstr);

   jstr = (*env)->NewStringUTF(env, "NewString");
   (*env)->SetObjectField(env, obj, fid, jstr);
}


JNIEXPORT void JNICALL Java_JNISamples_nativeMethod (JNIEnv *env, jobject obj, jint iDepth)
{
   jclass cls = (*env)->GetObjectClass(env, obj);
   static jmethodID method = 0;

   /*
   Method ID is valid only for as long as the class
   from which it is derived is not unloaded.
   Obtaining a method ID is a relatively expensive operation.

   Use NewGlobalRef to create a global ref in native code to
   prevent the class from being garbage collected.
   You MUST use DeleteGlobalRef to delete the global reference.

   Use DeleteLocalRef to delete a local ref to release mem immediately.
   */
   if(0 == method)
   {
      method = (*env)->GetMethodID(env, cls, "callback", "(I)V");
   }

   if (method == 0)
   {
      printf("Could not get method callback(I)V\n");
      return;
   }

   printf("In C, depth = %d, about to enter Java\n", iDepth);
   (*env)->CallVoidMethod(env, obj, method, iDepth);
   printf("In C, depth = %d, back from Java\n", iDepth);
}

JNIEXPORT jint JNICALL Java_JNISamples_stringArrAccess(JNIEnv *env, jobject obj, jobjectArray asArr)
{
   int iIndex;
   jsize len = (*env)->GetArrayLength(env, asArr);

   for(iIndex=0; iIndex < len; iIndex++)
   {
      jstring jstr = (*env)->GetObjectArrayElement(env, asArr, iIndex);
      printString(env, jstr);
      /* explicitly releasing to assist garbage collection, though not required */
      (*env)->DeleteLocalRef(env, jstr);
   }

   return len;
}

JNIEXPORT jintArray JNICALL Java_JNISamples_intArrAccess (JNIEnv *env, jobject obj, jintArray aiArr)
{
   int i, sum = 0;
   jintArray aiRet;
   jint *retBody;

   jsize len = (*env)->GetArrayLength(env, aiArr);
   jint *body = (*env)->GetIntArrayElements(env, aiArr, 0);
   /* to copy a region of the array only, use Get/Set<type>ArrayRegion functions */

   for (i=0; i<len; i++)
   {
      sum += body[i];
      body[i]++;
   }

   aiRet = (*env)->NewIntArray(env, len);
   retBody = (*env)->GetIntArrayElements(env, aiRet, 0);

   for (i=0; i<len; i++)
   {
      retBody[i] = body[i];
   }

   (*env)->ReleaseIntArrayElements(env, aiArr, body, 0);
   (*env)->ReleaseIntArrayElements(env, aiRet, retBody, 0);

   return aiRet;   
}


JNIEXPORT jstring JNICALL Java_JNISamples_stringAccess (JNIEnv *env, jobject obj, jstring prompt)
{
   char buf[128];
   const char * str = (*env)->GetStringUTFChars(env, prompt, 0);

   printf("Inside Native: %s\n", str);
   sprintf(buf, "Hello [%s][%d][%d]",
         str,
         (*env)->GetStringUTFLength(env, prompt),
         (*env)->GetStringLength(env, prompt));
   (*env)->ReleaseStringUTFChars(env, prompt, str);

   return (*env)->NewStringUTF(env, buf);
}

static void printString(JNIEnv *env, jstring jstr)
{
   const char * str = (*env)->GetStringUTFChars(env, jstr, 0);
   printf("%s\n", str);
   (*env)->ReleaseStringUTFChars(env, jstr, str);
}



JNISamples.h
Code:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JNISamples */

#ifndef _Included_JNISamples
#define _Included_JNISamples
#ifdef __cplusplus
extern "C" {
#endif
/* Inaccessible static: iStaticIntFld */
/*
 * Class:     JNISamples
 * Method:    fieldAccess
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_JNISamples_fieldAccess
  (JNIEnv *, jobject);

/*
 * Class:     JNISamples
 * Method:    intArrAccess
 * Signature: ([I)[I
 */
JNIEXPORT jintArray JNICALL Java_JNISamples_intArrAccess
  (JNIEnv *, jobject, jintArray);

/*
 * Class:     JNISamples
 * Method:    nativeCatchThrow
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_JNISamples_nativeCatchThrow
  (JNIEnv *, jobject);

/*
 * Class:     JNISamples
 * Method:    nativeMethod
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_JNISamples_nativeMethod
  (JNIEnv *, jobject, jint);

/*
 * Class:     JNISamples
 * Method:    stringAccess
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_JNISamples_stringAccess
  (JNIEnv *, jobject, jstring);

/*
 * Class:     JNISamples
 * Method:    stringArrAccess
 * Signature: ([Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_JNISamples_stringArrAccess
  (JNIEnv *, jobject, jobjectArray);

/*
 * Class:     JNISamples
 * Method:    syncNativeMethod
 * Signature: (Ljava/lang/Object;)V
 */
JNIEXPORT void JNICALL Java_JNISamples_syncNativeMethod
  (JNIEnv *, jobject, jobject);

#ifdef __cplusplus
}
#endif
#endif



JNISamples.java
Code:


public class JNISamples
{
   private native String stringAccess(String sStr);
   private native int [] intArrAccess(int [] aiInp);
   private native int stringArrAccess(String [] asInp);
   private native void nativeMethod(int iDepth);
   private synchronized native void syncNativeMethod(Object oSync);
   private native void fieldAccess();
   private native void nativeCatchThrow() throws IllegalArgumentException;

   static
   {
      System.loadLibrary("JNISamples");
   }

   static int iStaticIntFld;
   String sStringFld;

   public static void main(String [] args)
   {
      JNISamples sample = new JNISamples();

      System.out.println("String access test");
      sample.doString();
      System.out.println("int array test");
      sample.doIntArray();
      System.out.println("String array test");
      sample.doStrArray();
      System.out.println("Callback test");
      sample.callback(0);
      System.out.println("Field access test");
      sample.doFldAccess();
      System.out.println("Native exception catch and throw test");
      try
      {
         sample.nativeCatchThrow();
      }
      catch(IllegalArgumentException iae)
      {
         iae.printStackTrace();
      }
      System.out.println("Synchronized Native Methods");
      sample.syncNativeMethod(new Object());
      System.out.println("Success!");
   }

   private void javaCatchThrow() throws NullPointerException
   {
      throw new NullPointerException("Null pointer exception thrown in javaCatchThrow");
   }

   private void doFldAccess()
   {
      iStaticIntFld = 100;
      sStringFld = "sStringFld";

      fieldAccess();

      System.out.println("In Java");
      System.out.println("iStaticIntFld = " + iStaticIntFld);
      System.out.println("sStringFld = " + sStringFld);
   }

   private void doString()
   {
      String sRet = stringAccess("String test");
      System.out.println(sRet);
   }

   private void doStrArray()
   {
      String [] asInp = new String[10];
      int iIndex, iLen;

      for(iIndex=0; iIndex<10; iIndex++)
      {
         asInp[iIndex] = "String: " + Integer.toString(iIndex);
      }

      iLen = stringArrAccess(asInp);

      System.out.println("String array size: " + iLen);
   }

   private void doIntArray()
   {
      int [] aiInp = new int[10];
      int iIndex;

      for(iIndex=0; iIndex<10; iIndex++)
      {
         aiInp[iIndex] = iIndex;
      }

      int [] aiOut = intArrAccess(aiInp);

      System.out.print("Int array: {");
      for(iIndex=0; iIndex<10; iIndex++)
      {
         System.out.print(aiInp[iIndex] + ", ");
      }
      System.out.println("}");
   }

   private void callback(int iDepth)
   {
      System.out.println("In Java callback. Depth=" + iDepth);
      if(5 > iDepth)
      {
         nativeMethod(iDepth + 1);
      }
      else
      {
         System.out.println("Stopping recursion");
      }
   }
}




makefile
Code:

#SOLARIS
#---------------
#INCFLAGS=-I/usr/java1.2/include -I/usr/java1.2/include/solaris
#CC=cc
#CXX=CC
#LINK=ld
#KPIC_COMPILE=-KPIC
#KPIC_LINK=-G

#DIGITAL OSF
#---------------
INCFLAGS=-I/usr/opt/java122/include -I/usr/opt/java122/include/alpha -pthread
CC=cc
CXX=cxx
LINK=cc
KPIC_COMPILE=
KPIC_LINK=-shared

all : libJNISamples.so JNISamples.class
   echo "All done"

JNISamples.class : JNISamples.java
   javac JNISamples.java

JNISamples.h : JNISamples.class
   javah -jni JNISamples

libJNISamples.so : JNISamples.o
   ${LINK} ${KPIC_LINK} -o libJNISamples.so JNISamples.o

JNISamples.o : JNISamples.c JNISamples.h
   ${CC} ${KPIC_COMPILE} -c JNISamples.c ${INCFLAGS}


C++ version:

JNISamples.cpp
Code:

#include <jni.h>
#include "JNISamples.h"
#include <iostream.h>

static void printString(JNIEnv *env, jstring jstr);

JNIEXPORT void JNICALL Java_JNISamples_syncNativeMethod (JNIEnv *env, jobject obj, jobject syncObj)
{
   cout << "Inside synchronized native method\n";
   env->MonitorEnter(syncObj);
   cout << "After synchronizing syncObj\n";
   env->MonitorExit(syncObj);
   cout << "After releasing syncObj\n";
   /*
   The functions Object.wait, Object.notify, and Object.notifyAll provide
   another useful thread synchronization mechanism. While the JNI does not
   directly support these functions, a native method can always follow the
   JNI method call mechanism to invoke them.
   */
}

JNIEXPORT void JNICALL Java_JNISamples_nativeCatchThrow (JNIEnv *env, jobject obj)
{
   jclass cls = env->GetObjectClass(obj);
   jmethodID mid = env->GetMethodID(cls, "javaCatchThrow", "()V");
   jthrowable exc;
   jclass newException;

   if(0 == mid)
   {
      cout << "Error obtaining method id\n";
      return;
   }

   env->CallVoidMethod(obj, mid);
   exc = env->ExceptionOccurred();

   if(exc)
   {
      /*
      We don't do much with the exception, except that we print a debug message
      using ExceptionDescribe, clear it, and throw a new exception.
      */
      /*
      It is extremely important to check, handle, and clear the pending exception
      before calling subsequent JNI functions. Calling arbitrary JNI functions with
      a pending exception may lead to unexpected results. You can safely call only
      a small number of JNI functions when there is a pending exception. These
      functions are ExceptionOccurred, ExceptionDescribe, and ExceptionClear.
      */

      env->ExceptionDescribe();
       env->ExceptionClear();
   }

   newException = env->FindClass("java/lang/IllegalArgumentException");
   if (newException == 0)
   {
      /* Unable to find the new exception class, give up. */
      cout << "Error finding the new exception class\n";
       return;
   }

   env->ThrowNew(newException, "IllegalArgumentException thrown from C code");
}

JNIEXPORT void JNICALL Java_JNISamples_fieldAccess (JNIEnv *env, jobject obj)
{
   jfieldID fid;
   jstring jstr;
   const char *str;
   jint iStaticIntValue;
   jclass cls = env->GetObjectClass(obj);

   fid = env->GetStaticFieldID(cls, "iStaticIntFld", "I");
   if(0 == fid)
   {
      cout << "Error getting fid for iStaticIntFld\n";
      return;
   }
   iStaticIntValue = env->GetStaticIntField(cls, fid);
   cout << "iStaticIntValue=" << iStaticIntValue << "\n";
   env->SetStaticIntField(cls, fid, 200);

   fid = env->GetFieldID(cls, "sStringFld", "Ljava/lang/String;");
   if(0 == fid)
   {
      cout << "Error getting fid for sStringFld\n";
      return;
   }
   jstr = (jstring)env->GetObjectField(obj, fid);
   printString(env, jstr);

   jstr = env->NewStringUTF("NewString");
   env->SetObjectField(obj, fid, jstr);
}


JNIEXPORT void JNICALL Java_JNISamples_nativeMethod (JNIEnv *env, jobject obj, jint iDepth)
{
   jclass cls = env->GetObjectClass(obj);
   static jmethodID method = 0;

   /*
   Method ID is valid only for as long as the class
   from which it is derived is not unloaded.
   Obtaining a method ID is a relatively expensive operation.

   Use NewGlobalRef to create a global ref in native code to
   prevent the class from being garbage collected.
   You MUST use DeleteGlobalRef to delete the global reference.

   Use DeleteLocalRef to delete a local ref to release mem immediately.
   */
   if(0 == method)
   {
      method = env->GetMethodID(cls, "callback", "(I)V");
   }

   if (method == 0)
   {
      cout << "Could not get method callback(I)V\n";
      return;
   }

   cout << "In C, depth = " << iDepth << "about to enter Java\n";
   env->CallVoidMethod(obj, method, iDepth);
   cout << "In C, depth = " << iDepth << ", back from Java\n";
}

JNIEXPORT jint JNICALL Java_JNISamples_stringArrAccess(JNIEnv *env, jobject obj, jobjectArray asArr)
{
   int iIndex;
   jsize len = env->GetArrayLength(asArr);

   for(iIndex=0; iIndex < len; iIndex++)
   {
      jstring jstr = (jstring)env->GetObjectArrayElement(asArr, iIndex);
      printString(env, jstr);
      /* explicitly releasing to assist garbage collection, though not required */
      env->DeleteLocalRef(jstr);
   }

   return len;
}

JNIEXPORT jintArray JNICALL Java_JNISamples_intArrAccess (JNIEnv *env, jobject obj, jintArray aiArr)
{
   int i, sum = 0;
   jintArray aiRet;
   jint *retBody;

   jsize len = env->GetArrayLength(aiArr);
   jint *body = env->GetIntArrayElements(aiArr, 0);
   /* to copy a region of the array only, use Get/Set<type>ArrayRegion functions */

   for (i=0; i<len; i++)
   {
      sum += body[i];
      body[i]++;
   }

   aiRet = env->NewIntArray(len);
   retBody = env->GetIntArrayElements(aiRet, 0);

   for (i=0; i<len; i++)
   {
      retBody[i] = body[i];
   }

   env->ReleaseIntArrayElements(aiArr, body, 0);
   env->ReleaseIntArrayElements(aiRet, retBody, 0);

   return aiRet;   
}


JNIEXPORT jstring JNICALL Java_JNISamples_stringAccess (JNIEnv *env, jobject obj, jstring prompt)
{
   char buf[128];
   const char * str = env->GetStringUTFChars(prompt, 0);

   cout << "Inside Native: " << str << "\n";
   sprintf(buf, "Hello [%s][%d][%d]",
         str,
         env->GetStringUTFLength(prompt),
         env->GetStringLength(prompt));
   env->ReleaseStringUTFChars(prompt, str);

   return env->NewStringUTF(buf);
}

static void printString(JNIEnv *env, jstring jstr)
{
   const char * str = env->GetStringUTFChars(jstr, 0);
   cout << str << "\n";
   env->ReleaseStringUTFChars(jstr, str);
}




JNISamples.h
Code:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JNISamples */

#ifndef _Included_JNISamples
#define _Included_JNISamples
#ifdef __cplusplus
extern "C" {
#endif
/* Inaccessible static: iStaticIntFld */
/*
 * Class:     JNISamples
 * Method:    fieldAccess
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_JNISamples_fieldAccess
  (JNIEnv *, jobject);

/*
 * Class:     JNISamples
 * Method:    intArrAccess
 * Signature: ([I)[I
 */
JNIEXPORT jintArray JNICALL Java_JNISamples_intArrAccess
  (JNIEnv *, jobject, jintArray);

/*
 * Class:     JNISamples
 * Method:    nativeCatchThrow
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_JNISamples_nativeCatchThrow
  (JNIEnv *, jobject);

/*
 * Class:     JNISamples
 * Method:    nativeMethod
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_JNISamples_nativeMethod
  (JNIEnv *, jobject, jint);

/*
 * Class:     JNISamples
 * Method:    stringAccess
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_JNISamples_stringAccess
  (JNIEnv *, jobject, jstring);

/*
 * Class:     JNISamples
 * Method:    stringArrAccess
 * Signature: ([Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_JNISamples_stringArrAccess
  (JNIEnv *, jobject, jobjectArray);

/*
 * Class:     JNISamples
 * Method:    syncNativeMethod
 * Signature: (Ljava/lang/Object;)V
 */
JNIEXPORT void JNICALL Java_JNISamples_syncNativeMethod
  (JNIEnv *, jobject, jobject);

#ifdef __cplusplus
}
#endif
#endif


JNISamples.java
Code:


public class JNISamples
{
   private native String stringAccess(String sStr);
   private native int [] intArrAccess(int [] aiInp);
   private native int stringArrAccess(String [] asInp);
   private native void nativeMethod(int iDepth);
   private synchronized native void syncNativeMethod(Object oSync);
   private native void fieldAccess();
   private native void nativeCatchThrow() throws IllegalArgumentException;

   static
   {
      System.loadLibrary("JNISamples");
   }

   static int iStaticIntFld;
   String sStringFld;

   public static void main(String [] args)
   {
      JNISamples sample = new JNISamples();

      System.out.println("String access test");
      sample.doString();
      System.out.println("int array test");
      sample.doIntArray();
      System.out.println("String array test");
      sample.doStrArray();
      System.out.println("Callback test");
      sample.callback(0);
      System.out.println("Field access test");
      sample.doFldAccess();
      System.out.println("Native exception catch and throw test");
      try
      {
         sample.nativeCatchThrow();
      }
      catch(IllegalArgumentException iae)
      {
         iae.printStackTrace();
      }
      System.out.println("Synchronized Native Methods");
      sample.syncNativeMethod(new Object());
      System.out.println("Success!");
   }

   private void javaCatchThrow() throws NullPointerException
   {
      throw new NullPointerException("Null pointer exception thrown in javaCatchThrow");
   }

   private void doFldAccess()
   {
      iStaticIntFld = 100;
      sStringFld = "sStringFld";

      fieldAccess();

      System.out.println("In Java");
      System.out.println("iStaticIntFld = " + iStaticIntFld);
      System.out.println("sStringFld = " + sStringFld);
   }

   private void doString()
   {
      String sRet = stringAccess("String test");
      System.out.println(sRet);
   }

   private void doStrArray()
   {
      String [] asInp = new String[10];
      int iIndex, iLen;

      for(iIndex=0; iIndex<10; iIndex++)
      {
         asInp[iIndex] = "String: " + Integer.toString(iIndex);
      }

      iLen = stringArrAccess(asInp);

      System.out.println("String array size: " + iLen);
   }

   private void doIntArray()
   {
      int [] aiInp = new int[10];
      int iIndex;

      for(iIndex=0; iIndex<10; iIndex++)
      {
         aiInp[iIndex] = iIndex;
      }

      int [] aiOut = intArrAccess(aiInp);

      System.out.print("Int array: {");
      for(iIndex=0; iIndex<10; iIndex++)
      {
         System.out.print(aiInp[iIndex] + ", ");
      }
      System.out.println("}");
   }

   private void callback(int iDepth)
   {
      System.out.println("In Java callback. Depth=" + iDepth);
      if(5 > iDepth)
      {
         nativeMethod(iDepth + 1);
      }
      else
      {
         System.out.println("Stopping recursion");
      }
   }
}



makefile
Code:


all : libJNISamples.so JNISamples.class
   echo "All done"

JNISamples.class : JNISamples.java
   javac JNISamples.java

JNISamples.h : JNISamples.class
   javah -jni JNISamples

libJNISamples.so : JNISamples.o
   cxx -shared -o libJNISamples.so JNISamples.o

JNISamples.o : JNISamples.cpp JNISamples.h
   cxx -c JNISamples.cpp -I/usr/opt/java122/include -I/usr/opt/java122/include/alpha -pthread



 Printer Friendly Page  Printer Friendly Page
 Send to a Friend  Send to a Friend

.. Bookmark and Share

Search here again if you need more info!
Custom Search



Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy