/**
* 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.
*
* Copyright 2012-2016 the original author or authors.
*/
package org.assertj.db.type;
import org.assertj.db.type.lettercase.LetterCase;
import org.assertj.db.type.lettercase.WithLetterCase;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* This class represents element from the database (either a {@link AbstractDbData} or a {@link Change}).
* So this class contains : the way to access the database with {@link #getSource()} and {@link #getDataSource()} (one
* of them need to be set before loading the data).<br>
*
* @author RĂ©gis Pouiller
*
* @param <D> Class of the subclass (an implementation of {@link AbstractDbElement}) : useful for the fluent methods
* (setters).
*/
public abstract class AbstractDbElement<D extends AbstractDbElement<D>> implements DbElement, WithLetterCase {
/**
* Class of the element.
*/
protected final D myself;
/**
* Source of the data.
*/
private Source source;
/**
* Data source.
*/
private DataSource dataSource;
/**
* Letter case of the tables.
* @since 1.1.0
*/
private LetterCase tableLetterCase;
/**
* Letter case of the columns.
* @since 1.1.0
*/
private LetterCase columnLetterCase;
/**
* Letter case of the primary keys.
* @since 1.1.0
*/
private LetterCase primaryKeyLetterCase;
/**
* Default constructor.
* @param selfType Class of this element : a sub-class of {@code AbstractDbElement}.
*/
AbstractDbElement(Class<D> selfType) {
myself = selfType.cast(this);
setLetterCases();
}
/**
* Constructor.
* @param selfType Class of this element : a sub-class of {@code AbstractDbElement}.
* @param source The {@link Source} to connect to the database (must be not {@code null}).
* @throws NullPointerException If {@code source} is {@code null}.
*/
AbstractDbElement(Class<D> selfType, Source source) {
this(selfType);
this.source = source;
setLetterCases();
}
/**
* Constructor.
* @param selfType Class of this element : a sub-class of {@code AbstractDbElement}.
* @param dataSource The {@link DataSource} (must be not {@code null}).
* @throws NullPointerException If {@code dataSource} is {@code null}.
*/
AbstractDbElement(Class<D> selfType, DataSource dataSource) {
this(selfType);
this.dataSource = dataSource;
setLetterCases();
}
/**
* Sets the letter cases from informations in parameters.
* @param tableLetterCase Letter case of the tables.
* @param columnLetterCase Letter case of the columns.
* @param primaryKeyLetterCase Letter case of the primary keys.
* @return The actual instance.
*/
D setLetterCases(LetterCase tableLetterCase, LetterCase columnLetterCase, LetterCase primaryKeyLetterCase) {
this.tableLetterCase = tableLetterCase;
this.columnLetterCase = columnLetterCase;
this.primaryKeyLetterCase = primaryKeyLetterCase;
return myself;
}
/**
* Sets the letter cases from informations in {@code dataSource} and {@code source}.
*/
private void setLetterCases() {
if (dataSource instanceof WithLetterCase) {
WithLetterCase withLetterCase = (WithLetterCase) dataSource;
tableLetterCase = withLetterCase.getTableLetterCase();
columnLetterCase = withLetterCase.getColumnLetterCase();
primaryKeyLetterCase = withLetterCase.getPrimaryKeyLetterCase();
}
else if (source instanceof WithLetterCase) {
WithLetterCase withLetterCase = (WithLetterCase) source;
tableLetterCase = withLetterCase.getTableLetterCase();
columnLetterCase = withLetterCase.getColumnLetterCase();
primaryKeyLetterCase = withLetterCase.getPrimaryKeyLetterCase();
}
else {
tableLetterCase = LetterCase.TABLE_DEFAULT;
columnLetterCase = LetterCase.COLUMN_DEFAULT;
primaryKeyLetterCase = LetterCase.PRIMARY_KEY_DEFAULT;
}
}
/**
* {@inheritDoc}
*/
@Override
public LetterCase getColumnLetterCase() {
return columnLetterCase;
}
/**
* {@inheritDoc}
*/
@Override
public LetterCase getPrimaryKeyLetterCase() {
return primaryKeyLetterCase;
}
/**
* {@inheritDoc}
*/
@Override
public LetterCase getTableLetterCase() {
return tableLetterCase;
}
/**
* Return the source.
*
* @see #setSource(Source)
* @return The {@link Source} to connect.
*/
public Source getSource() {
return source;
}
/**
* Sets the source.
*
* @see #getSource()
* @param source {@link Source} to connect to the database (must be not {@code null}).
* @return The actual instance.
* @throws NullPointerException If {@code source} is {@code null}.
*/
public D setSource(Source source) {
if (source == null) {
throw new NullPointerException("source must be not null");
}
this.source = source;
this.dataSource = null;
setLetterCases();
return myself;
}
/**
* Return the data source.
*
* @see #setDataSource(DataSource)
* @return The data source.
*/
public DataSource getDataSource() {
return dataSource;
}
/**
* Sets the data source.
*
* @see #getDataSource()
* @param dataSource The {@link DataSource} (must be not {@code null}).
* @return The actual instance.
* @throws NullPointerException If {@code dataSource} is {@code null}.
*/
public D setDataSource(DataSource dataSource) {
if (dataSource == null) {
throw new NullPointerException("dataSource must be not null");
}
this.source = null;
this.dataSource = dataSource;
setLetterCases();
return myself;
}
/**
* Returns a {@link Connection} from a {@link DataSource} or from a {@link Source}.
*
* @return A {@link Connection} differently, depending if it is a {@link DataSource} or a {@link Source}.
* @throws SQLException SQL Exception
*/
protected Connection getConnection() throws SQLException {
if (dataSource == null && source == null) {
throw new NullPointerException("connection or dataSource must be not null");
}
// Get a Connection differently, depending if it is a DataSource or a Source.
if (dataSource != null) {
return dataSource.getConnection();
} else {
return DriverManager.getConnection(source.getUrl(), source.getUser(), source.getPassword());
}
}
/**
* Returns the catalog from a connection.
* @param connection The connection with the catalog
* @return The catalog from a connection.
* @throws SQLException SQL Exception
*/
protected static String getCatalog(Connection connection) throws SQLException {
try {
return connection.getCatalog();
}
catch (SQLException exception) {
throw exception;
}
catch (Throwable throwable) {
return null;
}
}
/**
* Returns the schema from a connection.
* @param connection The connection with the catalog
* @return The schema from a connection.
* @throws SQLException SQL Exception
*/
protected static String getSchema(Connection connection) throws SQLException {
try {
return connection.getSchema();
}
catch (SQLException exception) {
throw exception;
}
catch (Throwable throwable) {
return null;
}
}
}