blob: ce4f33684c66604c69d71df12f69d7816fc8a9f9 [file] [log] [blame]
/*
* 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.asterix.jdbc.core;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
public abstract class ADBDriverBase {
static final int JDBC_MAJOR_VERSION = 4;
static final int JDBC_MINOR_VERSION = 2;
static final String JDBC_SCHEME = "jdbc:";
static final String LOGGING_PROPERTY_SUFFIX = ".log.stderr";
protected final String urlScheme;
protected final int defaultApiPort;
private volatile ADBDriverContext context;
public ADBDriverBase(String driverScheme, int defaultApiPort) {
this.urlScheme = JDBC_SCHEME + Objects.requireNonNull(driverScheme);
this.defaultApiPort = defaultApiPort;
}
protected static void registerDriver(java.sql.Driver driver) {
try {
DriverManager.registerDriver(driver);
} catch (SQLException e) {
DriverManager.println(String.format("Error registering driver %s. %s", driver.getClass().getName(), e));
}
}
protected static void parseConnectionProperties(Properties inProps, ADBDriverContext driverContext,
Map<ADBDriverProperty, Object> outProperties, SQLWarning outWarning) throws SQLException {
if (inProps != null) {
for (Enumeration<?> en = inProps.propertyNames(); en.hasMoreElements();) {
String name = en.nextElement().toString();
String value = inProps.getProperty(name);
parseConnectionProperty(name, value, driverContext, outProperties, outWarning);
}
}
}
protected static void parseConnectionProperty(String name, String textValue, ADBDriverContext driverContext,
Map<ADBDriverProperty, Object> outProperties, SQLWarning outWarning) throws SQLException {
ADBDriverProperty property = driverContext.getSupportedProperties().get(name);
if (property == null) {
outWarning.setNextWarning(
new SQLWarning(driverContext.getErrorReporter().warningParameterNotSupported(name)));
return;
}
if (textValue == null || textValue.isEmpty()) {
return;
}
Object value;
try {
value = Objects.requireNonNull(property.getValueParser().apply(textValue));
} catch (RuntimeException e) {
throw driverContext.getErrorReporter().errorParameterValueNotSupported(name);
}
outProperties.put(property, value);
}
private static Logger getParentLogger(Class<?> driverClass) {
return Logger.getLogger(driverClass.getPackage().getName());
}
protected static void setupLogging(Class<? extends java.sql.Driver> driverClass) {
String logLevel = System.getProperty(driverClass.getPackage().getName() + LOGGING_PROPERTY_SUFFIX);
if (logLevel == null) {
return;
}
Level level;
try {
level = Boolean.TRUE.toString().equals(logLevel) ? Level.ALL : Level.parse(logLevel.toUpperCase());
} catch (IllegalArgumentException e) {
// ignore
return;
}
ConsoleHandler ch = new ConsoleHandler();
ch.setLevel(level);
Logger parentLogger = getParentLogger(driverClass);
parentLogger.setLevel(level);
parentLogger.addHandler(ch);
}
public boolean acceptsURL(String url) {
return url.startsWith(urlScheme);
}
public Connection connect(String url, Properties info) throws SQLException {
if (!acceptsURL(url)) {
return null;
}
URI subUri;
try {
subUri = new URI(url.substring(JDBC_SCHEME.length()));
} catch (URISyntaxException e) {
throw createErrorReporter().errorParameterValueNotSupported("URL");
}
String host = subUri.getHost();
if (host == null) {
throw createErrorReporter().errorParameterValueNotSupported("URL");
}
int port = subUri.getPort();
if (port <= 0) {
port = defaultApiPort;
}
Properties uriParams = getURIParameters(subUri);
ADBDriverContext driverContext = getOrCreateDriverContext();
SQLWarning warning = new SQLWarning();
Map<ADBDriverProperty, Object> properties = new HashMap<>();
parseConnectionProperties(uriParams, driverContext, properties, warning);
parseConnectionProperties(info, driverContext, properties, warning);
warning = warning.getNextWarning() != null ? warning.getNextWarning() : null;
String path = subUri.getPath();
String dataverseCanonicalName =
path != null && path.length() > 1 && path.startsWith("/") ? path.substring(1) : null;
ADBProtocolBase protocol = createProtocol(host, port, properties, driverContext);
try {
String databaseVersion = protocol.connect();
return createConnection(protocol, url, databaseVersion, dataverseCanonicalName, properties, warning);
} catch (SQLException e) {
try {
protocol.close();
} catch (SQLException e2) {
e.addSuppressed(e2);
}
throw e;
}
}
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
Collection<ADBDriverProperty> supportedProperties =
getOrCreateDriverContext().getSupportedProperties().values();
List<DriverPropertyInfo> result = new ArrayList<>(supportedProperties.size());
for (ADBDriverProperty property : supportedProperties) {
if (property.isHidden()) {
continue;
}
Object defaultValue = property.getDefaultValue();
DriverPropertyInfo propInfo = new DriverPropertyInfo(property.getPropertyName(),
defaultValue != null ? defaultValue.toString() : null);
result.add(propInfo);
}
return result.toArray(new DriverPropertyInfo[0]);
}
public int getMajorVersion() {
return getOrCreateDriverContext().getDriverVersion().getMajorVersion();
}
public int getMinorVersion() {
return getOrCreateDriverContext().getDriverVersion().getMinorVersion();
}
public boolean jdbcCompliant() {
return false;
}
public Logger getParentLogger() {
return getParentLogger(getClass());
}
protected Logger getLogger() {
return Logger.getLogger(getClass().getName());
}
private ADBDriverContext getOrCreateDriverContext() {
ADBDriverContext ctx = context;
if (ctx == null) {
synchronized (this) {
ctx = context;
if (ctx == null) {
context = ctx = createDriverContext();
}
}
}
return ctx;
}
protected ADBDriverContext createDriverContext() {
return new ADBDriverContext(getDriverVersion(), getDriverSupportedProperties(), createErrorReporter(),
getLogger());
}
protected ADBProductVersion getDriverVersion() {
return ADBProductVersion.parseDriverVersion(getClass().getPackage());
}
protected Collection<ADBDriverProperty> getDriverSupportedProperties() {
return Arrays.asList(ADBDriverProperty.Common.values());
}
protected ADBErrorReporter createErrorReporter() {
return new ADBErrorReporter();
}
protected abstract ADBProtocolBase createProtocol(String host, int port, Map<ADBDriverProperty, Object> properties,
ADBDriverContext driverContext) throws SQLException;
protected ADBConnection createConnection(ADBProtocolBase protocol, String url, String databaseVersion,
String dataverseCanonicalName, Map<ADBDriverProperty, Object> properties, SQLWarning connectWarning)
throws SQLException {
return new ADBConnection(protocol, url, databaseVersion, dataverseCanonicalName, properties, connectWarning);
}
protected abstract Properties getURIParameters(URI uri) throws SQLException;
}