Lazy initialization of tdlib native library

This commit is contained in:
Andrea Cavalli 2022-02-25 15:48:13 +01:00
parent 781b00eb1e
commit 9f1a4e5292
4 changed files with 31 additions and 23 deletions

View File

@ -28,7 +28,10 @@ import java.util.concurrent.ConcurrentHashMap;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public final class ConstructorDetector { public final class ConstructorDetector {
static { private static ConcurrentHashMap<Integer, Class> constructorHashMap;
private static ConcurrentHashMap<Class, Integer> constructorHashMapInverse;
private static void tryInit() {
// Call this to load static methods and prevent errors during startup! // Call this to load static methods and prevent errors during startup!
try { try {
Init.start(); Init.start();
@ -37,13 +40,10 @@ public final class ConstructorDetector {
} }
} }
private static ConcurrentHashMap<Integer, Class> constructorHashMap;
private static ConcurrentHashMap<Class, Integer> constructorHashMapInverse;
/** /**
* Initialize the ConstructorDetector, it is called from the Init class. * Initialize the ConstructorDetector, it is called from the Init class.
*/ */
public static void init() { static void init() {
if (constructorHashMap != null) { if (constructorHashMap != null) {
return; return;
} }
@ -59,6 +59,7 @@ public final class ConstructorDetector {
* @return The class related to CONSTRUCTOR. * @return The class related to CONSTRUCTOR.
*/ */
public static Class getClass(int CONSTRUCTOR) { public static Class getClass(int CONSTRUCTOR) {
tryInit();
return constructorHashMap.getOrDefault(CONSTRUCTOR, null); return constructorHashMap.getOrDefault(CONSTRUCTOR, null);
} }
@ -69,6 +70,7 @@ public final class ConstructorDetector {
* @return The CONSTRUCTOR. * @return The CONSTRUCTOR.
*/ */
public static int getConstructor(Class<? extends TdApi.Object> clazz) { public static int getConstructor(Class<? extends TdApi.Object> clazz) {
tryInit();
return Objects.requireNonNull(constructorHashMapInverse.get(clazz)); return Objects.requireNonNull(constructorHashMapInverse.get(clazz));
} }

View File

@ -32,23 +32,27 @@ public final class Init {
public static final Logger LOG = LoggerFactory.getLogger(Init.class); public static final Logger LOG = LoggerFactory.getLogger(Init.class);
private static boolean started = false; private static volatile boolean started = false;
/** /**
* Initialize Tdlib * Initialize Tdlib
* *
* @throws CantLoadLibrary An exception that is thrown when the LoadLibrary class fails to load the library. * @throws CantLoadLibrary An exception that is thrown when the LoadLibrary class fails to load the library.
*/ */
public synchronized static void start() throws CantLoadLibrary { public static void start() throws CantLoadLibrary {
if (!started) { if (!started) {
LoadLibrary.load("tdjni"); synchronized (Init.class) {
ConstructorDetector.init(); if (!started) {
try { LoadLibrary.load("tdjni");
NativeClientAccess.execute(new SetLogVerbosityLevel(1)); ConstructorDetector.init();
} catch (Throwable ex) { try {
LOG.error("Can't set verbosity level on startup", ex); NativeClientAccess.execute(new SetLogVerbosityLevel(1));
} catch (Throwable ex) {
LOG.error("Can't set verbosity level on startup", ex);
}
started = true;
}
} }
started = true;
} }
} }
} }

View File

@ -28,12 +28,6 @@ public final class InternalClientManager implements AutoCloseable {
private final AtomicLong currentQueryId = new AtomicLong(); private final AtomicLong currentQueryId = new AtomicLong();
private InternalClientManager(String implementationName) { private InternalClientManager(String implementationName) {
try {
Init.start();
} catch (Throwable ex) {
ex.printStackTrace();
System.exit(1);
}
this.implementationName = implementationName; this.implementationName = implementationName;
responseReceiver = new NativeResponseReceiver(this::handleClientEvents); responseReceiver = new NativeResponseReceiver(this::handleClientEvents);
} }
@ -46,6 +40,12 @@ public final class InternalClientManager implements AutoCloseable {
return false; return false;
} }
if (startCalled.compareAndSet(false, true)) { if (startCalled.compareAndSet(false, true)) {
try {
Init.start();
} catch (Throwable ex) {
ex.printStackTrace();
System.exit(1);
}
responseReceiver.start(); responseReceiver.start();
return true; return true;
} else { } else {
@ -54,14 +54,12 @@ public final class InternalClientManager implements AutoCloseable {
} }
public static InternalClientManager get(String implementationName) { public static InternalClientManager get(String implementationName) {
InternalClientManager clientManager = INSTANCE.updateAndGet(val -> { return INSTANCE.updateAndGet(val -> {
if (val == null) { if (val == null) {
return new InternalClientManager(implementationName); return new InternalClientManager(implementationName);
} }
return val; return val;
}); });
clientManager.startIfNeeded();
return clientManager;
} }
private void handleClientEvents(int clientId, private void handleClientEvents(int clientId,
@ -125,6 +123,7 @@ public final class InternalClientManager implements AutoCloseable {
} }
public void registerClient(int clientId, ClientEventsHandler internalClient) { public void registerClient(int clientId, ClientEventsHandler internalClient) {
this.startIfNeeded();
boolean replaced = registeredClientEventHandlers.put(clientId, internalClient) != null; boolean replaced = registeredClientEventHandlers.put(clientId, internalClient) != null;
if (replaced) { if (replaced) {
throw new IllegalStateException("Client " + clientId + " already registered"); throw new IllegalStateException("Client " + clientId + " already registered");

View File

@ -277,6 +277,9 @@ abstract class ResponseReceiver extends Thread implements AutoCloseable {
if (startCalled.get()) { if (startCalled.get()) {
if (closeCalled.compareAndSet(false, true)) { if (closeCalled.compareAndSet(false, true)) {
this.closeWait.await(); this.closeWait.await();
if (registeredClients.isEmpty()) {
this.interrupt();
}
} }
} }
} }