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
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.targethostBuild 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 installThis 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)
Java Programming with JNI excellent tutorial from IBM
Best Practices for using the JNI another from IBM
-
write the java file containing native methods
-
compile it with javac to get a class file, e.g.
$ cd jn-c; mvn compile -
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.CoServiceProviderNever 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.classbash 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_VERSIONNow 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.
See also Linking and 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
java.lang.reflect.InvocationTargetException
...
Caused by: java.lang.UnsatisfiedLinkError: no ocfjni_c in java.library.pathThis 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.targethostSecurity 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"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.targethostNOTE: 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.OCFTestServerJNI:
-
'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
Instead of returning an OCStackResult code we return void and throw Java exceptions as needed.
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