Add example of JSON interface usage from Java.
This commit is contained in:
parent
91ac878840
commit
f9b7e1bc2e
@ -8,6 +8,8 @@ endif()
|
||||
|
||||
project(TdJavaExample VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
option(TD_JSON_JAVA "Use \"ON\" to build Java wrapper for JSON API.")
|
||||
|
||||
if (POLICY CMP0054)
|
||||
# do not expand quoted arguments
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
@ -34,26 +36,40 @@ endif()
|
||||
message(STATUS "Found Java: ${Java_JAVAC_EXECUTABLE} ${Java_JAVADOC_EXECUTABLE}")
|
||||
|
||||
# Generating TdApi.java
|
||||
find_program(PHP_EXECUTABLE php)
|
||||
if ((CMAKE_SYSTEM_NAME MATCHES "FreeBSD") AND (CMAKE_SYSTEM_VERSION MATCHES "HBSD"))
|
||||
set(PHP_EXECUTABLE "PHP_EXECUTABLE-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(TD_API_JAVA_PACKAGE "org/drinkless/tdlib")
|
||||
set(TD_API_JAVA_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(TD_API_TLO_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/scheme/td_api.tlo)
|
||||
set(TD_API_TL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/scheme/td_api.tl)
|
||||
set(JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/JavadocTlDocumentationGenerator.php)
|
||||
set(GENERATE_JAVA_API_CMD ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td_generate_java_api TdApi ${TD_API_TLO_PATH} ${TD_API_JAVA_PATH} ${TD_API_JAVA_PACKAGE})
|
||||
if (PHP_EXECUTABLE)
|
||||
set(GENERATE_JAVA_API_CMD ${GENERATE_JAVA_API_CMD} && ${PHP_EXECUTABLE} ${JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH} ${TD_API_TL_PATH} ${TD_API_JAVA_PATH}/${TD_API_JAVA_PACKAGE}/TdApi.java)
|
||||
endif()
|
||||
set(JAVA_SOURCE_PATH "${TD_API_JAVA_PATH}/${TD_API_JAVA_PACKAGE}")
|
||||
if (TD_JSON_JAVA)
|
||||
add_custom_target(td_generate_java_api
|
||||
COMMAND cmake -E echo ""
|
||||
COMMENT "Skip generation of Java TDLib API source files"
|
||||
)
|
||||
|
||||
add_custom_target(td_generate_java_api
|
||||
COMMAND ${GENERATE_JAVA_API_CMD}
|
||||
COMMENT "Generating Java TDLib API source files"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td_generate_java_api ${TD_API_TLO_PATH} ${TD_API_TL_PATH} ${JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH}
|
||||
)
|
||||
set(JAVA_EXAMPLE_FILES "${JAVA_SOURCE_PATH}/example/JsonExample.java")
|
||||
set(JAVA_SOURCE_FILES "${JAVA_SOURCE_PATH}/JsonClient.java")
|
||||
else()
|
||||
find_program(PHP_EXECUTABLE php)
|
||||
if ((CMAKE_SYSTEM_NAME MATCHES "FreeBSD") AND (CMAKE_SYSTEM_VERSION MATCHES "HBSD"))
|
||||
set(PHP_EXECUTABLE "PHP_EXECUTABLE-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(TD_API_TLO_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/scheme/td_api.tlo)
|
||||
set(TD_API_TL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/scheme/td_api.tl)
|
||||
set(JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/JavadocTlDocumentationGenerator.php)
|
||||
set(GENERATE_JAVA_API_CMD ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td_generate_java_api TdApi "${TD_API_TLO_PATH}" "${TD_API_JAVA_PATH}" "${TD_API_JAVA_PACKAGE}")
|
||||
if (PHP_EXECUTABLE)
|
||||
set(GENERATE_JAVA_API_CMD ${GENERATE_JAVA_API_CMD} && ${PHP_EXECUTABLE} "${JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH}" "${TD_API_TL_PATH}" "${JAVA_SOURCE_PATH}/TdApi.java")
|
||||
endif()
|
||||
|
||||
add_custom_target(td_generate_java_api
|
||||
COMMAND ${GENERATE_JAVA_API_CMD}
|
||||
COMMENT "Generating Java TDLib API source files"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td_generate_java_api ${TD_API_TLO_PATH} ${TD_API_TL_PATH} ${JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH}
|
||||
)
|
||||
|
||||
set(JAVA_EXAMPLE_FILES "${JAVA_SOURCE_PATH}/example/Example.java")
|
||||
set(JAVA_SOURCE_FILES "${JAVA_SOURCE_PATH}/Client.java" "${JAVA_SOURCE_PATH}/TdApi.java")
|
||||
endif()
|
||||
|
||||
if (CMAKE_VERSION VERSION_LESS "3.17")
|
||||
set(CMAKE_RM_COMMAND remove_directory)
|
||||
@ -61,9 +77,6 @@ else()
|
||||
set(CMAKE_RM_COMMAND rm -rf --)
|
||||
endif()
|
||||
|
||||
set(JAVA_SOURCE_PATH "${TD_API_JAVA_PATH}/${TD_API_JAVA_PACKAGE}")
|
||||
set(JAVA_EXAMPLE_FILES "${JAVA_SOURCE_PATH}/example/Example.java")
|
||||
set(JAVA_SOURCE_FILES "${JAVA_SOURCE_PATH}/Client.java" "${JAVA_SOURCE_PATH}/TdApi.java")
|
||||
get_filename_component(JAVA_OUTPUT_DIRECTORY ${CMAKE_INSTALL_PREFIX}/bin REALPATH BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(MAKE_DIRECTORY ${JAVA_OUTPUT_DIRECTORY})
|
||||
add_custom_target(build_java
|
||||
@ -86,9 +99,17 @@ add_library(tdjni SHARED
|
||||
td_jni.cpp
|
||||
)
|
||||
target_include_directories(tdjni PRIVATE ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
|
||||
target_link_libraries(tdjni PRIVATE Td::TdStatic ${JAVA_JVM_LIBRARY})
|
||||
target_link_libraries(tdjni PRIVATE ${JAVA_JVM_LIBRARY})
|
||||
target_compile_definitions(tdjni PRIVATE PACKAGE_NAME="${TD_API_JAVA_PACKAGE}")
|
||||
|
||||
if (TD_JSON_JAVA)
|
||||
target_link_libraries(tdjni PRIVATE Td::TdJsonStatic)
|
||||
target_compile_definitions(tdjni PRIVATE TD_JSON_JAVA=1)
|
||||
set_target_properties(tdjni PROPERTIES OUTPUT_NAME "tdjsonjava")
|
||||
else()
|
||||
target_link_libraries(tdjni PRIVATE Td::TdStatic)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(GCC 1)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
|
@ -19,6 +19,8 @@ If you want to compile TDLib for 32-bit/64-bit Java on Windows using MSVC, you w
|
||||
|
||||
In Windows, use vcpkg toolchain file by adding parameter -DCMAKE_TOOLCHAIN_FILE=<VCPKG_DIR>/scripts/buildsystems/vcpkg.cmake
|
||||
|
||||
If you want to build JsonClient.java wrapper for JSON interface instead of the native JNI interface, add `-DTD_JSON_JAVA=ON` option to CMake.
|
||||
|
||||
After this you can compile the example source code:
|
||||
```
|
||||
cd <path to TDLib sources>/example/java
|
||||
@ -28,7 +30,7 @@ cmake -DCMAKE_BUILD_TYPE=Release -DTd_DIR=<full path to TDLib sources>/example/j
|
||||
cmake --build . --target install
|
||||
```
|
||||
|
||||
Compiled TDLib shared library and Java example after that will be placed in bin/ and Javadoc documentation in `docs/`.
|
||||
Compiled TDLib shared library and Java example after that will be placed in `bin/` and Javadoc documentation in `docs/`.
|
||||
|
||||
After this you can run the Java example:
|
||||
```
|
||||
@ -36,6 +38,8 @@ cd <path to TDLib sources>/example/java/bin
|
||||
java '-Djava.library.path=.' org/drinkless/tdlib/example/Example
|
||||
```
|
||||
|
||||
If you built JSON interface example using `-DTD_JSON_JAVA=ON` option, then use the command `java '-Djava.library.path=.' org/drinkless/tdlib/example/JsonExample` instead.
|
||||
|
||||
If you receive "Could NOT find JNI ..." error from CMake, you need to specify to CMake path to the installed JDK, for example, "-DJAVA_HOME=/usr/lib/jvm/java-8-oracle/".
|
||||
|
||||
If you receive java.lang.UnsatisfiedLinkError with "Can't find dependent libraries", you may also need to copy some dependent shared OpenSSL and zlib libraries to `bin/`.
|
||||
|
79
example/java/org/drinkless/tdlib/JsonClient.java
Normal file
79
example/java/org/drinkless/tdlib/JsonClient.java
Normal file
@ -0,0 +1,79 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
package org.drinkless.tdlib;
|
||||
|
||||
/**
|
||||
* Main class for interaction with the TDLib using JSON interface.
|
||||
*/
|
||||
public final class JsonClient {
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("tdjsonjava");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an opaque identifier of a new TDLib instance.
|
||||
* The TDLib instance will not send updates until the first request is sent to it.
|
||||
* @return Opaque identifier of a new TDLib instance.
|
||||
*/
|
||||
public static native int createClientId();
|
||||
|
||||
/**
|
||||
* Sends request to the TDLib client. May be called from any thread.
|
||||
* @param clientId TDLib client identifier.
|
||||
* @param request JSON-serialized request.
|
||||
*/
|
||||
public static native void send(int clientId, String request);
|
||||
|
||||
/**
|
||||
* Receives incoming updates and request responses. Must not be called simultaneously from two different threads.
|
||||
* @param timeout The maximum number of seconds allowed for this function to wait for new data.
|
||||
* @return JSON-serialized incoming update or request response. May be null if the timeout expired before new data received.
|
||||
*/
|
||||
public static native String receive(double timeout);
|
||||
|
||||
/**
|
||||
* Synchronously executes a TDLib request.
|
||||
* A request can be executed synchronously, only if it is documented with "Can be called synchronously".
|
||||
* @param request JSON-serialized request.
|
||||
* @return JSON-serialized request response. May be null if the request is invalid.
|
||||
*/
|
||||
public static native String execute(String request);
|
||||
|
||||
/**
|
||||
* Interface for handler of messages that are added to the internal TDLib log.
|
||||
*/
|
||||
public interface LogMessageHandler {
|
||||
/**
|
||||
* Callback called on messages that are added to the internal TDLib log.
|
||||
*
|
||||
* @param verbosityLevel Log verbosity level with which the message was added from -1 up to 1024.
|
||||
* If 0, then TDLib will crash as soon as the callback returns.
|
||||
* None of the TDLib methods can be called from the callback.
|
||||
* @param message The message added to the internal TDLib log.
|
||||
*/
|
||||
void onLogMessage(int verbosityLevel, String message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the handler for messages that are added to the internal TDLib log.
|
||||
* None of the TDLib methods can be called from the callback.
|
||||
*
|
||||
* @param maxVerbosityLevel The maximum verbosity level of messages for which the callback will be called.
|
||||
* @param logMessageHandler Handler for messages that are added to the internal TDLib log. Pass null to remove the handler.
|
||||
*/
|
||||
public static native void setLogMessageHandler(int maxVerbosityLevel, JsonClient.LogMessageHandler logMessageHandler);
|
||||
|
||||
/**
|
||||
* The class can't be instantiated.
|
||||
*/
|
||||
private JsonClient() {
|
||||
}
|
||||
}
|
47
example/java/org/drinkless/tdlib/example/JsonExample.java
Normal file
47
example/java/org/drinkless/tdlib/example/JsonExample.java
Normal file
@ -0,0 +1,47 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
package org.drinkless.tdlib.example;
|
||||
|
||||
import org.drinkless.tdlib.JsonClient;
|
||||
|
||||
/**
|
||||
* Example class for TDLib usage from Java using JSON interface.
|
||||
*/
|
||||
public final class JsonExample {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
// set log message handler to handle only fatal errors (0) and plain log messages (-1)
|
||||
JsonClient.setLogMessageHandler(0, new LogMessageHandler());
|
||||
|
||||
// disable TDLib log and redirect fatal errors and plain log messages to a file
|
||||
JsonClient.execute("{\"@type\":\"setLogVerbosityLevel\",\"new_verbosity_level\":0}");
|
||||
JsonClient.execute("{\"@type\":\"setLogStream\",\"log_stream\":{\"@type\":\"logStreamFile\",\"path\":\"tdlib.log\",\"max_file_size\":128000000}}");
|
||||
|
||||
// create client identifier
|
||||
int clientId = JsonClient.createClientId();
|
||||
|
||||
// send first request to activate the client
|
||||
JsonClient.send(clientId, "{\"@type\":\"getOption\",\"name\":\"version\"}");
|
||||
|
||||
// main loop
|
||||
while (true) {
|
||||
String result = JsonClient.receive(100.0);
|
||||
if (result != null) {
|
||||
System.out.println(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class LogMessageHandler implements JsonClient.LogMessageHandler {
|
||||
@Override
|
||||
public void onLogMessage(int verbosityLevel, String message) {
|
||||
System.err.print(message);
|
||||
if (verbosityLevel == 0) {
|
||||
System.err.println("Receive fatal error; the process will crash now");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,8 +4,12 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifdef TD_JSON_JAVA
|
||||
#include <td/telegram/td_json_client.h>
|
||||
#else
|
||||
#include <td/telegram/Client.h>
|
||||
#include <td/telegram/td_api.h>
|
||||
#endif
|
||||
|
||||
#include <td/tl/tl_jni_object.h>
|
||||
|
||||
@ -16,6 +20,31 @@
|
||||
|
||||
namespace td_jni {
|
||||
|
||||
#ifdef TD_JSON_JAVA
|
||||
static jint JsonClient_createClientId(JNIEnv *env, jclass clazz) {
|
||||
return static_cast<jint>(td_create_client_id());
|
||||
}
|
||||
|
||||
static void JsonClient_send(JNIEnv *env, jclass clazz, jint client_id, jstring request) {
|
||||
td_send(static_cast<int>(client_id), td::jni::from_jstring(env, request).c_str());
|
||||
}
|
||||
|
||||
static jstring JsonClient_receive(JNIEnv *env, jclass clazz, jdouble timeout) {
|
||||
auto result = td_receive(timeout);
|
||||
if (result == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return td::jni::to_jstring(env, result);
|
||||
}
|
||||
|
||||
static jstring JsonClient_execute(JNIEnv *env, jclass clazz, jstring request) {
|
||||
auto result = td_execute(td::jni::from_jstring(env, request).c_str());
|
||||
if (result == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return td::jni::to_jstring(env, result);
|
||||
}
|
||||
#else
|
||||
static td::td_api::object_ptr<td::td_api::Function> fetch_function(JNIEnv *env, jobject function) {
|
||||
td::jni::reset_parse_error();
|
||||
auto result = td::td_api::Function::fetch(env, function);
|
||||
@ -83,6 +112,7 @@ static jstring Object_toString(JNIEnv *env, jobject object) {
|
||||
static jstring Function_toString(JNIEnv *env, jobject object) {
|
||||
return td::jni::to_jstring(env, to_string(td::td_api::Function::fetch(env, object)));
|
||||
}
|
||||
#endif
|
||||
|
||||
static constexpr jint JAVA_VERSION = JNI_VERSION_1_6;
|
||||
static JavaVM *java_vm;
|
||||
@ -118,7 +148,11 @@ static void on_log_message(int verbosity_level, const char *log_message) {
|
||||
static void Client_nativeClientSetLogMessageHandler(JNIEnv *env, jclass clazz, jint max_verbosity_level,
|
||||
jobject new_log_message_handler) {
|
||||
if (log_message_handler) {
|
||||
#ifdef TD_JSON_JAVA
|
||||
td_set_log_message_callback(0, nullptr);
|
||||
#else
|
||||
td::ClientManager::set_log_message_callback(0, nullptr);
|
||||
#endif
|
||||
jobject old_log_message_handler = log_message_handler;
|
||||
log_message_handler = jobject();
|
||||
env->DeleteGlobalRef(old_log_message_handler);
|
||||
@ -131,7 +165,11 @@ static void Client_nativeClientSetLogMessageHandler(JNIEnv *env, jclass clazz, j
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TD_JSON_JAVA
|
||||
td_set_log_message_callback(static_cast<int>(max_verbosity_level), on_log_message);
|
||||
#else
|
||||
td::ClientManager::set_log_message_callback(static_cast<int>(max_verbosity_level), on_log_message);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,6 +186,16 @@ static jint register_native(JavaVM *vm) {
|
||||
reinterpret_cast<void *>(function_ptr));
|
||||
};
|
||||
|
||||
#ifdef TD_JSON_JAVA
|
||||
auto client_class = td::jni::get_jclass(env, PACKAGE_NAME "/JsonClient");
|
||||
|
||||
register_method(client_class, "createClientId", "()I", JsonClient_createClientId);
|
||||
register_method(client_class, "send", "(ILjava/lang/String;)V", JsonClient_send);
|
||||
register_method(client_class, "receive", "(D)Ljava/lang/String;", JsonClient_receive);
|
||||
register_method(client_class, "execute", "(Ljava/lang/String;)Ljava/lang/String;", JsonClient_execute);
|
||||
register_method(client_class, "setLogMessageHandler", "(IL" PACKAGE_NAME "/JsonClient$LogMessageHandler;)V",
|
||||
Client_nativeClientSetLogMessageHandler);
|
||||
#else
|
||||
auto client_class = td::jni::get_jclass(env, PACKAGE_NAME "/Client");
|
||||
auto object_class = td::jni::get_jclass(env, PACKAGE_NAME "/TdApi$Object");
|
||||
auto function_class = td::jni::get_jclass(env, PACKAGE_NAME "/TdApi$Function");
|
||||
@ -169,6 +217,7 @@ static jint register_native(JavaVM *vm) {
|
||||
|
||||
td::jni::init_vars(env, PACKAGE_NAME);
|
||||
td::td_api::get_package_name_ref() = PACKAGE_NAME;
|
||||
#endif
|
||||
|
||||
return JAVA_VERSION;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user