<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
<META NAME="Generator" CONTENT="Microsoft Word 97">
</HEAD>
<BODY LINK="#0000ff">
<FONT FACE="Arial" SIZE=2><P>This document describes how to interface a Java Program with a qt embedded application with the help of JNI(Java Native Interface) using kaffe-1.0.6 JVM and qt-embedded 2.3.1 toolkit.</P>
<P>We will try out a simple Java Program which calls the qt-embedded hello world function from within itself.</P>
<P>For better understanding of JNI principles, please refer to the following link:</P>
</FONT><FONT SIZE=2><P></FONT><A HREF="http://java.sun.com/docs/books/tutorial/native1.1/"><FONT SIZE=2>http://java.sun.com/docs/books/tutorial/native1.1/</FONT></A></P>
<FONT SIZE=2>
</FONT><FONT FACE="Arial" SIZE=2><P>The JNI allows Java code that runs within a Java Virtual Machine (VM) to operate with applications and libraries written in other languages, such as C, C++, and assembly. In our case, we will use the Kaffe JVM and Qt embedded toolkit as the native language.</P>
<P>Let us start with our example, writing a java program that calls the Qt function to display the helloworld widget.</P>
<P>For the purpose of this document we will assume that KAFFEDIR is the path where kaffe is installed on your machine, and QTDIR points to the Qt-embedded directory.</P>
<UL>
<B><U><LI>Writing the Java code</LI></UL>
</B></U><DIR>
<P>Let us begin by writing the Java program. Create a Java class that declares the native method; this class contains the declaration or signature for the native method. It also includes a </FONT><FONT FACE="Arial"><CODE>main</FONT></CODE><FONT FACE="Arial" SIZE=2> method which calls the native method. </P>
<P>The name of my program is Tryqt1.java and it contains the following code:</P>
</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P>class Tryqt1 {</P><DIR>
<DIR>
<DIR>
</FONT><FONT FACE="Arial" SIZE=2 COLOR="#008000"><P>// a declaration for the native function to be called</P></DIR>
</DIR>
</DIR>
</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P> public native void displayTryqt1();</P>
<DIR>
<DIR>
<DIR>
</FONT><FONT FACE="Arial" SIZE=2 COLOR="#008000"><P>// call to load the shared object library libTry.so containing the native function</P></DIR>
</DIR>
</DIR>
</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P> static {</P>
<P> System.loadLibrary("Try");</P>
<P>		</P>
<P> }</P>
<P> </P>
<P> public static void main(String[] args) {</P><DIR>
<DIR>
<DIR>
</FONT><FONT FACE="Arial" SIZE=2 COLOR="#008000"><P>//call the native function to display the hello world widget</P></DIR>
</DIR>
</DIR>
</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P> new Tryqt1().displayTryqt1();</P>
<P> }</P>
<P> }</P>
</FONT><FONT FACE="Arial" SIZE=2></DIR>
<P>When you write a method implementation in a language other than Java, you must include the keyword </FONT><FONT FACE="Arial" COLOR="#0000ff"><CODE>native</FONT></CODE><FONT FACE="Arial" SIZE=2> as part of the method's definition within the Java class. The </FONT><FONT FACE="Arial"><CODE>native</FONT></CODE><FONT FACE="Arial" SIZE=2> keyword signals to the Java compiler that the function is a native language function.</P>
<P>The </FONT><FONT FACE="Arial"><CODE>System.loadLibrary</FONT></CODE><FONT FACE="Arial" SIZE=2> method loads the shared library that will be created when you compile the implementation code. Place this method within a static initializer. The argument to </FONT><FONT FACE="Arial"><CODE>System.loadLibrary</FONT></CODE><FONT FACE="Arial" SIZE=2> is the shared library name. This can be any name that you choose.</P>
<P>The </FONT><FONT FACE="Arial"><CODE>main</FONT></CODE><FONT FACE="Arial" SIZE=2> method instantiates the Tryqt1 object and calls the </FONT><FONT FACE="Arial"><CODE>displayTryqt1</FONT></CODE><FONT FACE="Arial" SIZE=2> native method. </P>
<UL>
<B><U><LI>Compile the java code</LI></UL>
<DIR>
</B></U><P>Use the Kaffe Java compiler to compile the class that you created in the previous step. Here's the command to use: </P>
</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P>kjc Tryqt1.java</P>
</FONT><FONT FACE="Arial" SIZE=2><P>before you compile make sure that the PATH variable points to KAFFEDIR/bin, the CLASSPATH variable points to KAFFEDIR/share/kaffe/Klasses.jar as well as the native directory where you are working, the variable QTDIR is defined properly, and the variable LD_LIBRARY_PATH=$QTDIR/lib:$KAFFEDIR/lib:/$KAFFEDIR/lib/kaffe:.</P>
<P>The Tryqt1.class file will be created on successful compile.</P>
</DIR>
<UL>
<B><U><LI>Create the .h file</LI></UL>
</B></U><P>In this step, you use the </FONT><FONT FACE="Arial"><CODE>kaffeh</FONT></CODE><FONT FACE="Arial" SIZE=2> utility program to generate a header file (a </FONT><FONT FACE="Arial"><CODE>.h</FONT></CODE><FONT FACE="Arial" SIZE=2> file) from the </FONT><FONT FACE="Arial"><CODE>Tryqt1</FONT></CODE><FONT FACE="Arial" SIZE=2> class. The header file provides a C function signature for the implementation of the native method </FONT><FONT FACE="Arial"><CODE>displayTryqt1</FONT></CODE><FONT FACE="Arial" SIZE=2> defined in that class. </P>
<P>Run </FONT><FONT FACE="Arial"><CODE>kaffeh</FONT></CODE><FONT FACE="Arial" SIZE=2> now on the </FONT><FONT FACE="Arial"><CODE>Tryqt1</FONT></CODE><FONT FACE="Arial" SIZE=2> class that you created in the previous steps. </P>
</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P>kaffeh –jni Tryqt1</P>
</FONT><FONT FACE="Arial" SIZE=2>
<P>The name of the header file is the Java class name with a </FONT><FONT FACE="Arial"><CODE>.h</FONT></CODE><FONT FACE="Arial" SIZE=2> appended to the end. For example, the command shown above will generate a file named </FONT><FONT FACE="Arial"><CODE>Tryqt1.h</FONT></CODE><FONT FACE="Arial" SIZE=2>. </P>
<P>The file looks something like this:</P>
</FONT><FONT FACE="Courier New" SIZE=2>
<P>/* DO NOT EDIT THIS FILE - it is machine generated */</P>
<P>#include <jni.h></P>
<P>#ifndef _Included_Tryqt1</P>
<P>#define _Included_Tryqt1</P>
<P>#ifdef __cplusplus</P>
<P>extern "C" {</P>
<P>#endif</P>
<P>JNIEXPORT void JNICALL Java_Tryqt1_displayTryqt1(JNIEnv*, jobject);</P>
<P>#ifdef __cplusplus</P>
<P>}</P>
<P>#endif</P>
<P>#endif</P>
</FONT><FONT FACE="Arial" SIZE=2><P>The name of the native language function that implements the native method consists of the prefix </FONT><FONT FACE="Arial"><CODE>Java_</FONT></CODE><FONT FACE="Arial" SIZE=2>, the package name, the class name, and the name of the native method. Between each name component is an underscore "_" separator. We are not implementing a package hence our signature is the keyword Java followed by the classname, Tryqt1, followed by the method name i.e displayTryqt1. </P>
<UL>
<B><U><LI>Write the native method implementation</LI></UL>
</B></U><P ALIGN="CENTER"></P>
<P>Now, you can finally write the implementation for the native method in a language other than Java. </P>
<P>Here's the C++ language implementation for the native method </FONT><FONT FACE="Arial"><CODE>Java_Tryqt1_displayTryqt1</FONT></CODE><FONT FACE="Arial" SIZE=2>. This implementation is in the file named hello.cpp</P>
</FONT><FONT FACE="Courier New" SIZE=2><P>#include <qapplication.h></P>
<P>#include <qpushbutton.h></P>
<P>#include <stdio.h></P>
<P>#include <jni.h></P>
<P>#include "Tryqt1.h"</P>
<P>#include <stdio.h></P>
<P>int qt1_show()</P>
<P>{</P>
<P> char *argv1[2] = { "qt1", "-qws"}; </P>
<P> int argc = 2;</P>
<P> printf("you are in qt");</P>
<P> QApplication a(argc, argv1);</P>
<P> QPushButton *hello=new QPushButton( "Hello world!", 0 );</P>
<P> hello->resize( 100, 30 );</P>
<P> </P>
<P> QObject::connect( hello, SIGNAL(clicked()), &a, SLOT(quit()) );</P>
<P> </P>
<P> a.setMainWidget( hello );</P>
<P> hello->show();</P>
<P> </P>
<P> return a.exec();</P>
<P> //return 0;</P>
<P>} </P>
<P>JNIEXPORT void JNICALL Java_Tryqt1_displayTryqt1(JNIEnv* env, jobject obj) </P>
<P>{</P>
<P> int i=qt1_show();</P>
<P> printf("%d", i); </P>
<P>}</P>
<P> </P>
<P> </P>
</FONT><FONT FACE="Arial" SIZE=2><P>The </FONT><FONT FACE="Arial"><CODE>hello.cpp</FONT></CODE><FONT FACE="Arial" SIZE=2> file includes two important header files apart from the regular qt header files: </P>
<OL>
</FONT><FONT FACE="Arial"><CODE><LI>jni.h</FONT></CODE><FONT FACE="Arial" SIZE=2> - This header file provides information that the native language code requires to interact with the Java runtime system. <STRONG>When writing native methods, you must always include this file in your native language source files.</STRONG> </LI>
</FONT><FONT FACE="Arial"><CODE><LI>Tryqt1.h</FONT></CODE><FONT FACE="Arial" SIZE=2> - The </FONT><FONT FACE="Arial"><CODE>.h</FONT></CODE><FONT FACE="Arial" SIZE=2> file that you generated in Step 3: Create the .h File. </LI></OL>
<P>The qt1_show function contains the qt code for creating a widget with a hello world button. When the button is pressed, the application exits.</P>
<UL>
<B><U><LI>Create the shared library</LI></UL>
</B></U><P>Now, you must compile </FONT><FONT FACE="Arial"><CODE>hello.cpp </FONT></CODE><FONT FACE="Arial" SIZE=2>into a shared library, which you name Try to match the library name used in the </FONT><FONT FACE="Arial"><CODE>System.loadLibrary</FONT></CODE><FONT FACE="Arial" SIZE=2> method. Since we are compiling a qt program and it needs to link with qt libraries too, we use the following command:</P>
</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P>g++ -c –I$QTDIR/include –I$KAFFEDIR/include/kaffe -pipe -DQWS -fno-exceptions -fno-rtti -O2 -o Try.o hello.cpp </P>
<P>g++ -shared -L$QTDIR/lib -Wl,-rpath,$QTDIR/lib -o libTry.so Try.o -lqte</P>
<P> </P>
</FONT><FONT FACE="Arial" SIZE=2><P>Be sure to replace the variables QTDIR and KAFFEDIR with the actual paths. </P>
<UL>
<B><U><LI>Run the program</LI></UL>
</B></U><DIR>
<P>Now run the Java application (the </FONT><FONT FACE="Arial"><CODE>Tryqt1</FONT></CODE><FONT FACE="Arial" SIZE=2> class) with the Kaffe interpreter, as follows: </P><DIR>
</FONT><FONT FACE="Arial" COLOR="#0000ff"><PRE>kaffe Tryqt1</PRE></DIR>
</FONT><FONT FACE="Arial" SIZE=2><P>You should see the Helloworld widget popping up on the terminal.</P>
<P>If you get java.lang.UnsatisfiedLinkError, check the variable LD_LIBRARY_PATH and make sure that it includes the paths for Qt libs, kaffe libs as well as yuur current directory which conatins the libTry.so file.</P>
<P>This program demonstrates a very basic kind of interfacing between Java and qt-embedded using JNI but can be used as an initial stepping stone to creating more complicated applications with qt-embedded and java using JNI. There are various ways of </FONT><A HREF="http://java.sun.com/docs/books/tutorial/native1.1/integrating/types.html"><FONT FACE="Arial" SIZE=2>passing variables</FONT></A><FONT FACE="Arial" SIZE=2> back and forth, of </FONT><A HREF="http://java.sun.com/docs/books/tutorial/native1.1/implementing/cpp.html"><FONT FACE="Arial" SIZE=2>calling Java methods from C++</FONT></A><FONT FACE="Arial" SIZE=2> etc. They are explained in detail in the java tutorial on JNI from Sun. </P>
<P> </P>
<P> </P>
<P> </P>
<P> </P>
<B><U><P> </P>
</B></U><P> </P>
<B><U><P> </P>
</B></U><P> </P>
<B><U><P> </P>
</B></U><P> </P>
<P> </P>
<P> </P>
<P> </P>
<P> </P>
<P> </P>
<P> </P>
<P> </P>
<P> </P>
<P> </P></DIR>
</FONT></BODY>
</HTML>