Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JNI bindings for Roc #2

Merged
merged 14 commits into from
Apr 24, 2020
Merged

JNI bindings for Roc #2

merged 14 commits into from
Apr 24, 2020

Conversation

MatteoArella
Copy link
Member

This PR includes:

  • Java API for Roc library
  • JNI code binding
  • Java tests
  • Java API docs (based on javadoc)
  • build system based on Gradle

@gavv
Copy link
Member

gavv commented Apr 1, 2020

Wow, that's impressive! I'll review it in the coming days.

@gavv
Copy link
Member

gavv commented Apr 7, 2020

Huge work! I'm still reviewing the code, but here are some preliminary comments / questions (mostly cosmetic):

  1. Maybe change com.rocproject.roc to reflect a real URL? E.g. to com.github.rocproject.roc.

  2. Do we really need all these sub-packages, are there any benefits? Maybe just use a single package for all types?

  3. I suggest to rename the shared library from libnative.so to libroc_jni.so or something like this.

  4. Maybe call System.loadLibrary("roc_jni") automatically (e.g. on import?) and make it transparent for the user?

  5. Can we remove redundant prefixes from enum values? E.g. change roc.Protocol.ROC_PROTO_RTP_RS8M_SOURCE to just roc.Protocol.RTP_RS8M_SOURCE. They make sense in C, but I think there is no need for them in Java.

  6. Maybe make Address to be a NativeObject as well? And instead of replicating its fields in Java, delegate getters and setters to C. The current implementation is OK, but in v0.2 (which is not ready yet) we'll migrate from roc_address to roc_endpoint which will have much more getters and setters and logic behind them, and it's undesired to replicate it as well.

  7. Maybe add a builder for ContextConfig as well? Just for consistency with other config classes.

  8. Do we really need Receiver.readFloat() and Sender.write(float)? These single-float read/write versions are formally valid, but I think they encourage bad library usage, since it's usually a bad idea to read or write by one sample per time from the performance point of view. And likely it will work only for mono, which is not supported yet BTW.

  9. Do we want to add finalizers in addition to AutoClosable? To reduce the damage from leaks for long-running applications.

Note: if you agree with some points, but would not like to implement them in this PR, we can create individual issues for them.

@gavv
Copy link
Member

gavv commented Apr 7, 2020

I've tried to run ./gradlew build, but it didn't work out of the box. I had to re-generate gradle wrapper to make it working:

$ ./gradlew build
Error: Could not find or load main class org.gradle.wrapper.GradleWrapperMain

$ gradle wrapper
Starting a Gradle Daemon (subsequent builds will be faster)

BUILD SUCCESSFUL in 14s
1 actionable task: 1 executed

$ git diff
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 45d66e2..44e7c4d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Fri Mar 20 19:14:45 CET 2020
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists

$ ./gradlew build
<worked now>
$ gradle --version

------------------------------------------------------------
Gradle 5.2.1
------------------------------------------------------------

Build time:   2019-02-08 19:00:10 UTC
Revision:     f02764e074c32ee8851a4e1877dd1fea8ffb7183

Kotlin DSL:   1.1.3
Kotlin:       1.3.20
Groovy:       2.5.4
Ant:          Apache Ant(TM) version 1.9.13 compiled on July 10 2018
JVM:          1.8.0_242 (IcedTea 25.242-b08)
OS:           Linux 4.19.102 amd64

Is it a bug?

@MatteoArella
Copy link
Member Author

Huge work! I'm still reviewing the code, but here are some preliminary comments / questions (mostly cosmetic):

1. Maybe change `com.rocproject.roc` to reflect a real URL? E.g. to `com.github.rocproject.roc`.

2. Do we really need all these sub-packages, are there any benefits? Maybe just use a single package for all types?

3. I suggest to rename the shared library from `libnative.so` to `libroc_jni.so` or something like this.

4. Maybe call `System.loadLibrary("roc_jni")` automatically (e.g. on import?) and make it transparent for the user?

5. Can we remove redundant prefixes from enum values? E.g. change `roc.Protocol.ROC_PROTO_RTP_RS8M_SOURCE` to just `roc.Protocol.RTP_RS8M_SOURCE`. They make sense in C, but I think there is no need for them in Java.

6. Maybe make `Address` to be a `NativeObject` as well? And instead of replicating its fields in Java, delegate getters and setters to C. The current implementation is OK, but in v0.2 (which is not ready yet) we'll migrate from `roc_address` to [`roc_endpoint`](https://github.com/roc-project/roc/blob/develop/src/library/include/roc/endpoint.h) which will have much more getters and setters and logic behind them, and it's undesired to replicate it as well.

7. Maybe add a builder for `ContextConfig` as well? Just for consistency with other config classes.

8. Do we really need `Receiver.readFloat()` and `Sender.write(float)`? These single-float read/write versions are formally valid, but I think they encourage bad library usage, since it's usually a bad idea to read or write by one sample per time from the performance point of view. And likely it will work only for mono, which is not supported yet BTW.

9. Do we want to add finalizers in addition to `AutoClosable`? To reduce the damage from leaks for long-running applications.

Note: if you agree with some points, but would not like to implement them in this PR, we can create individual issues for them.

Thank you for your feedback.

  1. Yes I'll change package name to com.rocproject.roc in next commit.

  2. Since the low number of classes we can surely just place all classes into the same package. I've separated them in that way only for reflecting the same structure of the original C library; I'll move all classes to single package in next commit.

  3. Ok I'll rename it to "roc_jni" in next commit.

  4. Yes we can statically loadLibrary automatically on import without user effort. I'll implement it in next commit.

  5. Yes there is no need for them in Java; I've only done it in this way for mantaining the same names as C interface. I'll remove those prefixes in next commit.

  6. There is one problem wrapping entire roc_address object into a NativeObject. Since roc_address is not allocated by roc C library (contrary to other roc objects) a dynamic allocation would result in a memory leak unless a specific deallocation is performed by the user (objects allocated by JNI calls are not managed by JVM GC).
    A complete wrapping can be done after point 9 of this list is implemented.

  7. Yes surely

  8. No they are not really needed and they can be safely removed.

  9. Finalizers have been deprecated since Java 9 in favour of PhantomReferences, Cleaners and ReferenceQueues. A better approach should be studied deeply and implemented maybe in a separate issue.

I'll work soon implementing all those points except points 6 and 9 that can be implemented on separate issue.

@MatteoArella
Copy link
Member Author

I've tried to run ./gradlew build, but it didn't work out of the box. I had to re-generate gradle wrapper to make it working:

$ ./gradlew build
Error: Could not find or load main class org.gradle.wrapper.GradleWrapperMain

$ gradle wrapper
Starting a Gradle Daemon (subsequent builds will be faster)

BUILD SUCCESSFUL in 14s
1 actionable task: 1 executed

$ git diff
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 45d66e2..44e7c4d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Fri Mar 20 19:14:45 CET 2020
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists

$ ./gradlew build
<worked now>
$ gradle --version

------------------------------------------------------------
Gradle 5.2.1
------------------------------------------------------------

Build time:   2019-02-08 19:00:10 UTC
Revision:     f02764e074c32ee8851a4e1877dd1fea8ffb7183

Kotlin DSL:   1.1.3
Kotlin:       1.3.20
Groovy:       2.5.4
Ant:          Apache Ant(TM) version 1.9.13 compiled on July 10 2018
JVM:          1.8.0_242 (IcedTea 25.242-b08)
OS:           Linux 4.19.102 amd64

Is it a bug?

Yes gradle-wrapper.jar was wrongly excluded by .gitignore.
I'll correct it on next commit.

native/src/main/headers/frame_encoding.h Outdated Show resolved Hide resolved
src/test/java/com/rocproject/roc/context/ContextTest.java Outdated Show resolved Hide resolved
src/test/java/com/rocproject/roc/context/ContextTest.java Outdated Show resolved Hide resolved
native/src/main/cpp/common.cpp Outdated Show resolved Hide resolved
native/src/main/cpp/context.cpp Outdated Show resolved Hide resolved
native/src/main/cpp/sender.cpp Outdated Show resolved Hide resolved
native/src/main/cpp/logger.cpp Outdated Show resolved Hide resolved
native/src/main/cpp/logger.cpp Outdated Show resolved Hide resolved
native/src/main/cpp/logger.cpp Outdated Show resolved Hide resolved
@gavv
Copy link
Member

gavv commented Apr 7, 2020

There is one problem wrapping entire roc_address object into a NativeObject. Since roc_address is not allocated by roc C library (contrary to other roc objects) a dynamic allocation would result in a memory leak unless a specific deallocation is performed by the user (objects allocated by JNI calls are not managed by JVM GC).
A complete wrapping can be done after point 9 of this list is implemented.

Well, actually I think we can just allocate a private array of ROC_ADDRESS_SIZE bytes in Java code and pass it to C to use as raw memory for roc_address. roc_address does not need any deinitialization, so we can just leave the rest for GC.

BUT. In 0.2, roc_address is changed to roc_endpoint which does have deinitialization function (it's not flat anymore). Since roc_endpoint does not hold any resources except memory, I'd prefer to make its deinitialization handled by GC instead of having a close() method. So we again need finalizers or something.

So, while I think we can resolve this without some kind of finalizers for roc_address, let's keep it as is because we anyway will have to rework it in 0.2

@gavv
Copy link
Member

gavv commented Apr 7, 2020

And some final questions / suggestions:

  1. I'd add a define for the package name and reuse it (com/rocproject/roc currently).

  2. Maybe also add defines for exception names? Like java/lang/IllegalArgumentException. They occur quite frequently in code.

  3. What is the semantics of IOException? It seems strange to me that we often use it to report invalid usage of the API, e.g. in Context.close.

  4. I see that unit test logs are passed to the Java callback, but I didn't find where in code we invoke Logger.setCallback for that purpose. Is it a side effect of running LoggerTest before other tests? If yes, maybe make it more explicit?

  5. By default, when no logger callback is set, Roc prints messages to stderr. Does Java have some sort of standard logger? If yes, maybe by default we should pass messages to it?

@gavv
Copy link
Member

gavv commented Apr 7, 2020

Yes I'll change package name to com.rocproject.roc in next commit.

A typo? Because it's com.rocproject.roc already.

@gavv
Copy link
Member

gavv commented Apr 7, 2020

In general, the code looks great and I did not find any serious issues, and most of my comments are actually cosmetic. Big thanks, and a special thank for tests and documentation!

I hope we didn't miss any memory leaks in the C code. Maybe later we can add support for some leak detection tools like clang sanitizers and add them to CI.

BTW, did you create all those enums by hand or used some kind of automation?

@gavv
Copy link
Member

gavv commented Apr 7, 2020

Could you please also leave a comment in roc-streaming/roc-toolkit#233 so that I could re-assign it to you?

@MatteoArella
Copy link
Member Author

And some final questions / suggestions:

1. I'd add a define for the package name and reuse it (`com/rocproject/roc` currently).

2. Maybe also add defines for exception names? Like `java/lang/IllegalArgumentException`. They occur quite frequently in code.

3. What is the semantics of IOException? It seems strange to me that we often use it to report invalid usage of the API, e.g. in Context.close.

4. I see that unit test logs are passed to the Java callback, but I didn't find where in code we invoke Logger.setCallback for that purpose. Is it a side effect of running LoggerTest before other tests? If yes, maybe make it more explicit?

5. By default, when no logger callback is set, Roc prints messages to stderr. Does Java have some sort of standard logger? If yes, maybe by default we should pass messages to it?

1.-2. Ok
3. An IOException indicates and error due to any IO operation. I've used it for close operations taking inspiration from java.net.Socket. BTW while it could make sense for Sender and Receiver maybe not for Context. Do you suggest to throw a generic Exception or maybe a custom RocException?
4. Logger.setCallback is invoked only in TestValidLoggerSetCallback. Log messages of other tests are printed by default to stderr by roc library.
5. Yes java have a standard logger. Ok I'll add this feature on top of current API (keeping setCallback for user usage)

@MatteoArella
Copy link
Member Author

Yes I'll change package name to com.rocproject.roc in next commit.

A typo? Because it's com.rocproject.roc already.

Yes definitely I meant com.github.rocproject.roc

@MatteoArella
Copy link
Member Author

In general, the code looks great and I did not find any serious issues, and most of my comments are actually cosmetic. Big thanks, and a special thank for tests and documentation!

I hope we didn't miss any memory leaks in the C code. Maybe later we can add support for some leak detection tools like clang sanitizers and add them to CI.

BTW, did you create all those enums by hand or used some kind of automation?

Thank you, it's a pleasure to contribute to this awesome project.

Yes surely we can 👍

Unfortunately yes I've created enums by hand because I've no experience with any jni generator tools.

build.gradle Outdated Show resolved Hide resolved
@gavv
Copy link
Member

gavv commented Apr 13, 2020

An IOException indicates and error due to any IO operation. I've used it for close operations taking inspiration from java.net.Socket. BTW while it could make sense for Sender and Receiver maybe not for Context. Do you suggest to throw a generic Exception or maybe a custom RocException?

Let's keep it as is until libroc will have a more granular error reporting. Then we'll be able to translate roc errors to exception more accurately.

@gavv
Copy link
Member

gavv commented Apr 13, 2020

$ ./gradlew build

> Task :test
20:07:40.246 [err] roc_lib: roc_context_close: context is still in use: counter=1
20:07:40.249 [err] roc_lib: roc_context_close: context is still in use: counter=1

com.github.rocproject.roc.LoggerTest > TestValidLoggerSetCallback() FAILED
    org.opentest4j.AssertionFailedError at LoggerTest.java:38
        Caused by: java.lang.UnsatisfiedLinkError at LoggerTest.java:44
20:07:40.270 [err] roc_lib: roc_sender_bind: sender is already bound

com.github.rocproject.roc.LoggerTest > TestValidLoggerSetLevel() FAILED
    org.opentest4j.AssertionFailedError at LoggerTest.java:13
        Caused by: java.lang.NoClassDefFoundError at LoggerTest.java:14
20:07:40.274 [err] roc_lib: roc_sender_connect: can't be called after first write
20:07:40.278 [err] roc_lib: roc_sender_write: sender is not properly bound
20:07:40.279 [err] roc_lib: roc_sender: source port is not connected
20:07:40.279 [err] roc_lib: roc_sender_write: sender is not properly connected

  1) com.github.rocproject.roc.LoggerTest
        KO  TestValidLoggerSetCallback()
        OK  TestLoggerSetNullCallback()
        OK  TestInvalidLoggerSetLevel()
        KO  TestValidLoggerSetLevel()

  2) com.github.rocproject.roc.ContextTest
        OK  ContextWithInvalidConfigTest()
        OK  ContextDefaultConfigTest()
        OK  ContextCloseWithAttachedSender()
        OK  ContextCloseWithAttachedReceiver()

  3) com.github.rocproject.roc.AddressTest
        OK  BadArgsTest()
        OK  IPv4AddressTest()
        OK  IPv6AddressTest()
        OK  DetectAddressTest()

  4) com.github.rocproject.roc.SenderTest
        OK  TestInvalidSenderBind()
        OK  TestInvalidConnectAfterWrite()
        OK  TestInvalidSenderCreation()
        OK  TestInvalidSenderWriteFloatArray()
        OK  TestSenderBindEphemeralPort()
        OK  TestValidSenderBind()
        OK  TestValidSenderWriteFloatArray()
        OK  TestValidSenderCreationAndDeinitialization()
        OK  TestInvalidSenderConnect()
        OK  TestValidSenderConnect()

  5) com.github.rocproject.roc.ReceiverTest
        OK  TestValidReceiverCreationAndDeinitialization()
        OK  TestInvalidReadFloatArray()
        OK  TestValidReceiverBind()
        OK  TestReceiverBindEphemeralPort()
        OK  TestInvalidReceiverCreation()
        OK  TestInvalidReceiverBind()
        OK  TestReceiverReadZeroizedArray()

-----------------------------------------------------------------
|  Results: FAILURE (29 tests, 27 passed, 2 failed, 0 skipped)  |
-----------------------------------------------------------------

29 tests completed, 2 failed

> Task :test FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///home/victor/dev/roc-project/roc-java/build/reports/tests/test/index.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 14s
7 actionable tasks: 7 executed

@gavv
Copy link
Member

gavv commented Apr 13, 2020

Cool, except one minor issue (see above) and the failing tests, the PR looks good.

@MatteoArella
Copy link
Member Author

An IOException indicates and error due to any IO operation. I've used it for close operations taking inspiration from java.net.Socket. BTW while it could make sense for Sender and Receiver maybe not for Context. Do you suggest to throw a generic Exception or maybe a custom RocException?

Let's keep it as is until libroc will have a more granular error reporting. Then we'll be able to translate roc errors to exception more accurately.

Ok 👍

@MatteoArella
Copy link
Member Author

$ ./gradlew build

> Task :test
20:07:40.246 [err] roc_lib: roc_context_close: context is still in use: counter=1
20:07:40.249 [err] roc_lib: roc_context_close: context is still in use: counter=1

com.github.rocproject.roc.LoggerTest > TestValidLoggerSetCallback() FAILED
    org.opentest4j.AssertionFailedError at LoggerTest.java:38
        Caused by: java.lang.UnsatisfiedLinkError at LoggerTest.java:44
20:07:40.270 [err] roc_lib: roc_sender_bind: sender is already bound

com.github.rocproject.roc.LoggerTest > TestValidLoggerSetLevel() FAILED
    org.opentest4j.AssertionFailedError at LoggerTest.java:13
        Caused by: java.lang.NoClassDefFoundError at LoggerTest.java:14
20:07:40.274 [err] roc_lib: roc_sender_connect: can't be called after first write
20:07:40.278 [err] roc_lib: roc_sender_write: sender is not properly bound
20:07:40.279 [err] roc_lib: roc_sender: source port is not connected
20:07:40.279 [err] roc_lib: roc_sender_write: sender is not properly connected

  1) com.github.rocproject.roc.LoggerTest
        KO  TestValidLoggerSetCallback()
        OK  TestLoggerSetNullCallback()
        OK  TestInvalidLoggerSetLevel()
        KO  TestValidLoggerSetLevel()

  2) com.github.rocproject.roc.ContextTest
        OK  ContextWithInvalidConfigTest()
        OK  ContextDefaultConfigTest()
        OK  ContextCloseWithAttachedSender()
        OK  ContextCloseWithAttachedReceiver()

  3) com.github.rocproject.roc.AddressTest
        OK  BadArgsTest()
        OK  IPv4AddressTest()
        OK  IPv6AddressTest()
        OK  DetectAddressTest()

  4) com.github.rocproject.roc.SenderTest
        OK  TestInvalidSenderBind()
        OK  TestInvalidConnectAfterWrite()
        OK  TestInvalidSenderCreation()
        OK  TestInvalidSenderWriteFloatArray()
        OK  TestSenderBindEphemeralPort()
        OK  TestValidSenderBind()
        OK  TestValidSenderWriteFloatArray()
        OK  TestValidSenderCreationAndDeinitialization()
        OK  TestInvalidSenderConnect()
        OK  TestValidSenderConnect()

  5) com.github.rocproject.roc.ReceiverTest
        OK  TestValidReceiverCreationAndDeinitialization()
        OK  TestInvalidReadFloatArray()
        OK  TestValidReceiverBind()
        OK  TestReceiverBindEphemeralPort()
        OK  TestInvalidReceiverCreation()
        OK  TestInvalidReceiverBind()
        OK  TestReceiverReadZeroizedArray()

-----------------------------------------------------------------
|  Results: FAILURE (29 tests, 27 passed, 2 failed, 0 skipped)  |
-----------------------------------------------------------------

29 tests completed, 2 failed

> Task :test FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///home/victor/dev/roc-project/roc-java/build/reports/tests/test/index.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 14s
7 actionable tasks: 7 executed

The build on my machine is actually passing. I've to investigate that problem deeply

@gavv
Copy link
Member

gavv commented Apr 13, 2020

I've created a few issues for future improvements: https://github.com/roc-project/roc-java/issues

@gavv
Copy link
Member

gavv commented Apr 13, 2020

FYI:

  • I did a fresh clone of your branch and killed the gradle daemon, the error is still there.

  • I've tried to replace TestValidLoggerSetLevel contents with just System.out.println(LogLevel.NONE); I still get java.lang.NoClassDefFoundError. So we're missing LogLevel values for some reason?

  • It seems that the java.lang.UnsatisfiedLinkError in TestValidLoggerSetCallback is also produced by Logger.setLevel.

@gavv
Copy link
Member

gavv commented Apr 13, 2020

Replacing enum initializers with constants fixes the issue:

    NONE( 0 ),
    ERROR( 1 ),
    INFO( 2 ),
    ...

So the problem is with getRocLogNone() etc.

System.out.println(LogLevel.NONE) produces java.lang.NoClassDefFoundError, but System.out.println(FecCode.DISABLE) works. So the problem is specific to LogLevel somehow...

@gavv
Copy link
Member

gavv commented Apr 13, 2020

Adding explicit call to RocLibrary.loadLibrary to the beginning of each LoggerTest test fixes the issue as well:

    @Test
    public void TestValidLoggerSetLevel() {
        RocLibrary.loadLibrary();
        assertDoesNotThrow(() -> {
            Logger.setLevel(LogLevel.NONE);
            ...

Maybe the order of:

static {
        RocLibrary.loadLibrary();
    }

and:

NONE( getRocLogNone() ),

is not guaranteed?

@gavv
Copy link
Member

gavv commented Apr 13, 2020

One stupid way to fix it:

diff --git a/src/main/java/com/github/rocproject/roc/LogLevel.java b/src/main/java/com/github/rocproject/roc/LogLevel.java
index 0339ffb..3d99b9b 100644
--- a/src/main/java/com/github/rocproject/roc/LogLevel.java
+++ b/src/main/java/com/github/rocproject/roc/LogLevel.java
@@ -10,7 +10,7 @@ public enum LogLevel {
      * No messages.
      * Setting this level disables logging completely.
      */
-    NONE( getRocLogNone() ),
+    NONE( RocLibrary.getEnum(() -> getRocLogNone()) ),
 
     /**
      * Error messages.
@@ -51,8 +51,4 @@ public enum LogLevel {
     private static native int getRocLogInfo();
     private static native int getRocLogDebug();
     private static native int getRocLogTrace();
-
-    static {
-        RocLibrary.loadLibrary();
-    }
 }
diff --git a/src/main/java/com/github/rocproject/roc/RocLibrary.java b/src/main/java/com/github/rocproject/roc/RocLibrary.java
index e3a0c18..ed19419 100644
--- a/src/main/java/com/github/rocproject/roc/RocLibrary.java
+++ b/src/main/java/com/github/rocproject/roc/RocLibrary.java
@@ -1,7 +1,16 @@
 package com.github.rocproject.roc;
 
+interface Getter {
+    int getIt();
+}
+
 class RocLibrary {
     static void loadLibrary() {
         System.loadLibrary("roc_jni");
     }
+
+    static int getEnum(Getter getter) {
+        loadLibrary();
+        return getter.getIt();
+    }
 }

Maybe you'll find a better approach.

@MatteoArella
Copy link
Member Author

Adding explicit call to RocLibrary.loadLibrary to the beginning of each LoggerTest test fixes the issue as well:

    @Test
    public void TestValidLoggerSetLevel() {
        RocLibrary.loadLibrary();
        assertDoesNotThrow(() -> {
            Logger.setLevel(LogLevel.NONE);
            ...

Maybe the order of:

static {
        RocLibrary.loadLibrary();
    }

and:

NONE( getRocLogNone() ),

is not guaranteed?

Yes enum initializer is executed before static block initializer. I'll fix soon in next commit

@gavv
Copy link
Member

gavv commented Apr 24, 2020

Tests are passing now. LGTM, thank you!

@gavv gavv merged commit fd01888 into roc-streaming:master Apr 24, 2020
@gavv
Copy link
Member

gavv commented Apr 24, 2020

@MatteoArella Do you plan to continue working on this in future? Please let me know if you would like to take maintainership and I'll add you to github team.

@MatteoArella
Copy link
Member Author

@MatteoArella Do you plan to continue working on this in future? Please let me know if you would like to take maintainership and I'll add you to github team.

Yes sure I'll be glad to work for this project

@gavv
Copy link
Member

gavv commented May 1, 2020

Great, sent you an invite!

@gavv
Copy link
Member

gavv commented May 1, 2020

You'll be able to manage issues & pull requests on this repo, and push to non-master branches. (The master branch is protected, so that we should use PRs to deliver changes to it). Let me know if you have any trouble.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants