content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.activemq.artemis.tests.db.common;
  
  import java.io.File;
  import java.net.URL;
  import java.net.URLClassLoader;
  import java.sql.Connection;
  import java.sql.Driver;
  import java.sql.DriverManager;
  import java.util.ArrayList;
  import java.util.List;
  
  import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
  import org.apache.activemq.artemis.utils.RandomUtil;
  
  public enum Database {
     MYSQL("mysql"), POSTGRES("postgres"), ORACLE("oracle"), MSSQL("mssql"), DB2("db2"), JOURNAL("journal"), DERBY("derby");
  
     private String dbname;
     private boolean load;
     private String jdbcURI;
     private String driverClass;
     private Driver driver;
     private ClassLoader dbClassLoader;
  
     Database(String dbname) {
        this.dbname = dbname;
        load = Boolean.parseBoolean(System.getProperty(dbname + ".load", "false"));
     }
  
     public static ClassLoader defineClassLoader(File location, ClassLoader parentClassLoader) throws Exception {
        File[] jars = location.listFiles((dir, name) -> name.toLowerCase().endsWith(".jar"));
  
        URL[] url = new URL[jars.length];
  
        for (int i = 0; i < jars.length; i++) {
           url[i] = jars[i].toURI().toURL();
        }
  
        return new URLClassLoader(url, parentClassLoader);
     }
  
     public Connection getConnection() throws Exception {
        return switch (this) {
           case DERBY -> DriverManager.getConnection(getJdbcURI());
           case JOURNAL -> null;
           default -> getDriver().connect(getJdbcURI(), null);
        };
     }
  
     // There is one artemis server for each database we provide on the tests
     public ClassLoader getDBClassLoader() throws Exception {
        if (this != JOURNAL && this != DERBY && dbClassLoader == null) {
           String serverLocation = ParameterDBTestBase.getServerLocation(getName());
           File lib = new File(serverLocation + "/lib");
           dbClassLoader = defineClassLoader(lib, getClass().getClassLoader());
        }
        return dbClassLoader;
     }
  
     public String getName() {
        return dbname;
     }
  
     public String getJdbcURI() {
        if (jdbcURI == null) {
           switch (this) {
              case DERBY:
                 String derbyData = ParameterDBTestBase.getServerLocation("derby") + "/data/derby/db";
                 jdbcURI = "jdbc:derby:" + derbyData + ";create=true";
                 break;
              case JOURNAL:
                 jdbcURI = null;
                 break;
              default:
                 jdbcURI = System.getProperty(dbname + ".uri");
                 if (jdbcURI != null) {
                    jdbcURI = jdbcURI.replaceAll("&#38;", "&");
                 }
           }
        }
        return jdbcURI;
     }
  
     public String getDriverClass() {
        if (driverClass != null) {
           return driverClass;
        }
  
        switch (this) {
           case DERBY:
              this.driverClass = ActiveMQDefaultConfiguration.getDefaultDriverClassName();
              break;
           case JOURNAL:
              this.driverClass = null;
              break;
           default:
              driverClass = System.getProperty(dbname + ".class");
        }
  
        return driverClass;
     }
  
     public Driver getDriver() throws Exception {
        if (driver == null) {
           String className = getDriverClass();
           ClassLoader loader = getDBClassLoader();
           driver = (Driver) loader.loadClass(className).getDeclaredConstructor().newInstance();
        }
        return driver;
     }
  
     // this must be called within the test classLoader (Thread Context Class Loader)
     public void registerDriver() throws Exception {
        if (driver != null) {
           DriverManager.registerDriver(driver);
        }
     }
  
     public boolean isLoad() {
        return load;
     }
  
     @Override
     public String toString() {
        return dbname;
     }
  
  
     // it will return a list of Databases selected to be tested
     public static List<Database> selectedList() {
        List<Database> dbList = new ArrayList<>();
  
        for (Database db : Database.values()) {
           if (db.isLoad()) {
              dbList.add(db);
           }
        }
  
        return dbList;
     }
  
     public static Database randomDB() {
        List<Database> selectedDatabases = selectedList();
        if (selectedDatabases.isEmpty()) {
           return null;
        } else {
           return selectedDatabases.get(RandomUtil.randomInterval(0, selectedDatabases.size()));
        }
     }
  
     public static List<Database> randomList() {
        List<Database> selectedDatabases = selectedList();
        List<Database> list = new ArrayList<>();
        Database randomDB = randomDB();
        if (randomDB != null) {
           list.add(randomDB);
        }
        return list;
     }
  
  }
  