Date: Sat, 1 Jan 2000 12:17:53 -0500 (EST) From: Brian Clapper <bmc@WillsCreek.COM> To: freebsd-java@FreeBSD.ORG Subject: Re: java JNI compile problems Message-ID: <200001011717.MAA47567@footbridge.willscreek.com> In-Reply-To: <14446.5474.172635.556466@vega.sudell.org> References: <386D454B.694B5093@1connect.com> <14446.5474.172635.556466@vega.sudell.org>
index | next in thread | previous in thread | raw e-mail
Perhaps this will help.
I've enclosed a shell archive containing a simple JNI test that works fine
for me on FreeBSD 3.1-RELEASE, with the latest JDK. It worked fine with the
1.1.6 JDK, too, which was the latest one available when I built this test
more than a year ago. I used a shar file, because I'm not sure what the
list server will do to a MIME attachment; seemed safer to use shar.
The archive contains four files:
Makefile
SystemCommandOutputReader.java
SystemCommandOutputReader.c
CommandTest.java
SystemCommandOutputReader.{c,java} implements a command-runner class that
uses native methods to permit a Java program to issue a command and read
its output. CommandTest.java is a simple test driver. To run the test:
1. Unpack the shell archive. Make sure you have all four files.
2. Make sure you have GNU make installed, or be prepared to hack the
Makefile a bit more than I've described here.
3. Edit the appropriate variables at the top of the Makefile--specifically,
JAVA_HOME. If you don't have the jikes port installed, you'll also need
to modify the setting of JAVAC.
4. Type "gmake"
5. Make sure that the current directory is in your LD_LIBRARY_PATH, and
type something like:
java CommandTest ls -CF /var
If it works, you should see output similar to this:
Command output follows:
-----------------------
account/ cron/ mail/ rwho/
at/ db/ msgs/ spool/
backups/ games/ preserve/ tmp/
crash/ log/ run/ yp/
I apologize for the almost complete lack of documentation in the code. It's
not used in production; I hacked it together just to provide a template for
doing JNI. It's not that difficult to adapt to a Windows environment, BTW;
I've done that, too, in the past.
Hope this helps.
Regards,
-Brian
Brian Clapper, bmc@WillsCreek.COM, http://WWW.WillsCreek.COM/
The reasonable man adapts himself to the world; the unreasonable one
persists in trying to adapt the world to himself. Therefore all
progress depends on the unreasonable man.
-- George Bernard Shaw
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: CommandTest.java Makefile SystemCommandOutputReader.c
# SystemCommandOutputReader.java
# Wrapped by bmc@current.willscreek.com on Sat Jan 1 12:14:20 2000
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'CommandTest.java' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'CommandTest.java'\"
else
echo shar: Extracting \"'CommandTest.java'\" \(1824 characters\)
sed "s/^X//" >'CommandTest.java' <<'END_OF_FILE'
Ximport java.io.*;
Ximport java.lang.*;
X
X// SystemCommandOutputReader class is currently in the default package.
X
Xpublic class CommandTest
X{
X // Main program, for testing the SystemCommandOutputReader class.
X
X public static void main(String[] args)
X {
X int exitCode = 0;
X
X if (args.length == 0)
X {
X System.err.println ("Usage: java Command command [args] ...");
X exitCode = 1;
X }
X
X else
X {
X String cmdString = args[0];
X int i;
X
X for (i = 1; i < args.length; i++)
X cmdString = cmdString + " " + args[i];
X
X System.out.println ("Command = \"" + cmdString + "\"");
X exitCode = runCommand (cmdString);
X }
X }
X
X private static int runCommand (String cmdString)
X {
X int exitCode = 0;
X SystemCommandOutputReader cmd = new SystemCommandOutputReader();
X
X // Start the command.
X
X try
X {
X cmd.start (cmdString);
X }
X
X catch (IOException e)
X {
X System.err.println ("Can't run \"" + cmdString + "\": "
X + e.toString());
X exitCode = 1;
X cmd = null;
X }
X
X // Now, read its output.
X
X try
X {
X int c;
X
X System.out.println ("Command output follows:");
X System.out.println ("-----------------------");
X
X while ( (c = cmd.read()) > 0 )
X {
X System.out.write (c);
X }
X }
X
X catch (Exception e)
X {
X System.err.println ("Error reading from command: " + e.toString());
X exitCode = 1;
X }
X
X if (cmd != null)
X cmd.convenientClose();
X
X return exitCode;
X }
X}
END_OF_FILE
if test 1824 -ne `wc -c <'CommandTest.java'`; then
echo shar: \"'CommandTest.java'\" unpacked with wrong size!
fi
# end of 'CommandTest.java'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(869 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
XJAVA_HOME = /usr/local/java/jdk1.1.8
XJAVA_BIN = $(JAVA_HOME)/bin
X#JAVAC = $(JAVA_BIN)/javac
XJAVAC = /usr/local/bin/jikes
XJAVAH = $(JAVA_BIN)/javah
XJAR = $(JAVA_BIN)/jar
XC_INCLUDES = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/freebsd -I.
X
X.SUFFIXES: .class .java
X
X%.class: %.java
X $(JAVAC) $<
X
X%.h: %.class
X $(JAVAH) -jni $*
X
X%.o: %.c
X $(CC) -Wall -c $< $(C_INCLUDES)
X
X.PHONY: Command all
X
Xall: Command
Xclean:
X rm -f *.class *.o *.h *.so
X
XHelloWorld: HelloWorld.class libhello.so
XHelloWorld.o: HelloWorld.c HelloWorld.h
Xlibhello.so: HelloWorld.o
X $(CC) -o libhello.so -shared HelloWorld.o
X
XCommand: SystemCommandOutputReader.class CommandTest.class libCommand.so
X
XSystemCommandOutputReader.o: SystemCommandOutputReader.h \
X SystemCommandOutputReader.c
X
XlibCommand.so: SystemCommandOutputReader.o
X $(CC) -o libCommand.so -shared SystemCommandOutputReader.o
END_OF_FILE
if test 869 -ne `wc -c <'Makefile'`; then
echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'SystemCommandOutputReader.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'SystemCommandOutputReader.c'\"
else
echo shar: Extracting \"'SystemCommandOutputReader.c'\" \(4059 characters\)
sed "s/^X//" >'SystemCommandOutputReader.c' <<'END_OF_FILE'
X/*---------------------------------------------------------------------------*\
X $Id$
X
X Native implemenation of SystemCommandOutputReader
X\*---------------------------------------------------------------------------*/
X
X/*---------------------------------------------------------------------------*\
X Includes
X\*---------------------------------------------------------------------------*/
X
X#include <stdio.h>
X#include <unistd.h>
X#include "SystemCommandOutputReader.h"
X
X/*---------------------------------------------------------------------------*\
X Local Routines
X\*---------------------------------------------------------------------------*/
X
Xstatic FILE *getFP (JNIEnv *env, jobject obj)
X{
X jclass cls = (*env)->GetObjectClass (env, obj);
X jfieldID fid = (*env)->GetFieldID (env, cls, "nativeData", "[B");
X jbyteArray array = (*env)->GetObjectField (env, obj, fid);
X FILE *fp;
X
X /*
X The file pointer (address) is stored in the nativeData instance variable
X array. Copy it back somewhere useful.
X */
X (*env)->GetByteArrayRegion (env, array, 0, sizeof (fp), (jbyte *) &fp);
X return fp;
X}
X
Xstatic void setFP (JNIEnv *env, jobject obj, FILE *fp)
X{
X jclass cls = (*env)->GetObjectClass (env, obj);
X jfieldID fid = (*env)->GetFieldID (env, cls, "nativeData", "[B");
X jbyteArray array = (*env)->GetObjectField (env, obj, fid);
X
X /*
X Copy the contents of the file pointer into the nativeData instance
X variable. getFP() will restore the pointer from the same array.
X */
X (*env)->SetByteArrayRegion (env, array, 0, sizeof (fp), (jbyte *) &fp);
X return;
X}
X
X
Xstatic void throwException (JNIEnv *env, jobject obj,
X const char *exceptionName,
X const char *reason)
X{
X jclass exc;
X
X /*
X Note: This code fragment was adapted from code in the Java JNI tutorial.
X */
X (*env)->ExceptionDescribe (env);
X (*env)->ExceptionClear (env);
X
X exc = (*env)->FindClass (env, exceptionName);
X if (exc != 0)
X (*env)->ThrowNew (env, exc, reason);
X
X return;
X}
X
Xstatic void doClose (JNIEnv *env, jobject obj, FILE *fp)
X{
X if (fp != NULL)
X {
X fclose (fp);
X setFP (env, obj, NULL);
X }
X
X return;
X}
X
X/*---------------------------------------------------------------------------*\
X Native Methods
X\*---------------------------------------------------------------------------*/
X
XJNIEXPORT jint JNICALL
XJava_SystemCommandOutputReader_available (JNIEnv *env, jobject obj)
X{
X return 0;
X}
X
XJNIEXPORT void JNICALL
XJava_SystemCommandOutputReader_close (JNIEnv *env, jobject obj)
X{
X doClose (env, obj, getFP (env, obj));
X return;
X}
X
XJNIEXPORT jint JNICALL
XJava_SystemCommandOutputReader_nativeDataSize (JNIEnv *env, jobject obj)
X{
X return sizeof (FILE *);
X}
X
XJNIEXPORT jint JNICALL
XJava_SystemCommandOutputReader_read (JNIEnv *env, jobject obj)
X{
X char c;
X FILE *fp;
X int count;
X jint result = -1;
X
X if ( (fp = getFP (env, obj)) == NULL )
X {
X throwException (env, obj, "java/io/FileNotFoundException",
X "command not started");
X }
X
X else if ( (count = fread (&c, sizeof (c), 1, fp)) == 0 )
X {
X result = 0;
X doClose (env, obj, fp);
X }
X
X else if (count < 0)
X {
X throwException (env, obj, "java/io/IOException", "read error on pipe");
X }
X
X else
X {
X result = (jint) c;
X }
X
X return result;
X}
X
XJNIEXPORT void JNICALL
XJava_SystemCommandOutputReader_start (JNIEnv *env, jobject obj,
X jstring commandString)
X{
X FILE *p;
X const char *cmd = (*env)->GetStringUTFChars (env, commandString, 0);
X
X p = popen (cmd, "r");
X (*env)->ReleaseStringUTFChars (env, commandString, cmd);
X
X if (p == NULL)
X throwException (env, obj, "java/io/IOException", "can't run command");
X
X else
X setFP (env, obj, p);
X
X return;
X}
END_OF_FILE
if test 4059 -ne `wc -c <'SystemCommandOutputReader.c'`; then
echo shar: \"'SystemCommandOutputReader.c'\" unpacked with wrong size!
fi
# end of 'SystemCommandOutputReader.c'
fi
if test -f 'SystemCommandOutputReader.java' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'SystemCommandOutputReader.java'\"
else
echo shar: Extracting \"'SystemCommandOutputReader.java'\" \(2632 characters\)
sed "s/^X//" >'SystemCommandOutputReader.java' <<'END_OF_FILE'
Ximport java.io.*;
Ximport java.lang.*;
X
Xpublic class SystemCommandOutputReader extends InputStream
X{
X /*----------------------------------------------------------------------*\
X Private Data Elements
X \*----------------------------------------------------------------------*/
X
X // nativeData[] is basically just a buffer into which the native
X // methods can store data that can't easily be represented as Java
X // types (e.g., pointers). The native method nativeDataSize()
X // determines how many bytes to allocate.
X
X private byte nativeData[];
X
X /*----------------------------------------------------------------------*\
X Static Initializer
X \*----------------------------------------------------------------------*/
X
X static
X {
X // Load the shared library containing the native methods as soon as
X // this file is read.
X
X System.loadLibrary ("Command");
X }
X
X /*----------------------------------------------------------------------*\
X Constructor
X \*----------------------------------------------------------------------*/
X
X public SystemCommandOutputReader()
X {
X super();
X nativeData = new byte [nativeDataSize()];
X }
X
X /*----------------------------------------------------------------------*\
X Public Methods
X \*----------------------------------------------------------------------*/
X
X public native int available() throws IOException;
X
X public native void close() throws IOException;
X
X public void convenientClose()
X {
X try
X {
X close();
X }
X
X catch (IOException e)
X {
X }
X
X return;
X }
X
X public boolean markSupported()
X {
X return false;
X }
X
X public synchronized void mark (int readlimit)
X {
X // no-op
X
X return;
X }
X
X public native int read() throws IOException;
X
X public synchronized void reset() throws IOException
X {
X throw new EOFException ("reset() unavailable for class Command");
X }
X
X public long skip (long n) throws IOException
X {
X long skipped = 0;
X
X while ( (read() > 0) && (skipped < n) )
X skipped++;
X
X return skipped;
X }
X
X public native void start (String command) throws IOException;
X
X /*----------------------------------------------------------------------*\
X Private Methods
X \*----------------------------------------------------------------------*/
X
X private native int nativeDataSize();
X}
X
END_OF_FILE
if test 2632 -ne `wc -c <'SystemCommandOutputReader.java'`; then
echo shar: \"'SystemCommandOutputReader.java'\" unpacked with wrong size!
fi
# end of 'SystemCommandOutputReader.java'
fi
echo shar: End of shell archive.
exit 0
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-java" in the body of the message
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200001011717.MAA47567>
