Skip to content

Commit

Permalink
Merge pull request #23 from briancorbinxyz/feature/native-api
Browse files Browse the repository at this point in the history
Feature/native api
  • Loading branch information
briancorbinxyz authored Sep 2, 2024
2 parents b4f26bd + 13a90ae commit cfa8ea5
Show file tree
Hide file tree
Showing 15 changed files with 64 additions and 48 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ Cargo.lock
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
bin/
bin/
native/src/main/resources/native/
30 changes: 0 additions & 30 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,25 +98,13 @@
"request": "launch",
"mainClass": "org.xxdc.oss.example.App",
"projectName": "app",
"env": {
"LIB_PATH": "${workspaceFolder}/app/build/cargo/debug",
"PATH": "${workspaceFolder}/app/build/cargo/debug",
"LD_LIBRARY_PATH": "${workspaceFolder}/app/build/cargo/debug",
"DYLD_LIBRARY_PATH": "${workspaceFolder}/app/build/cargo/debug"
}
},
{
"type": "java",
"name": "GameClient",
"request": "launch",
"mainClass": "org.xxdc.oss.example.GameClient",
"projectName": "app",
"env": {
"LIB_PATH": "${workspaceFolder}/app/build/cargo/debug",
"PATH": "${workspaceFolder}/app/build/cargo/debug",
"LD_LIBRARY_PATH": "${workspaceFolder}/app/build/cargo/debug",
"DYLD_LIBRARY_PATH": "${workspaceFolder}/app/build/cargo/debug"
}
},
{
"type": "java",
Expand All @@ -125,25 +113,13 @@
"vmArgs": "-XX:+UseZGC",
"mainClass": "org.xxdc.oss.example.GameClient",
"projectName": "app",
"env": {
"LIB_PATH": "${workspaceFolder}/app/build/cargo/debug",
"PATH": "${workspaceFolder}/app/build/cargo/debug",
"LD_LIBRARY_PATH": "${workspaceFolder}/app/build/cargo/debug",
"DYLD_LIBRARY_PATH": "${workspaceFolder}/app/build/cargo/debug"
}
},
{
"type": "java",
"name": "GameServer",
"request": "launch",
"mainClass": "org.xxdc.oss.example.GameServer",
"projectName": "app",
"env": {
"LIB_PATH": "${workspaceFolder}/app/build/cargo/debug",
"PATH": "${workspaceFolder}/app/build/cargo/debug",
"LD_LIBRARY_PATH": "${workspaceFolder}/app/build/cargo/debug",
"DYLD_LIBRARY_PATH": "${workspaceFolder}/app/build/cargo/debug"
}
},
{
"type": "java",
Expand All @@ -152,12 +128,6 @@
"vmArgs": "-XX:+UseZGC",
"mainClass": "org.xxdc.oss.example.GameServer",
"projectName": "app",
"env": {
"LIB_PATH": "${workspaceFolder}/app/build/cargo/debug",
"PATH": "${workspaceFolder}/app/build/cargo/debug",
"LD_LIBRARY_PATH": "${workspaceFolder}/app/build/cargo/debug",
"DYLD_LIBRARY_PATH": "${workspaceFolder}/app/build/cargo/debug"
}
}
]
}
2 changes: 0 additions & 2 deletions api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ val libSuffix = when {

dependencies {
// Native Library (Rust)
implementation(project(":native"))
//testRuntimeOnly("org.xxdc.oss.example:tictactoe-native-$libSuffix:1.1.0")

// JDK9: Platform Logging (Third-Party)
// -> JDK API -> SLF4J -> Logback
Expand Down
21 changes: 18 additions & 3 deletions api/src/main/java/org/xxdc/oss/example/GameBoard.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
Expand Down Expand Up @@ -113,15 +114,29 @@ static GameBoard withDimension(int dimension) {
GameBoard gameBoard;
try {
if (useNative.get()) {
gameBoard = new GameBoardNativeImpl(dimension);
// Use the native implementation of the game board if it is available
// using reflection.
Class<?> gameBoardNativeImplClass =
Class.forName("org.xxdc.oss.example.GameBoardNativeImpl");
gameBoard =
(GameBoard)
gameBoardNativeImplClass.getDeclaredConstructor(int.class).newInstance(dimension);
} else {
gameBoard = new GameBoardLocalImpl(dimension);
}
} catch (ExceptionInInitializerError e) {
} catch (ExceptionInInitializerError
| InstantiationException
| IllegalAccessException
| IllegalArgumentException
| InvocationTargetException
| NoSuchMethodException
| SecurityException
| ClassNotFoundException e) {
// Fallback to the Java implementation.
log.log(
Level.WARNING,
"Unable to use native logger, falling back to local logger: {0}",
"Unable to use native game board, falling back to local game board: {0}({1})",
e.getClass(),
e.getMessage());
useNative.set(false);
gameBoard = new GameBoardLocalImpl(dimension);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ testing {
}
}

val projectVersion by extra("1.1.1")
val projectVersion by extra("1.2.1")

public val jdkVersion = 22
// Apply a specific Java toolchain to ease working on different environments.
Expand Down
18 changes: 11 additions & 7 deletions native/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ repositories {
gradlePluginPortal()
}

dependencies {
implementation(project(":api"))
}

testing {
suites {
// Configure the built-in test suite
Expand Down Expand Up @@ -78,20 +82,20 @@ tasks.register<Delete>("cleanRust") {
tasks.named("clean") {
dependsOn("cleanRust")
}
// Force a build before running the application
tasks.named("build") {
dependsOn("formatRust")
}
tasks.named<Jar>("jar") {
from("${cargoBuildDir}/debug") {
include(libName)
}
tasks.register<Copy>("copyLib") {
from(libPath)
into("src/main/resources/native")
include(libName)
}
tasks.named("processResources") {
dependsOn("copyLib")
}
//
// Rust Build End
//
java {
}

// https://docs.gradle.org/current/userguide/publishing_maven.html
publishing {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

public class NativeLoader {

public static String NATIVE_ROOT = "/native/";

public static SymbolLookup loadLibrary(String libraryName, Arena arena) {
try {
var platformLibraryName = platformLibraryName(libraryName);
Expand All @@ -23,7 +25,7 @@ private static String platformLibraryName(String libraryName) {

private static SymbolLookup fromClassPathToTemp(String platformLibraryName, Arena arena)
throws IOException {
var resourceLookupString = "/" + platformLibraryName;
var resourceLookupString = NATIVE_ROOT + platformLibraryName;
var tempResourceFile = Files.createTempFile(platformLibraryName, ".tmp");
try (var inputStream = NativeLoader.class.getResourceAsStream(resourceLookupString);
OutputStream outputStream = Files.newOutputStream(tempResourceFile)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.xxdc.oss.example;

import static org.testng.Assert.assertNotNull;
import static org.xxdc.oss.example.TestData.*;

import java.lang.System.Logger;
import java.lang.System.Logger.Level;
Expand Down Expand Up @@ -103,4 +102,16 @@ public void should_clean_up_native_resources() {
}
}
}

public static GameBoard createBoardWith(String[][] content) {
GameBoard board = GameBoard.withDimension(content.length);
for (int row = 0; row < content.length; row++) {
for (int col = 0; col < content[row].length; col++) {
if (content[row][col] != null && !content[row][col].equals("_")) {
board = board.withMove(content[row][col], row * content.length + col);
}
}
}
return board;
}
}
15 changes: 15 additions & 0 deletions native/src/test/java/org/xxdc/oss/example/GameBoardTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.xxdc.oss.example;

import static org.testng.Assert.assertEquals;

import org.testng.annotations.Test;

public class GameBoardTest {

@Test
public void test_default_game_board_type_is_native() {
// should use the native implementation by default since it's in the classpath
GameBoard gameBoard = GameBoard.withDimension(3);
assertEquals(gameBoard.getClass(), GameBoardNativeImpl.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
import org.xxdc.oss.example.PlayerNode;

@Ignore
public class GamePerformanceTest {
public class GameServerPerformanceTest {

private static final Logger log = System.getLogger(GamePerformanceTest.class.getName());
private static final Logger log = System.getLogger(GameServerPerformanceTest.class.getName());

@Test
public void testGameClientServerBotPerformanceInParallelWithPlatformThreads() throws Exception {
Expand Down

0 comments on commit cfa8ea5

Please sign in to comment.