package com.airlock.iam.core.infrastructure;

import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.google.common.annotations.VisibleForTesting;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.lang.reflect.Method;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Optional;

public final class JdbcCleanup {
   private static final ELogger LOG = ELoggerFactory.getLogger(JdbcCleanup.class);

   private JdbcCleanup() {
   }

   public static void deregisterJdbcDrivers() {
      stopMysqlThread();
      DriverManager.getDrivers();
      Enumeration<Driver> drivers = DriverManager.getDrivers();

      while (drivers.hasMoreElements()) {
         Driver driver = drivers.nextElement();
         if (driver.getClass().getClassLoader() == JdbcCleanup.class.getClassLoader()) {
            try {
               LOG.debug("Deregistering JDBC driver " + driver.getClass().getName());
               DriverManager.deregisterDriver(driver);
            } catch (SQLException | RuntimeException e) {
               LOG.debug("Ignoring exception while deregistering driver " + driver.getClass().getName() + ": " + e.getMessage());
            }
         }
      }
   }

   @SuppressFBWarnings({"DE_MIGHT_IGNORE", "REC_CATCH_EXCEPTION"})
   private static void stopMysqlThread() {
      try {
         Optional<Method> shutdownMethod = getShutdownMethod();
         if (shutdownMethod.isPresent()) {
            LOG.debug("Stopping MySQL's AbandonedConnectionCleanupThread...");
            shutdownMethod.get().invoke(null);
            Thread.sleep(500L);
         }
      } catch (Exception var1) {
      }
   }

   @VisibleForTesting
   static Optional<Method> getShutdownMethod() {
      Optional<Class<?>> cleanupThreadClass = getCleanupThreadClass();
      if (cleanupThreadClass.isPresent()) {
         try {
            return Optional.of(cleanupThreadClass.get().getMethod("checkedShutdown"));
         } catch (NoSuchMethodException e) {
            return Optional.empty();
         }
      } else {
         return Optional.empty();
      }
   }

   @VisibleForTesting
   static Optional<Class<?>> getCleanupThreadClass() {
      try {
         return Optional.of(Class.forName("com.mysql.jdbc.AbandonedConnectionCleanupThread"));
      } catch (Exception e) {
         try {
            return Optional.of(Class.forName("com.mysql.cj.jdbc.AbandonedConnectionCleanupThread"));
         } catch (Exception ex) {
            return Optional.empty();
         }
      }
   }
}
