All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.jdbc.targetdriverdialect.TargetDriverDialectManager Maven / Gradle / Ivy

The newest version!
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed 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 software.amazon.jdbc.targetdriverdialect;

import java.sql.Driver;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.function.Function;
import java.util.logging.Logger;
import org.checkerframework.checker.nullness.qual.NonNull;
import software.amazon.jdbc.AwsWrapperProperty;
import software.amazon.jdbc.PropertyDefinition;
import software.amazon.jdbc.util.Messages;
import software.amazon.jdbc.util.StringUtils;

public class TargetDriverDialectManager implements TargetDriverDialectProvider {

  private static final Logger LOGGER = Logger.getLogger(TargetDriverDialectManager.class.getName());

  protected static TargetDriverDialect customDialect;

  public static final AwsWrapperProperty TARGET_DRIVER_DIALECT = new AwsWrapperProperty(
      "wrapperTargetDriverDialect", "",
      "A unique identifier for the target driver dialect.");

  public static final AwsWrapperProperty TARGET_DRIVER_AUTO_REGISTER = new AwsWrapperProperty(
      "targetDriverAutoRegister", "true",
      "Allows to auto-register a target driver.");

  /**
   * Every Dialect implementation SHOULD BE stateless!!!
   * Dialect objects are shared between different connections.
   * The order of entries in this map is the order in which dialects are called/verified.
   */
  protected static final Map knownDialectsByCode =
      new HashMap() {
        {
          put(TargetDriverDialectCodes.PG_JDBC, new PgTargetDriverDialect());
          put(TargetDriverDialectCodes.MYSQL_CONNECTOR_J, new MysqlConnectorJTargetDriverDialect());
          put(TargetDriverDialectCodes.MARIADB_CONNECTOR_J_VER_3, new MariadbTargetDriverDialect());
          put(TargetDriverDialectCodes.GENERIC, new GenericTargetDriverDialect());
        }
      };

  protected static final Map defaultDialectsByProtocol =
      new HashMap() {
        {
          put("jdbc:postgresql://", new PgTargetDriverDialect());
          put("jdbc:mysql://", new MysqlConnectorJTargetDriverDialect());
          put("jdbc:mariadb://", new MariadbTargetDriverDialect());
        }
      };

  static {
    PropertyDefinition.registerPluginProperties(TargetDriverDialectManager.class);
  }

  public static void setCustomDialect(final @NonNull TargetDriverDialect targetDriverDialect) {
    customDialect = targetDriverDialect;
  }

  public static void resetCustomDialect() {
    customDialect = null;
  }

  @Override
  public TargetDriverDialect getDialect(
      final @NonNull Driver driver,
      final @NonNull Properties props) throws SQLException {

    return this.getDialect(props, (targetDriverDialect -> targetDriverDialect.isDialect(driver)));
  }

  @Override
  public TargetDriverDialect getDialect(
      final @NonNull String dataSourceClass,
      final @NonNull Properties props) throws SQLException {

    return this.getDialect(props, (targetDriverDialect -> targetDriverDialect.isDialect(dataSourceClass)));
  }

  private TargetDriverDialect getDialect(
      final @NonNull Properties props,
      Function checkFunc) throws SQLException {

    if (customDialect != null) {
      if (checkFunc.apply(customDialect)) {
        this.logDialect("custom", customDialect);
        return customDialect;
      } else {
        LOGGER.warning(() -> Messages.get("TargetDriverDialectManager.customDialectNotSupported"));
      }
    }

    TargetDriverDialect result;
    String dialectCode = TARGET_DRIVER_DIALECT.getString(props);
    if (!StringUtils.isNullOrEmpty(dialectCode)) {
      result = knownDialectsByCode.get(dialectCode);
      if (result == null) {
        throw new SQLException(Messages.get(
            "TargetDriverDialectManager.unknownDialectCode",
            new Object[] {dialectCode}));
      }
      this.logDialect(dialectCode, result);
      return result;
    }

    for (Entry entry : knownDialectsByCode.entrySet()) {
      if (checkFunc.apply(entry.getValue())) {
        this.logDialect(entry.getKey(), entry.getValue());
        return entry.getValue();
      }
    }

    result = knownDialectsByCode.get(TargetDriverDialectCodes.GENERIC);
    this.logDialect(TargetDriverDialectCodes.GENERIC, result);
    return result;
  }

  private void logDialect(final String dialectCode, final TargetDriverDialect targetDriverDialect) {
    LOGGER.finest(() -> Messages.get(
        "TargetDriverDialectManager.useDialect",
        new Object[] {dialectCode, targetDriverDialect}));
  }

  /**
   * Tries to identify a driver corresponded to provided protocol and register it.
   * Driver registration may be disabled by provided configuration properties.
   *
   * @param protocol The protocol to identify a corresponding driver for registration.
   * @param props The properties
   * @return True, if a corresponding driver was found and registered.
   *        False, otherwise.
   * @throws SQLException when user provided invalid target driver dialect code,
   *        or when provided protocol is not recognized.
   */
  public boolean registerDriver(
      final @NonNull String protocol,
      final @NonNull Properties props) throws SQLException {

    if (!TARGET_DRIVER_AUTO_REGISTER.getBoolean(props)) {
      // Driver auto-registration isn't allowed.
      return false;
    }

    TargetDriverDialect targetDriverDialect = null;

    // Try to get a target driver dialect provided by the user.
    String dialectCode = TARGET_DRIVER_DIALECT.getString(props);
    if (!StringUtils.isNullOrEmpty(dialectCode)) {
      targetDriverDialect = knownDialectsByCode.get(dialectCode);
      if (targetDriverDialect == null) {
        throw new SQLException(Messages.get(
            "TargetDriverDialectManager.unknownDialectCode",
            new Object[] {dialectCode}));
      }
    }

    // Target driver dialect isn't found (or it's not provided by the user).
    // Try to find a dialect by provided protocol.
    if (targetDriverDialect == null) {
      targetDriverDialect = defaultDialectsByProtocol.get(protocol.toLowerCase());
      if (targetDriverDialect == null) {
        throw new SQLException(Messages.get(
            "TargetDriverDialectManager.unknownProtocol",
            new Object[] {protocol.toLowerCase()}));
      }
    }

    // Check if a driver associated with found dialect is registered. Register it if needed.
    if (!targetDriverDialect.isDriverRegistered()) {
      targetDriverDialect.registerDriver();
    }

    return true;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy