The reserved word native is used as a method
modifier to let you call a C/C++ implementation of the method.
When would you want to use a C/C++ implementation?
Disadvantages of using native methods:
There are two ways in which Java and C (or C++) can work together:
So, be warned.
In this module, we will explain only the former.
As a first example, let us call a C function that prints
"Hello World!" to the screen.
A number of steps need to be followed carefully to make this
work:
Note:
// A class with a native method.
class HelloWorld {
public native static void hello_world ();
}
public class native1 {
public static void main (String[] argv)
{
// Need to load the C implementation first.
System.loadLibrary ("helloworld");
// Now create an instance and call the method.
new HelloWorld().hello_world();
}
}
Note:
% javac native1.java
Now the current directory should have a class file for
HelloWorld.
% javah -jni HelloWorld
Note:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: hello_world
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_hello_1world
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
JNIEXPORT void JNICALL Java_HelloWorld_hello_1world
(JNIEnv *, jclass);
#include "HelloWorld.h"
#include <stdio.h>
#include "HelloWorld.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_HelloWorld_hello_1world
(JNIEnv *, jclass);
#include "HelloWorld.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_HelloWorld_hello_1world
(JNIEnv * jenv, jclass jcl)
{
printf ("Hello World!\n");
return;
}
Note:
% gcc -I/usr/local/lib/jdk_1.1.2/include -I/usr/local/lib/jdk_1.1.2/include/solaris hello_world.c -o libhelloworld.so
% java native1
System.loadLibrary ("helloworld");
public class native1 {
static {
// Need to load the C implementation first.
System.loadLibrary ("helloworld");
}
public static void main (String[] argv)
{
// Now create an instance and call the method.
new HelloWorld().hello_world();
}
}
The size of C types depends on the system. Therefore,
Java defines C types (using C's typedef)
that correspond to Java types:
In the next example, we will pass some parameters and obtain
return values.
Here is the Java program:
(source file)
Java-compilation of the above file produces a class file for
TestParams.
Next, we run javah -jni on TestParams to
get the C-header file:
(source file)
Here is the implementation in C:
(source file)
After this, compile the C file as shown earlier and run the
Java program.
We have only scratched the surface of the C-Java connection:
This way, we can be sure that a jint variable uses (no less
than) 4 bytes.
// A class with native methods.
class TestParams {
public native int factorial (int i);
public native String replicate (String s);
}
public class native2 {
static {
System.loadLibrary ("testparams");
}
public static void main (String[] argv)
{
// Create
TestParams tp = new TestParams ();
// Call the factorial method (native)
int k = tp.factorial (5);
System.out.println ("Java: native2: main: 5! = " + k);
// Call the native replicate method.
String s = tp.replicate ("Hello World!");
System.out.println ("Java: native2: main: string s = " + s);
}
}
Note:
(The factorial of the parameter is returned).
(We will implement this by concatening the input string to
itself).
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
Note:
#include "TestParams.h"
#include <stdio.h>
#include <string.h>
JNIEXPORT jint JNICALL Java_TestParams_factorial
(JNIEnv * env, jobject obj, jint i)
{
jint j, k;
printf ("Inside C: integer parameter i = %3d\n", i);
j = i; k = 1;
while (j != 1) {
k = k * j;
j = j - 1;
}
printf ("Inside C: factorial k = %3d\n", k);
return k;
}
JNIEXPORT jstring JNICALL Java_TestParams_replicate
(JNIEnv * env, jobject obj, jstring s)
{
const char *s2, *s2_copy, *s3;
jboolean copy;
jstring s4;
copy = JNI_TRUE;
s2 = (*env)->GetStringUTFChars (env, s, & copy);
s2_copy = (*env)->GetStringUTFChars (env, s, & copy);
printf ("Inside C: replicate String = %s\n", s2);
s3 = strcat (s2, s2_copy);
s4 = (*env)->NewStringUTF (env, s2);
printf ("Inside C: replicate return value = %s\n", s3);
return s4;
}
Note:
In general, these advanced features are to be used with extreme
caution, usually only if you are building a library of C-Java
interfaces.
JDBC (Java DataBase Connectivity) is a set of classes
provided in the package java.sql for the purpose
of letting Java programmers access standing databases:
Here's what you need to get JDBC working:
There are many JDBC drivers - we will assume the usage
of any JDBC driver (such as SequeLink) for the example below.
(For example, the Java class java.sql.Data
handles the SQL type DATE).
Some Oracle tutorial information is also included:
To access any of these tables, use my username to qualify
the table, e.g., select * from simha.customer.
create table acc_type (
acc_code integer,
acc_name varchar2(10)
);
create table accounts (
ssn varchar2(12),
acc_code integer,
accnum integer,
branchnum integer,
amount integer
);
create table customer (
ssn varchar2(12),
name varchar2(12),
addr varchar2(25),
city varchar2(12),
state varchar2(4)
);
create table branch (
branchnum integer,
bname varchar2(15),
city varchar2(12),
mgrssn varchar2(12)
);
create table managers (
ssn varchar2(12),
name varchar2(12),
addr varchar2(25),
city varchar2(12),
state varchar2(4)
);
The first thing we need to do is to make sure that JDBC is
working. You can actually continue with the first example in
the next section, since by this time the Driver will probably
have been set up correctly for anyone to use.
If the example did not work, come back
here and use these instructions
to test JDBC.
Once JDBC is working, we are ready to write our first Java
program that connects to the database.
Note: To run the program:
In the example, we will write code to:
Here is the code:
(source file)
Note:
Exercise 14.1:
Try the above code with your username and password.
In this next example, we will:
The appearance of the application will be
When the user connects by pressing the Connect button,
we will present a dialog:
When the connection is made, we will indicate so to the
user and let the user enter a query and a column name.
Finally, when the user presses the Submit button, we will
execute the query and return the results.
Note: this application is somewhat crude because it only allows
one column value to be displayed.
Here is are parts of the code:
(complete source file)
Note:
Exercise 14.2:
Try the above code with your username and password. Then
modify the code so that a second column can be entered by the
user. Then, show the results when a join is used to pair up
customers and their account amounts.
(Although, in general, JDBC drivers can be run anywhere).
import java.net.*;
import java.sql.*;
import java.io.*;
public class Jdbc1 {
public static void main (String[] argv)
{
try{
// First, load the "SequeLinkDriver" class.
Class.forName ("intersolv.jdbc.sequelink.SequeLinkDriver");
// Now prepare the strings needed to make the connection.
String connection_url =
"jdbc:sequelink://delphi:4003/[Oracle];OSUser=simha;OSPassword=*";
String oracle_username = "simha";
String oracle_password = "*";
System.out.println ("Trying connection ... ");
// Make the connection.
Connection con = DriverManager.getConnection (connection_url,
oracle_username,
oracle_password);
System.out.println ("Connection succeeded");
// Next, some SQL.
System.out.println ("Trying SQL ...");
// Create a Statement instance first.
Statement st = con.createStatement();
// Call the executeQuery method in the instance.
ResultSet rs = st.executeQuery ("select NAME from simha.CUSTOMER");
System.out.println ("SQL execution returned with:");
// Repeatedly fetch tuples from the result set.
while (rs.next()) {
String name = rs.getString (1);
System.out.println (name);
}
// Close the connection.
con.close();
}
catch (SQLException e){ System.out.println(e);}
}
}
(This path leads off from one of the CLASSPATH values).
String connection_url =
"jdbc:sequelink://delphi:4003/[Oracle];OSUser=simha;OSPassword=*";
Thus, instead of simha you will use your Unix username
and instead of * you will use your Unix password.
// Make the connection.
Connection con = DriverManager.getConnection (connection_url,
oracle_username,
oracle_password);
DriverManager has methods that let you:
(Statement is actually an interface).
(For example, is the actual integer 5 to be returned as an
int or as the string "5"?)
(Here, "1" indicates the first column).
String name = rs.getString ("NAME");
JDBC: a more complex example
where
Here:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.sql.*;
import java.net.*;
class JDBCClient extends JFrame {
JTextField // TextFields to read stuff from user.
queryfield, // SQL query.
columnfield; // A column name.
String
query, // The string that will hold the query.
column; // The column name.
boolean is_connected = false;
JTextArea message_board; // To display the results
JScrollPane sc;
// Constructor.
public JDBCClient ()
{
// Create the frame (not shown).
// ...
// Create the scrollable panel (not shown).
// ...
// A top panel for the query and column name.
JPanel top_panel = new JPanel();
top_panel.setLayout (new GridLayout (2,2));
// The query textfield that gets the query string
// into "query" (not shown).
// ...
// The column textfield that gets the column name
// into the variable "column" (not shown)
// ...
// Add the top panel to the frame.
cPane.add (top_panel, BorderLayout.NORTH);
// A bottom panel for three buttons.
JPanel bottom_panel = new JPanel ();
// A quit button that calls quit() (not shown)
// ...
// A connect button that calls connect() (not shown).
// ...
// A submit button that calls submit() (not shown).
// ...
// Add the bottom panel.
cPane.add (bottom_panel, BorderLayout.SOUTH);
// Display the frame.
this.setVisible (true);
}
// Display text on a message panel using Label's.
void display_text (String s, Color c)
{
// ... (not shown) ...
}
// These variables will be used in the connection dialog.
JDialog connect_dialog; // A connection dialog.
JTextField // Textfields in the dialog.
Unixnamef,
Oraclenamef;
JPasswordField // Password fields in the dialog.
Unixpassf,
Oraclepassf;
String // String variables for the
Unixname, Unixpass, // usernames and passwords.
Oraclename, Oraclepass;
void connect ()
{
// If already connected, return.
if (is_connected) return;
// Set up the dialog.
connect_dialog = new JDialog (this, true);
connect_dialog.setTitle ("Connect to Oracle");
connect_dialog.setSize (400,200);
connect_dialog.setLocation (200,200);
Container cPane = connect_dialog.getContentPane();
cPane.setBackground (Color.cyan);
cPane.setLayout (new GridLayout(5,2));
// Unix username textfield that gets the
// username into the String variable "Unixname".
JLabel L = new JLabel ("UNIX USERNAME:");
cPane.add (L);
Unixnamef = new JTextField (20);
Unixnamef.setForeground (Color.blue);
Unixnamef.addActionListener (
new ActionListener () {
public void actionPerformed (ActionEvent t)
{
Unixname = Unixnamef.getText();
}
}
);
cPane.add (Unixnamef);
// Unix password textfield.
L = new JLabel ("UNIX PASSWORD:");
cPane.add (L);
Unixpassf = new JPasswordField (20);
Unixpassf.setForeground (Color.blue);
Unixpassf.addActionListener (
new ActionListener () {
public void actionPerformed (ActionEvent t)
{
Unixpass = new String (Unixpassf.getPassword());
}
}
);
cPane.add (Unixpassf);
// Oracle username textfield (not shown)
// ...
// Oracle password textfield (not shown).
// ...
// A connect button.
JButton connectb = new JButton ("CONNECT");
connectb.setBackground (Color.green);
connectb.addActionListener (
new ActionListener () {
public void actionPerformed (ActionEvent a)
{
connect_db ();
connect_dialog.dispose ();
}
}
);
cPane.add (connectb);
// A cancel button (not shown).
// ...
// Display the dialog.
connect_dialog.setVisible (true);
}
Connection con;
void connect_db ()
{
try {
// Load the JDBC Driver.
Class.forName ("intersolv.jdbc.sequelink.SequeLinkDriver");
// Set up the connection URL
String connection_url =
"jdbc:sequelink://delphi:4003/[Oracle];OSUser=" + Unixname +
";OSPassword=" + Unixpass;
display_text ("Trying connection ... ", Color.blue);
con = DriverManager.getConnection (connection_url,
Oraclename,
Oraclepass);
// It worked.
display_text ("Connection succeeded", Color.blue);
display_text ("Enter query above", Color.blue);
is_connected = true;
}
catch(SQLException e){
System.out.println(e);
display_text ("Connection attempt failed", Color.blue);
}
catch (ClassNotFoundException e) { System.out.println(e); }
}
// Handle a query.
void submit ()
{
// If not connected, don't do anything.
if (!is_connected) {
display_text ("Not connected ... try connecting", Color.red);
return;
}
// If bad strings are given, pass.
if ( (query == null) || (column == null) ) {
display_text ("Null query or column... try again", Color.red);
return;
}
// Otherwise, execute the query.
try {
display_text ("Trying SQL: " + query, Color.blue);
// Get a Statement instance first.
Statement st = con.createStatement();
// Execute the query.
ResultSet rs = st.executeQuery (query);
display_text ("SQL execution returned with:", Color.blue);
int index = 1;
try {
// Use the given column name.
index = rs.findColumn (column);
}
catch (SQLException e){
display_text ("Column name not found ... try again", Color.blue);
return;
}
// If the column name was valid, get the values.
while (rs.next()) {
String result = rs.getString (index);
display_text (result, Color.black);
}
}
catch (SQLException e){
System.out.println(e);
display_text ("SQL query failed ... try again", Color.blue);
}
}
// Exit gracefully.
void quit ()
{
try {
con.close ();
System.exit (0);
}
catch (SQLException e){ System.out.println(e);}
}
}
public class Jdbc2 {
public static void main (String[] argv)
{
JDBCClient jc = new JDBCClient ();
}
}