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")
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!
try {
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.
*/
public static void init() {
static void init() {
if (constructorHashMap != null) {
return;
}
@ -59,6 +59,7 @@ public final class ConstructorDetector {
* @return The class related to CONSTRUCTOR.
*/
public static Class getClass(int CONSTRUCTOR) {
tryInit();
return constructorHashMap.getOrDefault(CONSTRUCTOR, null);
}
@ -69,6 +70,7 @@ public final class ConstructorDetector {
* @return The CONSTRUCTOR.
*/
public static int getConstructor(Class<? extends TdApi.Object> clazz) {
tryInit();
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);
private static boolean started = false;
private static volatile boolean started = false;
/**
* Initialize Tdlib
*
* @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) {
LoadLibrary.load("tdjni");
ConstructorDetector.init();
try {
NativeClientAccess.execute(new SetLogVerbosityLevel(1));
} catch (Throwable ex) {
LOG.error("Can't set verbosity level on startup", ex);
synchronized (Init.class) {
if (!started) {
LoadLibrary.load("tdjni");
ConstructorDetector.init();
try {
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 InternalClientManager(String implementationName) {
try {
Init.start();
} catch (Throwable ex) {
ex.printStackTrace();
System.exit(1);
}
this.implementationName = implementationName;
responseReceiver = new NativeResponseReceiver(this::handleClientEvents);
}
@ -46,6 +40,12 @@ public final class InternalClientManager implements AutoCloseable {
return false;
}
if (startCalled.compareAndSet(false, true)) {
try {
Init.start();
} catch (Throwable ex) {
ex.printStackTrace();
System.exit(1);
}
responseReceiver.start();
return true;
} else {
@ -54,14 +54,12 @@ public final class InternalClientManager implements AutoCloseable {
}
public static InternalClientManager get(String implementationName) {
InternalClientManager clientManager = INSTANCE.updateAndGet(val -> {
return INSTANCE.updateAndGet(val -> {
if (val == null) {
return new InternalClientManager(implementationName);
}
return val;
});
clientManager.startIfNeeded();
return clientManager;
}
private void handleClientEvents(int clientId,
@ -125,6 +123,7 @@ public final class InternalClientManager implements AutoCloseable {
}
public void registerClient(int clientId, ClientEventsHandler internalClient) {
this.startIfNeeded();
boolean replaced = registeredClientEventHandlers.put(clientId, internalClient) != null;
if (replaced) {
throw new IllegalStateException("Client " + clientId + " already registered");

View File

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