Most of the documentation that details how to get started with JNI described how to build a new JNI application using X-Code. Can anyone link me to a description of how to use JNI to interface with Objective-C in an existing application.
NOTE: I have completely re-written this answer from scratch, now that I know for sure it works ;-).
Use Rococoa instead of JNI.
Here is a brief sample I was able to whip up that displays the picture taker dialog (based on your comment to Stephen C's answer).
/***
* INCOMPLETE: Doesn't have imports or anything like that.
***/
public interface Quartz extends Library
{
public static Quartz instance = (Quartz)Native.loadLibrary("Quartz", Quartz.class);
}
public interface IKPictureTaker extends NSObject
{
public static final _Class CLASS = Rococoa.createClass("IKPictureTaker", _Class.class);
public interface _Class extends NSClass
{
/**
* Returns a shared {#code IKPictureTaker} instance, creating it if necessary.
* #return an {#code IKPictureTaker} object.
*/
IKPictureTaker pictureTaker();
}
NSInteger runModal();
}
public class IKPictureTakerTest extends JFrame
{
public static void main(String[] args) throws Exception
{
// You need a GUI before this will work.
new IKPictureTakerTest().setVisible(true);
NSAutoreleasePool pool = NSAutoreleasePool.new_();
// Initialize the Quartz framework.
Quartz.instance.toString();
// Display the dialog.
IKPictureTaker pictureTaker = IKPictureTaker.CLASS.pictureTaker();
NSInteger result = pictureTaker.runModal();
if (result.intValue() == 0) // NSCancelButton
{
System.out.println("User cancelled.");
}
else
{
assert result.intValue() == 1; // NSOKButton
System.out.println("User chose an image.");
}
System.out.println(pictureTaker.inputImage()); // null if the user cancelled
pool.release();
}
}
If you get lost, try the Rococoa mailing lists. The developers are very helpful.
You will still need to write a JNI library of some sort to wrap your access to the existing code (aka, shared object, DLL, service program, etc). This is because JNI requires a rather obtuse (but sensible) naming convention for the native functions invoked, because you need to move data in and out of Java memory space and because you need to have conceptual "bridging" code between Java and your native function.
For example, I wrote a JNI library to provide access to existing C functions on the iSeries. One such function to read from a data area looks as follows:
JNIEXPORT void JNICALL Java_com_xxx_jni400_DataArea_jniGetDataArea(JNIEnv *jep, jobject thsObj, jbyteArray qulnam, jint str, jint len, jbyteArray rtndta, jint rtnlen) {
jbyte *qn,*rd;
Qwc_Rdtaa_Data_Returned_t *drt;
QFBK2_T fbk;
byte nam[11],lib[11];
byte *ptr;
// SETUP
thsObj=thsObj;
qn=(*jep)->GetByteArrayElements(jep,qulnam,0);
rd=(*jep)->GetByteArrayElements(jep,rtndta,0);
fbk.pro=sizeof(fbk); fbk.avl=0;
// INVOKE
QWCRDTAA(rd,rtnlen,(byte*)qn,str,len,&fbk);
// HANDLE SUCCESSFUL INVOCATION
if(fbk.avl==0) {
drt=(Qwc_Rdtaa_Data_Returned_t*)rd;
if(drt->Length_Value_Returned>0) { /* pad with spaces until the length requested */
ptr=(byte*)(rd+sizeof(*drt)+drt->Length_Value_Returned);
for(; drt->Length_Value_Returned<len; drt->Length_Value_Returned++,ptr++) { *ptr=' '; }
}
}
// RELEASE JAVA MEMORY LOCKS
(*jep)->ReleaseByteArrayElements(jep,qulnam,qn,JNI_ABORT); /* discard array changes */
(*jep)->ReleaseByteArrayElements(jep,rtndta,rd,0 ); /* copy back changes */
// TRANSFORM NATIVE ERROR INTO AN EXCEPTION AND THROW
if(fbk.avl!=0) {
byte eid[8],dta[201];
word dtalen;
f2s(nam,sizeof(nam),(byte*)qn ,10);
f2s(lib,sizeof(lib),(byte*)(qn+10),10);
dtalen=(word)mMin( sizeof(fbk.dta),(fbk.avl-(sizeof(fbk)-sizeof(fbk.dta))) );
f2s(eid,sizeof(eid),fbk.eid,sizeof(fbk.eid));
f2s(dta,sizeof(dta),fbk.dta,dtalen);
if(mStrEquI(eid,"CPF1015") || mStrEquI(eid,"CPF1021")) {
throwEscape(jep,90301,"Could not find data area %s in library %s",nam,lib);
}
else if(mStrEquI(eid,"CPF1016") || mStrEquI(eid,"CPF1022")) {
throwEscape(jep,90301,"Not authorized to data area %s in library %s",nam,lib);
}
else if(mStrEquI(eid,"CPF1063") || mStrEquI(eid,"CPF1067")) {
throwEscape(jep,90301,"Cannot allocate data area %s in library %s",nam,lib);
}
else if(mStrEquI(eid,"CPF1088") || mStrEquI(eid,"CPF1089")) {
throwEscape(jep,90301,"Substring %i,%i for data area %s in library %s are not valid",str,len,nam,lib);
}
else {
if(strlen(dta)>0) { throwEscape(jep,90001,"System API QWCRDTAA returned error message ID %s (%s)",eid,dta);}
else { throwEscape(jep,90001,"System API QWCRDTAA returned error message ID %s",eid); }
}
}
}
Note the one-line invocation for underlying existing API, QWCRDTAA, which is provided by IBM; the rest is Java-centric wrapping which is necessary to make the call and deal with the results.
Also, be very careful that what you invoke is thread-safe, or that you protect the code from concurrent invocations globally in the Java layer, or that you protect the code with a mutex in the O/S layer.
PS: Note that non-threadsafe native code is globally non-threadsafe; you must prevent concurrent invocation with all other non-threadsafe native code, not just the one method you are invoking. This is because it might be unsafe due to an underlying call to some other function which other unsafe methods call (like strerror(), (if my C memory serves well)).
Assuming that the Object-C application can be run via the command line, a simpler (and less problematic) approach would be to launch it using one of the java.lang.Runtime.exec(...) methods.
JNI is fraught with complexity and stability issues, and it is best to avoid it if you can.
EDIT: The OP has explained that this is a "widget" not a command line application. That makes it harder to avoid using JNI. But I still think that you ought to try. For example, you could consider wrapping the Objective-C widget in an Objective-C application, that runs the widget in a new window.
Related
I've managed to get COM4J to use some functionality in the windows IMAPI (CD writing).
However I've failed to get any of the calls that return SAFEARRAYs working, but this project doesn't appear to be currently active ...
The DLL is usually in C:\Windows\System32\imapi2.dll, and using it also requires using C:\Windows\System32\imapi2fs.dll
Looking around for a JAVA-COM bridge project that is active led me to JNA.
The remit of the project to simplify JAVA-COM bridging intrigued me .... however I fell at the first hurdle, and am hoping someone can help.
So far I've taken the Microsoft IMAPI examples and written a Powershell application, from which I have the series of calls I need to make to the API.[CDInterface][1]
The first thing you need to do with IMAPI is create an Instance of IDiskMaster2, so I've declared that via an Imapi2 interface, like so
public interface Imapi2 extends Library {
Imapi2 INSTANCE = (Imapi2)
Native.load("C:/Windows/System32/imapi2.dll" , Imapi2.class);
public static class IDiscMaster2 extends Structure {
int getCount;
public int getCount() {
return getCount;
}
}
IDiscMaster2 createMsftDiscMaster2();
}
Then in the main code
Imapi2.IDiscMaster2 recorderList = Imapi2.INSTANCE.createMsftDiscMaster2();
System.out.println("Found " + recorderList.getCount() + " Recorders");
Just putting 'imapi2' in the call to Native.load() didn't work either.
I'm guessing I'm doing something fundamentally wrong, but it's not clear how you get JNA to 'see' a new dll you want to interface to ..... and also I am kind of afraid there is something very different about this API from the othe APIs that people are using JNA to talk to, so may not be worth trying!
public interface Imapi2 extends Library {
Imapi2 INSTANCE = (Imapi2)
Native.load("C:/Windows/System32/imapi2.dll" , Imapi2.class);
public class IDiscMaster2 extends Dispatch {
public static final CLSID CLSID_MsftDiscMaster2 = new CLSID("2735412F-7F64-5B0F-8F00-5D77AFBE261E");
public IDiscMaster2() {
}
private IDiscMaster2(Pointer pvInstance) {
super(pvInstance);
}
public static IDiscMaster2 create() {
PointerByReference pbr = new PointerByReference();
WinNT.HRESULT hres = Ole32.INSTANCE.CoCreateInstance(CLSID_MsftDiscMaster2, null, WTypes.CLSCTX_ALL, null, pbr);
if (COMUtils.FAILED(hres)) {
System.out.println("ERROR: Failed to create instance");
return null;
}
return new IDiscMaster2(pbr.getValue());
}
public WinNT.HRESULT _getCount(Pointer count ){
return (WinNT.HRESULT) _invokeNativeObject(2, new Object[]{count}, WinNT.HRESULT.class);
}
public long getCount() {
try {
long count = -1;
Pointer ptr = new Pointer(count);
WinNT.HRESULT result = _getCount(ptr);
COMUtils.checkRC(result);
return count;
} catch ( Exception e ) {
System.out.println("Error : " + e.getMessage());
}
return -1;
}
}
Then invocation in main changed to
Imapi2 imapi2Lib = Imapi2.INSTANCE;
Imapi2.IDiscMaster2 recorderList = new Imapi2.IDiscMaster2();
System.out.println("Found " + recorderList.getCount() + " Recorders");
IntelliJ shows up uninvoked methods, so it doesn't look like create() is getting called. Not sure if this is because I need to call it, or down to the function implementing IDispatch not IUnknown.
[1]: https://github.com/nosdod/CDInterface
I've answered this in a similar question which I originally marked this as a duplicate of. However, given the difficulty loading this, your case is unique enough that I'll attempt to give a separate answer.
The general case for COM is that there is an API function that creates the object. You have mapped this as createMsftDiscMaster2(). Note that you have allocated a resource here and it needs to be disposed of when you are done with it; the API documentation should tell you how to do that (possibly by calling Release() from IUnknown.)
Your next step is to map the IDiscMaster2 COM class. I see two mappings here, so I'm confused as to which one you want. The one at the top of your question is incorrect, but the one extending Dispatch later is the correct way to start, but I'm not clear where you've gone after that. The rest of the class should look similar to the internals of the Dispatch class in JNA.
In that class you can see the boilerplate that you will follow. Note that it extends Unknown which follows the same boilerplate for offsets 0, 1, and 2 for the first 3 COM functions QueryInterface, AddRef, and Release. Dispatch picks up with offsets 3, 4, 5, and 6 for COM functions GetTypeInfoCount, GetTypeInfo, GetIDsOfNames, and Invoke.
So in your mapping for DiskMaster2 you will pick up with offset 7, and your mapping will look like:
public HRESULT TheFunctionName(FOO foo, BAR bar) {
return (HRESULT) this._invokeNativeObject(7,
new Object[] { this.getPointer(), foo, bar },
HRESULT.class);
}
This is where you need to locate the actual header file for this class to determine the order in which the functions appear in the Vtbl. It looks like you attempted to do this with your code, but the offset 2 is already assigned in Unknown, the lowest one you'll be able to use is 7 (and continue on with 8, 9, 10 for each function in this COM interface, in the correct order -- which you must determine from the Vtbl.)
Based on this header, you can see those functions mapped in order and your offsets should be: 7: get__NewEnum, 8: get_Item, 9: get_Count, and 10: get_IsSupportedEnvironment. Use those header function mappings as a start and change them to the _invokeNativeObject() format above. (They all return HRESULT, you'll just be changing the argument list.)
I'm using the Omnetpp-5.6.1 and I want get the time simulation. I'm using tic toc example, and when I put the function simTime(), it only returns 0. My code is like this:
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
/**
* Derive the Txc1 class from cSimpleModule. In the Tictoc1 network,
* both the `tic' and `toc' modules are Txc1 objects, created by OMNeT++
* at the beginning of the simulation.
*/
class Txc1 : public cSimpleModule
{
protected:
virtual void initialize() override;
virtual void handleMessage(cMessage *msg) override;
};
// The module class needs to be registered with OMNeT++
Define_Module(Txc1);
void Txc1::initialize()
{
if (strcmp("source", getName()) == 0) {
// create and send first message on gate "out". "tictocMsg" is an
// arbitrary string which will be the name of the message object.
cMessage *msg = new cMessage("tictocMsg");
send(msg, "out");
}
}
void Txc1::handleMessage(cMessage *msg)
{
EV<< msg->getSendingTime()<< Simtime() ;
send(msg, "out"); // send out the message
}
I found this function here but I don't know how to use it.
How can I solve this ?
In some Tic Toc examples there is neither delay in a channel nor delay in processing a message, therefore everything may happen at t=0.
Take a look whether in your example there is a delay in channels or there is scheduleAt() with future time in the C++ code.
This question already has an answer here:
How to get jmap histogram programmatically?
(1 answer)
Closed 7 years ago.
Is there a way to find no. of alive objects of a class at any point of time in a running application? By alive/live objects, I mean those objects which are NOT eligible for garbage collection. Is there any way to find it without using any tools?
Assume that the entire application is personally coded. So the classes can be customised as per our need. Also, assume that the class whose live instance count we want to find, is a user defined class, not any inbuilt class.
The simple answer is no - there is no simple class or method call to make to find this data. However, there are many ways that people have come up with. It depends on why you need the data and the structure of your program.
There are good discussions on this topic here: http://www.coderanch.com/t/581790/java/java/ways-find-number-alive-instances and here: How to find the number of objects in the heap.
Give some of those a try and see which works best for you.
Yes.
Create a class based static instance counter that is synchronous
Up it by one in the class method(s) that instantiate..
Then u will have to override the dispose method to decrement instance counter..
UPDATE
Here is a nebulous class.. that can be used to track some things...
package myclasses;
import java.util.Vector;
public class ClassA {
private static int iCountInstances = 0;
private static int iCountCleanups = 0;
private static int iCountGCFinalize = 0;
private String m_str1 = null;
private Vector m_vct1 = null;
public ClassA() {
// bump the instance count
incrementCountInstance();
}
private static synchronized void incrementCountInstance() {
iCountInstances++;
}
private static synchronized void incrementCountCleanup() {
iCountCleanups++;
}
private static synchronized void incrementGCFinalize() {
iCountGCFinalize++;
}
/**
* reportOut - you can change this up on how ever you like
*
* an in control app in a perfect world will have all three counts THE SAME after a final
* GC and right before exist.
*
* The True number of 'active' classes in an app is going to be
* ICountInstances - iCountGCFinalize.
*
* The idea here is that if GC did not dispose of it.. its still in memory.. and still
* active.. even if your app thinks its no longer using it...
*
* #return
*/
public static String reportOut() {
return "ClassA Counts: incnt:" + ClassA.iCountInstances +", clncnt:" + ClassA.iCountCleanups + ", gccnt:" + ClassA.iCountGCFinalize;
}
public void cleanup() {
//
// ok.. initialize all member variables here
// do not worry about what other object refereneces this guy
// you only care about what you have as member variables.
// you only de-refrence what you point to ..
// if every class took care of what it referenced.. then all is well.
// so.. clean up your object and help GC ...
this.setM_str1(null);
this.getM_vct1().removeAllElements();
ClassA.incrementCountCleanup(); // Increment the cleanup count..
//
// feel free to write to a logger reporting out that programmer has cleaned up this instance..
//
}
#Override
protected void finalize() throws Throwable
{
// Incrementing means GC determined this guy is truly an Object Orphan and has been
// completely de-referenced.
ClassA.incrementGCFinalize();
//
// feel free to write to a logger reporting out that GC is removing this instance..
//
}
public String getM_str1() {
return m_str1;
}
public void setM_str1(String m_str1) {
this.m_str1 = m_str1;
}
public void setM_vct1(Vector m_vct1) {
this.m_vct1 = m_vct1;
}
public Vector getM_vct1() {
return m_vct1;
}
}
Here is another class that can be made to help report out whats going on during execution.. etc..
package myclasses;
public final class CheckCounts {
// No create instance allowed..
private CheckCounts() {
}
/**
* Report out on interesting counts...
*/
public static void reportOut() {
/// Add all the reportouts here..
System.out.println(ClassA.reportOut());
}
}
You can get fancy with this and create a background thread monitor that simply reports out stats on the classes you want to track.. and have it write to a logger every 30 seconds or so..
Notice I count up everything. You can use math to see how effective your code is at cleaning up after itself.. When you clean up an object.. you want to dereference what that objected pointed to and clear out any lists, arrays, hashmaps, etc. Be careful though, dont go crazy, and start cleaning up objects that live in a Vector of your class - just clean up the vector itself...
Give it a try.. its easy to implement.. and it may help you see whats going on in a runtime env vs what you think is happening just by looking at your code..
This question already has answers here:
#ifdef #ifndef in Java
(8 answers)
Closed 9 years ago.
I'm writing a program that reads structures from a file. For debugging purposes, it would be very convenient if I could have a compile-time toggle that prints the names and values of everything read which could be disabled for better performance/code size in the production version. In C, I could use the preprocessor like such to accomplish this:
#ifdef DEBUG
#define READ(name, in) { name = read(in); printf("#name: %d\n", name); }
#else
#define READ(name, in) { name = read(in); }
#endif
void myreader(mystream_t *in)
{
int a, b, c;
READ(a, in);
READ(b, in);
READ(c, in);
}
Is there any way I can reproduce this construct? I thought about this:
private static final boolean DEBUG_ENABLED = true;
private int debugRead(MyInputStream in, String name) {
int val = in.read();
if (DEBUG_ENABLED) {
System.out.println(String.format("%s: %d", name, val));
}
return val;
}
public MyReader(MyInputStream in) {
int a, b, c;
a = debugRead(in, "a");
b = debugRead(in, "b");
c = debugRead(in, "c");
}
However, this requires me to type the name of all the variables twice as well as storing the strings corresponding to all the names even on the release version. Is there a better approach to this?
EDIT: The biggest concern I have is code verbosity. The last thing I want is to have my code cluttered with debug/print/trace statements that obscure the actual reading logic.
I'm not sure if this is an apples to apples solution, but one thing that's idiomatic in Java is to use a logging framework. With it, you can execute log.debug wherever you might need debugging. SLF4j is a common facade for logging frameworks. You could just use it with JUL logging.
Usually you leave the logging code there and you configure the logger externally to either print or not print the messages.
If you're using SLF4j, the debug message will look like this:
log.debug("Setting the creation timestamp to {}", timestamp);
Most loggers can be configured to tell you what time, class and method the logging message came from.
This has some pros and cons compared to what you're used to.
Cons
I have to admit, this will take a lot of effort to learn when all you really want right now is a System.out.println.
Most of the loggers are configured on the classpath. The classpath is a non-trivial part of java to learn but you will have to learn it eventually anyway. It's really important to understand.
It won't automatically print out the name of the variable passed in. AFAIK, you'll have to write that detail yourself
Pros
Using a logger is very robust. You can leave the code there for production and dev mode and just configure the verbosity appropriately
It can automatically print out the context of the class/method and date of the message and other things like that
You can configure the output in lots of different ways. For example, "output to the console and log.txt but when that file becomes > 100mb, rollover the old data to log2.txt and keep at most 5 log files."
To the general problem of emulating C/C++ macros in Java, there are several solutions. The particular case of logging is usually resolved in a simpler way. The simplest, conceptually closest, and puristic form is abstracting the macro in an interface and producing alternative implementations:
public class Sample {
class mystream_t {
}
public int read(mystream_t is) {
return 0 ;
}
static final boolean DEBUG= false ;
interface ReadType {
public void apply(int[] name,mystream_t in);
}
ReadType READ; {
if( DEBUG ) {
READ= new ReadType(){
public void apply(int[] name,mystream_t in) {
name[0]= read(in) ; System.out.printf("#name: %d\n",name);
}
};
} else {
READ= new ReadType(){
public void apply(int[] name,mystream_t in) {
name[0]= read(in) ;
}
};
}
}
void myreader(mystream_t in) {
int[] a= new int[1], b= new int[1], c= new int[1];
READ.apply(a, in);
READ.apply(b, in);
READ.apply(c, in);
}
}
This makes use of a simple, static form of code injection. I tried to make the code as close as possible to the original.
The second most relevant way of emulating C/C++ macros in Java requires Annotations and Annotation Processing. It's even closer to C/C++ macros, but requires more effort and resorts to a mechanism that could not be considered pure part of the language.
And the third one is using an Aspect-Oriented Programming framework like AspectJ.
I use JNI to access shared memory segments previously created. I use a Java/Jni read/write function which could either take the address of the shared buffer, or the id of the mapped region.
Unfortunately, it seems like every time I call the read/write functions I have to remap the segment using the function below. Is there any way to get round this? I would like (i have tried this, but it didn't work, to only have to map the segment once, and simply use the void* addr parameter in the future, as opposed to every time I call the JNI method read or write, to have to call map_shared_memory. The current code works well, but remains relatively slow. Hence the desire to minimise seemingly unnecessary operations.
void* map_shared_memory(int id) {
void* addr;
if (id == 0)
return NULL;
addr = shmat(id, NULL, 0);
shmctl(id, IPC_RMID, NULL);
if(addr<=0)
perror("Error Mapping Shared Memory: ");
return addr;
}
I suggest a collaboration between a class ShmFactory which opens (or create) the Shared Memory and and ShmAccess which offer read/write methods.
interface ShmAccess
{
void read( shmId, byte[] bytes );
void write( shmId, byte[] bytes );
}
interface ShmFactory
{
public native ShmAccess open( int shmId );
}