Translate C struct of function pointers to JNA code - java

// original c code
struct callback {
void (*recv_msg_)(const char * msg, int type, unsigned int len);
void (*connected_)(void *cs);
void (*disconnected_)(void *cs);
};
void recv_msg(const char *msg, int type, unsigned int len)
{
// some code
//......
}
void connected(void *s)
{
// some code
//......
}
void disconnected(void *s)
{
// some code
//......
}
struct callback cb;
cb.recv_msg_ = recv_msg;
cb.connected_ = connected;
cb.disconnected = disconnected;
init("127.0.0.1", 5672, &cb);
// C code end
////////////////////////////////////////////////////////////////////////
// THE JNA code
interface RecvMsg extends Callback {
void invoke(String msg, int type, int con_len);
}
interface CbConnected extends Callback {
void invoke(Pointer ctx);
}
interface CbDisconnected extends Callback {
void invoke(Pointer ctx);
}
class RecvMsgImpl implements RecvMsg {
#Override
public void invoke(String msg, int type, int len) {
System.out.println("recv msg: " + msg);
}
}
class CbConnectedImpl implements CbConnected {
#Override
public void invoke(Pointer ctx) {
System.out.println("connected.");
}
}
class CbDisconnectedImpl implements CbDisconnected {
#Override
public void invoke(Pointer ctx) {
System.out.println("diconnected.");
}
}
public class MyCallBack extends Structure {
public RecvMsg recv_msg_;
public CbConnected cb_connected_;
public CbDisconnected cb_disconnected_;
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[] {"recv_msg_", "cb_connected_", "cb_disconnected_"});
}
}
MyCallBack cb = new MyCallBack();
cb.recv_msg_ = new RecvMsgImpl();
cb.cb_connected_ = new CbConnectedImpl();
cb.cb_disconnected_ = new CbDisconnectedImpl();
Xxx xxx = (Xxx) Native.loadLibrary("***", Xxx.class);
xxx.init("127.0.0.1", 5672, cb);
// Java code end
////////////////////////////////////////////////////////////////////
I run the java code, got exception like this:
Exception in thread "main" java.lang.IllegalArgumentException: Structure field "cb_connected_" was declared as interface DLLTest.CbConnected, which is not supported within a Structure
at com.sun.jna.Structure.writeField(Structure.java:808)
at com.sun.jna.Structure.write(Structure.java:718)
at com.sun.jna.Structure.autoWrite(Structure.java:1923)
at com.sun.jna.Function.convertArgument(Function.java:505)
at com.sun.jna.Function.invoke(Function.java:297)
at com.sun.jna.Library$Handler.invoke(Library.java:212)
at com.sun.proxy.$Proxy1.init(Unknown Source)
at DLLTest.Tester.main(Tester.java:55)
Please tell me how to translate it to java with JNA.

This is my test for this with jna library.
I think you have to find some difference with mine.
I made my own code because you didn't show me the full source code.
My environment of development are a mingw64 with msys2 and a eclipse(oxygen) with the java(1.8)
Here are some more details.
Gcc version
Using built-in specs.
COLLECT_GCC=C:\DEV\COMP\msys32\mingw64\bin\gcc.exe
COLLECT_LTO_WRAPPER=C:/DEV/COMP/msys32/mingw64/bin/../lib/gcc/x86_64-w64-
mingw32/6.3.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: .....skip
Thread model: posix
gcc version 6.3.0 (Rev1, Built by MSYS2 project)
Java information
java.class.version::52.0
sun.management.compiler::HotSpot 64-Bit Tiered Compilers
sun.arch.data.model::64
sun.desktop::windows
sun.cpu.isalist::amd64
First, A complete code of a JnaTest class from yours.
package stackoverflow;
import java.util.Arrays;
import java.util.List;
import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
public class JnaTest {
public interface JnaInf extends Library {
public void init(String val, int port, MyCallBack cb);
}
public static void main(String[] args) {
MyCallBack cb = new MyCallBack();
cb.recv_msg_ = new RecvMsgImpl();
cb.cb_connected_ = new CbConnectedImpl();
cb.cb_disconnected_ = new CbDisconnectedImpl();
System.load("C:\\DEV\\COMP\\msys32\\home\\stackoverflow\\jna_inf.dll");
JnaInf xxx = (JnaInf) Native.loadLibrary("jna_inf", JnaInf.class);
xxx.init("127.0.0.1", 5672, cb);
}
interface RecvMsg extends Callback {
void invoke(String msg, int type, int con_len);
}
interface CbConnected extends Callback {
void invoke(Pointer ctx);
}
interface CbDisconnected extends Callback {
void invoke(Pointer ctx);
}
static class RecvMsgImpl implements RecvMsg {
#Override
public void invoke(String msg, int type, int len) {
System.out.println("recv msg: " + msg);
System.out.println("type: " + type);
System.out.println("len: " + len);
}
}
static class CbConnectedImpl implements CbConnected {
#Override
public void invoke(Pointer ctx) {
System.out.println("connected.");
}
}
static class CbDisconnectedImpl implements CbDisconnected {
#Override
public void invoke(Pointer ctx) {
System.out.println("diconnected.");
}
}
public static class MyCallBack extends Structure {
public RecvMsg recv_msg_;
public CbConnected cb_connected_;
public CbDisconnected cb_disconnected_;
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[] { "recv_msg_", "cb_connected_", "cb_disconnected_" });
}
}
}
Then, the c source code name, jna_info.c is as follows,
struct callback {
void (*recv_msg_)(const char * msg, int type, unsigned int len);
void (*connected_)(void *cs);
void (*disconnected_)(void *cs);
};
void recv_msg(const char *msg, int type, unsigned int len)
{
// some code
//......
}
void connected(void *s)
{
// some code
//......
return;
}
void disconnected(void *s)
{
// some code
//......
return;
}
void init(const char *msg, int type, struct callback *mycallback)
{
mycallback->recv_msg_("123", 22, 3);
mycallback->connected_("123");
return;
}
Compile the c source code
gcc -c jna_inf.c
gcc -shared -o jna_inf.dll jna_inf.o
The output looks like what i am expecting..
I sincerely hope this helps you.

Related

turtle programm Java, handing over variety of classes as a parameter and check which class it is

i am trying to programm a Turtle programm in Java following the Visitor pattern.
therefore i have the Visitor:
public interface Visitor {
void visit(Go go);
void visit(Turn turn);
void visit(Call call);
void visit(PenDown pendown);
void visit(PenUp penup);
void visit(Repeat repeat);
void visit(Sequence sequence);
void visit(Subroutine subroutine);
}
and the Abstract Visitor which should implement some of the visit methods:
public abstract class AbstractVisitor implements Visitor {
protected Turtle turtle;
protected AbstractVisitor(Turtle turtle){
this.turtle = turtle;
}
public AbstractVisitor() {
}
public void visit(Turn turn){
turtle.turn(turn.w);
}
public void visit(Sequence sequence){
}
public void visit(Repeat repeat) {
int d = repeat.rep;
for(int i = 0; i<repeat.rep; i++){
for(int s = 0; s<repeat.d.size(); s++){
}
}
}
public void visit(Subroutine subroutine) {
}
public void visit(Call call) {
}
public void visit(PenDown penDown) {
}
public void visit(PenUp penUp) {
}
}
i am Trying to implement the visit(Repeat repeat)
public class Repeat implements Stmt {
public int rep;
public List<Object> d;
public Repeat(int i,Stmt ... s1) {
this.rep = i;
for (int q = 0; q < s1.length; q++) {
d.add( s1[q]);
}
}
#Override
public void accept(Visitor v) {
{
v.visit(this);
}
}
}
this method should get an integer i and some other classes which also implements the Interface Stmt
public interface Stmt {
void accept(Visitor v);
}
like the Class Go
public class Go implements Stmt {
public double dist;
public Go(double d){
if(d<0 ) {
throw new IllegalArgumentException("Die Strecke muss positiv sein");
} this.dist = d;
}
public void accept(Visitor v) {
}
}
So You should be able to hand over an Integer i and as many Classes like Go.
the repeat class should do the visit method for each class handed over and repeat it i times.
Now my Question is how can I check which Class is in the Array of Stmt's I hand over to Repeat? Or is it Wrong how I did the parameters in Repeat?
As a example i want to be able to call
PROG1.accept(visitor)
with
public static final Stmt PROG1 = new Repeat(4, new Go(50), new Turn(90));
I didn't understand completely your problem! But if your question is :
You have an Interface
public interface Stmt {
void accept(Visitor v);
}
and you have two classes implementing this interface each them has a different body for the accept method
public class X implements Stmt{
public void accept(Visitor v) {
//code
}
}
and
public class Y implements Stmt{
public void accept(Visitor v) {
//code
}}
and your question as I understand it is:
HOW do I know which body will be used if I call the accept() method ! is the accept() from X class or the accept() from the Y class ??
Answer :
it depends on your main application, as you know you cannot instantiate an interface!
so it depends on which class you have instantiated!
you will have for example :
Stmt var = new X();
for this one var.accept() will call the body from the X class!

Reason for ambiguous error in java generics code while trying to overload/override

While going through generics, I am not able to understand why the error is coming:
class Box <T> {
private T theThing;
public Box( T t) { theThing = t; }
public void reset( T t) { theThing = t; }
}
class WordBox< S extends CharSequence > extends Box< String > {
public WordBox( S t) { super(t.toString().toLowerCase()); }
public void reset( S t) {
// super.reset(t.toString().toLowerCase());
}
}
public class ss {
public static void main(String[] args) {
WordBox<String> city = new WordBox<String>("Skogland");
city.reset("Stavanger"); // error: ambiguous**
}
}
I can understand, method worldbox.reset () is not overriding the method from BOX, instead it is overloading.
After type erasure, I am assuming this will be code :
class Box {
private Object theThing;
public Box( Object t) { theThing = t; }
public void reset( Object t) { theThing = t; }
}
class WordBox extends Box{
public WordBox( CharSequence t) { super(t.toString().toLowerCase()); }
public void reset( CharSequence t) {
super.reset(t.toString().toLowerCase());
}
}
public class ss {
public static void main(String[] args) {
WordBox<String> city = new WordBox<String>("Skogland");
city.reset("Stavanger");
}
}
So, city.reset("Stavanger") should call the method from Worldbox.reset , as String extends charsequence and it seems to be closest match.
Could anyone please explain why the ambiguous error is coming in this code?

JNA callback function with additional argument

I have got problem getting JNA all worked out. I am trying to invoke a function that takes as a arguments pointer to function and const char*. My C code looks like this:
typedef void (*example_ptr)(const char*);
void exampleMethod(const char* value)
{
printf("This is the string: %s\n", value);
}
void example_triggerCallback(const example_ptr func, const char* str) {
printf("provided str: %s", str);
func(str);
}
To get this going I wrote such JNA wrapper in Java
public class Main {
public interface TestLibrary extends Library {
TestLibrary INSTANCE = (TestLibrary)
Native.loadLibrary("libtest",
TestLibrary.class);
interface ExampleCallback extends Callback {
void invoke(String str);
}
class ExampleCallbackImpl implements ExampleCallback {
public void invoke(String str) {
System.out.println("example: " + str);
}
}
void example_triggerCallback(ExampleCallback callback, String str);
}
public static void main(String[] args) {
TestLibrary testLibrary = TestLibrary.INSTANCE;
final TestLibrary.ExampleCallbackImpl callback = new TestLibrary.ExampleCallbackImpl();
testLibrary.example_triggerCallback(callback, "testiddy test test");
}
}
The problem I am facing is that the printf in example_triggerCallback in C code is in fact being called and I am getting the output on Java console but what I am really trying to achieve here is that I would like to pass from Java side the pointer for the exampleMethod from C so it would be printing the passed String. Right now func(str) seems to be ignored. What am I missing here?
Based on something found in JNA documentation:
typedef void (*ExampleCallback)(const char*);
void exampleMethod(const char* value)
{
printf("This is the string: %s\n", value);
}
void example_triggerCallback(const example_ptr func, const char* str) {
printf("provided str: %s", str);
func(str);
}
public interface CLibrary extends Library {
// define an interface that wraps the callback code
public interface ExampleCallbackInterface extends Callback {
void invoke(String val);
}
// functions available in library (name must match)
public void exampleMethod(String value);
public void example_triggerCallback(ExampleCallbackInterface callback);
}
// define an implementation of the callback interface
public static class CallbackExample implements Example22CallbackInterface {
private CLibrary lib;
public CallbackExample(CLibrary useLib) {
lib = useLib;
}
#Override
public void invoke(String val) {
lib.exampleMethod(val);
}
}
...
final CLibrary clib = (CLibrary)Native.loadLibrary("testlib", CLibrary.class);
...
// instantiate a callback wrapper instance
final CallbackExample callback = new CallbackExample(clib);
// pass the callback wrapper to the C library
clib.example_triggerCallback(callback);
Since I answered this question in some other internet location, I know that it works for the questioner.

JNA: Library function call returns java.lang.Error: Invalid memory access

I am working on a java project. In my project i am using java native access(jna) to use a c library pjsip.
I have successfully used some of the function. But when i try to call pj_pool_create() , i get: java.lang.Error: Invalid memory access
I have searched all the related problem published on mailing list, stack overflow, github etc. But I can not get to the solution.
I placed some printf in the source code of the function before compiling it. All the printf statement get printed even the last one which is just before the return statement.
So can someone help me out?
Here is the necessary mappings:
function(plz click and hava a look):
pj_pool_t * pj_pool_create (pj_pool_factory *factory, const char
*name, pj_size_t initial_size, pj_size_t increment_size,
pj_pool_callback *callback)
public pj_pool_t pj_pool_create( pj_pool_factory factory,String
name,NativeLong initial_size,NativeLong increment_size,pj_pool_callback
callback);
pj_pool_t:
public static class pj_pool_t extends Structure {
public static class ByReference extends pj_pool_t implements Structure.ByReference {}
public static class ByValue extends pj_pool_t implements Structure.ByValue { }
public pj_pool_t.ByReference prev;
public pj_pool_t.ByReference next;
public byte[] obj_name = new byte[32];
public pj_pool_factory.ByReference factory;
public Pointer factory_data;
public NativeLong capacity;
public NativeLong increment_size;
public pj_pool_block block_list;
public pj_pool_callback callback;
// public pj_pool_mem.ByReference first_mem; // There is no such field in the source code
// public NativeLong used_size; // There is no such field in the source code
// public pj_pool_callback cb; // There is not such field in the source code
#Override
protected List<String> getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList(new String[] {"prev","next","obj_name","factory","factory_data","capacity","increment_size","block_list","callback"});
}
}
pj_pool_factory:
public static class pj_pool_factory extends Structure {
public static class ByReference extends pj_pool_factory implements Structure.ByReference {
public ByReference() {}
public ByReference(Pointer p) { super(p); read();}
}
public static class ByValue extends pj_pool_factory implements Structure.ByValue{}
public pj_pool_factory() {}
public pj_pool_factory(Pointer p) { super(p); read();}
public static interface create_pool extends Callback {
public pj_pool_t invoke(pj_pool_factory factory,String name,NativeLong initial_size, NativeLong increment_size, pj_pool_callback callback);
}
public static interface release_pool extends Callback {
public void invoke(pj_pool_factory factory,pj_pool_t pool);
}
public static interface dump_status extends Callback {
public void invoke(pj_pool_factory factory, int detail);
}
public static interface on_block_alloc extends Callback {
public int invoke(pj_pool_factory factory, NativeLong size);
}
public static interface on_block_free extends Callback {
public void invoke(pj_pool_factory factory, NativeLong size);
}
public pj_pool_factory_policy policy;
public create_pool create_pool;
public release_pool release_pool;
public dump_status dump_status;
public on_block_alloc on_block_alloc;
public on_block_free on_block_free;
//public int dummy;
#Override
protected List<String> getFieldOrder() {
// TODO Auto-generated method stub
return Arrays.asList(new String[] { "policy","create_pool","release_pool","dump_status","on_block_alloc","on_block_free"});
}
}
pj_pool_callback
public interface pj_pool_callback extends Callback {
void invoke(pj_pool_t pool, NativeLong size);
}
Calling the function:
//creating an empty pool
Test.pj_pool_t pool = new Test.pj_pool_t();
//creating an empty caching_pool
Test.pj_caching_pool cp = new Test.pj_caching_pool();
//parameter for the function call. long -> NativeLong
NativeLong zero = new NativeLong(0,true);
//initialize caching_pool. This get initialized properly
pjlib.pj_caching_pool_init(cp, null, zero);
//initialized pool_factory
Test.pj_pool_factory pf = cp.factory;
//long parameter for function call
NativeLong thousands = new NativeLong(1000,true);
//finally call the library function. but error occurs here
pool = pjlib.pj_pool_create( pf , "server", thousands, thousands, null);// null is ok for the last parameter
//pool = pjlib.pj_pool_create( pf , "server", 1000, 1000, null); tried this also
Error!
Exception in thread "Thread-0" java.lang.Error: Invalid memory access
at com.sun.jna.Native._getPointer(Native Method)
at com.sun.jna.Native.getPointer(Native.java:2138)
at com.sun.jna.Pointer.getPointer(Pointer.java:651)
at com.sun.jna.Pointer.getValue(Pointer.java:376)
at com.sun.jna.Structure.readField(Structure.java:720)
at com.sun.jna.Structure.read(Structure.java:580)
at com.sun.jna.Structure.autoRead(Structure.java:2074)
at com.sun.jna.Structure.conditionalAutoRead(Structure.java:550)
at com.sun.jna.Structure.updateStructureByReference(Structure.java:678)
at com.sun.jna.Pointer.getValue(Pointer.java:376)

Java generics software engineering design

I have a class RabbitQueue which basically acts like a queue and implements my Pollable interface.
I also have a class SaveToDatabaseStrategy which implements my DataProcessingStrategy interface. This is designed following the strategy-pattern.
Now, my class InputHandler which implements my interface InputListener, contains an instance of the Pollable interface and one of the DataProcessingStrategy interface.
However, I don't want to set the Generic type (String) when I declare these two fields, since the Generic type depends on the implementation of this interface which is given later on.
How would you design this?
public interface Pollable<T> {
T poll();
}
public class RabbitQueue implements Pollable<String> {
// code..
}
public interface DataProcessingStrategy<T> {
void processData(T t);
}
public class SaveToDatabaseStrategy<T> implements DataProcessingStrategy<T> {
private Repository<T, ?> repo;
public SaveToDatabaseStrategy(Repository<T, ?> repo) {
this.repo = repo;
}
#Override
public void processData(T data) {
repo.create(data);
System.out.printf("Received data of type %s: %s\n", data.getClass().getSimpleName(), data);
}
}
public interface InputListener<T> {
void inputReceived();
void inputReceived(T t);
}
public class InputHandler implements InputListener<String> {
private Pollable<String> queue;
private DataProcessingStrategy<String> strategy;
public InputHandler(String host, String queueName) throws IOException, TimeoutException {
queue = new RabbitQueue(host, queueName, this);
}
public void setStrategy(DataProcessingStrategy strategy) {
this.strategy = strategy;
}
#Override
public void inputReceived() {
System.out.println("Input received!");
strategy.processData(queue.poll());
}
#Override
public void inputReceived(String s) {
System.out.println("Input received: " + s + "!");
System.out.println("> " + queue.poll());
}
}
You could add a type parameter to the InputHandler class.
public class InputHandler<T> implements InputListener<T> {
private Pollable<T> queue;
private DataProcessingStrategy<T> strategy;
public InputHandler(String host, String queueName) throws IOException, TimeoutException {
queue = new RabbitQueue(host, queueName, this);
}
public void setStrategy(DataProcessingStrategy strategy) {
this.strategy = strategy;
}
#Override
public void inputReceived() {
System.out.println("Input received!");
strategy.processData(queue.poll());
}
#Override
public void inputReceived(String s) {
System.out.println("Input received: " + s + "!");
System.out.println("> " + queue.poll().toString());
}
}
Then create a new object like
new InputHandler<String>(host, queueName)

Categories