package adql.db;
/*
* This file is part of ADQLLibrary.
*
* ADQLLibrary is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ADQLLibrary is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2012-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institut (ARI)
*/
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Default implementation of {@link DBTable}.
*
* @author Grégory Mantelet (CDS;ARI)
* @version 1.4 (08/2015)
*/
public class DefaultDBTable implements DBTable {
protected String dbCatalogName;
protected String dbSchemaName;
protected String dbName;
protected String adqlCatalogName = null;
protected String adqlSchemaName = null;
protected String adqlName = null;
protected Map<String,DBColumn> columns = new LinkedHashMap<String,DBColumn>();
/**
* <p>Builds a default {@link DBTable} with the given DB name.</p>
*
* <p>With this constructor: ADQL name = DB name.</p>
*
* <p><i><u>Note:</u> The table name can be prefixed by a schema and a catalog: t1 or schema1.t1 or cat1.schema1.t2</i></p>
*
* @param dbName Database name (it will be also used as ADQL table name).
*
* @see #DefaultDBTable(String, String)
*/
public DefaultDBTable(final String dbName){
this(dbName, null);
}
/**
* <p>Builds a default {@link DBTable} with the given DB and ADQL names.</p>
*
* <p><i><u>Note:</u> The table names can be prefixed by a schema and a catalog: t1 or schema1.t1 or cat1.schema1.t2</i></p>
*
* @param dbName Database name.
* @param adqlName Name used in ADQL queries.
*/
public DefaultDBTable(final String dbName, final String adqlName){
// DB names:
String[] names = splitTableName(dbName);
if (names[2] == null || names[2].length() == 0)
throw new NullPointerException("Missing DB name !");
else
this.dbName = names[2];
this.dbSchemaName = names[1];
this.dbCatalogName = names[0];
// ADQL names:
names = splitTableName(adqlName);
if (names[2] == null || names[2].length() == 0){
this.adqlName = this.dbName;
this.adqlSchemaName = this.dbSchemaName;
this.adqlCatalogName = this.dbCatalogName;
}else{
this.adqlName = names[2];
this.adqlSchemaName = names[1];
this.adqlCatalogName = names[0];
}
}
/**
* Builds default {@link DBTable} with a DB catalog, schema and table names.
*
* @param dbCatName Database catalog name (it will be also used as ADQL catalog name).
* @param dbSchemName Database schema name (it will be also used as ADQL schema name).
* @param dbName Database table name (it will be also used as ADQL table name).
*
* @see #DefaultDBTable(String, String, String, String, String, String)
*/
public DefaultDBTable(final String dbCatName, final String dbSchemName, final String dbName){
this(dbCatName, null, dbSchemName, null, dbName, null);
}
/**
* Builds default {@link DBTable} with the DB and ADQL names for the catalog, schema and table.
*
* @param dbCatName Database catalog name.
* @param adqlCatName Catalog name used in ADQL queries.
* <em>If NULL, it will be set to dbCatName.</em>
* @param dbSchemName Database schema name.
* @param adqlSchemName Schema name used in ADQL queries.
* <em>If NULL, it will be set to dbSchemName.</em>
* @param dbName Database table name.
* @param adqlName Table name used in ADQL queries.
* <em>If NULL, it will be set to dbName.</em>
*/
public DefaultDBTable(final String dbCatName, final String adqlCatName, final String dbSchemName, final String adqlSchemName, final String dbName, final String adqlName){
if (dbName == null || dbName.length() == 0)
throw new NullPointerException("Missing DB name !");
this.dbName = dbName;
this.adqlName = (adqlName == null) ? dbName : adqlName;
dbSchemaName = dbSchemName;
adqlSchemaName = (adqlSchemName == null) ? dbSchemName : adqlSchemName;
dbCatalogName = dbCatName;
adqlCatalogName = (adqlCatName == null) ? dbCatName : adqlCatName;
}
@Override
public final String getDBName(){
return dbName;
}
@Override
public final String getDBSchemaName(){
return dbSchemaName;
}
@Override
public final String getDBCatalogName(){
return dbCatalogName;
}
@Override
public final String getADQLName(){
return adqlName;
}
public void setADQLName(final String name){
adqlName = (name != null) ? name : dbName;
}
@Override
public final String getADQLSchemaName(){
return adqlSchemaName;
}
public void setADQLSchemaName(final String name){
adqlSchemaName = (name != null) ? name : dbSchemaName;
}
@Override
public final String getADQLCatalogName(){
return adqlCatalogName;
}
public void setADQLCatalogName(final String name){
adqlName = (name != null) ? null : dbName;
}
/**
* <p>Case sensitive !</p>
* <p>Research optimized for researches by ADQL name.</p>
*
* @see adql.db.DBTable#getColumn(java.lang.String, boolean)
*/
@Override
public DBColumn getColumn(String colName, boolean byAdqlName){
if (byAdqlName)
return columns.get(colName);
else{
for(DBColumn col : columns.values()){
if (col.getDBName().equals(colName))
return col;
}
return null;
}
}
public boolean hasColumn(String colName, boolean byAdqlName){
return (getColumn(colName, byAdqlName) != null);
}
@Override
public Iterator<DBColumn> iterator(){
return columns.values().iterator();
}
public void addColumn(DBColumn column){
if (column != null)
columns.put(column.getADQLName(), column);
}
public void addAllColumns(Collection<DBColumn> colList){
if (colList != null){
for(DBColumn column : colList)
addColumn(column);
}
}
/**
* Splits the given table name in 3 parts: catalog, schema, table.
*
* @param table The table name to split.
*
* @return A String array of 3 items: [0]=catalog, [1]=schema, [0]=table.
*/
public static final String[] splitTableName(final String table){
String[] splitRes = new String[]{null,null,null};
if (table == null || table.trim().length() == 0)
return splitRes;
String[] names = table.trim().split("\\.");
switch(names.length){
case 1:
splitRes[2] = table.trim();
break;
case 2:
splitRes[2] = names[1].trim();
splitRes[1] = names[0].trim();
break;
case 3:
splitRes[2] = names[2].trim();
splitRes[1] = names[1].trim();
splitRes[0] = names[0].trim();
break;
default:
splitRes[2] = names[names.length - 1].trim();
splitRes[1] = names[names.length - 2].trim();
StringBuffer buff = new StringBuffer(names[0].trim());
for(int i = 1; i < names.length - 2; i++)
buff.append('.').append(names[i].trim());
splitRes[0] = buff.toString();
}
return splitRes;
}
/**
* <p>Join the last 3 items of the given string array with a dot ('.').
* These three parts should be: [0]=catalog name, [1]=schema name, [2]=table name.</p>
*
* <p>
* If the array contains less than 3 items, all the given items will be though joined.
* However, if it contains more than 3 items, only the three last items will be.
* </p>
*
* <p>A null item will be written as an empty string (string of length 0 ; "").</p>
*
* <p>
* In the case the first and the third items are not null, but the second is null, the final string will contain in the middle two dots.
* Example: if the array is {"cat", NULL, "table"}, then the joined string will be: "cat..table".
* </p>
*
* @param nameParts String items to join.
*
* @return A string joining the 3 last string items of the given array,
* or an empty string if the given array is NULL.
*
* @since 1.3
*/
public static final String joinTableName(final String[] nameParts){
if (nameParts == null)
return "";
StringBuffer str = new StringBuffer();
boolean empty = true;
for(int i = (nameParts.length <= 3) ? 0 : (nameParts.length - 3); i < nameParts.length; i++){
if (!empty)
str.append('.');
String part = (nameParts[i] == null) ? null : nameParts[i].trim();
if (part != null && part.length() > 0){
str.append(part);
empty = false;
}
}
return str.toString();
}
@Override
public DBTable copy(String dbName, String adqlName){
dbName = (dbName == null) ? joinTableName(new String[]{dbCatalogName,dbSchemaName,this.dbName}) : dbName;
adqlName = (adqlName == null) ? joinTableName(new String[]{adqlCatalogName,adqlSchemaName,this.adqlName}) : adqlName;
DefaultDBTable copy = new DefaultDBTable(dbName, adqlName);
for(DBColumn col : this){
if (col instanceof DBCommonColumn)
copy.addColumn(new DBCommonColumn((DBCommonColumn)col, col.getDBName(), col.getADQLName()));
else
copy.addColumn(col.copy(col.getDBName(), col.getADQLName(), copy));
}
return copy;
}
}