Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

jni-c

A Java wrapper around the Iotivity C API.

Warning
Work-in-Progress. Discovery seems to work, and GET works for resources with "*" permissions. I expect to have a more-or-less complete (but basic) implementation within a week or so.

See also

prerequisites

  • Scons

  • Java 8

  • Maven

  • doxygen for C docs

  • …​ etc. …​

  • Xcode (OS X)

building

The build mechanism uses environment variables set using the source shell command. The files to be source -ed are located in a separate repository, xc. This is admittedly clunky, but the files are used across multiple projects (e.g. iochibity, iochibity-java, etc.).

First clone xc and edit the devhost and target host files as needed. For example, you need to set IOTIVITY_FLAVOR to either "iotivity" or "iochibity", depending on which implementation you’re targeting. You’ll also need to set some paths, e.g. IOTIVITY_HOME, PREFIX, etc. See darwin.devhost and darwin.targethost as examples.

Then source the devhost and targethost files; e.g. to develop on a mac, targeting the mac, do:

source ~/xc/source.me/darwin.devhost
source ~/xc/source.me/darwin.targethost

Build the jni-c shared library:

$ scons jni-c
## options:  VERBOSE=0 | 1, LOGGING= 0 | 1
Note
if you get something like jni-c/src/c/jni_utils.h:6:10: fatal error: 'jni.h' file not found, it means you did not source the right files, or they were not correctly configured.

This will put the shared lib in ${INSTALL_SYSROOT}/lib. For example, `$HOME/iochibity/sysroot/darwin/x86_64/debug/lib/libocfjni_c.jnilib on the Mac (libocfjni_c.so on Linux).

Then build the jni-c Java library:

$ cd jni-c
$ mvn install

This will create the jar file in the targets subdir, and copy it to your local Maven repo (e.g. $HOME/.m2/repository/org/iochibity/jni-c/0.1.0-SNAPSHOT/jni-c-0.1.0-SNAPSHOT.pom)

dev tools and techniques

Java Programming with JNI excellent tutorial from IBM

  1. write the java file containing native methods

  2. compile it with javac to get a class file, e.g. $ cd jn-c; mvn compile

  3. run javah against the class name (not the path) to generate the JNI C header file:

jni-c $ javah -jni -cp target/classes/ -d src/c/ org.iochibity.CoServiceProvider

Never manually edit the generated header files.

To see the signatures of methods, use javap, e.g. from jni-c:

$ javap -s target/classes/org/iochibity/CoServiceManager.class

os x

bash code to set the jdk version:

function removeFromPath() {
  export PATH=$(echo $PATH | sed -E -e "s;:$1;;" -e "s;$1:?;;")
}

function setjdk() {
  if [ $# -ne 0 ]; then
   removeFromPath '/System/Library/Frameworks/JavaVM.framework/Home/bin'
   if [ -n "${JAVA_HOME+x}" ]; then
    removeFromPath $JAVA_HOME
   fi
   export JAVA_HOME=`/usr/libexec/java_home -v $@`
   export PATH=$PATH:$JAVA_HOME/bin
  fi
 }

JAVA_VERSION=1.8
setjdk $JAVA_VERSION

Now you can run setjdk on the command line to switch to another version, e.g. $ setjdk 1.7.

otool is like ldd or readelf on Linux. E.g. use $ otool -L to print the shared libs used by a file.

Use install_name_tool to change install names.

Compiling a shared lib on OS X: -Wl,-undefined -Wl,dynamic_lookup or clang -shared -undefined dynamic_lookup -o libfoo.so foo.c

troubleshooting

java.lang.reflect.InvocationTargetException
...
Caused by: java.lang.UnsatisfiedLinkError: no ocfjni_c in java.library.path

This probably means you did not source the right files in xc/source.me, e.g.:

$ source ~/xc/source.me/darwin.devhost
$ source ~/xc/source.me/darwin.targethost

examples

Security configuration is required. You must create the appropriate CBOR files and tell the implementation where to find them (in the "Init" call); see the example code.

Then run the example:

$ cd examples
$ export MAVEN_OPTS="-Djava.library.path=${INSTALL_SYSROOT}/lib"
$ mvn exec:java -Dexec.mainClass="org.iochibity.test.OCFTestClient"
or
$ mvn exec:java -Dexec.mainClass="org.iochibity.test.OCFTestServer"

edison

You can cross-compile to target the Intel Edison. Currently this has only been tested on OS X as the dev host, but it should work for Linux as well.

To target the Intel Edison, source the appropriate devhost file, then edison.targethost. E.g., I develop on the Mac, so I do this:

source ~/xc/source.me/darwin.devhost
source ~/xc/source.me/edison.targethost

NOTE: you may need to edit the devhost and targethost files to fit your system.

Then build the library as above, and scp the result to the Edison.

Open a terminal to the Edison and (assuming you’ve copied Iochibity/Iotivity and the jni- lib to $HOME/iochibity, and the jar files to $HOME) do:

$ export LD_LIBRARY_PATH=$HOME/iochibity/lib
$ java -Djava.library.path=$HOME/iochibity/lib -cp "jni-c-0.1.0-SNAPSHOT.jar:iochibity-eg-0.1.0-SNAPSHOT.jar" org.iochibity.test.OCFTestServer

naming conventions

JNI:

  • 'klass' is reserved for the jclass arg (Class object) of static methods

  • 'this' is reserved for the (this) jobject arg of object methods

  • k_ is the prefix used for klasses other than the klass object

  • fid_ is the prefix for field ids from GetFieldId, e.g. fid_class_method

  • mid_ is the prefix for method ids from GetMethodId, e.g. mid_class_method

  • mids_ is for static methods

  • j_ - prefix for java objects

  • c_ - prefix for native c data

UPPER_CASE prefixes are used for global vars, set by JNI_OnLoad (in ocf_init.c); e.g. K_LINKED_LIST for the java.util.LinkedList class, MID_LL_CTOR for the LinkedList constructor etc.

Java:

  • _ - underscore prefix marks a field as both private and corresponding to an underlying var, ptr, struct, e.g. _handle

exceptions

Instead of returning an OCStackResult code we return void and throw Java exceptions as needed.

conceptual structure

We eschew talk of "Resources" and "Representations", because those terms are so abstract as to be useless; in software, everything is both a "resource" and a "representation".

The basic idea is that servers are ServiceProviders, and clients are ServiceRequestors. The mechanism of communication is the message. Messages may contain payloads, and may reference state ("Resource").

The library itself provides services to clients and servers. The Messenger provides messaging services; the ServiceManager keeps track of service requestors and providers (callbacks).

ServiceProviders are composed of some meta-data, such as a URL path, a state machine that functions as a callback/handler for dealing with incoming messages requesting services, and data. The data are state data (conventionally, they are a "resource representation). The state machine may maintain state data in memory, or it may acquire it dynamically (as in the case of "reading" a sensor instrument).

On a ServiceProvider (server), the state machine is a routine called serviceRequestIn; on a ServiceRequestor (client), it’s a routine called serviceResponseIn;

ServiceProviders must be registered with the ServiceManager.

A Client (ServiceRequestor) creates an outgoing service request message (MsgRequestOut), and uses the Messenger to send it (Messenger.sendRequest(…​)).

A (application) Server (ServiceProvider) receives (from a client ServiceRequestor) an incoming request message (MsgRequestIn), which refers to Resources (ResourceLocal). The ServiceProvider creates an outgoing message (MsgResponseOut), creates a Payload containing relevant (state) data, inserts it in the MsgResponseOut, and asks the Messenger to send it to the client ServiceRequestor.

The client ServiceRequestor then receives an incoming response message (MsgResponseIn) that corresponds to the MsgResponseOut sent by the ServiceProvider.

ServiceProviders (on the server side) are always associated with state, and the messages handled by ServiceProviders (MsgRequestIn/MsgResponseOut) always contain a reference to that state.

Messages may also contain payloads.

setPlatformInfo ⇒ ServicesManager.registerPlatformProvider

setDeviceInfo ⇒ ServicesManager.registerDeviceProvider

OCCreateResource ⇒ ServicesManager.registerServiceProvider

new: Messenger

OCDoResource ⇒ Messenger.sendRequest

OCDoResponse ⇒ Messenger.sendResponse

OCResource ⇒ Resource

ResourceLocal  (new; resource on server)
ResourceRemote (new; resource on client, rec'd from server)

new: IMessage, Message implements IMessage

new: MsgForServiceProvider extends Message

OCEntityHandlerRequest ⇒ MsgRequestIn extends MsgForServiceProvider

OCEntityHandlerResponse ⇒ MsgResponseOut extends MsgForServiceProvider

new: MsgForServiceRequestor extends Message

OCClientResponse ⇒ MsgResponseIn extends MsgForServiceRequestor

new: MsgRequestOut extends MsgForServiceRequestor