Skip to content
TSMUtil.java 15.6 KiB
Newer Older
/* 
 * _____________________________________________________________________________
 * 
 * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
 * Trieste INAF - IA2 Italian Center for Astronomical Archives
 * _____________________________________________________________________________
 * 
 * Copyright (C) 2016 Istituto Nazionale di Astrofisica
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License Version 3 as published by the
 * Free Software Foundation.
 * 
 * This program 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 General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import it.inaf.ia2.tsm.api.contract.DatabaseType;
import it.inaf.ia2.tsm.api.contract.ChildEntity;
import it.inaf.ia2.tsm.api.contract.Column;
import it.inaf.ia2.tsm.api.contract.Key;
import it.inaf.ia2.tsm.api.contract.KeyColumn;
import it.inaf.ia2.tsm.api.contract.Schema;
import it.inaf.ia2.tsm.api.contract.Status;
import it.inaf.ia2.tsm.api.contract.Table;
import it.inaf.ia2.tsm.api.contract.TapSchema;
import it.inaf.ia2.tsm.api.contract.TapSchemaEntity;
import it.inaf.ia2.tsm.api.contract.TapSchemaVersion;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.postgresql.ds.PGPoolingDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 * Utility class that contains some static methods to manage various operations
 * with the TAP_SCHEMA entities.
 * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
public class TSMUtil {
    private static final Logger log = LoggerFactory.getLogger(TSMUtil.class);
    public static DataSource createDataSource(Credentials credentials) {

        switch (credentials.getDatabaseType()) {

            case MYSQL:
                MysqlDataSource myds = new MysqlDataSource();

                myds.setServerName(credentials.getHostname());
                myds.setPortNumber(credentials.getPort());
                myds.setUser(credentials.getUsername());
                myds.setPassword(credentials.getPassword());

                return myds;

            case POSTGRES:
                PGPoolingDataSource pgds = new PGPoolingDataSource();

                pgds.setServerName(credentials.getHostname());
                pgds.setPortNumber(credentials.getPort());
                pgds.setUser(credentials.getUsername());
                pgds.setPassword(credentials.getPassword());
                pgds.setDatabaseName(credentials.getDatabase());

                return pgds;

            default:
                throw new UnsupportedOperationException(credentials.getDatabaseType() + " not supported yet.");
        }
    }

    protected static List<String> sortStringsList(List<String> list) {
        Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
        return list;
    }

    protected static <T extends ChildEntity> List<T> getChildrenByStatus(Iterable<T> entities, Status... statuses) {
        List<T> ret = new ArrayList<>();
        for (T child : entities) {
            if (statuses == null || statuses.length == 0) {
Sonia Zorba's avatar
Sonia Zorba committed
                if (child != null) {
                    ret.add(child);
                }
            } else {
                for (Status status : statuses) {
                    if (child != null && child.getStatus().equals(status)) {
                        ret.add(child);
                        break;
                    }
                }
            }
        }
        return Collections.unmodifiableList(ret);
    }

    protected static <T extends ChildEntity> T getChild(Map<String, T> children, String childName, Status... statuses) {
        T child = children.get(childName);
        if (child == null) {
            return null;
        }
        if (statuses == null || statuses.length == 0) {
            return child;
        }
        for (Status status : statuses) {
            if (child.getStatus().equals(status)) {
                return child;
    protected static <T extends ChildEntity> List<String> getAddableChildrenNames(Map<String, T> children) {
        List<String> list = new ArrayList<>();

        for (Map.Entry<String, T> entry : children.entrySet()) {
            T entity = entry.getValue();
            if (entity == null || entity.getStatus() == Status.LOADED) {
                list.add(entry.getKey());
            }
        }
        return Collections.unmodifiableList(list);
    }

     * This method is thought for avoiding various problem encountered using the
     * standard {@code ResultSet} {@code getObject()} method.
     * In particular:
     * <ul>
     * <li>In some cases the {@code getObject()} method (e.g. with
     * {@code Integer.class}) returns 0 instead of null.
     * </li>
     * <li>
     * Method
     * {@code org.postgresql.jdbc4.Jdbc4ResultSet.getObject(int, Class<T>)} is
     * not yet implemented.
     * </li>
     * </ul>
    protected static <T> T getObject(ResultSet rs, String key, Class<T> type) throws SQLException {
        T ret;
        if (type == String.class) {
            ret = (T) rs.getString(key);
        } else if (type == Integer.class) {
            ret = (T) (Integer) rs.getInt(key);
        } else if (type == Long.class) {
            ret = (T) (Long) rs.getLong(key);
        } else if (type == Boolean.class) {
            ret = (T) (Boolean) rs.getBoolean(key);
        } else {
            throw new UnsupportedOperationException("Type " + type.getCanonicalName() + " not supported by " + TSMUtil.class.getCanonicalName() + " getObject() method");
     * Same as {@link DLUtil.getObject(ResultSet, String, Class<T>)}.
    protected static <T> T getObject(ResultSet rs, int i, Class<T> type) throws SQLException {
        T ret;
        if (type == String.class) {
            ret = (T) rs.getString(i);
        } else if (type == Integer.class) {
            ret = (T) (Integer) rs.getInt(i);
        } else if (type == Long.class) {
            ret = (T) (Long) rs.getLong(i);
        } else if (type == Boolean.class) {
            ret = (T) (Boolean) rs.getBoolean(i);
        } else {
            throw new UnsupportedOperationException("Type " + type.getCanonicalName() + " not supported by " + TSMUtil.class.getCanonicalName() + " getObject() method");
    protected static DataSource getSchemaDataSource(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) {
        return schemaName.equals(tapSchema.getName()) ? dbWrapper.getTapSchemaDataSource() : dbWrapper.getSourceDataSource();
    }

    protected static DatabaseType getSchemaDatabaseType(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) {
        return schemaName.equals(tapSchema.getName()) ? dbWrapper.getTapSchemaDatabaseType() : dbWrapper.getSourceDatabaseType();
    }

    protected static boolean isTapSchema(TapSchema tapSchema, String schemaName) {
        return schemaName.equals(tapSchema.getName());
    }

    protected static UnsupportedOperationException getUnsupportedOperationException(TapSchemaVersion version, String unsupportedFeature) {
        return new UnsupportedOperationException("Version \"" + version.name() + "\" doesn't support " + unsupportedFeature);
    }

    protected static boolean is1_1(TapSchemaVersion version) {
        return version == TapSchemaVersion.TAP_SCHEMA_1_1 || version == TapSchemaVersion.TAP_SCHEMA_1_1_IA2;
    }

    protected static boolean isIA2(TapSchemaVersion version) {
        return version == TapSchemaVersion.TAP_SCHEMA_1_IA2 || version == TapSchemaVersion.TAP_SCHEMA_1_1_IA2;
    }

    protected static String escapeName(String name, DatabaseType dbType) {
        char escapeChar;
        switch (dbType) {
            case MYSQL:
                escapeChar = '`';
                break;
            case POSTGRES:
                escapeChar = '"';
                break;
            default:
                throw new UnsupportedOperationException("Database type " + dbType + " not supported");
        }

        return String.format("%s%s%s", escapeChar, name, escapeChar);
    }

    protected static String getTapSchemaTableNameFromEntity(TapSchemaEntity entity) {
        if (entity instanceof Schema) {
            return TapSchema.SCHEMAS_TABLE;
        } else if (entity instanceof Table) {
            return TapSchema.TABLES_TABLE;
        } else if (entity instanceof Column) {
            return TapSchema.COLUMNS_TABLE;
        } else if (entity instanceof Key) {
            return TapSchema.KEYS_TABLE;
        } else if (entity instanceof KeyColumn) {
            return TapSchema.KEY_COLUMNS_TABLE;
        }
        log.warn("getTapSchemaTableNameFromEntity returns null for {}" + entity.getClass().getCanonicalName());
        return null;
    private static void setTSColumnDescription(Table table, String columnName, String description) {
        Column column = table.getChild(columnName);
        column.setDescription(description);
        column.setStd(true);
    public static String getNaturalLangueName(TapSchemaEntity entity) {
        if (entity instanceof Schema) {
            return "schema";
        } else if (entity instanceof Table) {
            return "table";
        } else if (entity instanceof Column) {
            return "column";
        } else if (entity instanceof Key) {
            return "key";
        } else if (entity instanceof KeyColumn) {
            return "key_column";
        } else {
            throw new UnsupportedOperationException("entity class " + entity.getClass().getCanonicalName() + " not supported yet");
        }
    }

    public static String getName(TapSchemaEntity entity) {
        if (entity instanceof Schema) {
            return ((Schema) entity).getName();
        } else if (entity instanceof Table) {
            return ((Table) entity).getCompleteName();
        } else if (entity instanceof Column) {
            Column column = (Column) entity;
            return column.getParent().getCompleteName() + "." + column.getName();
        } else if (entity instanceof Key) {
            return printKeyInfo((Key) entity);
        } else if (entity instanceof KeyColumn) {
            KeyColumn keyColumn = (KeyColumn) entity;
            return String.format("%s -> %s [key: %s]",
                    keyColumn.getFromColumn(), keyColumn.getTargetColumn(),
                    printKeyInfo(keyColumn.getParent()));
        } else {
            throw new UnsupportedOperationException("entity class " + entity.getClass().getCanonicalName() + " not supported yet");
        }
    }

    public static String printKeyInfo(Key key) {
        StringBuilder sb = new StringBuilder();

        sb.append(String.format("[%s] %s(", key.getId(), key.getFromTableCompleteName()));

        boolean first = true;
        for (KeyColumn keyColumn : key.getKeyColumns()) {
            if (!first) {
                sb.append(",");
            }
            first = false;
            sb.append(keyColumn.getFromColumn());
        }

        sb.append(String.format(") -> %s(", key.getTargetTableCompleteName()));

        first = true;
        for (KeyColumn keyColumn : key.getKeyColumns()) {
            if (!first) {
                sb.append(",");
            }
            first = false;
            sb.append(keyColumn.getTargetColumn());
        }

        sb.append(")");

        return sb.toString();
    }

    /**
     * Fill descriptions of the TAP_SCHEMA schema entities.
     *
     * @param schema the TAP_SCHEMA schema <code>SchemaEntity</code>.
     */
    protected static void putInfoIntoTapSchemaSchema(Schema schema) {

        schema.setDescription("a special schema to describe a TAP tableset");

        // SCHEMAS
        Table schemasTable = schema.getChild("schemas");
        schemasTable.setDescription("description of schemas in this tableset");

        setTSColumnDescription(schemasTable, "schema_name", "schema name for reference to TAP_SCHEMA.schemas");
        setTSColumnDescription(schemasTable, "utype", "lists the utypes of schemas in the tableset");
        setTSColumnDescription(schemasTable, "description", "describes schemas in the tableset");
        Table tablesTable = schema.getChild("tables");
        tablesTable.setDescription("description of tables in this tableset");

        setTSColumnDescription(tablesTable, "schema_name", "the schema this table belongs to");
        setTSColumnDescription(tablesTable, "table_name", "the fully qualified table name");
        setTSColumnDescription(tablesTable, "table_type", "one of: table view");
        setTSColumnDescription(tablesTable, "utype", "lists the utype of tables in the tableset");
        setTSColumnDescription(tablesTable, "description", "describes tables in the tableset");
        Table columnsTable = schema.getChild("columns");
        columnsTable.setDescription("description of columns in this tableset");

        setTSColumnDescription(columnsTable, "table_name", "the table this column belongs to");
        setTSColumnDescription(columnsTable, "column_name", "the column name");
        setTSColumnDescription(columnsTable, "utype", "lists the utypes of columns in the tableset");
        setTSColumnDescription(columnsTable, "ucd", "lists the UCDs of columns in the tableset");
        setTSColumnDescription(columnsTable, "unit", "lists the unit used for column values in the tableset");
        setTSColumnDescription(columnsTable, "description", "describes the columns in the tableset");
        setTSColumnDescription(columnsTable, "datatype", "lists the ADQL datatype of columns in the tableset");
        setTSColumnDescription(columnsTable, "size", "lists the size of variable-length columns in the tableset");
        setTSColumnDescription(columnsTable, "principal", "a principal column; 1 means 1, 0 means 0");
        setTSColumnDescription(columnsTable, "indexed", "an indexed column; 1 means 1, 0 means 0");
        setTSColumnDescription(columnsTable, "std", "a standard column; 1 means 1, 0 means 0");
        Table keysTable = schema.getChild("keys");
        keysTable.setDescription("description of foreign keys in this tableset");

        setTSColumnDescription(keysTable, "key_id", "unique key to join to TAP_SCHEMA.key_columns");
        setTSColumnDescription(keysTable, "from_table", "the table with the foreign key");
        setTSColumnDescription(keysTable, "target_table", "the table with the primary key");
        setTSColumnDescription(keysTable, "utype", "lists the utype of keys in the tableset");
        setTSColumnDescription(keysTable, "description", "describes keys in the tableset");
        Table keyColumnsTable = schema.getChild("key_columns");
        keyColumnsTable.setDescription("description of foreign key columns in this tableset");

        setTSColumnDescription(keyColumnsTable, "key_id", "key to join to TAP_SCHEMA.keys");
        setTSColumnDescription(keyColumnsTable, "from_column", "column in the from_table");
        setTSColumnDescription(keyColumnsTable, "target_column", "column in the target_table");