From 5e47eda676eac809b5eb7ff7913d40d4a803e006 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Tue, 8 Sep 2020 16:25:14 +0200 Subject: [PATCH] Fix fatal error callback --- .../tdlight/tdlib/FatalErrorCallbackPtr.java | 29 ++++++++ .../it/tdlight/tdlib/NativeLog.java | 58 +++++++++++++--- .../it/tdlight/tdlib/ObjectsUtils.java | 67 +++++++++++++++++++ 3 files changed, 146 insertions(+), 8 deletions(-) create mode 100644 src/tdlib-java/it/tdlight/tdlib/FatalErrorCallbackPtr.java create mode 100644 src/tdlib-java/it/tdlight/tdlib/ObjectsUtils.java diff --git a/src/tdlib-java/it/tdlight/tdlib/FatalErrorCallbackPtr.java b/src/tdlib-java/it/tdlight/tdlib/FatalErrorCallbackPtr.java new file mode 100644 index 0000000..bdb697a --- /dev/null +++ b/src/tdlib-java/it/tdlight/tdlib/FatalErrorCallbackPtr.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018. Ernesto Castellotti + * This file is part of JTdlib. + * + * JTdlib is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * JTdlib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with JTdlib. If not, see . + */ + +package it.tdlight.tdlib; + +/** + * A type of callback function that will be called when a fatal error happens. + */ +public interface FatalErrorCallbackPtr { + /** + * Send error message to callback. + * @param error_message String with a description of a happened fatal error. + */ + void onFatalError(String error_message); +} diff --git a/src/tdlib-java/it/tdlight/tdlib/NativeLog.java b/src/tdlib-java/it/tdlight/tdlib/NativeLog.java index a7a3e15..6bb56f7 100644 --- a/src/tdlib-java/it/tdlight/tdlib/NativeLog.java +++ b/src/tdlib-java/it/tdlight/tdlib/NativeLog.java @@ -18,26 +18,68 @@ package it.tdlight.tdlib; /** - * Interface for managing the internal logging of TDLib. By default TDLib writes logs to stderr or an OS specific log and uses a verbosity level of 5. + * Class used for managing internal TDLib logging. + * Use TdApi.*Log* methods instead. */ public class NativeLog { + private static final FatalErrorCallbackPtr defaultFatalErrorCallbackPtr = System.err::println; + private static FatalErrorCallbackPtr fatalErrorCallback = defaultFatalErrorCallbackPtr; + /** - * Sets the path to the file to where the internal TDLib log will be written. By default TDLib writes logs to stderr or an OS specific log. Use this method to write the log to a file instead. - * @param filePath Path to a file where the internal TDLib log will be written. Use an empty path to switch back to the default logging behaviour. - * @return True on success, or false otherwise, i.e. if the file can't be opened for writing. + * Sets file path for writing TDLib internal log. By default TDLib writes logs to the System.err. + * Use this method to write the log to a file instead. + * + * @deprecated As of TDLib 1.4.0 in favor of {@link TdApi.SetLogStream}, to be removed in the future. + * @param filePath Path to a file for writing TDLib internal log. Use an empty path to + * switch back to logging to the System.err. + * @return whether opening the log file succeeded. */ + @Deprecated public static native boolean setFilePath(String filePath); /** - * Sets maximum size of the file to where the internal TDLib log is written before the file will be auto-rotated. Unused if log is not written to a file. Defaults to 10 MB. - * @param maxFileSize Maximum size of the file to where the internal TDLib log is written before the file will be auto-rotated. Should be positive. + * Changes the maximum size of TDLib log file. + * + * @deprecated As of TDLib 1.4.0 in favor of {@link TdApi.SetLogStream}, to be removed in the future. + * @param maxFileSize The maximum size of the file to where the internal TDLib log is written + * before the file will be auto-rotated. Must be positive. Defaults to 10 MB. */ + @Deprecated public static native void setMaxFileSize(long maxFileSize); /** - * Sets the verbosity level of the internal logging of TDLib. By default the TDLib uses a verbosity level of 5 for logging. - * @param verbosityLevel New value of the verbosity level for logging. Value 0 corresponds to fatal errors, value 1 corresponds to errors, value 2 corresponds to warnings and debug warnings, value 3 corresponds to informational, value 4 corresponds to debug, value 5 corresponds to verbose debug, value greater than 5 and up to 1024 can be used to enable even more logging. + * Changes TDLib log verbosity. + * + * @deprecated As of TDLib 1.4.0 in favor of {@link TdApi.SetLogVerbosityLevel}, to be removed in the future. + * @param verbosityLevel New value of log verbosity level. Must be non-negative. + * Value 0 corresponds to fatal errors, + * value 1 corresponds to java.util.logging.Level.SEVERE, + * value 2 corresponds to java.util.logging.Level.WARNING, + * value 3 corresponds to java.util.logging.Level.INFO, + * value 4 corresponds to java.util.logging.Level.FINE, + * value 5 corresponds to java.util.logging.Level.FINER, + * value greater than 5 can be used to enable even more logging. + * Default value of the log verbosity level is 5. */ + @Deprecated public static native void setVerbosityLevel(int verbosityLevel); + + /** + * This function is called from the JNI when a fatal error happens to provide a better error message. + * The function does not return. + * + * @param errorMessage Error message. + */ + private static synchronized void onFatalError(String errorMessage) { + new Thread(() -> NativeLog.fatalErrorCallback.onFatalError(errorMessage)).start(); + } + + /** + * Sets the callback that will be called when a fatal error happens. None of the TDLib methods can be called from the callback. The TDLib will crash as soon as callback returns. By default the callback set to print in stderr. + * @param fatalErrorCallback Callback that will be called when a fatal error happens. Pass null to restore default callback. + */ + public static synchronized void setFatalErrorCallback(FatalErrorCallbackPtr fatalErrorCallback) { + NativeLog.fatalErrorCallback = ObjectsUtils.requireNonNullElse(fatalErrorCallback, defaultFatalErrorCallbackPtr); + } } diff --git a/src/tdlib-java/it/tdlight/tdlib/ObjectsUtils.java b/src/tdlib-java/it/tdlight/tdlib/ObjectsUtils.java new file mode 100644 index 0000000..8d9f544 --- /dev/null +++ b/src/tdlib-java/it/tdlight/tdlib/ObjectsUtils.java @@ -0,0 +1,67 @@ +package it.tdlight.tdlib; + +public class ObjectsUtils { + /** + * Returns the first argument if it is non-{@code null} and + * otherwise returns the non-{@code null} second argument. + * + * @param obj an object + * @param defaultObj a non-{@code null} object to return if the first argument + * is {@code null} + * @param the type of the reference + * @return the first argument if it is non-{@code null} and + * otherwise the second argument if it is non-{@code null} + * @throws NullPointerException if both {@code obj} is null and + * {@code defaultObj} is {@code null} + * @since 9 + */ + public static T requireNonNullElse(T obj, T defaultObj) { + return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj"); + } + + /** + * Checks that the specified object reference is not {@code null}. This + * method is designed primarily for doing parameter validation in methods + * and constructors, as demonstrated below: + *
+	 * public Foo(Bar bar) {
+	 *     this.bar = Objects.requireNonNull(bar);
+	 * }
+	 * 
+ * + * @param obj the object reference to check for nullity + * @param the type of the reference + * @return {@code obj} if not {@code null} + * @throws NullPointerException if {@code obj} is {@code null} + */ + public static T requireNonNull(T obj) { + if (obj == null) + throw new NullPointerException(); + return obj; + } + + /** + * Checks that the specified object reference is not {@code null} and + * throws a customized {@link NullPointerException} if it is. This method + * is designed primarily for doing parameter validation in methods and + * constructors with multiple parameters, as demonstrated below: + *
+	 * public Foo(Bar bar, Baz baz) {
+	 *     this.bar = Objects.requireNonNull(bar, "bar must not be null");
+	 *     this.baz = Objects.requireNonNull(baz, "baz must not be null");
+	 * }
+	 * 
+ * + * @param obj the object reference to check for nullity + * @param message detail message to be used in the event that a {@code + * NullPointerException} is thrown + * @param the type of the reference + * @return {@code obj} if not {@code null} + * @throws NullPointerException if {@code obj} is {@code null} + */ + public static T requireNonNull(T obj, String message) { + if (obj == null) + throw new NullPointerException(message); + return obj; + } +}