diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/ChildEntity.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ChildEntity.java
similarity index 65%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/ChildEntity.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/ChildEntity.java
index 4f55929696ffb7115371793703f15d609d99193a..e6e9e5ddff14a1e9795271d3f4cdcb05df1f1106 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/ChildEntity.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ChildEntity.java
@@ -20,7 +20,10 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api.contract;
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.xmlmodel.TableModel;
+import java.util.Map;
 
 /**
  * A {@link TapSchemaEntity} that can be a child of an
@@ -28,23 +31,44 @@ package it.inaf.ia2.tsm.api.contract;
  *
  * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
  */
-public interface ChildEntity<T extends EntitiesContainer> extends TapSchemaEntity {
+public abstract class ChildEntity<T extends EntitiesContainer> extends TapSchemaEntity {
+
+    private static final long serialVersionUID = -8941059435527998685L;
+
+    private Status status;
+
+    protected ChildEntity() {
+    }
+
+    public ChildEntity(TapSchema tapSchema, TableModel tableModel, Map<String, Object> metadata) {
+        super(tapSchema, tableModel, metadata);
+    }
 
     /**
-     * Each child has a name that is univocal for a given parent, in this way
-     * the parent can search a child by name.
+     * The persistence status of the {@link ChildEntity}.
      */
-    String getName();
+    public Status getStatus() {
+        return status;
+    }
+
+    public void setStatus(Status status) {
+        this.status = status;
+    }
+
+    @Override
+    public void save() {
+        setStatus(Status.ADDED_PERSISTED);
+        super.save();
+    }
 
     /**
-     * The {@link EntitiesContainer} that owns the {@link ChildEntity}.
+     * Each child has a name that is univocal for a given parent, in this way
+     * the parent can search a child by name.
      */
-    T getParent();
+    public abstract String getName();
 
     /**
-     * The persistence status of the {@link ChildEntity}.
+     * The {@link EntitiesContainer} that owns the {@link ChildEntity}.
      */
-    Status getStatus();
-
-    void setStatus(Status status);
+    public abstract T getParent();
 }
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Column.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Column.java
new file mode 100644
index 0000000000000000000000000000000000000000..aae711c003939e1cd2bcc0202731e34badb55ff0
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Column.java
@@ -0,0 +1,120 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import java.util.Objects;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class Column extends ChildEntity<Table> {
+
+    public final static String TABLE_NAME_KEY = "table_name";
+    public final static String COLUMN_NAME_KEY = "column_name";
+    public final static String DATATYPE_KEY = "datatype";
+    public final static String SIZE_KEY = "size";
+    public final static String ARRAYSIZE_KEY = "arraysize";
+    public final static String INDEXED_KEY = "indexed";
+    public final static String PRIMARY_KEY = "primary_key";
+
+    private static final long serialVersionUID = 9175956487892235521L;
+    private static final Logger LOG = LoggerFactory.getLogger(Column.class);
+
+    private boolean foreignKeySearched;
+    private KeyMetadata foreignKey;
+
+    private Table parentTable;
+
+    private Column() {
+        // for serialization
+        super();
+    }
+
+    protected Column(TapSchema tapSchema, Table table, String columnName) {
+        super(tapSchema, tapSchema.getTableModel(TapSchema.COLUMNS_TABLE), table.getColumnMetadata(columnName));
+        parentTable = table;
+        setStatus(Status.LOADED);
+    }
+
+    public KeyMetadata getForeignKey() {
+        if (!foreignKeySearched) { // lazy loading (but the foreignKey value can be null, so we use this boolean)
+            foreignKey = tapSchema.searchKeyMetadata(parentTable.getParent().getName(), parentTable.getName(), getName());
+        }
+
+        return foreignKey;
+    }
+
+    public String getTableCompleteName() {
+        return getValue(TABLE_NAME_KEY, String.class);
+    }
+
+    @Override
+    public String getName() {
+        return getValue(COLUMN_NAME_KEY, String.class);
+    }
+
+    public boolean getIndexed() {
+        return getValue(INDEXED_KEY, Boolean.class);
+    }
+
+    /**
+     * This information is not stored into the TAP_SCHEMA, so it will be
+     * reloaded from the source schema each time.
+     */
+    public boolean isPrimaryKey() {
+        return (boolean) getMetadata(PRIMARY_KEY);
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 29 * hash + Objects.hashCode(getTableCompleteName());
+        hash = 29 * hash + Objects.hashCode(getName());
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final Column other = (Column) obj;
+        if (!Objects.equals(this.getTableCompleteName(), other.getTableCompleteName())) {
+            return false;
+        }
+        return Objects.equals(this.getName(), other.getName());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Table getParent() {
+        return parentTable;
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/ConsistencyChecks.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ConsistencyChecks.java
similarity index 98%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/ConsistencyChecks.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/ConsistencyChecks.java
index 13c5d690c3f357b46f751d8d7fe037dc128e9773..1b9f6d6fa85578fc9742474497198a97aea69541 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/ConsistencyChecks.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ConsistencyChecks.java
@@ -20,10 +20,10 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm;
 
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
-import it.inaf.ia2.tsm.api.contract.TapSchema;
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
 import java.io.Serializable;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Dao.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Dao.java
new file mode 100644
index 0000000000000000000000000000000000000000..42ae18d0720b346e730f60123f401776020060cb
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Dao.java
@@ -0,0 +1,707 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.datalayer.Credentials;
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import javax.sql.DataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class that contains static methods for interacting with databases.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class Dao {
+
+//    private static final Logger log = LoggerFactory.getLogger(Dao.class);
+//
+//    /**
+//     * Creates the TAP_SCHEMA schema and its tables.
+//     */
+//    private static void createTapSchemaStructure(DatabaseType dbType, Connection conn, TapSchema tapSchema) throws SQLException {
+//
+//        String tapSchemaName = tapSchema.getName();
+//        String version = tapSchema.getVersion();
+//
+//        if (dbType == DatabaseType.MYSQL) {
+//            try (Statement statement = conn.createStatement()) {
+//
+//                /////////////////////////////////////
+//                //         CREATE DATABASE         //
+//                /////////////////////////////////////
+//                String queryString = String.format("CREATE DATABASE IF NOT EXISTS `%s`", tapSchemaName);
+//                log.debug("Executing query {}", queryString);
+//                statement.executeUpdate(queryString);
+//
+//                StringBuilder querySb = new StringBuilder();
+//
+//                /////////////////////////////////////
+//                //      CREATE schemas TABLE       //
+//                /////////////////////////////////////
+//                querySb.append("CREATE TABLE IF NOT EXISTS `");
+//                querySb.append(tapSchemaName);
+//                querySb.append("`.`schemas` (\n");
+//                querySb.append("schema_name   varchar(64),\n");
+//                querySb.append("utype         varchar(512) NULL,\n");
+//                querySb.append("description   varchar(512) NULL,\n");
+//                if (TSMUtil.isIA2(version)) {
+//                    querySb.append("schemaID      bigint,\n");
+//                }
+//                querySb.append("PRIMARY KEY (schema_name))");
+//
+//                queryString = querySb.toString();
+//                log.debug("Creating \"schemas\" table");
+//                log.debug("Executing query {}", queryString);
+//                statement.executeUpdate(queryString);
+//
+//                /////////////////////////////////////
+//                //       CREATE tables TABLE       //
+//                /////////////////////////////////////
+//                querySb = new StringBuilder();
+//                querySb.append("CREATE TABLE IF NOT EXISTS `");
+//                querySb.append(tapSchemaName);
+//                querySb.append("`.tables (\n");
+//                querySb.append("schema_name   varchar(64),\n");
+//                querySb.append("table_name    varchar(128),\n");
+//                querySb.append("table_type    varchar(8),\n");
+//                querySb.append("utype         varchar(512) NULL,\n");
+//                querySb.append("description   varchar(512) NULL,\n");
+//                if (TSMUtil.isIA2(version)) {
+//                    querySb.append("tableID       bigint,\n");
+//                }
+//                querySb.append("PRIMARY KEY (table_name),\n");
+//                querySb.append("FOREIGN KEY (schema_name) REFERENCES `");
+//                querySb.append(tapSchemaName);
+//                querySb.append("`.`schemas` (schema_name))");
+//
+//                queryString = querySb.toString();
+//                log.debug("Creating \"tables\" table");
+//                log.debug("Executing query {}", queryString);
+//                statement.executeUpdate(queryString);
+//
+//                /////////////////////////////////////
+//                //      CREATE columns TABLE       //
+//                /////////////////////////////////////
+//                querySb = new StringBuilder();
+//                querySb.append("CREATE TABLE IF NOT EXISTS `");
+//                querySb.append(tapSchemaName);
+//                querySb.append("`.columns (\n");
+//                querySb.append("table_name    varchar(128),\n");
+//                querySb.append("column_name   varchar(64),\n");
+//                querySb.append("utype         varchar(512) NULL,\n");
+//                querySb.append("ucd           varchar(64)  NULL,\n");
+//                querySb.append("unit          varchar(64)  NULL,\n");
+//                querySb.append("description   varchar(512) NULL,\n");
+//                querySb.append("datatype      varchar(64)  NOT NULL,\n");
+//                querySb.append("size          integer      NULL,\n");
+//                querySb.append("principal     integer      NOT NULL,\n");
+//                querySb.append("indexed       integer      NOT NULL,\n");
+//                querySb.append("std           integer      NOT NULL,\n");
+//                if (TSMUtil.isIA2(version)) {
+//                    querySb.append("id      integer,\n");
+//                    querySb.append("columnID      bigint,\n");
+//                }
+//                querySb.append("PRIMARY KEY (table_name, column_name),\n");
+//                querySb.append("FOREIGN KEY (table_name) REFERENCES `");
+//                querySb.append(tapSchemaName);
+//                querySb.append("`.tables (table_name))");
+//
+//                queryString = querySb.toString();
+//                log.debug("Creating \"columns\" table");
+//                log.debug("Executing query {}", queryString);
+//                statement.executeUpdate(queryString);
+//
+//                /////////////////////////////////////
+//                //        CREATE keys TABLE        //
+//                /////////////////////////////////////
+//                querySb = new StringBuilder();
+//                querySb.append("CREATE TABLE IF NOT EXISTS `");
+//                querySb.append(tapSchemaName);
+//                querySb.append("`.keys (\n");
+//                querySb.append("key_id        varchar(64),\n");
+//                querySb.append("from_table    varchar(128) NOT NULL,\n");
+//                querySb.append("target_table  varchar(128) NOT NULL,\n");
+//                querySb.append("utype         varchar(512) NULL,\n");
+//                querySb.append("description   varchar(512) NULL,\n");
+//                if (TSMUtil.isIA2(version)) {
+//                    querySb.append("keyID         bigint,\n");
+//                }
+//                querySb.append("PRIMARY KEY (key_id),\n");
+//                querySb.append("FOREIGN KEY (from_table) REFERENCES `");
+//                querySb.append(tapSchemaName);
+//                querySb.append("`.tables (table_name),\n");
+//                querySb.append("FOREIGN KEY (target_table) REFERENCES `");
+//                querySb.append(tapSchemaName);
+//                querySb.append("`.tables (table_name))");
+//
+//                queryString = querySb.toString();
+//                log.debug("Creating \"keys\" table");
+//                log.debug("Executing query {}", queryString);
+//                statement.executeUpdate(queryString);
+//
+//                /////////////////////////////////////
+//                //    CREATE key_columns TABLE     //
+//                /////////////////////////////////////
+//                querySb = new StringBuilder();
+//                querySb.append("CREATE TABLE IF NOT EXISTS `");
+//                querySb.append(tapSchemaName);
+//                querySb.append("`.key_columns (\n");
+//                querySb.append("key_id          varchar(64),\n");
+//                querySb.append("from_column     varchar(64)   NOT NULL,\n");
+//                querySb.append("target_column   varchar(64) NOT NULL,\n");
+//                if (TSMUtil.isIA2(version)) {
+//                    querySb.append("key_columnID    bigint,\n");
+//                }
+//                querySb.append("FOREIGN KEY (key_id) REFERENCES `");
+//                querySb.append(tapSchemaName);
+//                querySb.append("`.keys (key_id))");
+//
+//                queryString = querySb.toString();
+//                log.debug("Creating \"key_columns\" table");
+//                log.debug("Executing query {}", queryString);
+//                statement.executeUpdate(queryString);
+//            }
+//        } else if (dbType == DatabaseType.POSTGRES) {
+//            try (Statement statement = conn.createStatement()) {
+//                String tapSchemaNameEscaped = TSMUtil.escapeName(tapSchemaName, dbType);
+//
+//                statement.executeUpdate("CREATE SCHEMA IF NOT EXISTS " + tapSchemaNameEscaped);
+//
+//                StringBuilder querySb = new StringBuilder();
+//
+//                /////////////////////////////////////
+//                //      CREATE schemas TABLE       //
+//                /////////////////////////////////////
+//                querySb.append("CREATE TABLE IF NOT EXISTS ");
+//                querySb.append(tapSchemaNameEscaped);
+//                querySb.append(".schemas (\n");
+//                querySb.append("schema_name character varying(64) NOT NULL,\n");
+//                querySb.append("description character varying(512),\n");
+//                if (TSMUtil.isIA2(version)) {
+//                    querySb.append("schemaid bigint,\n");
+//                }
+//                querySb.append("utype character varying(512))");
+//
+//                String queryString = querySb.toString();
+//                log.debug("Creating \"schemas\" table");
+//                log.debug("Executing query {}", queryString);
+//                int updateResult = statement.executeUpdate(queryString);
+//
+//                if (updateResult > 0) {
+//                    queryString = "ALTER TABLE ONLY schemas ADD CONSTRAINT schemas_pkey PRIMARY KEY (schema_name)";
+//                    log.debug("Adding constraints to \"schemas\" table");
+//                    log.debug("Executing query {}", queryString);
+//                    statement.executeUpdate(queryString);
+//                }
+//
+//                /////////////////////////////////////
+//                //       CREATE tables TABLE       //
+//                /////////////////////////////////////
+//                querySb = new StringBuilder();
+//
+//                querySb.append("CREATE TABLE IF NOT EXISTS ");
+//                querySb.append(tapSchemaNameEscaped);
+//                querySb.append(".tables (\n");
+//                querySb.append("table_name character varying(128) NOT NULL,\n");
+//                querySb.append("description character varying(512),\n");
+//                querySb.append("schema_name character varying(64),\n");
+//                if (TSMUtil.isIA2(version)) {
+//                    querySb.append("tableid bigint,\n");
+//                }
+//                querySb.append("table_type character varying(8),\n");
+//                querySb.append("utype character varying(512))");
+//
+//                queryString = querySb.toString();
+//                log.debug("Creating \"tables\" table");
+//                log.debug("Executing query {}", queryString);
+//                updateResult = statement.executeUpdate(queryString);
+//
+//                if (updateResult > 0) {
+//                    log.debug("Adding constraints to \"tables\" table");
+//                    queryString = "ALTER TABLE ONLY tables ADD CONSTRAINT tables_pkey PRIMARY KEY (table_name)";
+//                    log.debug("Executing query {}", queryString);
+//                    statement.executeUpdate(queryString);
+//                    queryString = "ALTER TABLE ONLY tables ADD CONSTRAINT fk_tables_schema_name FOREIGN KEY (schema_name) REFERENCES schemas(schema_name)";
+//                    log.debug("Executing query {}", queryString);
+//                    statement.executeUpdate(queryString);
+//                }
+//
+//                /////////////////////////////////////
+//                //      CREATE columns TABLE       //
+//                /////////////////////////////////////
+//                querySb = new StringBuilder();
+//
+//                querySb.append("CREATE TABLE IF NOT EXISTS ");
+//                querySb.append(tapSchemaNameEscaped);
+//                querySb.append(".columns (\n");
+//                querySb.append("table_name character varying(128) NOT NULL,\n");
+//                querySb.append("column_name character varying(64) NOT NULL,\n");
+//                if (TSMUtil.isIA2(version)) {
+//                    querySb.append("columnid bigint,\n");
+//                }
+//                querySb.append("datatype character varying(64),\n");
+//                querySb.append("description character varying(512),\n");
+//                querySb.append("id integer,\n");
+//                querySb.append("indexed boolean,\n");
+//                querySb.append("principal boolean,\n");
+//                querySb.append("size integer,\n");
+//                querySb.append("std boolean,\n");
+//                querySb.append("ucd character varying(64),\n");
+//                querySb.append("unit character varying(64),\n");
+//                querySb.append("utype character varying(512))");
+//
+//                queryString = querySb.toString();
+//                log.debug("Creating \"columns\" table");
+//                log.debug("Executing query {}", queryString);
+//                updateResult = statement.executeUpdate(queryString);
+//
+//                if (updateResult > 0) {
+//                    log.debug("Adding constraints to \"columns\" table");
+//                    queryString = "ALTER TABLE ONLY columns ADD CONSTRAINT columns_pkey PRIMARY KEY (table_name, column_name)";
+//                    log.debug("Executing query {}", queryString);
+//                    statement.executeUpdate(queryString);
+//                    queryString = "ALTER TABLE ONLY columns ADD CONSTRAINT fk_columns_table_name FOREIGN KEY (table_name) REFERENCES tables(table_name)";
+//                    log.debug("Executing query {}", queryString);
+//                    statement.executeUpdate(queryString);
+//                }
+//
+//                /////////////////////////////////////
+//                //        CREATE keys TABLE        //
+//                /////////////////////////////////////
+//                querySb = new StringBuilder();
+//
+//                querySb.append("CREATE TABLE IF NOT EXISTS ");
+//                querySb.append(tapSchemaNameEscaped);
+//                querySb.append(".keys (\n");
+//                querySb.append("key_id character varying(64) NOT NULL,\n");
+//                querySb.append("description character varying(512),\n");
+//                querySb.append("from_table character varying(128),\n");
+//                if (TSMUtil.isIA2(version)) {
+//                    querySb.append("keyid bigint,\n");
+//                }
+//                querySb.append("target_table character varying(128),\n");
+//                querySb.append("utype character varying(512))");
+//
+//                queryString = querySb.toString();
+//                log.debug("Creating \"keys\" table");
+//                log.debug("Executing query {}", queryString);
+//                updateResult = statement.executeUpdate(queryString);
+//
+//                if (updateResult > 0) {
+//                    log.debug("Adding constraints to \"keys\" table");
+//                    queryString = "ALTER TABLE ONLY keys ADD CONSTRAINT keys_pkey PRIMARY KEY (key_id)";
+//                    log.debug("Executing query {}", queryString);
+//                    statement.executeUpdate(queryString);
+//                    queryString = "ALTER TABLE ONLY keys ADD CONSTRAINT \"FK_keys_from_table\" FOREIGN KEY (from_table) REFERENCES tables(table_name)";
+//                    log.debug("Executing query {}", queryString);
+//                    statement.executeUpdate(queryString);
+//                    queryString = "ALTER TABLE ONLY keys ADD CONSTRAINT \"FK_keys_target_table\" FOREIGN KEY (target_table) REFERENCES tables(table_name)";
+//                    log.debug("Executing query {}", queryString);
+//                    statement.executeUpdate(queryString);
+//                }
+//
+//                /////////////////////////////////////
+//                //    CREATE key_columns TABLE     //
+//                /////////////////////////////////////
+//                querySb = new StringBuilder();
+//
+//                querySb.append("CREATE TABLE IF NOT EXISTS ");
+//                querySb.append(tapSchemaNameEscaped);
+//                querySb.append(".key_columns (\n");
+//                querySb.append("from_column character varying(64) NOT NULL,\n");
+//                querySb.append("target_column character varying(64) NOT NULL,\n");
+//                if (TSMUtil.isIA2(version)) {
+//                    querySb.append("key_columnid bigint,\n");
+//                }
+//                querySb.append("key_id character varying(64) NOT NULL)");
+//
+//                queryString = querySb.toString();
+//                log.debug("Creating \"key_columns\" table");
+//                log.debug("Executing query {}", queryString);
+//                updateResult = statement.executeUpdate(queryString);
+//
+//                if (updateResult > 0) {
+//                    log.debug("Adding constraints to \"key_columns\" table");
+//                    queryString = "ALTER TABLE ONLY key_columns ADD CONSTRAINT key_columns_pkey PRIMARY KEY (from_column, target_column, key_id)";
+//                    log.debug("Executing query {}", queryString);
+//                    statement.executeUpdate(queryString);
+//                    queryString = "ALTER TABLE ONLY key_columns ADD CONSTRAINT fk_key_columns_key_id FOREIGN KEY (key_id) REFERENCES keys(key_id)";
+//                    log.debug("Executing query {}", queryString);
+//                    statement.executeUpdate(queryString);
+//                }
+//            }
+//        } else {
+//            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//        }
+//    }
+//
+//    protected static void save(DBWrapper dbWrapper, TapSchema tapSchema) throws SQLException {
+//
+//        log.debug("Saving TAP_SCHEMA");
+//
+//        DatabaseType dbType = dbWrapper.getTapSchemaDatabaseType();
+//        DataSource dataSource = dbWrapper.getTapSchemaDataSource();
+//
+//        Connection connection = null;
+//        PreparedStatement statement = null;
+//        boolean transactionStarted = false;
+//
+//        try {
+//            connection = dataSource.getConnection();
+//
+//            UpdateOperations operations = new UpdateOperations(tapSchema);
+//
+//            if (!tapSchema.exists()) {
+//                createTapSchemaStructure(dbType, connection, tapSchema);
+//            }
+//
+//            // Start update
+//            connection.setAutoCommit(false); // start transaction
+//            transactionStarted = true;
+//
+//            String tapSchemaNameEscaped = TSMUtil.escapeName(tapSchema.getName(), dbType);
+//
+//            // REMOVE ELEMENTS
+//            if (tapSchema.exists()) {
+//                for (Key key : operations.getKeysToRemove()) {
+//                    String keyId = key.getId();
+//
+//                    String query = String.format("DELETE FROM %s.%s WHERE key_id = ?", tapSchemaNameEscaped, TSMUtil.escapeName("key_columns", dbType));
+//                    statement = connection.prepareStatement(query);
+//                    statement.setString(1, keyId);
+//                    log.debug("Executing query {} [key_id={}]", query, keyId);
+//                    statement.executeUpdate();
+//
+//                    query = String.format("DELETE FROM %s.%s WHERE key_id = ?", tapSchemaNameEscaped, TSMUtil.escapeName("keys", dbType));
+//                    statement = connection.prepareStatement(query);
+//                    statement.setString(1, keyId);
+//                    log.debug("Executing query {} [key_id={}]", query, keyId);
+//                    statement.executeUpdate();
+//                }
+//
+//                for (Column column : operations.getColumnsToRemove()) {
+//                    String query = String.format("DELETE FROM %s.%s WHERE table_name = ? AND column_name = ?", tapSchemaNameEscaped, TSMUtil.escapeName("columns", dbType));
+//                    statement = connection.prepareStatement(query);
+//                    String tableName = column.getTableCompleteName();
+//                    String columnName = column.getName();
+//                    statement.setString(1, tableName);
+//                    statement.setString(2, columnName);
+//                    log.debug("Executing query {} [table_name={}, column_name={}]", query, tableName, columnName);
+//                    statement.executeUpdate();
+//                }
+//
+//                for (Table table : operations.getTablesToRemove()) {
+//                    String query = String.format("DELETE FROM %s.%s WHERE table_name = ?", tapSchemaNameEscaped, TSMUtil.escapeName("tables", dbType));
+//                    statement = connection.prepareStatement(query);
+//                    String tableCompleteName = table.getCompleteName();
+//                    statement.setString(1, tableCompleteName);
+//                    log.debug("Executing query {} [table_name={}]", query, tableCompleteName);
+//                    statement.executeUpdate();
+//                }
+//
+//                for (Schema schema : operations.getSchemasToRemove()) {
+//                    String query = String.format("DELETE FROM %s.%s WHERE schema_name = ?", tapSchemaNameEscaped, TSMUtil.escapeName("schemas", dbType));
+//                    statement = connection.prepareStatement(query);
+//                    String schemaName = schema.getName();
+//                    statement.setString(1, schemaName);
+//                    log.debug("Executing query {} [schema_name={}]", query, schemaName);
+//                    statement.executeUpdate();
+//                }
+//            }
+//
+//            // INSERT ELEMENTS
+//            if (!operations.getSchemasToAdd().isEmpty()) {
+//                log.debug("Inserting {} new schemas", operations.getSchemasToAdd().size());
+//            }
+//            for (Schema schema : operations.getSchemasToAdd()) {
+//                DaoSchema.insertNewSchema(dbType, connection, tapSchema, schema);
+//            }
+//
+//            if (!operations.getTablesToAdd().isEmpty()) {
+//                log.debug("Inserting {} new tables", operations.getTablesToAdd().size());
+//            }
+//            for (Table table : operations.getTablesToAdd()) {
+//                DaoTable.insertNewTable(dbType, connection, tapSchema, table);
+//            }
+//
+//            if (!operations.getColumnsToAdd().isEmpty()) {
+//                log.debug("Inserting {} new columns", operations.getColumnsToAdd().size());
+//            }
+//            for (Column column : operations.getColumnsToAdd()) {
+//                DaoColumn.insertNewColumn(dbType, connection, tapSchema, column);
+//            }
+//
+//            if (!operations.getKeysToAdd().isEmpty()) {
+//                log.debug("Inserting {} new keys", operations.getKeysToAdd().size());
+//            }
+//            for (Key key : operations.getKeysToAdd()) {
+//                // insert new keys and their key columns
+//                DaoKey.insertNewKey(dbType, connection, tapSchema, key);
+//            }
+//
+//            //UPDATE ELEMENTS
+//            if (tapSchema.exists()) {
+//                for (Key key : operations.getKeysToUpdate()) {
+//                    // update keys and their key columns
+//                    DaoKey.updateKey(dbType, connection, tapSchema, key);
+//                }
+//
+//                for (Schema schema : operations.getSchemasToUpdate()) {
+//                    DaoSchema.updateSchema(dbType, connection, tapSchema, schema);
+//                }
+//
+//                for (Table table : operations.getTablesToUpdate()) {
+//                    DaoTable.updateTable(dbType, connection, tapSchema, table);
+//                }
+//
+//                for (Column column : operations.getColumnsToUpdate()) {
+//                    DaoColumn.updateColumn(dbType, connection, tapSchema, column);
+//                }
+//            }
+//
+//            connection.commit();
+//
+//            // Status cleanup after commit
+//            // added
+//            for (Key key : operations.getKeysToAdd()) {
+//                key.save();
+//            }
+//            for (Schema schema : operations.getSchemasToAdd()) {
+//                schema.save();
+//            }
+//            for (Table table : operations.getTablesToAdd()) {
+//                table.save();
+//            }
+//            for (Column column : operations.getColumnsToAdd()) {
+//                column.save();
+//            }
+//
+//            // removed
+//            for (Key key : operations.getKeysToRemove()) {
+//                key.initProperty(Key.ID_KEY, null);
+//                for (KeyColumn keyColumn : key.getKeyColumns()) {
+//                    keyColumn.initProperty(KeyColumn.KEY_ID_KEY, null);
+//                }
+//            }
+//            for (Column column : operations.getColumnsToRemove()) {
+//                column.setStatus(Status.LOADED);
+//            }
+//            for (Column column : operations.getColumnsToClean()) {
+//                column.setStatus(Status.LOADED);
+//            }
+//            for (Table table : operations.getTablesToRemove()) {
+//                Schema schema = tapSchema.getChild(table.getSchemaName());
+//                if (schema != null) {
+//                    ((Schema) schema).cleanTable(table.getName());
+//                }
+//            }
+//            for (Table table : operations.getTablesToClean()) {
+//                Schema schema = tapSchema.getChild(table.getSchemaName());
+//                if (schema != null) {
+//                    ((Schema) schema).cleanTable(table.getName());
+//                }
+//            }
+//            for (Schema schema : operations.getSchemasToRemove()) {
+//                ((TapSchema) tapSchema).cleanSchema(schema.getName());
+//            }
+//            for (Schema schema : operations.getSchemasToClean()) {
+//                ((TapSchema) tapSchema).cleanSchema(schema.getName());
+//            }
+//
+//            // updated
+//            for (Key key : operations.getKeysToUpdate()) {
+//                key.save();
+//            }
+//            for (Schema schema : operations.getSchemasToUpdate()) {
+//                schema.save();
+//            }
+//            for (Table table : operations.getTablesToUpdate()) {
+//                table.save();
+//            }
+//            for (Column column : operations.getColumnsToUpdate()) {
+//                column.save();
+//            }
+//        } catch (SQLException e) {
+//            log.error("Exception caught", e);
+//            try {
+//                if (connection != null && transactionStarted) {
+//                    log.debug("Executing rollback");
+//                    connection.rollback();
+//                }
+//            } catch (SQLException e2) {
+//                log.error("Exception caught", e2);
+//            }
+//            throw e;
+//        } finally {
+//            if (connection != null) {
+//                try {
+//                    if (statement != null) {
+//                        statement.close();
+//                    }
+//                    connection.close();
+//                } catch (SQLException e2) {
+//                    log.error("Exception caught", e2);
+//                }
+//            }
+//        }
+//    }
+//
+//    public static List<String> getAllTAPSchemasNames(Credentials credentials) throws SQLException {
+//        DatabaseType dbType = credentials.getDatabaseType();
+//        DataSource ds = TSMUtil.createDataSource(credentials);
+//        List<String> allSchemas = DaoSchema.getAllSchemasNames(ds, dbType);
+//        return getAllTAPSchemasNames(ds, dbType, allSchemas);
+//    }
+//
+//    public static List<String> getAllTAPSchemasNames(DBWrapper dbs) throws SQLException {
+//        List<String> allSchemas = DaoSchema.getAllSchemasNames(dbs.getTapSchemaDataSource(), dbs.getTapSchemaDatabaseType());
+//        return getAllTAPSchemasNames(dbs, allSchemas);
+//    }
+//
+//    public static List<String> getAllTAPSchemasNames(DBWrapper dbs, List<String> allSchemas) throws SQLException {
+//        return getAllTAPSchemasNames(dbs.getTapSchemaDataSource(), dbs.getTapSchemaDatabaseType(), allSchemas);
+//    }
+//
+//    /**
+//     * Retrieve the list of all TAP_SCHEMA schemas names contained in the
+//     * TAP_SCHEMA <code>DataSource</code>.<br>
+//     * TAP_SCHEMA schemas are selected simply checking if they contains the
+//     * TAP_SCHEMA standard tables. Currently no check on columns is performed.
+//     *
+//     * @param allSchemas usually the TAP_SCHEMA schemas list is loaded together
+//     * the list of all schemas, so this list is passed by parameter to avoid
+//     * repeating the query twice.
+//     *
+//     * @return list of all TAP_SCHEMA schemas names alphabetically and case
+//     * insensitively ordered.
+//     */
+//    public static List<String> getAllTAPSchemasNames(DataSource dataSource, DatabaseType dbType, List<String> allSchemas) throws SQLException {
+//
+//        List<String> allTAPSchemas = new ArrayList<>();
+//
+//        for (String schemaName : allSchemas) {
+//
+//            boolean schemas = false,
+//                    tables = false,
+//                    columns = false,
+//                    keys = false,
+//                    keyColumns = false;
+//
+//            String query;
+//            switch (dbType) {
+//                case MYSQL:
+//                    query = "SHOW TABLES FROM `" + schemaName + "`";
+//                    break;
+//                case POSTGRES:
+//                    query = "SELECT tablename FROM pg_catalog.pg_tables where schemaname = '" + schemaName + "'";
+//                    break;
+//                default:
+//                    throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//            }
+//
+//            log.debug("Executing query {}", query);
+//
+//            try (Connection connection = dataSource.getConnection();
+//                    Statement statement = connection.createStatement();
+//                    ResultSet resultSet = statement.executeQuery(query)) {
+//                while (resultSet.next()) {
+//                    String shortTableName = resultSet.getString(1);
+//
+//                    if (null != shortTableName) {
+//                        switch (shortTableName) {
+//                            case "schemas":
+//                                schemas = true;
+//                                break;
+//                            case "tables":
+//                                tables = true;
+//                                break;
+//                            case "columns":
+//                                columns = true;
+//                                break;
+//                            case "keys":
+//                                keys = true;
+//                                break;
+//                            case "key_columns":
+//                                keyColumns = true;
+//                                break;
+//                        }
+//                    }
+//                }
+//            }
+//
+//            if (schemas && tables && columns && keys && keyColumns) {
+//                // the schema is a TAP_SCHEMA
+//                allTAPSchemas.add(schemaName);
+//            }
+//        }
+//
+//        log.debug("{} TAP_SCHEMA schemas found", allTAPSchemas.size());
+//
+//        return TSMUtil.sortStringsList(allTAPSchemas);
+//    }
+//
+//    /**
+//     * Retrieve the list of the name of the schemas exposed by the TAP_SCHEMA
+//     * specified by the <code>tapSchemaName</code> parameter.
+//     *
+//     * @return list of exposed schemas names alphabetically and case
+//     * insensitively ordered.
+//     */
+//    public static List<String> getExposedSchemas(DBWrapper dbs, String tapSchemaName) throws SQLException {
+//
+//        final List<String> exposedSchemas = new ArrayList<>();
+//
+//        DatabaseType dbType = dbs.getTapSchemaDatabaseType();
+//
+//        String query;
+//        if (dbType == DatabaseType.MYSQL) {
+//            query = "SELECT schema_name FROM `" + tapSchemaName + "`.`schemas`";
+//        } else if (dbType == DatabaseType.POSTGRES) {
+//            query = "SELECT schema_name FROM \"" + tapSchemaName + "\".\"schemas\"";
+//        } else {
+//            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//        }
+//
+//        log.debug("Executing query " + query);
+//
+//        try (Connection connection = dbs.getTapSchemaConnection();
+//                Statement statement = connection.createStatement();
+//                ResultSet resultSet = statement.executeQuery(query)) {
+//            while (resultSet.next()) {
+//                exposedSchemas.add(resultSet.getString(1));
+//            }
+//        }
+//
+//        return exposedSchemas;
+//    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoColumn.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoColumn.java
new file mode 100644
index 0000000000000000000000000000000000000000..6aafd03a20393456d8ef0bfadcbe0f2c712b222a
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoColumn.java
@@ -0,0 +1,298 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+import javax.sql.DataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class that contains static methods for managing {@link Column}s into
+ * the database.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class DaoColumn {
+//
+//    private static final Logger log = LoggerFactory.getLogger(DaoColumn.class);
+//
+//    private static boolean equalsOneOf(String string, String... values) {
+//        for (String value : values) {
+//            if (string.equals(value)) {
+//                return true;
+//            }
+//        }
+//        return false;
+//    }
+//
+//    /**
+//     * Returns the list of all the columns names given a schema name and a table
+//     * name, also if these objects have never been added into the TAP_SCHEMA.
+//     * This can be useful to retrieve the source database structure.
+//     */
+//    public static List<String> getAllColumnsNames(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName, String tableSimpleName) throws SQLException {
+//        final List<String> allColumns = new ArrayList<>();
+//
+//        DataSource dataSource = TSMUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName);
+//        DatabaseType dbType = TSMUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName);
+//
+//        String query;
+//        if (dbType == DatabaseType.MYSQL) {
+//            query = String.format("SHOW COLUMNS FROM `%s`.`%s`", schemaName, tableSimpleName);
+//        } else if (dbType == DatabaseType.POSTGRES) {
+//            query = "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schemaName + "' AND table_name = '" + tableSimpleName + "'";
+//        } else {
+//            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//        }
+//
+//        log.debug("Executing query {}", query);
+//
+//        try (Connection connection = dataSource.getConnection();
+//                Statement statement = connection.createStatement();
+//                ResultSet resultSet = statement.executeQuery(query)) {
+//
+//            while (resultSet.next()) {
+//
+//                String columnName;
+//                if (dbType == DatabaseType.MYSQL) {
+//                    columnName = resultSet.getString("Field");
+//                } else if (dbType == DatabaseType.POSTGRES) {
+//                    columnName = resultSet.getString("column_name");
+//                } else {
+//                    throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//                }
+//
+//                allColumns.add(columnName);
+//            }
+//        }
+//
+//        return allColumns;
+//    }
+//
+//    /**
+//     * For performance reasons all columns of a {@link Table} are loaded
+//     * together using this method. Columns {@link Status} is at first set as
+//     * {@code LOADED}.
+//     */
+//    protected static List<Column> loadAllTableColumns(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName, Table table) throws SQLException {
+//        String tableSimpleName = table.getName();
+//        final List<Column> allColumns = new ArrayList<>();
+//
+//        DataSource dataSource = TSMUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName);
+//        DatabaseType dbType = TSMUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName);
+//
+//        String query;
+//        if (dbType == DatabaseType.MYSQL) {
+//            query = String.format("SHOW COLUMNS FROM `%s`.`%s`", schemaName, tableSimpleName);
+//        } else if (dbType == DatabaseType.POSTGRES) {
+//            query = "SELECT c.column_name, c.data_type, r.contype AS column_type, c.character_maximum_length, c.numeric_precision\n" //, c.numeric_precision_radix
+//                    + "FROM information_schema.columns c\n"
+//                    + "JOIN pg_catalog.pg_tables t ON c.table_schema = t.schemaname AND c.table_name = t.tablename\n"
+//                    + "LEFT JOIN pg_catalog.pg_constraint r ON c.ordinal_position = ANY(r.conkey) AND r.conrelid = (t.schemaname || '.' || t.tablename)::regclass::oid\n"
+//                    + "WHERE t.schemaname = '" + schemaName + "' AND t.tablename = '" + tableSimpleName + "'";
+//        } else {
+//            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//        }
+//
+//        log.debug("Executing query {}", query);
+//
+//        try (Connection connection = dataSource.getConnection();
+//                Statement statement = connection.createStatement();
+//                ResultSet resultSet = statement.executeQuery(query)) {
+//
+//            while (resultSet.next()) {
+//
+//                String columnName;
+//                if (dbType == DatabaseType.MYSQL) {
+//                    columnName = resultSet.getString("Field");
+//                } else if (dbType == DatabaseType.POSTGRES) {
+//                    columnName = resultSet.getString("column_name");
+//                } else {
+//                    throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//                }
+//
+//                boolean indexed = false, primaryKey = false;
+//
+//                // Key type
+//                if (dbType == DatabaseType.MYSQL) {
+//                    String key = resultSet.getString("Key");
+//                    primaryKey = key.equals("PRI");
+//                    indexed = equalsOneOf(key, "PRI", "UNI", "MUL");
+//                } else if (dbType == DatabaseType.POSTGRES) {
+//                    String columnType = resultSet.getString("column_type");
+//                    if (columnType != null) {
+//                        primaryKey = "p".equals(columnType);
+//                        indexed = equalsOneOf(columnType, "p", "f", "u");
+//                    }
+//                } else {
+//                    throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//                }
+//
+//                // Datatype and Size
+//                int size = 0;
+//                String datatype;
+//
+//                if (dbType == DatabaseType.MYSQL) {
+//                    String type = resultSet.getString("Type").toLowerCase();
+//
+//                    if (type.startsWith("int")) {
+//                        datatype = "adql:INTEGER";
+//                    } else if (type.startsWith("smallint")) {
+//                        datatype = "adql:SMALLINT";
+//                    } else if (type.startsWith("bigint")) {
+//                        datatype = "adql:BIGINT";
+//                    } else if (type.startsWith("float")) {
+//                        datatype = "adql:REAL";
+//                    } else if (type.startsWith("char")) {
+//                        int beginIndex = type.indexOf('(');
+//                        int endIndex = type.indexOf(')');
+//                        size = Integer.parseInt(type.substring(beginIndex + 1, endIndex));
+//                        datatype = "adql:CHAR";
+//                    } else if (type.startsWith("varchar")) {
+//                        int beginIndex = type.indexOf('(');
+//                        int endIndex = type.indexOf(')');
+//                        size = Integer.parseInt(type.substring(beginIndex + 1, endIndex));
+//                        datatype = "adql:VARCHAR";
+//                    } else if (type.contains("timestamp")) {
+//                        datatype = "adql:TIMESTAMP";
+//                    } else {
+//                        datatype = "adql:" + type.toUpperCase();
+//                    }
+//                } else if (dbType == DatabaseType.POSTGRES) {
+//                    String type = resultSet.getString("data_type");
+//
+//                    if (type.startsWith("int")) {
+//                        datatype = "adql:INTEGER";
+//                    } else if (type.startsWith("smallint")) {
+//                        datatype = "adql:SMALLINT";
+//                    } else if (type.startsWith("bigint")) {
+//                        datatype = "adql:BIGINT";
+//                    } else if (type.startsWith("double") || type.startsWith("real")) {
+//                        datatype = "adql:REAL";
+//                    } else if (type.startsWith("character varying")) {
+//                        datatype = "adql:VARCHAR";
+//                        size = resultSet.getInt("character_maximum_length");
+//                    } else if (type.startsWith("char")) {
+//                        datatype = "adql:CHAR";
+//                        size = resultSet.getInt("character_maximum_length");
+//                    } else if (type.contains("timestamp")) {
+//                        datatype = "adql:TIMESTAMP";
+//                    } else {
+//                        datatype = "adql:" + type.toUpperCase();
+//                    }
+//                } else {
+//                    throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//                }
+//
+//                Integer arraySize = null; // TODO (v 1.1)
+//
+//                Column column = new Column(dbWrapper, tapSchema, table, columnName, indexed, primaryKey, datatype, size, arraySize);
+//
+//                allColumns.add(column);
+//            }
+//        }
+//
+//        return allColumns;
+//    }
+//
+//    /**
+//     * Retrieves saved {@code Column}s from the database and add them into the
+//     * specified {@code TapSchema}.
+//     */
+//    protected static void fillSavedColumns(DBWrapper dbWrapper, final TapSchema tapSchema) throws SQLException {
+//
+//        log.debug("fillSavedColumns");
+//
+//        SelectQueryBuilder selectQueryBuilder = new SelectQueryBuilder(dbWrapper.getTapSchemaDatabaseType(), tapSchema, TapSchema.COLUMNS_TABLE) {
+//
+//            @Override
+//            protected TapSchemaEntity getEntity(ResultSet rs) throws SQLException {
+//                String tableCompleteName = rs.getString("table_name");
+//                String columnName = rs.getString("column_name");
+//
+//                String[] tableNameSplit = tableCompleteName.split(Pattern.quote("."));
+//                String schemaName = tableNameSplit[0];
+//                String tableSimpleName = tableNameSplit[1];
+//
+//                Schema schema = tapSchema.getChild(schemaName);
+//                if (schema == null) {
+//                    return null;
+//                }
+//                Table table = schema.getChild(tableSimpleName);
+//                if (table == null) {
+//                    return null;
+//                }
+//                Column column = table.addChild(columnName);
+//                if (column == null) {
+//                    return null;
+//                }
+//                column.setStatus(Status.ADDED_PERSISTED);
+//                return column;
+//            }
+//        };
+//
+//        selectQueryBuilder.executeQuery(dbWrapper.getTapSchemaConnection());
+//    }
+//
+//    /**
+//     * Save a new {@code Column} into the TAP_SCHEMA schema.
+//     */
+//    protected static void insertNewColumn(DatabaseType dbType, Connection connection, TapSchema tapSchema, Column column) throws SQLException {
+//
+//        log.debug("insertNewColumn");
+//
+//        InsertQueryBuilder insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, column, TapSchema.COLUMNS_TABLE);
+//        insertQueryBuilder.executeQuery(connection);
+//    }
+//
+//    /**
+//     * Updates an existing {@code Column}.
+//     */
+//    protected static void updateColumn(DatabaseType dbType, Connection connection, TapSchema tapSchema, Column column) throws SQLException {
+//
+//        UpdateQueryBuilder updateQueryBuilder = new UpdateQueryBuilder(dbType, tapSchema, column, TapSchema.COLUMNS_TABLE, "column_name = ? AND table_name = ?");
+//
+//        String query = updateQueryBuilder.getQuery();
+//
+//        try (PreparedStatement statement = connection.prepareStatement(query)) {
+//
+//            log.debug("Executing query {}", query);
+//
+//            int i = updateQueryBuilder.addStatementValues(statement);
+//            statement.setString(i, column.getName());
+//            statement.setString(i + 1, column.getTableCompleteName());
+//
+//            statement.executeUpdate();
+//        }
+//    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoKey.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..28599ae3cecbd2d812ef46d43fedd9f8133ccec4
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoKey.java
@@ -0,0 +1,489 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import javax.sql.DataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class that contains static methods for managing {@link Key}s and
+ * {@link KeyColumn}s into the database.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class DaoKey {
+//
+//    private static final Logger log = LoggerFactory.getLogger(DaoKey.class);
+//
+//    /**
+//     * Generate list of KeyEntity for a given schema, specifying its
+//     * <code>DataSource</code> and its name.<br>
+//     * <strong>IMPORTANT</strong>: this keys are without id. The id has to be
+//     * set when a table is added to a schema.
+//     */
+//    protected static List<Key> getSchemaKeys(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) throws SQLException {
+//
+//        log.debug("getSchemaKeys");
+//
+//        DataSource dataSource = TSMUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName);
+//        DatabaseType dbType = TSMUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName);
+//
+//        if (dbType == DatabaseType.MYSQL) {
+//
+//            Map<String, Key> schemaKeys = new HashMap<>();
+//
+//            String query = "SELECT\n"
+//                    + "c.`CONSTRAINT_NAME` AS constraint_name,\n"
+//                    + "k.`TABLE_SCHEMA` AS from_schema,\n"
+//                    + "k.`TABLE_NAME` AS from_table,\n"
+//                    + "k.`COLUMN_NAME` AS from_column,\n"
+//                    + "k.`REFERENCED_TABLE_SCHEMA` AS target_schema,\n"
+//                    + "k.`REFERENCED_TABLE_NAME` AS target_table,\n"
+//                    + "k.`REFERENCED_COLUMN_NAME` AS target_column\n"
+//                    + "FROM information_schema.TABLE_CONSTRAINTS c \n"
+//                    + "LEFT JOIN information_schema.KEY_COLUMN_USAGE k \n"
+//                    + "ON c.`CONSTRAINT_NAME` = k.`CONSTRAINT_NAME` AND c.`TABLE_SCHEMA` = k.`TABLE_SCHEMA`\n"
+//                    + "WHERE c.`CONSTRAINT_TYPE` = 'FOREIGN KEY' \n"
+//                    + "AND k.`TABLE_SCHEMA` = '" + schemaName + "' OR k.`REFERENCED_TABLE_SCHEMA` = '" + schemaName + "'";
+//
+//            try (Connection connection = dataSource.getConnection();
+//                    Statement statement = connection.createStatement();
+//                    ResultSet resultSet = statement.executeQuery(query)) {
+//
+//                while (resultSet.next()) {
+//                    String constraintName = resultSet.getString("constraint_name");
+//
+//                    Key key = schemaKeys.get(constraintName);
+//                    if (key == null) {
+//                        key = new Key(
+//                                dbWrapper,
+//                                tapSchema,
+//                                resultSet.getString("from_schema"),
+//                                resultSet.getString("from_table"),
+//                                resultSet.getString("target_schema"),
+//                                resultSet.getString("target_table")
+//                        );
+//                        schemaKeys.put(constraintName, key);
+//                    }
+//
+//                    ((Key) key).addKeyColumn(resultSet.getString("from_column"), resultSet.getString("target_column"));
+//                }
+//            }
+//
+//            return new ArrayList<>(schemaKeys.values());
+//
+//        } else if (dbType == DatabaseType.POSTGRES) {
+//
+//            String databaseName
+//                    = schemaName.equals(tapSchema.getName())
+//                    ? dbWrapper.getTapSchemaCredentials().getDatabase()
+//                    : dbWrapper.getSourceCredentials().getDatabase();
+//
+//            List<Key> schemaKeys = new ArrayList<>();
+//
+//            String queryKeys = "SELECT\n"
+//                    + "conname AS constraint_name,\n"
+//                    + "conrelid::regclass AS from_table, \n"
+//                    + "confrelid::regclass AS target_table\n"
+//                    + "FROM pg_catalog.pg_constraint\n"
+//                    + "WHERE contype = 'f'\n"
+//                    + "AND ((conrelid::regclass || '' LIKE '" + schemaName + ".%')\n"
+//                    + "OR (confrelid::regclass || '' LIKE '" + schemaName + ".%'))";
+//
+//            try (Connection connection = dataSource.getConnection();
+//                    Statement statement = connection.createStatement();
+//                    ResultSet resultSet = statement.executeQuery(queryKeys)) {
+//
+//                log.debug("Executing query {}", queryKeys);
+//
+//                while (resultSet.next()) {
+//
+//                    String constraintName = resultSet.getString("constraint_name");
+//
+//                    String[] fromTableFullNameSplit = resultSet.getString("from_table").split(Pattern.quote("."));
+//                    String fromSchema = fromTableFullNameSplit[0];
+//                    String fromTable = fromTableFullNameSplit[1];
+//
+//                    String[] targetTableFullNameSplit = resultSet.getString("target_table").split(Pattern.quote("."));
+//                    String targetSchema = targetTableFullNameSplit[0];
+//                    String targetTable = targetTableFullNameSplit[1];
+//
+//                    Key key = new Key(dbWrapper, tapSchema, fromSchema, fromTable, targetSchema, targetTable);
+//                    schemaKeys.add(key);
+//
+//                    // conkey conrelid
+//                    String queryFromKC = "SELECT\n"
+//                            + "c.column_name AS key_column\n"
+//                            + "FROM information_schema.columns c\n"
+//                            + "JOIN pg_catalog.pg_constraint r ON c.ordinal_position = ANY(r.conkey)\n"
+//                            + "AND (c.table_schema || '.' || c.table_name) = (r.conrelid::regclass || '')\n"
+//                            + "WHERE r.conname = '" + constraintName + "' AND r.contype = 'f'\n"
+//                            + "AND c.table_schema = '" + fromSchema + "'\n"
+//                            + "AND table_catalog = '" + databaseName + "'";
+//
+//                    // as above, but with confkey and confrelid and different c.table_schema where condition
+//                    String queryTargetKC = "SELECT\n"
+//                            + "c.column_name AS key_column\n"
+//                            + "FROM information_schema.columns c\n"
+//                            + "JOIN pg_catalog.pg_constraint r ON c.ordinal_position = ANY(r.confkey)\n"
+//                            + "AND (c.table_schema || '.' || c.table_name) = (r.confrelid::regclass || '')\n"
+//                            + "WHERE r.conname = '" + constraintName + "' AND r.contype = 'f'\n"
+//                            + "AND c.table_schema = '" + targetSchema + "'\n"
+//                            + "AND table_catalog = '" + databaseName + "'";
+//
+//                    try (Statement statFromKC = connection.createStatement();
+//                            Statement statTargetKC = connection.createStatement()) {
+//
+//                        try (ResultSet rsFromKC = statFromKC.executeQuery(queryFromKC);
+//                                ResultSet rsTargetKC = statTargetKC.executeQuery(queryTargetKC)) {
+//
+//                            log.debug("Executing query {}", queryFromKC);
+//                            log.debug("Executing query {}", queryTargetKC);
+//
+//                            while (rsFromKC.next()) {
+//                                if (rsTargetKC.next()) {
+//                                    ((Key) key).addKeyColumn(
+//                                            rsFromKC.getString("key_column"),
+//                                            rsTargetKC.getString("key_column")
+//                                    );
+//                                }
+//                            }
+//                        }
+//                    }
+//                }
+//            }
+//
+//            return schemaKeys;
+//        } else {
+//            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//        }
+//    }
+//
+//    /**
+//     * Retrieves saved {@code Key}s from the database and add them into the
+//     * specified {@code TapSchema}.
+//     */
+//    protected static void fillSavedKeys(DBWrapper dbWrapper, TapSchema tapSchema) throws SQLException {
+//
+//        log.debug("fillSavedKeys");
+//
+//        // We can decide to work only on from tables or target tables, because 
+//        // the same key is contained on both.
+//        // Schemas and tables have to be already added to the TAP_SCHEMA.
+//        List<Key> allVisibleKeys = new ArrayList<>();
+//
+//        // Reset to null all generated keyId.
+//        for (Key key : ((TapSchema) tapSchema).getAllKeys()) {
+//            key.initProperty(Key.ID_KEY, null);
+//
+//            // Meanwhile we add all the visible keys to this list for 
+//            // further checks
+//            if (key.isVisible()) {
+//                allVisibleKeys.add(key);
+//            }
+//        }
+//
+//        // Building query for the keys table
+//        SelectQueryBuilder keysSelect = new SelectQueryBuilder(dbWrapper.getTapSchemaDatabaseType(), tapSchema, TapSchema.KEYS_TABLE) {
+//            @Override
+//            protected TapSchemaEntity getEntity(ResultSet rs) throws SQLException {
+//                throw new UnsupportedOperationException();
+//            }
+//        };
+//        String queryKeys = keysSelect.getQuery();
+//        
+//        // Building query for the key_columns table
+//        SelectQueryBuilder keyColumnsSelect = new SelectQueryBuilder(dbWrapper.getTapSchemaDatabaseType(), tapSchema, TapSchema.KEY_COLUMNS_TABLE) {
+//            @Override
+//            protected TapSchemaEntity getEntity(ResultSet rs) throws SQLException {
+//                throw new UnsupportedOperationException();
+//            }
+//        };
+//        String queryKeyColumns = String.format("%s WHERE %s = ?",
+//                keyColumnsSelect.getQuery(),
+//                TSMUtil.escapeName(KeyColumn.KEY_ID_KEY, dbWrapper.getTapSchemaDatabaseType()));
+//
+//        boolean supportKeyID = EntityPropertyInfo.getEntityPropertyInfo(TapSchema.KEYS_TABLE, Key.KEY_ID_KEY).acceptVersion(tapSchema.getVersion());
+//        boolean supportKeyColumnID = EntityPropertyInfo.getEntityPropertyInfo(TapSchema.KEY_COLUMNS_TABLE, KeyColumn.KEY_COLUMN_ID_KEY).acceptVersion(tapSchema.getVersion());
+//
+//        try (Connection conn = dbWrapper.getTapSchemaConnection()) {
+//
+//            log.debug("Executing query {}", queryKeys);
+//
+//            // ResultSet type and concurrency are necessary for PostgreSQL
+//            try (Statement statementKeys = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
+//                    ResultSet rsKeys = statementKeys.executeQuery(queryKeys)) {
+//
+//                while (rsKeys.next()) {
+//                    // Searching the keys.
+//
+//                    String keyId = rsKeys.getString(Key.ID_KEY);
+//                    String fromTableCompleteNameSplit[] = rsKeys.getString(Key.FROM_TABLE_KEY).split(Pattern.quote("."));
+//                    String fromSchemaName = fromTableCompleteNameSplit[0];
+//                    String fromTableName = fromTableCompleteNameSplit[1];
+//
+//                    Schema fromSchema = tapSchema.getChild(fromSchemaName);
+//
+//                    if (fromSchema == null) {
+//                        tapSchema.getConsistencyChecks().addUnexistingKey(keyId);
+//                    } else {
+//                        Table fromTable = fromSchema.getChild(fromTableName);
+//                        if (fromTable == null) {
+//                            tapSchema.getConsistencyChecks().addUnexistingKey(keyId);
+//                        } else {
+//                            // ResultSet type and concurrency are necessary for PostgreSQL
+//                            try (PreparedStatement statementKeyColumns = conn.prepareStatement(queryKeyColumns, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) {
+//
+//                                statementKeyColumns.setString(1, keyId);
+//                                log.debug("Executing query {} [key_id={}]", queryKeyColumns, keyId);
+//
+//                                try (ResultSet rsKeyColumns = statementKeyColumns.executeQuery()) {
+//                                    for (Key fromKey : fromTable.getAllFromKeys()) {
+//
+//                                        boolean columnsFound = false;
+//
+//                                        for (KeyColumn keyColumn : fromKey.getKeyColumns()) {
+//                                            columnsFound = false;
+//
+//                                            rsKeyColumns.beforeFirst();
+//                                            while (rsKeyColumns.next()) {
+//                                                String fromColumn = rsKeyColumns.getString(KeyColumn.FROM_COLUMN_KEY);
+//                                                String targetColumn = rsKeyColumns.getString(KeyColumn.TARGET_COLUMN_KEY);
+//                                                if (keyColumn.getFromColumn().equals(fromColumn)
+//                                                        && keyColumn.getTargetColumn().equals(targetColumn)) {
+//                                                    columnsFound = true;
+//                                                    break;
+//                                                }
+//                                            }
+//                                            if (!columnsFound) {
+//                                                break;
+//                                            }
+//                                        }
+//
+//                                        if (columnsFound) {
+//                                            // all columns found --> key found!
+//
+//                                            // Updating key
+//                                            String keyDescription = rsKeys.getString(Key.DESCRIPTION_KEY);
+//                                            String keyUtype = rsKeys.getString(Key.UTYPE_KEY);
+//
+//                                            fromKey.initProperty(Key.ID_KEY, keyId);
+//                                            fromKey.initProperty(Key.DESCRIPTION_KEY, keyDescription);
+//                                            fromKey.initProperty(Key.UTYPE_KEY, keyUtype);
+//                                            if (supportKeyID) {
+//                                                fromKey.initProperty(Key.KEY_ID_KEY, TSMUtil.getObject(rsKeys, Key.KEY_ID_KEY, Long.class));
+//                                            }
+//                                            ((Key) fromKey).setVisible(true);
+//
+//                                            // Updating key columns
+//                                            for (KeyColumn keyColumn : fromKey.getKeyColumns()) {
+//                                                rsKeyColumns.beforeFirst();
+//                                                while (rsKeyColumns.next()) {
+//                                                    String fromColumn = rsKeyColumns.getString(KeyColumn.FROM_COLUMN_KEY);
+//                                                    String targetColumn = rsKeyColumns.getString(KeyColumn.TARGET_COLUMN_KEY);
+//                                                    if (keyColumn.getFromColumn().equals(fromColumn)
+//                                                            && keyColumn.getTargetColumn().equals(targetColumn)) {
+//                                                        keyColumn.initProperty(KeyColumn.KEY_ID_KEY, keyId);
+//                                                        if (supportKeyColumnID) {
+//                                                            keyColumn.initProperty(KeyColumn.KEY_COLUMN_ID_KEY, TSMUtil.getObject(rsKeyColumns, KeyColumn.KEY_COLUMN_ID_KEY, Long.class));
+//                                                        }
+//                                                        break;
+//                                                    }
+//                                                }
+//                                            }
+//
+//                                            break;
+//                                        }
+//                                    }
+//                                }
+//                            }
+//                        }
+//                    }
+//                }
+//
+//                // Check if the saved TAP_SCHEMA contains keys that aren't loaded (fictitious keys).
+//                List<Key> fictitiousKeys = new ArrayList<>();
+//
+//                rsKeys.beforeFirst();
+//                while (rsKeys.next()) {
+//                    String keyId = rsKeys.getString(Key.ID_KEY);
+//                    boolean keyIdFound = false;
+//                    for (Key key : allVisibleKeys) {
+//                        if (keyId.equals(key.getId())) {
+//                            keyIdFound = true;
+//                            break;
+//                        }
+//                    }
+//                    if (!keyIdFound && !tapSchema.getConsistencyChecks().getUnexistingKeys().contains(keyId)) {
+//                        String fromTableCompleteName = rsKeys.getString(Key.FROM_TABLE_KEY);
+//                        String targetTableCompleteName = rsKeys.getString(Key.TARGET_TABLE_KEY);
+//                        Key key = new Key(dbWrapper, tapSchema, fromTableCompleteName, targetTableCompleteName);
+//                        key.initProperty(Key.ID_KEY, keyId);
+//                        if (supportKeyID) {
+//                            key.initProperty(Key.KEY_ID_KEY, TSMUtil.getObject(rsKeys, Key.KEY_ID_KEY, Long.class));
+//                        }
+//                        key.setVisible(true);
+//                        fictitiousKeys.add(key);
+//
+//                        tapSchema.getChild(key.getFromSchemaName()).getChild(key.getFromTableSimpleName()).addFromKey(key);
+//                        tapSchema.getChild(key.getTargetSchemaName()).getChild(key.getTargetTableSimpleName()).addTargetKey(key);
+//                    }
+//                }
+//
+//                // filling fictitious keys columns
+//                for (Key key : fictitiousKeys) {
+//                    try (PreparedStatement statementKeyColumns = conn.prepareStatement(queryKeyColumns)) {
+//
+//                        String keyId = key.getId();
+//                        statementKeyColumns.setString(1, keyId);
+//                        log.debug("Executing query {} [key_id={}]", queryKeyColumns, keyId);
+//
+//                        try (ResultSet rsKeyColumns = statementKeyColumns.executeQuery()) {
+//
+//                            while (rsKeyColumns.next()) {
+//                                String fromColumn = rsKeyColumns.getString(KeyColumn.FROM_COLUMN_KEY);
+//                                String targetColumn = rsKeyColumns.getString(KeyColumn.TARGET_COLUMN_KEY);
+//
+//                                KeyColumn keyColumn = ((Key) key).addKeyColumn(fromColumn, targetColumn);
+//                                if (supportKeyColumnID) {
+//                                    keyColumn.initProperty(KeyColumn.KEY_COLUMN_ID_KEY, TSMUtil.getObject(rsKeyColumns, KeyColumn.KEY_COLUMN_ID_KEY, Long.class));
+//                                }
+//                            }
+//                        }
+//                    }
+//
+//                    // adding fictitious key to key set
+//                    ((TapSchema) tapSchema).getAllKeys().add(key);
+//                }
+//
+//                if (!fictitiousKeys.isEmpty()) {
+//                    log.debug("{} fictitious keys found", fictitiousKeys.size());
+//                    for (Key key : fictitiousKeys) {
+//                        log.debug("   {}", key);
+//                    }
+//                }
+//
+//                // Check if there are remaining keys with keyId = null (valid keys
+//                // that weren't saved into the TAP_SCHEMA).
+//                int keyId = ((TapSchema) tapSchema).getMaxKeyId() + 1;
+//                for (Key key : allVisibleKeys) {
+//                    if (key.getId() == null) {
+//                        key.setId(keyId + "");
+//                        keyId++;
+//                    }
+//                }
+//            }
+//        }
+//    }
+//
+//    /**
+//     * Save a new {@code Key} into the TAP_SCHEMA schema.
+//     */
+//    protected static void insertNewKey(DatabaseType dbType, Connection connection, TapSchema tapSchema, Key key) throws SQLException {
+//        log.debug("insertNewKey");
+//
+//        InsertQueryBuilder insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, key, TapSchema.KEYS_TABLE);
+//        insertQueryBuilder.executeQuery(connection);
+//
+//        for (KeyColumn keyColumn : key.getKeyColumns()) {
+//            insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, keyColumn, TapSchema.KEY_COLUMNS_TABLE);
+//            insertQueryBuilder.executeQuery(connection);
+//        }
+//    }
+//
+//    /**
+//     * Updates an existing {@code Key}.
+//     */
+//    protected static void updateKey(DatabaseType dbType, Connection connection, TapSchema tapSchema, Key key) throws SQLException {
+//        log.debug("updateKey");
+//
+//        if (key.getId() == null) {
+//            throw new IllegalStateException("Unable to update key: key_id is null");
+//        }
+//
+//        boolean keyIdChanged = key.isChanged(Key.ID_KEY);
+//
+//        if (keyIdChanged) {
+//            // Deleting key columns to avoid problem with foreign key constraint failures
+//
+//            String tapSchemaNameEscaped = TSMUtil.escapeName(tapSchema.getName(), dbType);
+//            String keyColumnsNameEscaped = TSMUtil.escapeName("key_columns", dbType);
+//
+//            String query = String.format("DELETE FROM %s.%s WHERE key_id = ?", tapSchemaNameEscaped, keyColumnsNameEscaped);
+//
+//            try (PreparedStatement statement = connection.prepareStatement(query)) {
+//                String originalKey = key.getOriginalValue(Key.ID_KEY, String.class);
+//                statement.setString(1, originalKey);
+//                log.debug("Executing query {} [key_id={}]", query, originalKey);
+//                statement.executeUpdate();
+//            }
+//        }
+//
+//        // Updating keys
+//        UpdateQueryBuilder updateQueryBuilder = new UpdateQueryBuilder(dbType, tapSchema, key, TapSchema.KEYS_TABLE, "key_id = ?");
+//        String query = updateQueryBuilder.getQuery();
+//        try (PreparedStatement statement = connection.prepareStatement(query)) {
+//            int i = updateQueryBuilder.addStatementValues(statement);
+//            String keyId = key.getId();
+//            statement.setString(i, keyId);
+//            log.debug("Executing query {} [key_id={}]", query, keyId);
+//            statement.executeUpdate();
+//        }
+//
+//        if (keyIdChanged) {
+//            // Re-insert deleted key columns
+//            for (KeyColumn keyColumn : key.getKeyColumns()) {
+//                InsertQueryBuilder insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, keyColumn, TapSchema.KEY_COLUMNS_TABLE);
+//                insertQueryBuilder.executeQuery(connection);
+//            }
+//        } else {
+//            // Update key columns
+//            for (KeyColumn keyColumn : key.getKeyColumns()) {
+//                if (keyColumn.isChanged()) {
+//                    updateQueryBuilder = new UpdateQueryBuilder(dbType, tapSchema, keyColumn, TapSchema.KEY_COLUMNS_TABLE, "key_id = ?");
+//                    query = updateQueryBuilder.getQuery();
+//                    try (PreparedStatement statement = connection.prepareStatement(query)) {
+//                        int i = updateQueryBuilder.addStatementValues(statement);
+//                        String keyId = key.getId();
+//                        statement.setString(i, keyId);
+//                        log.debug("Executing query {} [key_id={}]", query, keyId);
+//                        statement.executeUpdate();
+//                    }
+//                }
+//            }
+//        }
+//    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoSchema.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoSchema.java
new file mode 100644
index 0000000000000000000000000000000000000000..74429dde4750563440530033e207bdcbc9229511
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoSchema.java
@@ -0,0 +1,146 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.datalayer.Credentials;
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import javax.sql.DataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class that contains static methods for managing {@link Schema}s into
+ * the database.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class DaoSchema {
+//
+//    private static final Logger log = LoggerFactory.getLogger(DaoSchema.class);
+//
+//    public static List<String> getAllSchemasNames(Credentials credentials) throws SQLException {
+//        DataSource ds = TSMUtil.createDataSource(credentials);
+//        return getAllSchemasNames(ds, credentials.getDatabaseType());
+//    }
+//
+//    /**
+//     * Retrieve the list of the names of the all the schemas contained into the
+//     * database specified by the <code>DataSource</code> parameter.
+//     *
+//     * @return list of schemas names alphabetically and case insensitively
+//     * ordered.
+//     */
+//    public static List<String> getAllSchemasNames(DataSource dataSource, DatabaseType dbType) throws SQLException {
+//
+//        log.debug("getAllSchemasNames");
+//
+//        String query;
+//        if (dbType == DatabaseType.MYSQL) {
+//            query = "SHOW DATABASES";
+//        } else if (dbType == DatabaseType.POSTGRES) {
+//            query = "SELECT schema_name FROM information_schema.schemata";
+//        } else {
+//            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//        }
+//
+//        log.debug("Executing query {}", query);
+//
+//        List<String> allSchemas = new ArrayList<>();
+//
+//        try (Connection connection = dataSource.getConnection();
+//                Statement statement = connection.createStatement();
+//                ResultSet resultSet = statement.executeQuery(query)) {
+//            while (resultSet.next()) {
+//                allSchemas.add(resultSet.getString(1));
+//            }
+//        }
+//
+//        log.debug("{} schemas found", allSchemas.size());
+//
+//        return TSMUtil.sortStringsList(allSchemas);
+//    }
+//
+//    /**
+//     * Retrieves saved {@code Schema}s from the database and add them into the
+//     * specified {@code TapSchema}.
+//     */
+//    protected static void fillSavedSchemas(DBWrapper dbWrapper, final TapSchema tapSchema) throws SQLException {
+//
+//        log.debug("fillSavedSchemas");
+//
+//        SelectQueryBuilder selectQueryBuilder = new SelectQueryBuilder(dbWrapper.getTapSchemaDatabaseType(), tapSchema, TapSchema.SCHEMAS_TABLE) {
+//
+//            @Override
+//            protected TapSchemaEntity getEntity(ResultSet rs) throws SQLException {
+//                String schemaName = rs.getString("schema_name");
+//                Schema schema = tapSchema.addChild(schemaName);
+//                if (schema == null) {
+//                    return null;
+//                }
+//                schema.setStatus(Status.ADDED_PERSISTED);
+//                return schema;
+//            }
+//        };
+//
+//        selectQueryBuilder.executeQuery(dbWrapper.getTapSchemaConnection());
+//    }
+//
+//    /**
+//     * Save a new {@code Schema} into the TAP_SCHEMA schema.
+//     */
+//    protected static void insertNewSchema(DatabaseType dbType, Connection connection, TapSchema tapSchema, Schema schema) throws SQLException {
+//
+//        log.debug("insertNewSchema");
+//
+//        InsertQueryBuilder insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, schema, TapSchema.SCHEMAS_TABLE);
+//        insertQueryBuilder.executeQuery(connection);
+//    }
+//
+//    /**
+//     * Updates an existing {@code Schema}.
+//     */
+//    protected static void updateSchema(DatabaseType dbType, Connection connection, TapSchema tapSchema, Schema schema) throws SQLException {
+//
+//        UpdateQueryBuilder updateQueryBuilder = new UpdateQueryBuilder(dbType, tapSchema, schema, TapSchema.SCHEMAS_TABLE, "schema_name = ?");
+//
+//        String query = updateQueryBuilder.getQuery();
+//
+//        try (PreparedStatement statement = connection.prepareStatement(query)) {
+//
+//            log.debug("Executing query {}", query);
+//
+//            int i = updateQueryBuilder.addStatementValues(statement);
+//            statement.setString(i, schema.getName());
+//
+//            statement.executeUpdate();
+//        }
+//    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoTable.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoTable.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a42d7f247a8de15b0d00b581bf58d6855363a53
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/DaoTable.java
@@ -0,0 +1,202 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import javax.sql.DataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class that contains static methods for managing {@link Table}s into
+ * the database.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class DaoTable {
+
+//    private static final Logger log = LoggerFactory.getLogger(DaoTable.class);
+//
+//    /**
+//     * Retrieve the list of the names of all the tables contained in a schema,
+//     * given its name, also if the schema has never been added into the
+//     * TAP_SCHEMA.
+//     *
+//     * @return list of all tables names alphabetically and case insensitively
+//     * ordered.
+//     */
+//    public static List<String> getAllTablesNames(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) throws SQLException {
+//
+//        DataSource dataSource = TSMUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName);
+//        DatabaseType dbType = TSMUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName);
+//
+//        String query;
+//        switch (dbType) {
+//            case MYSQL:
+//                query = "SHOW TABLES FROM `" + schemaName + "`";
+//                break;
+//            case POSTGRES:
+//                query = "SELECT tablename FROM pg_catalog.pg_tables where schemaname = '" + schemaName + "'";
+//                break;
+//            default:
+//                throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//        }
+//
+//        log.debug("Executing query {}", query);
+//
+//        List<String> allTables = new ArrayList<>();
+//        try (Connection connection = dataSource.getConnection();
+//                Statement statement = connection.createStatement();
+//                ResultSet resultSet = statement.executeQuery(query)) {
+//            while (resultSet.next()) {
+//                allTables.add(resultSet.getString(1));
+//            }
+//        }
+//
+//        return TSMUtil.sortStringsList(allTables);
+//    }
+//
+//    /**
+//     * Retrieve the association between the tables names and their types
+//     * (<code>table</code> or <code>view</code>), given a
+//     * <code>DataSource</code> and a schema name.
+//     *
+//     * @return a map which has the tables names as keys and the table types as
+//     * values.
+//     */
+//    protected static Map<String, String> getTablesTypes(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) throws SQLException {
+//
+//        log.debug("getTablesTypes");
+//
+//        final Map<String, String> tablesTypes = new HashMap<>();
+//
+//        DataSource dataSource = TSMUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName);
+//        DatabaseType dbType = TSMUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName);
+//
+//        String query;
+//        switch (dbType) {
+//            case MYSQL:
+//                query = "SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = '" + schemaName + "'";
+//                break;
+//            case POSTGRES:
+//                query = "SELECT tablename AS table_name, 'table' AS table_type\n"
+//                        + "FROM pg_catalog.pg_tables WHERE schemaname = '" + schemaName + "'\n"
+//                        + "UNION\n"
+//                        + "SELECT table_name AS table_name, 'view' AS table_type\n"
+//                        + "FROM INFORMATION_SCHEMA.views\n"
+//                        + "WHERE table_schema = '" + schemaName + "'";
+//                break;
+//            default:
+//                throw new UnsupportedOperationException("Database type " + dbType + " not supported");
+//        }
+//
+//        log.debug("Executing query {}", query);
+//
+//        try (Connection connection = dataSource.getConnection();
+//                Statement statement = connection.createStatement();
+//                ResultSet resultSet = statement.executeQuery(query)) {
+//            while (resultSet.next()) {
+//                String tableName = resultSet.getString("table_name");
+//                String tableType = resultSet.getString("table_type").equalsIgnoreCase("VIEW") ? "view" : "table";
+//                tablesTypes.put(tableName, tableType);
+//            }
+//        }
+//
+//        return tablesTypes;
+//    }
+//
+//    /**
+//     * Retrieves saved {@code Table}s from the database and add them into the
+//     * specified {@code TapSchema}.
+//     */
+//    protected static void fillSavedTables(DBWrapper dbWrapper, final TapSchema tapSchema) throws SQLException {
+//
+//        log.debug("fillSavedTables");
+//
+//        SelectQueryBuilder selectQueryBuilder = new SelectQueryBuilder(dbWrapper.getTapSchemaDatabaseType(), tapSchema, TapSchema.TABLES_TABLE) {
+//
+//            @Override
+//            protected TapSchemaEntity getEntity(ResultSet rs) throws SQLException {
+//                String schemaName = rs.getString("schema_name");
+//                String completeTableName = rs.getString("table_name");
+//
+//                Schema schema = tapSchema.getChild(schemaName);
+//
+//                if (schema != null) {
+//                    Table table = schema.addChild(completeTableName.split(Pattern.quote("."))[1]);
+//                    if (table == null) {
+//                        return null;
+//                    }
+//                    table.setStatus(Status.ADDED_PERSISTED);
+//                    return table;
+//                }
+//                // Schema was marked for removal in the ConsistencyChecks
+//                return null;
+//            }
+//        };
+//
+//        selectQueryBuilder.executeQuery(dbWrapper.getTapSchemaConnection());
+//    }
+//
+//    /**
+//     * Save a new {@code Table} into the TAP_SCHEMA schema.
+//     */
+//    protected static void insertNewTable(DatabaseType dbType, Connection connection, TapSchema tapSchema, Table table) throws SQLException {
+//
+//        log.debug("insertNewTable");
+//
+//        InsertQueryBuilder insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, table, TapSchema.TABLES_TABLE);
+//        insertQueryBuilder.executeQuery(connection);
+//    }
+//
+//    /**
+//     * Updates an existing {@code Table}.
+//     */
+//    protected static void updateTable(DatabaseType dbType, Connection connection, TapSchema tapSchema, Table table) throws SQLException {
+//
+//        UpdateQueryBuilder updateQueryBuilder = new UpdateQueryBuilder(dbType, tapSchema, table, TapSchema.TABLES_TABLE, "table_name = ?");
+//
+//        String query = updateQueryBuilder.getQuery();
+//
+//        try (PreparedStatement statement = connection.prepareStatement(query)) {
+//
+//            log.debug("Executing query {}", query);
+//
+//            int i = updateQueryBuilder.addStatementValues(statement);
+//            statement.setString(i, table.getCompleteName());
+//
+//            statement.executeUpdate();
+//        }
+//    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/EntitiesContainer.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/EntitiesContainer.java
similarity index 98%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/EntitiesContainer.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/EntitiesContainer.java
index 13febd04d9b4578ff8e1f928cf9dfbb7578e7829..8c10dd114d4c03ed822234ae597203bdb4b6dba2 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/EntitiesContainer.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/EntitiesContainer.java
@@ -20,7 +20,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api.contract;
+package it.inaf.ia2.tsm;
 
 import java.sql.SQLException;
 import java.util.List;
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/EditableProperty.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/EntityProperty.java
similarity index 54%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/EditableProperty.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/EntityProperty.java
index 89c20cce13437a829cb03cbecf46f9e36e3b0844..ec37b228cef30774bbb69be1dc43c811d3b5831a 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/EditableProperty.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/EntityProperty.java
@@ -20,66 +20,91 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm;
 
+import it.inaf.ia2.tsm.xmlmodel.PropertyModel;
 import java.io.Serializable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
- * Represent an {@code EntityProperty} which value can be modified by the user.
+ * Store the value of an entity property (that corresponds to a column of the
+ * mapped table).
  *
  * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
  */
-public class EditableProperty<T> implements EntityProperty, Serializable {
+public class EntityProperty<T> implements Serializable {
 
-    private static final long serialVersionUID = 4896192667771442640L;
-    private static final Logger log = LoggerFactory.getLogger(EditableProperty.class);
+    private static final long serialVersionUID = 6735553751078589085L;
 
-    private final T defaultValue;
-    private final boolean allowsNull;
+    private PropertyModel propertyModel;
+    private Class<T> type;
     private T originalValue;
     private T value;
+    private boolean changed;
 
-    public EditableProperty() {
-        this.defaultValue = null;
-        this.allowsNull = true;
-        this.init(defaultValue);
+    private EntityProperty() {
     }
 
-    public EditableProperty(T defaultValue, boolean allowsNull) {
-        this.defaultValue = defaultValue;
-        this.allowsNull = allowsNull;
+    public EntityProperty(PropertyModel propertyModel, T defaultValue) {
+        this.propertyModel = propertyModel;
+        this.type = propertyModel.getType();
         this.init(defaultValue);
     }
 
-    @Override
+    /**
+     * Retrieve the current value.
+     */
+    public T getValue() {
+        return value;
+    }
+
+    /**
+     * Retrieve the current value.
+     */
     public <X> X getValue(Class<X> type) {
         return (X) value;
     }
 
+    public T getOriginalValue() {
+        return originalValue;
+    }
+
     public <X> X getOriginalValue(Class<X> type) {
         return (X) originalValue;
     }
 
     public <X> void setValue(X value) {
-        if (value == null && !allowsNull) {
-            throw new IllegalArgumentException("This EditableProperty instance doesn't allow null values");
+        this.setValue(value, true);
+    }
+
+    private <X> void setValue(X value, boolean checkUpdatable) {
+        if (checkUpdatable && !propertyModel.isUpdatable()) {
+            throw new UnsupportedOperationException("This EntityProperty instance (" + propertyModel.getName() + ") is not updatable");
+        }
+        if (value == null && !propertyModel.isNullable()) {
+            throw new IllegalArgumentException("This EntityProperty instance (" + propertyModel.getName() + ") doesn't allow null values");
         }
         this.value = (T) value;
     }
 
-    @Override
     public boolean isChanged() {
+        if (changed) {
+            return true;
+        }
         if (originalValue == null) {
             return value != null;
         }
         return !originalValue.equals(value);
     }
 
-    @Override
+    public void setChanged(boolean changed) {
+        this.changed = changed;
+    }
+
+    /**
+     * Initialize the value.
+     */
     public final <X> void init(X initialValue) {
-        setValue(initialValue);
+        setValue(initialValue, false);
         this.originalValue = (T) initialValue;
     }
 
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/InconsistentValue.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/InconsistentValue.java
similarity index 98%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/InconsistentValue.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/InconsistentValue.java
index 6f6892328f60d2a9de6d3c60f27d9150b3b24871..d7e6c11597feaeedceb7d8868f6c051ec3040f7e 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/InconsistentValue.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/InconsistentValue.java
@@ -20,7 +20,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm;
 
 /**
  *
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/InsertQueryBuilder.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/InsertQueryBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..712c16c38652354efe6ecb50dbfccdcc0eb1e0a2
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/InsertQueryBuilder.java
@@ -0,0 +1,97 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Prepares an {@code INSERT} SQL query for a given {@link TapSchemaEntity} and
+ * a given {@link TapSchema}.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class InsertQueryBuilder {
+//
+//    private static final Logger log = LoggerFactory.getLogger(InsertQueryBuilder.class);
+//
+//    private final String query;
+//    private final List<EntityPropertyInfo> addedProperties;
+//    private final TapSchemaEntity tapSchemaEntity;
+//
+//    protected InsertQueryBuilder(DatabaseType dbType, TapSchema tapSchema, TapSchemaEntity tapSchemaEntity, String tapSchemaTableName) {
+//
+//        StringBuilder querySb = new StringBuilder("INSERT INTO ");
+//        querySb.append(TSMUtil.escapeName(tapSchema.getName(), dbType));
+//        querySb.append(".");
+//        querySb.append(TSMUtil.escapeName(tapSchemaTableName, dbType));
+//        querySb.append(" (");
+//
+//        addedProperties = new ArrayList<>();
+//        this.tapSchemaEntity = tapSchemaEntity;
+//
+//        boolean first = true;
+//        for (EntityPropertyInfo propertyInfo : EntityPropertyInfo.getEntityPropertiesInfo(tapSchemaTableName)) {
+//            if (propertyInfo.acceptVersion(tapSchema.getVersion())) {
+//
+//                if (!first) {
+//                    querySb.append(", ");
+//                }
+//                querySb.append(propertyInfo.getPropertyKey());
+//                addedProperties.add(propertyInfo);
+//                first = false;
+//            }
+//        }
+//        querySb.append(") VALUES (");
+//        for (int i = 0; i < addedProperties.size(); i++) {
+//            if (i > 0) {
+//                querySb.append(",");
+//            }
+//            querySb.append("?");
+//        }
+//        querySb.append(")");
+//
+//        query = querySb.toString();
+//    }
+//
+//    protected void executeQuery(Connection connection) throws SQLException {
+//
+//        try (PreparedStatement statement = connection.prepareStatement(query)) {
+//            log.debug("Executing query {}", query);
+//            int i = 1;
+//            for (EntityPropertyInfo property : addedProperties) {
+//                Object value = tapSchemaEntity.getValue(property.getPropertyKey(), property.getPropertyType());
+//                //log.debug("  [{}] {} ({})", i, value, property.getSqlType());
+//                statement.setObject(i, value, property.getSqlType());
+//                i++;
+//            }
+//            statement.executeUpdate();
+//        }
+//    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/KeyImpl.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Key.java
similarity index 55%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/KeyImpl.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/Key.java
index db2277ad8476c5c6d36dc0609fe7f96e8311d3df..dfbe3a140470222468bbbd5153b9833451ffb6a5 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/KeyImpl.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Key.java
@@ -20,67 +20,48 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm;
 
-import it.inaf.ia2.tsm.api.contract.Key;
-import it.inaf.ia2.tsm.api.contract.KeyColumn;
-import it.inaf.ia2.tsm.api.contract.TapSchema;
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
-import java.util.regex.Pattern;
 
 /**
  * The main implementation of {@link Key}.
  *
  * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
  */
-public class KeyImpl extends TapSchemaEntityImpl implements Key {
+public class Key extends TapSchemaEntity implements Serializable {
+
+    public static final String ID_KEY = "key_id";
+    public static final String FROM_TABLE_KEY = "from_table";
+    public static final String TARGET_TABLE_KEY = "target_table";
 
     private static final long serialVersionUID = -8783695875831579336L;
 
-    private final List<KeyColumn> keyColumns;
+    private KeyMetadata keyMetadata;
+    private List<KeyColumn> keyColumns;
 
-    private String fromSchema;
-    private String fromTable;
-    private String targetSchema;
-    private String targetTable;
     private boolean visible;
 
-    private KeyImpl() {
-        // for serialization
+    private Key() {
         super();
-        keyColumns = new ArrayList<>();
     }
 
-    public KeyImpl(DBWrapper dbWrapper, TapSchema tapSchema, String fromSchema, String fromTable, String targetSchema, String targetTable) {
-        this(dbWrapper, tapSchema, fromSchema + "." + fromTable, targetSchema + "." + targetTable);
-    }
-
-    public KeyImpl(DBWrapper dbWrapper, TapSchema tapSchema, String fromTableCompleteName, String targetTableCompleteName) {
-        super(dbWrapper, tapSchema);
-
-        addProperty(FROM_TABLE_KEY, new FixedEntityProperty<>(fromTableCompleteName));
-        addProperty(TARGET_TABLE_KEY, new FixedEntityProperty<>(targetTableCompleteName));
-
-        addProperty(ID_KEY, new EditableProperty<String>());
-        addProperty(UTYPE_KEY, new EditableProperty<String>());
-        addProperty(DESCRIPTION_KEY, new EditableProperty<String>());
-        addProperty(KEY_ID_KEY, new EditableProperty<Long>());
+    public Key(TapSchema tapSchema, KeyMetadata keyMetadata) {
+        super(tapSchema, tapSchema.getTableModel(TapSchema.KEYS_TABLE), keyMetadata.getKeyMetadata());
 
+        this.keyMetadata = keyMetadata;
         keyColumns = new ArrayList<>();
-
-        String fromTableCompleteNameSplit[] = fromTableCompleteName.split(Pattern.quote("."));
-        String targetTableCompleteNameSplit[] = targetTableCompleteName.split(Pattern.quote("."));
-        this.fromSchema = fromTableCompleteNameSplit[0];
-        this.fromTable = fromTableCompleteNameSplit[1];
-        this.targetSchema = targetTableCompleteNameSplit[0];
-        this.targetTable = targetTableCompleteNameSplit[1];
         visible = false;
     }
 
-    @Override
+    public KeyMetadata getKeyMetadata() {
+        return keyMetadata;
+    }
+
     public boolean isVisible() {
         return visible;
     }
@@ -89,12 +70,10 @@ public class KeyImpl extends TapSchemaEntityImpl implements Key {
         this.visible = visible;
     }
 
-    @Override
     public String getId() {
         return getValue(ID_KEY, String.class);
     }
 
-    @Override
     public void setId(String id) {
         setValue(ID_KEY, id);
         for (KeyColumn keyColumn : keyColumns) {
@@ -102,73 +81,36 @@ public class KeyImpl extends TapSchemaEntityImpl implements Key {
         }
     }
 
-    @Override
     public List<KeyColumn> getKeyColumns() {
         return Collections.unmodifiableList(keyColumns);
     }
 
-    @Override
     public String getFromSchemaName() {
-        return fromSchema;
+        return keyMetadata.getFromSchema();
     }
 
-    @Override
     public String getFromTableSimpleName() {
-        return fromTable;
+        return keyMetadata.getFromTable();
     }
 
-    @Override
     public String getFromTableCompleteName() {
         return getValue(FROM_TABLE_KEY, String.class);
     }
 
-    @Override
     public String getTargetSchemaName() {
-        return targetSchema;
+        return keyMetadata.getTargetSchema();
     }
 
-    @Override
     public String getTargetTableSimpleName() {
-        return targetTable;
+        return keyMetadata.getTargetTable();
     }
 
-    @Override
     public String getTargetTableCompleteName() {
         return getValue(TARGET_TABLE_KEY, String.class);
     }
 
-    @Override
-    public String getUtype() {
-        return getValue(UTYPE_KEY, String.class);
-    }
-
-    @Override
-    public void setUtype(String utype) {
-        setValue(UTYPE_KEY, utype);
-    }
-
-    @Override
-    public String getDescription() {
-        return getValue(DESCRIPTION_KEY, String.class);
-    }
-
-    @Override
-    public void setDescription(String description) {
-        setValue(DESCRIPTION_KEY, description);
-    }
-
-    @Override
-    public Long getKeyID() {
-        return getValue(KEY_ID_KEY, Long.class);
-    }
-
-    @Override
-    public void setKeyID(Long keyID) {
-        setValue(KEY_ID_KEY, keyID);
-    }
-
     public KeyColumn addKeyColumn(String fromColumn, String targetColumn) {
-        KeyColumn keyColumn = new KeyColumnImpl(dbWrapper, tapSchema, this, fromColumn, targetColumn);
+        KeyColumn keyColumn = new KeyColumn(tapSchema, this, fromColumn, targetColumn);
         keyColumns.add(keyColumn);
         return keyColumn;
     }
@@ -200,11 +142,11 @@ public class KeyImpl extends TapSchemaEntityImpl implements Key {
         if (obj == null) {
             return false;
         }
-        if (getClass() != obj.getClass()) {
+        if (Key.class != obj.getClass()) {
             return false;
         }
 
-        final KeyImpl other = (KeyImpl) obj;
+        final Key other = (Key) obj;
         List<KeyColumn> otherKeyColumns = other.getKeyColumns();
 
         // Comparing each key column
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/KeyColumnImpl.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/KeyColumn.java
similarity index 72%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/KeyColumnImpl.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/KeyColumn.java
index 8294c918fbf68615d37563c0e662be81226af674..b7aeb1159b1cbbcf99936502afb4021b83c635b9 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/KeyColumnImpl.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/KeyColumn.java
@@ -20,75 +20,55 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm;
 
-import it.inaf.ia2.tsm.api.contract.Key;
-import it.inaf.ia2.tsm.api.contract.KeyColumn;
-import it.inaf.ia2.tsm.api.contract.TapSchema;
 import java.util.Objects;
 
 /**
  * The main implementation of {@link KeyColumn}.
- * 
+ *
  * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
  */
-public class KeyColumnImpl extends TapSchemaEntityImpl implements KeyColumn {
+public class KeyColumn extends TapSchemaEntity {
+
+    public static final String KEY_ID_KEY = "key_id";
+    public static final String FROM_COLUMN_KEY = "from_column";
+    public static final String TARGET_COLUMN_KEY = "target_column";
 
     private static final long serialVersionUID = -3681677723432728327L;
 
     private Key key;
 
-    private KeyColumnImpl() {
+    private KeyColumn() {
         // for serialization
         super();
     }
 
-    protected KeyColumnImpl(DBWrapper dbWrapper, TapSchema tapSchema, Key key, String fromColumn, String targetColumn) {
-        super(dbWrapper, tapSchema);
+    protected KeyColumn(TapSchema tapSchema, Key key, String fromColumn, String targetColumn) {
+        super(tapSchema, tapSchema.getTableModel(TapSchema.KEY_COLUMNS_TABLE), key.getKeyMetadata().getKeyColumnMetadata(fromColumn, targetColumn));
         this.key = key;
-
-        addProperty(FROM_COLUMN_KEY, new FixedEntityProperty<>(fromColumn));
-        addProperty(TARGET_COLUMN_KEY, new FixedEntityProperty<>(targetColumn));
-
-        addProperty(KEY_ID_KEY, new EditableProperty<>(key.getId(), true));
-        addProperty(KEY_COLUMN_ID_KEY, new EditableProperty<Long>());
     }
 
-    @Override
     public Key getParent() {
         return key;
     }
 
-    @Override
     public String getKeyId() {
         return getValue(KEY_ID_KEY, String.class);
     }
 
-    @Override
     public void setKeyId(String keyId) {
         setValue(KEY_ID_KEY, keyId);
     }
 
-    @Override
     public String getFromColumn() {
         return getValue(FROM_COLUMN_KEY, String.class);
     }
 
-    @Override
     public String getTargetColumn() {
         return getValue(TARGET_COLUMN_KEY, String.class);
     }
 
-    @Override
-    public Long getKeyColumnID() {
-        return getValue(KEY_COLUMN_ID_KEY, Long.class);
-    }
-
-    @Override
-    public void setKeyColumnID(Long keyColumnID) {
-        setValue(KEY_COLUMN_ID_KEY, keyColumnID);
-    }
-
     @Override
     public int hashCode() {
         int hash = 3;
@@ -107,7 +87,7 @@ public class KeyColumnImpl extends TapSchemaEntityImpl implements KeyColumn {
         if (getClass() != obj.getClass()) {
             return false;
         }
-        final KeyColumnImpl other = (KeyColumnImpl) obj;
+        final KeyColumn other = (KeyColumn) obj;
         if (!Objects.equals(this.key.getFromTableCompleteName(), other.key.getFromTableCompleteName())) {
             return false;
         }
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/KeyMetadata.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/KeyMetadata.java
new file mode 100644
index 0000000000000000000000000000000000000000..02b93715d3fa8fe63928322f85f70fea5121e951
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/KeyMetadata.java
@@ -0,0 +1,162 @@
+/*
+ * _____________________________________________________________________________
+ * 
+ * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
+ * Trieste INAF - IA2 Italian Center for Astronomical Archives
+ * _____________________________________________________________________________
+ * 
+ * Copyright (C) 2017 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.
+ */
+package it.inaf.ia2.tsm;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class KeyMetadata implements Serializable {
+
+    public static final String NEW_KEY = "#NEW#";
+    private static final long serialVersionUID = -30688540834789724L;
+
+    private final String fromSchema;
+    private final String fromTable;
+    private final List<String> fromColumns;
+    private final String targetSchema;
+    private final String targetTable;
+    private final List<String> targetColumns;
+
+    public KeyMetadata(String fromSchema, String fromTable, String targetSchema, String targetTable) {
+        this.fromSchema = fromSchema;
+        this.fromTable = fromTable;
+        this.fromColumns = new ArrayList<>();
+        this.targetSchema = targetSchema;
+        this.targetTable = targetTable;
+        this.targetColumns = new ArrayList<>();
+    }
+
+    public String getFromSchema() {
+        return fromSchema;
+    }
+
+    public String getFromTable() {
+        return fromTable;
+    }
+
+    public List<String> getFromColumns() {
+        return fromColumns;
+    }
+
+    public String getTargetSchema() {
+        return targetSchema;
+    }
+
+    public String getTargetTable() {
+        return targetTable;
+    }
+
+    public List<String> getTargetColumns() {
+        return targetColumns;
+    }
+
+    public void addKeyColumn(String fromColumn, String targetColumn) {
+        fromColumns.add(fromColumn);
+        targetColumns.add(targetColumn);
+    }
+
+    public Map<String, Object> getKeyMetadata() {
+        Map<String, Object> metadata = new HashMap<>();
+        metadata.put(Key.ID_KEY, NEW_KEY);
+        metadata.put(Key.FROM_TABLE_KEY, fromSchema + "." + fromTable);
+        metadata.put(Key.TARGET_TABLE_KEY, targetSchema + "." + targetTable);
+        return metadata;
+    }
+
+    public Map<String, Object> getKeyColumnMetadata(String fromColumn, String targetColumn) {
+        Map<String, Object> metadata = new HashMap<>();
+        metadata.put(KeyColumn.KEY_ID_KEY, NEW_KEY);
+        metadata.put(KeyColumn.FROM_COLUMN_KEY, fromColumn);
+        metadata.put(KeyColumn.TARGET_COLUMN_KEY, targetColumn);
+        return metadata;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 17 * hash + Objects.hashCode(this.fromSchema);
+        hash = 17 * hash + Objects.hashCode(this.fromTable);
+        for (String fromColumn : fromColumns) {
+            hash = 17 * hash + Objects.hashCode(fromColumn);
+        }
+        hash = 17 * hash + Objects.hashCode(this.targetSchema);
+        hash = 17 * hash + Objects.hashCode(this.targetTable);
+        for (String targetColumn : targetColumns) {
+            hash = 17 * hash + Objects.hashCode(targetColumn);
+        }
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final KeyMetadata other = (KeyMetadata) obj;
+        if (!Objects.equals(this.fromSchema, other.fromSchema)) {
+            return false;
+        }
+        if (!Objects.equals(this.fromTable, other.fromTable)) {
+            return false;
+        }
+        if (!Objects.equals(this.targetSchema, other.targetSchema)) {
+            return false;
+        }
+        if (!Objects.equals(this.targetTable, other.targetTable)) {
+            return false;
+        }
+        if (this.fromColumns.size() != other.fromColumns.size()) {
+            return false;
+        }
+        for (int i = 0; i < fromColumns.size(); i++) {
+            String fromColumn = fromColumns.get(i);
+            if (!Objects.equals(fromColumn, other.fromColumns.get(i))) {
+                return false;
+            }
+        }
+        if (this.targetColumns.size() != other.targetColumns.size()) {
+            return false;
+        }
+        for (int i = 0; i < targetColumns.size(); i++) {
+            String targetColumn = targetColumns.get(i);
+            if (!Objects.equals(targetColumn, other.targetColumns.get(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/SchemaImpl.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Schema.java
similarity index 67%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/SchemaImpl.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/Schema.java
index 22bc9e822a3b6f302d60c765e184329b65d1d945..fe02380623dcbe95df899ca9bc622426214ad625 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/SchemaImpl.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Schema.java
@@ -20,14 +20,11 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm;
 
-import it.inaf.ia2.tsm.api.contract.Key;
-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.datalayer.DBBroker;
 import java.sql.SQLException;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -40,35 +37,34 @@ import org.slf4j.LoggerFactory;
  *
  * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
  */
-public class SchemaImpl extends ChildEntityImpl<TapSchema> implements Schema {
+public class Schema extends ChildEntity<TapSchema> implements EntitiesContainer<Table> {
+
+    public final static String SCHEMA_NAME_KEY = "schema_name";
 
     private static final long serialVersionUID = 8828583158332877855L;
-    private static final Logger log = LoggerFactory.getLogger(SchemaImpl.class);
+    private static final Logger LOG = LoggerFactory.getLogger(Schema.class);
 
     private final Map<String, Table> tables;
     private Map<String, String> tablesTypes;
 
-    private SchemaImpl() {
+    private Schema() {
         // for serialization
         super();
         tables = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
     }
 
-    public SchemaImpl(DBWrapper dbWrapper, TapSchema tapSchema, String name) throws SQLException {
-        super(dbWrapper, tapSchema);
+    public Schema(TapSchema tapSchema, String name) throws SQLException {
+        super(tapSchema, tapSchema.getTableModel(TapSchema.SCHEMAS_TABLE), tapSchema.getSchemaMetadata(name));
+
+        DBBroker broker = tapSchema.getDBBroker(name);
 
         tables = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        tablesTypes = DaoTable.getTablesTypes(dbWrapper, tapSchema, name);
+        tablesTypes = broker.getAllTableTypes(name);
 
-        for (String tableName : DaoTable.getAllTablesNames(dbWrapper, tapSchema, name)) {
+        for (String tableName : broker.getAllTablesNames(name)) {
             tables.put(tableName, null);
         }
-        log.debug("Schema {} contains {} tables", name, tables.size());
-
-        addProperty(SCHEMA_NAME_KEY, new FixedEntityProperty<>(name));
-        addProperty(UTYPE_KEY, new EditableProperty<String>());
-        addProperty(DESCRIPTION_KEY, new EditableProperty<String>());
-        addProperty(SCHEMA_ID, new EditableProperty<Long>());
+        LOG.debug("Schema {} contains {} tables", name, tables.size());
 
         setStatus(Status.LOADED);
     }
@@ -89,7 +85,7 @@ public class SchemaImpl extends ChildEntityImpl<TapSchema> implements Schema {
     public Table addChild(String tableSimpleName) throws SQLException {
         String schemaName = getName();
 
-        log.debug("Adding table {} into schema {}", tableSimpleName, schemaName);
+        LOG.debug("Adding table {} into schema {}", tableSimpleName, schemaName);
 
         if (!tables.containsKey(tableSimpleName)) {
             //throw new IllegalArgumentException("The table " + tableSimpleName + " doesn't exist into the schema " + schemaName + ". Are you sure you are using the simple table name?");
@@ -100,21 +96,9 @@ public class SchemaImpl extends ChildEntityImpl<TapSchema> implements Schema {
             Table table = tables.get(tableSimpleName);
 
             if (table == null) {
-                table = new TableImpl(dbWrapper, tapSchema, this, tableSimpleName, tablesTypes.get(tableSimpleName));
-
-                // Adding fromKeys and targetKeys to the table. The keys could be hidden,
-                // their status is not important here. We are adding all tables keys.
-                // It is the method {@link #TableImpl.checkKeys()} that set their visibility.
-                // We have to loop on all keys of all schemas to retrieve also the
-                // target keys.
-                for (Key key : ((TapSchemaImpl) tapSchema).getAllKeys()) {
-                    if (key.getFromTableCompleteName().equals(table.getCompleteName())) {
-                        ((TableImpl) table).addFromKey(key);
-                    }
-                    if (key.getTargetTableCompleteName().equals(table.getCompleteName())) {
-                        ((TableImpl) table).addTargetKey(key);
-                    }
-                }
+                table = new Table(tapSchema, this, tableSimpleName);
+
+                tapSchema.checkKeys();
 
                 tables.put(tableSimpleName, table);
                 table.setStatus(Status.ADDED_NOT_PERSISTED);
@@ -131,7 +115,7 @@ public class SchemaImpl extends ChildEntityImpl<TapSchema> implements Schema {
                 }
             }
 
-            ((TapSchemaImpl) tapSchema).checkKeys();
+            tapSchema.checkKeys();
 
             return table;
         }
@@ -144,7 +128,7 @@ public class SchemaImpl extends ChildEntityImpl<TapSchema> implements Schema {
     public void removeChild(String tableSimpleName) {
         String schemaName = getName();
 
-        log.debug("Removing table {} from schema {}", tableSimpleName, schemaName);
+        LOG.debug("Removing table {} from schema {}", tableSimpleName, schemaName);
 
         if (!tables.containsKey(tableSimpleName)) {
             throw new IllegalArgumentException("The table " + tableSimpleName + " doesn't exist into the schema " + schemaName + ". Are you sure you are using the simple table name?");
@@ -166,7 +150,7 @@ public class SchemaImpl extends ChildEntityImpl<TapSchema> implements Schema {
             table.setStatus(Status.TO_REMOVE);
         }
 
-        ((TapSchemaImpl) tapSchema).checkKeys();
+        tapSchema.checkKeys();
     }
 
     /**
@@ -209,45 +193,6 @@ public class SchemaImpl extends ChildEntityImpl<TapSchema> implements Schema {
         return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED, Status.TO_REMOVE, Status.REMOVED_NOT_PERSISTED);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getUtype() {
-        return getValue(UTYPE_KEY, String.class);
-    }
-
-    @Override
-    public void setUtype(String utype) {
-        setValue(UTYPE_KEY, utype);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getDescription() {
-        return getValue(DESCRIPTION_KEY, String.class);
-    }
-
-    @Override
-    public void setDescription(String description) {
-        setValue(DESCRIPTION_KEY, description);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Long getSchemaID() {
-        return getValue(SCHEMA_ID, Long.class);
-    }
-
-    @Override
-    public void setSchemaID(Long schemaID) {
-        setValue(SCHEMA_ID, schemaID);
-    }
-
     @Override
     public int hashCode() {
         int hash = 5;
@@ -263,11 +208,8 @@ public class SchemaImpl extends ChildEntityImpl<TapSchema> implements Schema {
         if (getClass() != obj.getClass()) {
             return false;
         }
-        final SchemaImpl other = (SchemaImpl) obj;
-        if (!Objects.equals(this.getName(), other.getName())) {
-            return false;
-        }
-        return true;
+        final Schema other = (Schema) obj;
+        return Objects.equals(this.getName(), other.getName());
     }
 
     /**
@@ -275,7 +217,7 @@ public class SchemaImpl extends ChildEntityImpl<TapSchema> implements Schema {
      * to the database, in order to remove from the memory the tables with
      * status {@code Status.TO_REMOVE} or {@code Status.REMOVED_NOT_PERSISTED}.
      */
-    protected void cleanTable(String tableSimpleName) {
+    public void cleanTable(String tableSimpleName) {
         if (!tables.containsKey(tableSimpleName)) {
             throw new IllegalArgumentException("Schema " + getName() + "doesn't contain the table " + tableSimpleName);
         }
@@ -289,4 +231,12 @@ public class SchemaImpl extends ChildEntityImpl<TapSchema> implements Schema {
     public TapSchema getParent() {
         return tapSchema;
     }
+
+    public Map<String, Object> getTableMetadata(String tableSimpleName) {
+        Map<String, Object> metadata = new HashMap<>();
+        metadata.put(Table.SCHEMA_NAME_KEY, getName());
+        metadata.put(Table.TABLE_NAME_KEY, getName() + "." + tableSimpleName);
+        metadata.put(Table.TABLE_TYPE_KEY, tablesTypes.get(tableSimpleName));
+        return metadata;
+    }
 }
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/SelectQueryBuilder.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/SelectQueryBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3db4d2cebb5cf2087ed62a08c090172640e1480
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/SelectQueryBuilder.java
@@ -0,0 +1,127 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Prepares a {@code SELECT} SQL query for a given {@link TapSchemaEntity} and a
+ * given {@link TapSchema}.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public abstract class SelectQueryBuilder {
+//
+//    private static final Logger log = LoggerFactory.getLogger(SelectQueryBuilder.class);
+//
+//    private final TapSchema tapSchema;
+//    private final String query;
+//    private final List<EntityPropertyInfo> addedProperties;
+//
+//    protected SelectQueryBuilder(DatabaseType dbType, TapSchema tapSchema, String tapSchemaTableName) {
+//
+//        this.tapSchema = tapSchema;
+//
+//        StringBuilder querySb = new StringBuilder("SELECT ");
+//
+//        addedProperties = new ArrayList<>();
+//
+//        boolean first = true;
+//        for (EntityPropertyInfo propertyInfo : EntityPropertyInfo.getEntityPropertiesInfo(tapSchemaTableName)) {
+//            if (propertyInfo.acceptVersion(tapSchema.getVersion())) {
+//                if (!first) {
+//                    querySb.append(", ");
+//                }
+//                querySb.append(propertyInfo.getPropertyKey());
+//                addedProperties.add(propertyInfo);
+//                first = false;
+//            }
+//        }
+//
+//        querySb.append(" FROM ");
+//
+//        querySb.append(TSMUtil.escapeName(tapSchema.getName(), dbType));
+//        querySb.append(".");
+//        querySb.append(TSMUtil.escapeName(tapSchemaTableName, dbType));
+//
+//        query = querySb.toString();
+//    }
+//
+//    protected abstract TapSchemaEntity getEntity(ResultSet rs) throws SQLException;
+//
+//    protected void executeQuery(Connection connection) throws SQLException {
+//
+//        log.debug("Executing query {}", query);
+//
+//        try (Statement statement = connection.createStatement();
+//                ResultSet rs = statement.executeQuery(query)) {
+//
+//            while (rs.next()) {
+//
+//                TapSchemaEntity entity = getEntity(rs);
+//
+//                if (entity != null) {
+//                    for (EntityPropertyInfo property : addedProperties) {
+//                        String key = property.getPropertyKey();
+//                        Class type = property.getPropertyType();
+//                        Object value = TSMUtil.getObject(rs, key, type);
+//                        if (property.isUpdatable()) {
+//                            entity.initProperty(key, value);
+//                        } else {
+//                            Object correctValue = entity.getValue(key, type);
+//                            boolean changed = (correctValue == null && value != null) || (correctValue != null && !correctValue.equals(value));
+//                            if (changed) {
+//
+//                                entity.amendProperty(key, correctValue);
+//
+//                                InconsistentValue inconsistentValue = new InconsistentValue(
+//                                        TSMUtil.getNaturalLangueName(entity),
+//                                        TSMUtil.getName(entity),
+//                                        key,
+//                                        value,
+//                                        correctValue
+//                                );
+//
+//                                tapSchema.getConsistencyChecks().addInconsistency(inconsistentValue);
+//
+//                                //throw new InconsistentTapSchemaException(debugInfo);
+//                            }
+//                        }
+//                    }
+//                }
+//            }
+//        }
+//    }
+//
+//    public String getQuery() {
+//        return query;
+//    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Status.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Status.java
similarity index 98%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Status.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/Status.java
index 7081f27e39cc74135104f3baef312299238f2020..59f2a6204059973ad033ed59491fcef6d11aacca 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Status.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Status.java
@@ -20,7 +20,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api.contract;
+package it.inaf.ia2.tsm;
 
 /**
  * Define the persistence status of a {@link ChildEntity}.
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TSMUtil.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TSMUtil.java
similarity index 69%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TSMUtil.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/TSMUtil.java
index 8548bdf7c8adc56f34fca053a09f490b80b75896..a584a6e276348d94c21f58ed4807daf8445259c5 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TSMUtil.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TSMUtil.java
@@ -20,20 +20,12 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm;
 
+import it.inaf.ia2.tsm.datalayer.Credentials;
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
 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;
@@ -53,7 +45,7 @@ import org.slf4j.LoggerFactory;
  */
 public class TSMUtil {
 
-    private static final Logger log = LoggerFactory.getLogger(TSMUtil.class);
+    private static final Logger LOG = LoggerFactory.getLogger(TSMUtil.class);
 
     public static DataSource createDataSource(Credentials credentials) {
 
@@ -208,16 +200,8 @@ public class TSMUtil {
         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 UnsupportedOperationException getUnsupportedOperationException(String version, String unsupportedFeature) {
+        return new UnsupportedOperationException("Version \"" + version + "\" doesn't support " + unsupportedFeature);
     }
 
     protected static String escapeName(String name, DatabaseType dbType) {
@@ -248,15 +232,15 @@ public class TSMUtil {
         } else if (entity instanceof KeyColumn) {
             return TapSchema.KEY_COLUMNS_TABLE;
         }
-        log.warn("getTapSchemaTableNameFromEntity returns null for {}" + entity.getClass().getCanonicalName());
+        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);
-    }
+//    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) {
@@ -330,59 +314,59 @@ public class TSMUtil {
      * @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");
-
-        // TABLES
-        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");
-
-        // COLUMNS
-        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");
-
-        // KEYS
-        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");
-
-        // KEY COLUMNS
-        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");
+//
+//        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");
+//
+//        // TABLES
+//        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");
+//
+//        // COLUMNS
+//        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");
+//
+//        // KEYS
+//        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");
+//
+//        // KEY COLUMNS
+//        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");
     }
 }
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Table.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Table.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ad2590fe03cc421824ed827d9e59d32e3b4a5e0
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Table.java
@@ -0,0 +1,234 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.datalayer.DBBroker;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The main implementation of {@link Table}.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class Table extends ChildEntity<Schema> implements EntitiesContainer<Column> {
+
+    public final static String SCHEMA_NAME_KEY = "schema_name";
+    public final static String TABLE_NAME_KEY = "table_name";
+    public final static String TABLE_TYPE_KEY = "table_type";
+
+    private static final long serialVersionUID = 8265331530960896871L;
+    private static final Logger LOG = LoggerFactory.getLogger(Table.class);
+
+    private Map<String, Map<String, Object>> columnsMetadata;
+    private Map<String, Column> columns;
+
+    private String simpleName;
+    private Schema parentSchema;
+
+    private Table() {
+        // for serialization
+        super();
+    }
+
+    protected Table(TapSchema tapSchema, Schema schema, String tableSimpleName) throws SQLException {
+        super(tapSchema, tapSchema.getTableModel(TapSchema.TABLES_TABLE), schema.getTableMetadata(tableSimpleName));
+
+        parentSchema = schema;
+        this.simpleName = tableSimpleName;
+
+        columns = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+
+        DBBroker broker = tapSchema.getDBBroker(schema.getName());
+        columnsMetadata = broker.getAllColumnsMetadata(schema.getName(), tableSimpleName);
+        for (Map.Entry<String, Map<String, Object>> entry : columnsMetadata.entrySet()) {
+            // Adding table names to columns metadata
+            entry.getValue().put(Column.TABLE_NAME_KEY, schema.getName() + "." + tableSimpleName);
+            // Initializing columns map
+            columns.put(entry.getKey(), null);
+        }
+
+        setStatus(Status.LOADED);
+    }
+
+    /**
+     * Only the table name.
+     */
+    @Override
+    public String getName() {
+        return simpleName;
+    }
+
+    /**
+     * {@code schema_name.table_name}.
+     */
+    public String getCompleteName() {
+        return getValue(TABLE_NAME_KEY, String.class);
+    }
+
+    /**
+     * {@inheritDoc }
+     */
+    @Override
+    public Column addChild(String columnName) {
+        String tableCompleteName = getCompleteName();
+
+        LOG.debug("Adding column {} into table {}", columnName, tableCompleteName);
+
+        if (!columns.containsKey(columnName)) {
+            tapSchema.getConsistencyChecks().addUnexistingColumn(getCompleteName(), columnName);
+            return null;
+        } else {
+            Column column = columns.get(columnName);
+            if (column == null) {
+                column = new Column(tapSchema, this, columnName);
+                columns.put(columnName, column);
+                column.setStatus(Status.ADDED_NOT_PERSISTED);
+            } else {
+                switch (column.getStatus()) {
+                    case REMOVED_NOT_PERSISTED: // undo removal
+                        column.setStatus(Status.ADDED_NOT_PERSISTED);
+                        break;
+                    case TO_REMOVE: // undo removal
+                        column.setStatus(Status.ADDED_PERSISTED);
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Cannot add column " + columnName + " in table " + tableCompleteName + ". Invalid column status: " + column.getStatus());
+                }
+            }
+
+            tapSchema.checkKeys();
+
+            return column;
+        }
+    }
+
+    /**
+     * {@inheritDoc }
+     */
+    @Override
+    public void removeChild(String columnName) {
+        String tableCompleteName = getCompleteName();
+
+        LOG.debug("Removing column {} from table {}", columnName, tableCompleteName);
+
+        if (!columns.containsKey(columnName)) {
+            throw new IllegalArgumentException("Column " + columnName + " doesn't exists in table " + tableCompleteName);
+        }
+
+        Column column = columns.get(columnName);
+
+        switch (column.getStatus()) {
+            case ADDED_NOT_PERSISTED:
+                column.setStatus(Status.REMOVED_NOT_PERSISTED);
+                break;
+            case ADDED_PERSISTED:
+                column.setStatus(Status.TO_REMOVE);
+                break;
+            default:
+                throw new IllegalArgumentException("Cannot remove column " + columnName + " in table " + tableCompleteName + ". Invalid column status: " + column.getStatus());
+        }
+
+        tapSchema.checkKeys();
+    }
+
+    /**
+     * {@inheritDoc }
+     */
+    @Override
+    public Column getChild(String childName, Status... statuses) {
+        return TSMUtil.getChild(columns, childName, statuses);
+    }
+
+    /**
+     * {@inheritDoc }
+     */
+    @Override
+    public List<Column> getChildren(Status... statuses) {
+        return TSMUtil.getChildrenByStatus(columns.values(), statuses);
+    }
+
+    /**
+     * {@inheritDoc }
+     */
+    @Override
+    public List<String> getAddableChildrenNames() {
+        return TSMUtil.getAddableChildrenNames(columns);
+    }
+
+    @Override
+    public List<Column> getAddedChildren() {
+        return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
+    }
+
+    @Override
+    public List<Column> getAddedOrRemovedChildren() {
+        return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED, Status.TO_REMOVE, Status.REMOVED_NOT_PERSISTED);
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 29 * hash + Objects.hashCode(this.getCompleteName());
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final Table other = (Table) obj;
+        if (!Objects.equals(this.getCompleteName(), other.getCompleteName())) {
+            return false;
+        }
+        return true;
+    }
+
+    protected void afterUpdate() {
+        for (Column column : columns.values()) {
+            if (column.getStatus() == Status.ADDED_NOT_PERSISTED) {
+                column.setStatus(Status.ADDED_PERSISTED);
+            } else if (column.getStatus() != Status.ADDED_PERSISTED) {
+                column.setStatus(Status.LOADED);
+            }
+        }
+    }
+
+    @Override
+    public Schema getParent() {
+        return parentSchema;
+    }
+
+    public Map<String, Object> getColumnMetadata(String columnName) {
+        return columnsMetadata.get(columnName);
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchema.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchema.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b008b7047f6842b855200a734b5ff063ce1f265
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchema.java
@@ -0,0 +1,601 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.datalayer.DBBroker;
+import it.inaf.ia2.tsm.datalayer.DBBrokerFactory;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
+import it.inaf.ia2.tsm.xmlmodel.TableModel;
+import it.inaf.ia2.tsm.xmlmodel.TapSchemaModel;
+import it.inaf.ia2.tsm.xmlmodel.TapSchemaModels;
+import java.io.Serializable;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The main implementation of {@link TapSchema}.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class TapSchema implements EntitiesContainer<Schema>, Serializable {
+
+    // Mandatory tables constants
+    public static final String TABLES_TABLE = "tables";
+    public static final String SCHEMAS_TABLE = "schemas";
+    public static final String COLUMNS_TABLE = "columns";
+    public static final String KEYS_TABLE = "keys";
+    public static final String KEY_COLUMNS_TABLE = "key_columns";
+
+    private static final long serialVersionUID = 1678083091602571256L;
+
+    private static final Logger LOG = LoggerFactory.getLogger(TapSchema.class);
+
+    private final Map<String, Schema> schemas;
+    private final List<KeyMetadata> keysMetadata;
+    private final Set<Key> allKeys;
+    private final ConsistencyChecks consistencyChecks;
+
+    private boolean loading;
+    private String version;
+    private DBWrapper dbWrapper;
+    private String tapSchemaName;
+    private boolean exists;
+
+    private transient DBBroker sourceDBBroker;
+    private transient DBBroker tapSchemaDBBroker;
+
+    public final DBBroker getSourceDBBroker() {
+        if (sourceDBBroker == null) {
+            sourceDBBroker = DBBrokerFactory.getDBBroker(dbWrapper.getSourceDataSourceWrapper());
+        }
+        return sourceDBBroker;
+    }
+
+    public final DBBroker getTapSchemaDBBroker() {
+        if (tapSchemaDBBroker == null) {
+            tapSchemaDBBroker = DBBrokerFactory.getDBBroker(dbWrapper.getTapSchemaDataSourceWrapper());
+        }
+        return tapSchemaDBBroker;
+    }
+
+    private TapSchema() {
+        // for serialization
+        schemas = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        allKeys = new HashSet<>();
+        keysMetadata = new ArrayList<>();
+        consistencyChecks = new ConsistencyChecks();
+    }
+
+    public TapSchema(String version, DBWrapper dbWrapper, String tapSchemaName, boolean exists) throws SQLException {
+        this();
+
+        loading = true;
+        this.version = version;
+        this.dbWrapper = dbWrapper;
+        this.tapSchemaName = tapSchemaName;
+        this.exists = exists;
+
+        // Initializing schemas map
+        for (String schemaName : getSourceDBBroker().getAllSchemaNames()) {
+            schemas.put(schemaName, null);
+        }
+        schemas.put(tapSchemaName, null); // the TAP_SCHEMA contains itself
+
+//        if (exists) {
+//            DaoSchema.fillSavedSchemas(dbWrapper, (this));
+//            DaoTable.fillSavedTables(dbWrapper, (this));
+//            DaoColumn.fillSavedColumns(dbWrapper, (this));
+//            DaoKey.fillSavedKeys(dbWrapper, (this));
+//        }
+        loading = false;
+        checkKeys();
+    }
+
+    public DBBroker getDBBroker(String schemaName) {
+        if (schemaName.equals(tapSchemaName)) {
+            return getTapSchemaDBBroker();
+        } else {
+            return getSourceDBBroker();
+        }
+    }
+
+    /**
+     * The name of the TAP_SCHEMA schema.
+     */
+    public String getName() {
+        return tapSchemaName;
+    }
+
+    /**
+     * The version selected for this TAP_SCHEMA.
+     */
+    public String getVersion() {
+        return version;
+    }
+
+    private void loadSchemaKeysMetadata(String schemaName) throws SQLException {
+        keysMetadata.addAll(getDBBroker(schemaName).getKeysMetadata(schemaName));
+    }
+
+    protected Set<Key> getAllKeys() {
+        return allKeys;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Schema addChild(String schemaName) throws SQLException {
+        LOG.debug("Adding schema {}", schemaName);
+
+        Schema schema;
+
+        if (!schemas.containsKey(schemaName)) {
+
+            consistencyChecks.addUnexistingSchema(schemaName);
+            schema = null;
+        } else {
+
+            schema = schemas.get(schemaName);
+
+            if (schema == null) {
+                schema = new Schema(this, schemaName);
+                schema.setStatus(Status.ADDED_NOT_PERSISTED);
+                schemas.put(schemaName, schema);
+                loadSchemaKeysMetadata(schemaName);
+            } else {
+                switch (schema.getStatus()) {
+                    case TO_REMOVE:
+                        schema.setStatus(Status.ADDED_PERSISTED);
+                        break;
+                    case REMOVED_NOT_PERSISTED:
+                        schema.setStatus(Status.ADDED_NOT_PERSISTED);
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Cannot add the schema " + schemaName + ". Invalid status. Schema status is " + schema.getStatus());
+                }
+            }
+        }
+
+        checkKeys();
+
+        return schema;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void removeChild(String schemaName) {
+        LOG.debug("Removing schema {}", schemaName);
+
+        if (!schemas.containsKey(schemaName)) {
+            throw new IllegalArgumentException("The database doesn't contains a schema named " + schemaName);
+        }
+
+        Schema schema = schemas.get(schemaName);
+        if (schema == null || schema.getStatus() == Status.LOADED) {
+            throw new IllegalArgumentException("Cannot remove the schema " + schemaName + ". It has never been added.");
+        }
+
+        if (schema.getStatus() == Status.ADDED_NOT_PERSISTED) {
+            schema.setStatus(Status.REMOVED_NOT_PERSISTED);
+        } else if (schema.getStatus() == Status.ADDED_PERSISTED) {
+            schema.setStatus(Status.TO_REMOVE);
+        }
+
+        checkKeys();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Schema getChild(String childName, Status... statuses) {
+        return TSMUtil.getChild(schemas, childName, statuses);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<Schema> getChildren(Status... statuses) {
+        return TSMUtil.getChildrenByStatus(schemas.values(), statuses);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<String> getAddableChildrenNames() {
+        return TSMUtil.getAddableChildrenNames(schemas);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<Schema> getAddedChildren() {
+        return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<Schema> getAddedOrRemovedChildren() {
+        return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED, Status.TO_REMOVE, Status.REMOVED_NOT_PERSISTED);
+    }
+
+    /**
+     * This method has to be used after TAP_SCHEMA modifications are committed
+     * to the database, in order to remove from the memory the schemas with
+     * status {@code Status.TO_REMOVE} or {@code Status.REMOVED_NOT_PERSISTED}.
+     */
+    public void cleanSchema(String schemaName) {
+        if (!schemas.containsKey(schemaName)) {
+            throw new IllegalArgumentException("The TAP_SCHEMA doesn't contain the schema " + schemaName);
+        }
+        schemas.put(schemaName, null);
+    }
+
+    /**
+     * Save or update the TAP_SCHEMA changes into the database.
+     */
+    public void save() throws SQLException {
+
+        fillKeyIds();
+
+        DBBroker broker = getTapSchemaDBBroker();
+
+        broker.save(this);
+
+        if (!exists) {
+            // Adding TAP_SCHEMA into TAP_SCHEMA
+            Schema tapSchemaSchema = addChild(tapSchemaName);
+            for (String tableName : tapSchemaSchema.getAddableChildrenNames()) {
+                Table table = tapSchemaSchema.addChild(tableName);
+                for (String columnName : table.getAddableChildrenNames()) {
+                    table.addChild(columnName);
+                }
+            }
+            LOG.debug(this.toString());
+            TSMUtil.putInfoIntoTapSchemaSchema(tapSchemaSchema);
+
+            exists = true; // important!
+
+            //broker.save(this); // save again
+        }
+
+        exists = true;
+
+        consistencyChecks.getInconsistencies().clear();
+    }
+
+    /**
+     * Retrieve the maximum key id from all the schemas that are added into the
+     * TAP_SCHEMA.
+     *
+     * @return the maximum key, if it exists, zero otherwise.
+     */
+    private int getMaxKeyId() {
+        int maxKeyId = 0;
+        for (Key key : allKeys) {
+            if (key.getId() != null && !KeyMetadata.NEW_KEY.equals(key.getId())) {
+                int keyId = Integer.parseInt(key.getId());
+                if (keyId > maxKeyId) {
+                    maxKeyId = keyId;
+                }
+            }
+        }
+        return maxKeyId;
+    }
+
+    private void fillKeyIds() {
+
+        List<Key> newKeys = new ArrayList<>();
+        for (Key key : allKeys) {
+            if (key.isVisible() && KeyMetadata.NEW_KEY.equals(key.getId())) {
+                newKeys.add(key);
+            }
+        }
+
+        int maxKeyId = getMaxKeyId();
+        for (Key newKey : newKeys) {
+            maxKeyId++;
+            newKey.setId(maxKeyId + "");
+        }
+    }
+
+//    /**
+//     * Set keys visibility based on other entities visibility (a key is visible
+//     * if all schemas, tables and columns involved have
+//     * {@link Status} {@code ADDED_PERSISTED} or {@code ADDED_NOT_PERSISTED}).
+//     */
+//    protected void checkKeys() {
+//
+//        int currentKey = getMaxKeyId() + 1;
+//
+//        for (Key key : allKeys) {
+//
+//            ((Key) key).setVisible(false);
+//
+//            Schema fromSchema = getChild(key.getFromSchemaName(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
+//            Schema targetSchema = getChild(key.getTargetSchemaName(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
+//            if (fromSchema != null && targetSchema != null) {
+//
+//                Table fromTable = fromSchema.getChild(key.getFromTableSimpleName(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
+//                Table targetTable = targetSchema.getChild(key.getTargetTableSimpleName(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
+//
+//                if (fromTable != null && targetTable != null) {
+//
+//                    boolean allColumnsVisible = true;
+//
+//                    for (KeyColumn keyColumn : key.getKeyColumns()) {
+//
+//                        Column fromColumn = fromTable.getChild(keyColumn.getFromColumn(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
+//                        Column targetColumn = targetTable.getChild(keyColumn.getTargetColumn(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
+//
+//                        if (fromColumn == null || targetColumn == null) {
+//                            allColumnsVisible = false;
+//                            break;
+//                        }
+//                    }
+//
+//                    if (allColumnsVisible) {
+//                        ((Key) key).setVisible(true);
+//                        if (key.getId() == null) {
+//                            key.setId(currentKey + "");
+//                            currentKey++;
+//                        }
+//                    }
+//                }
+//            }
+//        }
+//        for (Key key : allKeys) {
+//            log.debug("{} [{}]", key, key.getStatus());
+//        }
+//    }
+//
+//    public void addFictitiousKey(Table fromTable, String[] fromColumns, Table targetTable, String[] targetColumns) {
+//        Key key = new Key(dbWrapper, this, fromTable.getCompleteName(), targetTable.getCompleteName());
+//        key.setId((getMaxKeyId() + 1) + "");
+//
+//        for (int i = 0; i < fromColumns.length; i++) {
+//            key.addKeyColumn(fromColumns[i], targetColumns[i]);
+//        }
+//
+//        fromTable.addFromKey(key);
+//        targetTable.addTargetKey(key);
+//
+//        allKeys.add(key);
+//        checkKeys();
+//    }
+    /**
+     * Automatically add and remove keys that should be visible.
+     */
+    public final void checkKeys() {
+        if (!loading) {
+
+            for (KeyMetadata keyMetadata : keysMetadata) {
+
+                // Check if key should be exposed in TAP_SCHEMA
+                boolean keyVisible = true;
+
+                for (String fromColumn : keyMetadata.getFromColumns()) {
+                    if (!isColumnVisible(keyMetadata.getFromSchema(), keyMetadata.getFromTable(), fromColumn)) {
+                        keyVisible = false;
+                        break;
+                    }
+                }
+                if (keyVisible) {
+                    for (String targetColumn : keyMetadata.getTargetColumns()) {
+                        if (!isColumnVisible(keyMetadata.getTargetSchema(), keyMetadata.getTargetTable(), targetColumn)) {
+                            keyVisible = false;
+                            break;
+                        }
+                    }
+                }
+
+                Key key = null;
+                for (Key k : allKeys) {
+                    if (k.getKeyMetadata().equals(keyMetadata)) {
+                        key = k;
+                        break;
+                    }
+                }
+
+                // TODO: use status instead of set visibile [?]
+                if (keyVisible) {
+                    if (key == null) {
+                        key = new Key(this, keyMetadata);
+                        allKeys.add(key);
+                    }
+                    key.setVisible(true);
+                } else if (key != null) {
+                    key.setVisible(false);
+                }
+            }
+        }
+    }
+
+    /**
+     * Print all TAP_SCHEMA tree (useful for debugging).
+     */
+    @Override
+    public String toString() {
+
+        StringBuilder sb = new StringBuilder("\n");
+
+        sb.append(String.format(">> TAP_SCHEMA %s <<\n", tapSchemaName));
+
+//        for (Schema schema : getChildren()) {
+//            sb.append("--");
+//            sb.append(schema.getName());
+//            sb.append(String.format(" [%s]", schema.getStatus()));
+//            sb.append("\n");
+//            List<Table> tables = schema.getChildren();
+//            for (int i = 0; i < tables.size(); i++) {
+//                Table table = tables.get(i);
+//                sb.append("   |--");
+//                sb.append(table.getName());
+//                sb.append(String.format(" [%s]", table.getStatus()));
+//                sb.append("\n");
+//
+//                String padder = i < tables.size() - 1 ? "   |   " : "       ";
+//
+//                for (Column column : table.getChildren()) {
+//                    sb.append(padder);
+//                    sb.append("|--");
+//                    sb.append(column.getName());
+//                    sb.append(String.format(" [%s]", column.getStatus()));
+//                    sb.append("\n");
+//                }
+//
+//                if (table.getAllFromKeys().size() > 0) {
+//                    sb.append(padder);
+//                    sb.append("** From keys **\n");
+//                    for (Key fromKey : table.getAllFromKeys()) {
+//                        sb.append(padder);
+//                        sb.append("* ");
+//                        sb.append(fromKey.toString());
+//                        sb.append(String.format(" [visible=%s]", fromKey.isVisible()));
+//                        sb.append("\n");
+//                    }
+//                }
+//                if (table.getAllTargetKeys().size() > 0) {
+//                    sb.append(padder);
+//                    sb.append("** Target keys **\n");
+//                    for (Key targetKey : table.getAllTargetKeys()) {
+//                        sb.append(padder);
+//                        sb.append("* ");
+//                        sb.append(targetKey.toString());
+//                        sb.append(String.format(" [visible=%s]", targetKey.isVisible()));
+//                        sb.append("\n");
+//                    }
+//                }
+//
+//                sb.append("\n");
+//            }
+//        }
+        return sb.toString();
+    }
+
+    public boolean isSchemaVisible(String schemaName) {
+        Schema schema = schemas.get(schemaName);
+        if (schema == null) {
+            return false;
+        }
+        return schema.getStatus() == Status.ADDED_PERSISTED
+                || schema.getStatus() == Status.ADDED_NOT_PERSISTED;
+    }
+
+    public boolean isTableVisible(String schemaName, String tableName) {
+        if (!isSchemaVisible(schemaName)) {
+            return false;
+        }
+
+        Table table = schemas.get(schemaName).getChild(tableName);
+        if (table == null) {
+            return false;
+        }
+
+        if (table.getStatus() == Status.ADDED_PERSISTED
+                || table.getStatus() == Status.ADDED_NOT_PERSISTED) {
+            return isSchemaVisible(schemaName);
+        }
+
+        return false;
+    }
+
+    public boolean isColumnVisible(String schemaName, String tableName, String columnName) {
+        if (!isTableVisible(schemaName, tableName)) {
+            return false;
+        }
+
+        Column column = schemas.get(schemaName).getChild(tableName).getChild(columnName);
+        if (column == null) {
+            return false;
+        }
+
+        if (column.getStatus() == Status.ADDED_PERSISTED
+                || column.getStatus() == Status.ADDED_NOT_PERSISTED) {
+            return isTableVisible(schemaName, tableName);
+        }
+
+        return false;
+    }
+
+    /**
+     * Define if the TAP_SCHEMA schema was already written into the database.
+     */
+    public boolean exists() {
+        return exists;
+    }
+
+    public ConsistencyChecks getConsistencyChecks() {
+        return consistencyChecks;
+    }
+
+    public TapSchemaModel getTapSchemaModel() {
+        return TapSchemaModels.getTapSchemaModel(version);
+    }
+
+    public TableModel getTableModel(String tableName) {
+        return getTapSchemaModel().getTables().get(tableName);
+    }
+
+    public KeyMetadata searchKeyMetadata(String fromSchemaName, String fromTableName, String fromColumnName) {
+        for (KeyMetadata km : keysMetadata) {
+            if (km.getFromSchema().equals(fromSchemaName) && km.getFromTable().equals(fromTableName)
+                    && km.getFromColumns().contains(fromColumnName)) {
+                return km;
+            }
+        }
+        return null;
+    }
+
+    public Map<String, Object> getSchemaMetadata(String schemaName) {
+        Map<String, Object> metadata = new HashMap<>();
+        metadata.put(Schema.SCHEMA_NAME_KEY, schemaName);
+        return metadata;
+    }
+
+    public List<Key> getVisibileKeys() {
+        List<Key> visibleKeys = new ArrayList<>();
+        for (Key key : allKeys) {
+            if (key.isVisible()) {
+                visibleKeys.add(key);
+            }
+        }
+        return visibleKeys;
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchemaEntity.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchemaEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..86aa23db791b02542b046251fecb1d50aa76357c
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchemaEntity.java
@@ -0,0 +1,169 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.xmlmodel.PropertyModel;
+import it.inaf.ia2.tsm.xmlmodel.TableModel;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents an object that is mapped on a table of the TAP_SCHEMA.
+ *
+ * A TapSchemaEntity has some properties that correspond to columns of the table
+ * represented by the TapSchemaEntity.<br>
+ * Property value can be changed but the original value has to be maintained
+ * until the {@link #save()} method is called.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public abstract class TapSchemaEntity implements Serializable {
+
+    private static final long serialVersionUID = 5515596028279668709L;
+    private static final Logger LOG = LoggerFactory.getLogger(TapSchemaEntity.class);
+
+    private Map<String, Object> metadata;
+    private Map<String, EntityProperty> properties;
+    protected TapSchema tapSchema;
+    private TableModel tableModel;
+
+    protected TapSchemaEntity() {
+    }
+
+    public TapSchemaEntity(TapSchema tapSchema, TableModel tableModel, Map<String, Object> metadata) {
+        this.tapSchema = tapSchema;
+        this.tableModel = tableModel;
+        this.metadata = metadata;
+        this.properties = new HashMap<>();
+        fillProperties();
+    }
+
+    private void fillProperties() {
+        for (PropertyModel propModel : tableModel.getProperties().values()) {
+            Object defaultValue = null;
+            if (propModel.getLoaderKey() != null) {
+                defaultValue = metadata.get(propModel.getLoaderKey());
+            }
+            EntityProperty ep = new EntityProperty(propModel, defaultValue);
+            this.properties.put(propModel.getName(), ep);
+        }
+    }
+
+    public Object getMetadata(String key) {
+        return metadata.get(key);
+    }
+
+    /**
+     * Initializes the value of a property (store the original value).
+     */
+    public <T> void initProperty(String key, T value) {
+        properties.get(key).init(value);
+    }
+
+    protected String getVersion() {
+        return tapSchema.getVersion();
+    }
+
+    /**
+     * Returns true if one or more property values is changed (the current value
+     * is different from the original value).
+     */
+    public boolean isChanged() {
+        for (EntityProperty property : properties.values()) {
+            if (property.isChanged()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public Object getValue(String key) {
+        return properties.get(key);
+    }
+
+    /**
+     * Retrieve the current value of the property (the last value set).
+     */
+    public <T> T getValue(String key, Class<T> type) {
+        return (T) properties.get(key).getValue(type);
+    }
+
+    public void setValue(String key, Object value) {
+        properties.get(key).setValue(value);
+    }
+
+    /**
+     * Retrieve the original value of the property.
+     *
+     * @param key the name of the property (the name of the table column).
+     * @param type the class of the property value.
+     * @return
+     */
+    public <T> T getOriginalValue(String key, Class<T> type) {
+        return (T) properties.get(key).getValue();
+    }
+
+    /**
+     * Returns true the value of property which key is passed as parameter is
+     * changed (the current value is different from the original value).
+     */
+    public boolean isChanged(String key) {
+        return properties.get(key).isChanged();
+    }
+
+    /**
+     * Retrieve a list of all properties names (the names of the table columns).
+     */
+    public List<String> getPropertiesKeys() {
+        return new ArrayList<>(properties.keySet());
+    }
+
+    /**
+     * Marks the TapSchemaEntity as saved (all original values are set equals to
+     * current values).
+     */
+    public void save() {
+        for (EntityProperty p : properties.values()) {
+            p.save();
+        }
+    }
+
+    /**
+     * Set the correct value for a fixed property that has inconsistent value in
+     * the TAP_SCHEMA.
+     */
+    public <T> void amendProperty(String key, T value) {
+        EntityProperty prop = properties.get(key);
+        prop.init(value);
+        prop.setChanged(true);
+    }
+
+    public TableModel getTableModel() {
+        return tableModel;
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/UpdateOperations.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/UpdateOperations.java
similarity index 93%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/UpdateOperations.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/UpdateOperations.java
index bf82d260533910fcc2e5b9b569a50b9326a0260b..ff8357c4971e91922c765f6255c638d4b90d5301 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/UpdateOperations.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/UpdateOperations.java
@@ -20,14 +20,12 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
-
-import it.inaf.ia2.tsm.api.contract.Column;
-import it.inaf.ia2.tsm.api.contract.Key;
-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;
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.datalayer.DBBroker;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
 import org.slf4j.Logger;
@@ -37,15 +35,17 @@ import org.slf4j.LoggerFactory;
  * List of operations that have to be performed by the
  * {@link it.inaf.oats.ia2.tapschemamanager.contract.TapSchema#save()} method,
  * in terms of adding, updating or removing
- * {@link it.inaf.ia2.tsm.api.contract.TapSchemaEntity}
- * entities. Could be used stand-alone to obtain a preview of the operations
- * that will be performed on the database.
+ * {@link it.inaf.ia2.tsm.api.TapSchemaEntity} entities. Could be used
+ * stand-alone to obtain a preview of the operations that will be performed on
+ * the database.
  *
  * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
  */
 public class UpdateOperations {
 
-    private static final Logger log = LoggerFactory.getLogger(UpdateOperations.class);
+    private static final Logger LOG = LoggerFactory.getLogger(UpdateOperations.class);
+
+    private final TapSchema tapSchema;
 
     private final List<Schema> schemasToRemove;
     private final List<Schema> schemasToAdd;
@@ -75,6 +75,9 @@ public class UpdateOperations {
     }
 
     public UpdateOperations(TapSchema tapSchema) {
+
+        this.tapSchema = tapSchema;
+
         schemasToRemove = new ArrayList<>();
         schemasToAdd = new ArrayList<>();
         schemasToUpdate = new ArrayList<>();
@@ -91,13 +94,13 @@ public class UpdateOperations {
         keysToAdd = new ArrayList<>();
         keysToUpdate = new ArrayList<>();
 
-        for (Key key : ((TapSchemaImpl) tapSchema).getAllKeys()) {
+        for (Key key : ((TapSchema) tapSchema).getAllKeys()) {
 
             if (key.getId() != null) {
 
                 if (key.isVisible()) {
                     String originalKeyId = key.getOriginalValue(Key.ID_KEY, String.class);
-                    if (originalKeyId == null) {
+                    if (originalKeyId == null || KeyMetadata.NEW_KEY.equals(originalKeyId)) {
                         keysToAdd.add(key);
                     } else if (key.isChanged()) {
                         keysToUpdate.add(key);
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/UpdateQueryBuilder.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/UpdateQueryBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f8bbb60373a8f2e28f82dd9313a9b5c632c04ba
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/UpdateQueryBuilder.java
@@ -0,0 +1,94 @@
+/* 
+ * _____________________________________________________________________________
+ * 
+ * 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.
+ */
+package it.inaf.ia2.tsm;
+
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Prepares an {@code UPDATE } SQL query for a given {@link TapSchemaEntity} and
+ * a given {@link TapSchema}.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class UpdateQueryBuilder {
+//
+//    private static final Logger log = LoggerFactory.getLogger(UpdateQueryBuilder.class);
+//
+//    private final String query;
+//    private final List<EntityPropertyInfo> addedProperties;
+//    private final TapSchemaEntity tapSchemaEntity;
+//
+//    protected UpdateQueryBuilder(DatabaseType dbType, TapSchema tapSchema, TapSchemaEntity tapSchemaEntity, String tapSchemaTableName, String whereCondition) {
+//
+//        StringBuilder querySb = new StringBuilder("UPDATE ");
+//        querySb.append(TSMUtil.escapeName(tapSchema.getName(), dbType));
+//        querySb.append(".");
+//        querySb.append(TSMUtil.escapeName(tapSchemaTableName, dbType));
+//        querySb.append("\nSET");
+//
+//        addedProperties = new ArrayList<>();
+//        this.tapSchemaEntity = tapSchemaEntity;
+//
+//        boolean first = true;
+//        for (EntityPropertyInfo propertyInfo : EntityPropertyInfo.getEntityPropertiesInfo(tapSchemaTableName)) {
+//            if (propertyInfo.acceptVersion(tapSchema.getVersion())
+//                    && tapSchemaEntity.isChanged(propertyInfo.getPropertyKey())) {
+//
+//                if (!first) {
+//                    querySb.append(",");
+//                }
+//                querySb.append(" ");
+//                querySb.append(propertyInfo.getPropertyKey());
+//                querySb.append(" = ?");
+//                addedProperties.add(propertyInfo);
+//                first = false;
+//            }
+//        }
+//
+//        querySb.append("\nWHERE ");
+//        querySb.append(whereCondition);
+//
+//        query = querySb.toString();
+//    }
+//
+//    public String getQuery() {
+//        return query;
+//    }
+//
+//    protected int addStatementValues(PreparedStatement statement) throws SQLException {
+//        int i = 1;
+//        for (EntityPropertyInfo property : addedProperties) {
+//            Object value = tapSchemaEntity.getValue(property.getPropertyKey(), property.getPropertyType());
+//            statement.setObject(i, value, property.getSqlType());
+//            log.debug("\t[{}] {}", property.getPropertyKey(), value);
+//            i++;
+//        }
+//        return i;
+//    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/ChildEntityImpl.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/ChildEntityImpl.java
deleted file mode 100644
index 366c3274fc3c4ff87803e4ed052bc9ceacc4d739..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/ChildEntityImpl.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-import it.inaf.ia2.tsm.api.contract.ChildEntity;
-import it.inaf.ia2.tsm.api.contract.EntitiesContainer;
-import it.inaf.ia2.tsm.api.contract.Status;
-import it.inaf.ia2.tsm.api.contract.TapSchema;
-
-/**
- * The main implementation of {@link ChildEntity}.
- * 
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public abstract class ChildEntityImpl<T extends EntitiesContainer> extends TapSchemaEntityImpl implements ChildEntity<T> {
-    
-    private static final long serialVersionUID = -8941059435527998685L;
-
-    private Status status;
-
-    protected ChildEntityImpl() {
-        // for serialization
-        super();
-    }
-    
-    public ChildEntityImpl(DBWrapper dbWrapper, TapSchema tapSchema) {
-        super(dbWrapper, tapSchema);
-    }
-
-    @Override
-    public Status getStatus() {
-        return status;
-    }
-
-    @Override
-    public void setStatus(Status status) {
-        this.status = status;
-    }
-    
-    @Override
-    public void save() {
-        setStatus(Status.ADDED_PERSISTED);
-        super.save();
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/ColumnImpl.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/ColumnImpl.java
deleted file mode 100644
index 62040864902bb76d5e8b75ee2aff5c9d65c7d877..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/ColumnImpl.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-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.Status;
-import it.inaf.ia2.tsm.api.contract.Table;
-import it.inaf.ia2.tsm.api.contract.TapSchema;
-import java.util.Objects;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The main implementation of {@link Column}.
- * 
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public class ColumnImpl extends ChildEntityImpl<Table> implements Column {
-
-    private static final long serialVersionUID = 9175956487892235521L;
-    private static final Logger log = LoggerFactory.getLogger(ColumnImpl.class);
-
-    private boolean isPrimaryKey;
-
-    private boolean foreignKeySearched;
-    private Key foreignKey;
-
-    private Table parentTable;
-
-    private ColumnImpl() {
-        // for serialization
-        super();
-    }
-
-    protected ColumnImpl(DBWrapper dbWrapper, TapSchema tapSchema, Table table, String columnName, boolean indexed, boolean isPrimaryKey, String datatype, Integer size, Integer arraySize) {
-        super(dbWrapper, tapSchema);
-
-        this.isPrimaryKey = isPrimaryKey;
-
-        parentTable = table;
-
-        addProperty(TABLE_NAME_KEY, new FixedEntityProperty<>(table.getCompleteName()));
-        addProperty(COLUMN_NAME_KEY, new FixedEntityProperty<>(columnName));
-        addProperty(DATATYPE_KEY, new FixedEntityProperty<>(datatype));
-        addProperty(SIZE_KEY, new FixedEntityProperty<>(size));
-        addProperty(ARRAYSIZE_KEY, new FixedEntityProperty<>(arraySize));
-        addProperty(INDEXED_KEY, new FixedEntityProperty<>(indexed));
-
-        // Updatables
-        addProperty(DESCRIPTION_KEY, new EditableProperty<String>());
-        addProperty(UTYPE_KEY, new EditableProperty<String>());
-        addProperty(UNIT_KEY, new EditableProperty<String>());
-        addProperty(UCD_KEY, new EditableProperty<String>());
-        addProperty(PRINCIPAL_KEY, new EditableProperty<>(isPrimaryKey, false));
-        addProperty(STD_KEY, new EditableProperty<>(false, false));
-        addProperty(COLUMN_INDEX_KEY, new EditableProperty<Integer>());
-        addProperty(ID_KEY, new EditableProperty<Integer>());
-        addProperty(COLUMN_ID_KEY, new EditableProperty<Long>());
-
-        setStatus(Status.LOADED);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Key getForeignKey() {
-        if (!foreignKeySearched) { // lazy loading (but the foreignKey value can be null, so we use this boolean)
-
-            String tableCompleteName = getParent().getCompleteName();
-            String columnName = getValue(COLUMN_NAME_KEY, String.class);
-
-            keysloop: // we want to loop on all schema keys, also hidden ones.
-            for (Key key : ((TapSchemaImpl) tapSchema).getAllKeys()) {
-                if (key.getFromTableCompleteName().equals(tableCompleteName)) {
-                    for (KeyColumn keyColumn : key.getKeyColumns()) {
-                        if (keyColumn.getFromColumn().equals(columnName)) {
-                            foreignKey = key;
-                            break keysloop;
-                        }
-                    }
-                }
-            }
-
-            foreignKeySearched = true;
-        }
-
-        return foreignKey;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getTableCompleteName() {
-        return getValue(TABLE_NAME_KEY, String.class);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getName() {
-        return getValue(COLUMN_NAME_KEY, String.class);
-    }
-
-    @Override
-    public boolean getIndexed() {
-        return getValue(INDEXED_KEY, Boolean.class);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * This information is not stored into the TAP_SCHEMA, so it will be
-     * reloaded from the source schema each time.
-     */
-    @Override
-    public boolean isPrimaryKey() {
-        return isPrimaryKey;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getDatatype() {
-        return getValue(DATATYPE_KEY, String.class);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Integer getArraySize() {
-        return getValue(ARRAYSIZE_KEY, Integer.class);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Integer getSize() {
-        return getValue(SIZE_KEY, Integer.class);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getDescription() {
-        return getValue(DESCRIPTION_KEY, String.class);
-    }
-
-    @Override
-    public void setDescription(String description) {
-        setValue(DESCRIPTION_KEY, description);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getUtype() {
-        return getValue(UTYPE_KEY, String.class);
-    }
-
-    @Override
-    public void setUtype(String utype) {
-        setValue(UTYPE_KEY, utype);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getUnit() {
-        return getValue(UNIT_KEY, String.class);
-    }
-
-    @Override
-    public void setUnit(String unit) {
-        setValue(UNIT_KEY, unit);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getUCD() {
-        return getValue(UCD_KEY, String.class);
-    }
-
-    @Override
-    public void setUCD(String ucd) {
-        setValue(UCD_KEY, ucd);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean getPrincipal() {
-        return getValue(PRINCIPAL_KEY, Boolean.class);
-    }
-
-    @Override
-    public void setPrincipal(boolean principal) {
-        setValue(PRINCIPAL_KEY, principal);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean getStd() {
-        return getValue(STD_KEY, Boolean.class);
-    }
-
-    @Override
-    public void setStd(boolean std) {
-        setValue(STD_KEY, std);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Integer getColumnIndex() {
-        return getValue(COLUMN_INDEX_KEY, Integer.class);
-    }
-
-    @Override
-    public void setColumnIndex(Integer columnIndex) {
-        setValue(COLUMN_INDEX_KEY, columnIndex);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Long getColumnID() {
-        return getValue(COLUMN_ID_KEY, Long.class);
-    }
-
-    @Override
-    public void setColumnID(Long columnID) {
-        setValue(COLUMN_ID_KEY, columnID);
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 7;
-        hash = 29 * hash + Objects.hashCode(getTableCompleteName());
-        hash = 29 * hash + Objects.hashCode(getName());
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final ColumnImpl other = (ColumnImpl) obj;
-        if (!Objects.equals(this.getTableCompleteName(), other.getTableCompleteName())) {
-            return false;
-        }
-        if (!Objects.equals(this.getName(), other.getName())) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Table getParent() {
-        return parentTable;
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/Dao.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/Dao.java
deleted file mode 100644
index 28d4c61780c10fbac7bccadfc049f7b3b2c4976b..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/Dao.java
+++ /dev/null
@@ -1,713 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
-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.TapSchemaVersion;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.List;
-import javax.sql.DataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Utility class that contains static methods for interacting with databases.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public class Dao {
-
-    private static final Logger log = LoggerFactory.getLogger(Dao.class);
-
-    /**
-     * Creates the TAP_SCHEMA schema and its tables.
-     */
-    private static void createTapSchemaStructure(DatabaseType dbType, Connection conn, TapSchema tapSchema) throws SQLException {
-
-        String tapSchemaName = tapSchema.getName();
-        TapSchemaVersion version = tapSchema.getVersion();
-
-        if (dbType == DatabaseType.MYSQL) {
-            try (Statement statement = conn.createStatement()) {
-
-                /////////////////////////////////////
-                //         CREATE DATABASE         //
-                /////////////////////////////////////
-                String queryString = String.format("CREATE DATABASE IF NOT EXISTS `%s`", tapSchemaName);
-                log.debug("Executing query {}", queryString);
-                statement.executeUpdate(queryString);
-
-                StringBuilder querySb = new StringBuilder();
-
-                /////////////////////////////////////
-                //      CREATE schemas TABLE       //
-                /////////////////////////////////////
-                querySb.append("CREATE TABLE IF NOT EXISTS `");
-                querySb.append(tapSchemaName);
-                querySb.append("`.`schemas` (\n");
-                querySb.append("schema_name   varchar(64),\n");
-                querySb.append("utype         varchar(512) NULL,\n");
-                querySb.append("description   varchar(512) NULL,\n");
-                if (TSMUtil.isIA2(version)) {
-                    querySb.append("schemaID      bigint,\n");
-                }
-                querySb.append("PRIMARY KEY (schema_name))");
-
-                queryString = querySb.toString();
-                log.debug("Creating \"schemas\" table");
-                log.debug("Executing query {}", queryString);
-                statement.executeUpdate(queryString);
-
-                /////////////////////////////////////
-                //       CREATE tables TABLE       //
-                /////////////////////////////////////
-                querySb = new StringBuilder();
-                querySb.append("CREATE TABLE IF NOT EXISTS `");
-                querySb.append(tapSchemaName);
-                querySb.append("`.tables (\n");
-                querySb.append("schema_name   varchar(64),\n");
-                querySb.append("table_name    varchar(128),\n");
-                querySb.append("table_type    varchar(8),\n");
-                querySb.append("utype         varchar(512) NULL,\n");
-                querySb.append("description   varchar(512) NULL,\n");
-                if (TSMUtil.isIA2(version)) {
-                    querySb.append("tableID       bigint,\n");
-                }
-                querySb.append("PRIMARY KEY (table_name),\n");
-                querySb.append("FOREIGN KEY (schema_name) REFERENCES `");
-                querySb.append(tapSchemaName);
-                querySb.append("`.`schemas` (schema_name))");
-
-                queryString = querySb.toString();
-                log.debug("Creating \"tables\" table");
-                log.debug("Executing query {}", queryString);
-                statement.executeUpdate(queryString);
-
-                /////////////////////////////////////
-                //      CREATE columns TABLE       //
-                /////////////////////////////////////
-                querySb = new StringBuilder();
-                querySb.append("CREATE TABLE IF NOT EXISTS `");
-                querySb.append(tapSchemaName);
-                querySb.append("`.columns (\n");
-                querySb.append("table_name    varchar(128),\n");
-                querySb.append("column_name   varchar(64),\n");
-                querySb.append("utype         varchar(512) NULL,\n");
-                querySb.append("ucd           varchar(64)  NULL,\n");
-                querySb.append("unit          varchar(64)  NULL,\n");
-                querySb.append("description   varchar(512) NULL,\n");
-                querySb.append("datatype      varchar(64)  NOT NULL,\n");
-                querySb.append("size          integer      NULL,\n");
-                querySb.append("principal     integer      NOT NULL,\n");
-                querySb.append("indexed       integer      NOT NULL,\n");
-                querySb.append("std           integer      NOT NULL,\n");
-                if (TSMUtil.isIA2(version)) {
-                    querySb.append("id      integer,\n");
-                    querySb.append("columnID      bigint,\n");
-                }
-                querySb.append("PRIMARY KEY (table_name, column_name),\n");
-                querySb.append("FOREIGN KEY (table_name) REFERENCES `");
-                querySb.append(tapSchemaName);
-                querySb.append("`.tables (table_name))");
-
-                queryString = querySb.toString();
-                log.debug("Creating \"columns\" table");
-                log.debug("Executing query {}", queryString);
-                statement.executeUpdate(queryString);
-
-                /////////////////////////////////////
-                //        CREATE keys TABLE        //
-                /////////////////////////////////////
-                querySb = new StringBuilder();
-                querySb.append("CREATE TABLE IF NOT EXISTS `");
-                querySb.append(tapSchemaName);
-                querySb.append("`.keys (\n");
-                querySb.append("key_id        varchar(64),\n");
-                querySb.append("from_table    varchar(128) NOT NULL,\n");
-                querySb.append("target_table  varchar(128) NOT NULL,\n");
-                querySb.append("utype         varchar(512) NULL,\n");
-                querySb.append("description   varchar(512) NULL,\n");
-                if (TSMUtil.isIA2(version)) {
-                    querySb.append("keyID         bigint,\n");
-                }
-                querySb.append("PRIMARY KEY (key_id),\n");
-                querySb.append("FOREIGN KEY (from_table) REFERENCES `");
-                querySb.append(tapSchemaName);
-                querySb.append("`.tables (table_name),\n");
-                querySb.append("FOREIGN KEY (target_table) REFERENCES `");
-                querySb.append(tapSchemaName);
-                querySb.append("`.tables (table_name))");
-
-                queryString = querySb.toString();
-                log.debug("Creating \"keys\" table");
-                log.debug("Executing query {}", queryString);
-                statement.executeUpdate(queryString);
-
-                /////////////////////////////////////
-                //    CREATE key_columns TABLE     //
-                /////////////////////////////////////
-                querySb = new StringBuilder();
-                querySb.append("CREATE TABLE IF NOT EXISTS `");
-                querySb.append(tapSchemaName);
-                querySb.append("`.key_columns (\n");
-                querySb.append("key_id          varchar(64),\n");
-                querySb.append("from_column     varchar(64)   NOT NULL,\n");
-                querySb.append("target_column   varchar(64) NOT NULL,\n");
-                if (TSMUtil.isIA2(version)) {
-                    querySb.append("key_columnID    bigint,\n");
-                }
-                querySb.append("FOREIGN KEY (key_id) REFERENCES `");
-                querySb.append(tapSchemaName);
-                querySb.append("`.keys (key_id))");
-
-                queryString = querySb.toString();
-                log.debug("Creating \"key_columns\" table");
-                log.debug("Executing query {}", queryString);
-                statement.executeUpdate(queryString);
-            }
-        } else if (dbType == DatabaseType.POSTGRES) {
-            try (Statement statement = conn.createStatement()) {
-                String tapSchemaNameEscaped = TSMUtil.escapeName(tapSchemaName, dbType);
-
-                statement.executeUpdate("CREATE SCHEMA IF NOT EXISTS " + tapSchemaNameEscaped);
-
-                StringBuilder querySb = new StringBuilder();
-
-                /////////////////////////////////////
-                //      CREATE schemas TABLE       //
-                /////////////////////////////////////
-                querySb.append("CREATE TABLE IF NOT EXISTS ");
-                querySb.append(tapSchemaNameEscaped);
-                querySb.append(".schemas (\n");
-                querySb.append("schema_name character varying(64) NOT NULL,\n");
-                querySb.append("description character varying(512),\n");
-                if (TSMUtil.isIA2(version)) {
-                    querySb.append("schemaid bigint,\n");
-                }
-                querySb.append("utype character varying(512))");
-
-                String queryString = querySb.toString();
-                log.debug("Creating \"schemas\" table");
-                log.debug("Executing query {}", queryString);
-                int updateResult = statement.executeUpdate(queryString);
-
-                if (updateResult > 0) {
-                    queryString = "ALTER TABLE ONLY schemas ADD CONSTRAINT schemas_pkey PRIMARY KEY (schema_name)";
-                    log.debug("Adding constraints to \"schemas\" table");
-                    log.debug("Executing query {}", queryString);
-                    statement.executeUpdate(queryString);
-                }
-
-                /////////////////////////////////////
-                //       CREATE tables TABLE       //
-                /////////////////////////////////////
-                querySb = new StringBuilder();
-
-                querySb.append("CREATE TABLE IF NOT EXISTS ");
-                querySb.append(tapSchemaNameEscaped);
-                querySb.append(".tables (\n");
-                querySb.append("table_name character varying(128) NOT NULL,\n");
-                querySb.append("description character varying(512),\n");
-                querySb.append("schema_name character varying(64),\n");
-                if (TSMUtil.isIA2(version)) {
-                    querySb.append("tableid bigint,\n");
-                }
-                querySb.append("table_type character varying(8),\n");
-                querySb.append("utype character varying(512))");
-
-                queryString = querySb.toString();
-                log.debug("Creating \"tables\" table");
-                log.debug("Executing query {}", queryString);
-                updateResult = statement.executeUpdate(queryString);
-
-                if (updateResult > 0) {
-                    log.debug("Adding constraints to \"tables\" table");
-                    queryString = "ALTER TABLE ONLY tables ADD CONSTRAINT tables_pkey PRIMARY KEY (table_name)";
-                    log.debug("Executing query {}", queryString);
-                    statement.executeUpdate(queryString);
-                    queryString = "ALTER TABLE ONLY tables ADD CONSTRAINT fk_tables_schema_name FOREIGN KEY (schema_name) REFERENCES schemas(schema_name)";
-                    log.debug("Executing query {}", queryString);
-                    statement.executeUpdate(queryString);
-                }
-
-                /////////////////////////////////////
-                //      CREATE columns TABLE       //
-                /////////////////////////////////////
-                querySb = new StringBuilder();
-
-                querySb.append("CREATE TABLE IF NOT EXISTS ");
-                querySb.append(tapSchemaNameEscaped);
-                querySb.append(".columns (\n");
-                querySb.append("table_name character varying(128) NOT NULL,\n");
-                querySb.append("column_name character varying(64) NOT NULL,\n");
-                if (TSMUtil.isIA2(version)) {
-                    querySb.append("columnid bigint,\n");
-                }
-                querySb.append("datatype character varying(64),\n");
-                querySb.append("description character varying(512),\n");
-                querySb.append("id integer,\n");
-                querySb.append("indexed boolean,\n");
-                querySb.append("principal boolean,\n");
-                querySb.append("size integer,\n");
-                querySb.append("std boolean,\n");
-                querySb.append("ucd character varying(64),\n");
-                querySb.append("unit character varying(64),\n");
-                querySb.append("utype character varying(512))");
-
-                queryString = querySb.toString();
-                log.debug("Creating \"columns\" table");
-                log.debug("Executing query {}", queryString);
-                updateResult = statement.executeUpdate(queryString);
-
-                if (updateResult > 0) {
-                    log.debug("Adding constraints to \"columns\" table");
-                    queryString = "ALTER TABLE ONLY columns ADD CONSTRAINT columns_pkey PRIMARY KEY (table_name, column_name)";
-                    log.debug("Executing query {}", queryString);
-                    statement.executeUpdate(queryString);
-                    queryString = "ALTER TABLE ONLY columns ADD CONSTRAINT fk_columns_table_name FOREIGN KEY (table_name) REFERENCES tables(table_name)";
-                    log.debug("Executing query {}", queryString);
-                    statement.executeUpdate(queryString);
-                }
-
-                /////////////////////////////////////
-                //        CREATE keys TABLE        //
-                /////////////////////////////////////
-                querySb = new StringBuilder();
-
-                querySb.append("CREATE TABLE IF NOT EXISTS ");
-                querySb.append(tapSchemaNameEscaped);
-                querySb.append(".keys (\n");
-                querySb.append("key_id character varying(64) NOT NULL,\n");
-                querySb.append("description character varying(512),\n");
-                querySb.append("from_table character varying(128),\n");
-                if (TSMUtil.isIA2(version)) {
-                    querySb.append("keyid bigint,\n");
-                }
-                querySb.append("target_table character varying(128),\n");
-                querySb.append("utype character varying(512))");
-
-                queryString = querySb.toString();
-                log.debug("Creating \"keys\" table");
-                log.debug("Executing query {}", queryString);
-                updateResult = statement.executeUpdate(queryString);
-
-                if (updateResult > 0) {
-                    log.debug("Adding constraints to \"keys\" table");
-                    queryString = "ALTER TABLE ONLY keys ADD CONSTRAINT keys_pkey PRIMARY KEY (key_id)";
-                    log.debug("Executing query {}", queryString);
-                    statement.executeUpdate(queryString);
-                    queryString = "ALTER TABLE ONLY keys ADD CONSTRAINT \"FK_keys_from_table\" FOREIGN KEY (from_table) REFERENCES tables(table_name)";
-                    log.debug("Executing query {}", queryString);
-                    statement.executeUpdate(queryString);
-                    queryString = "ALTER TABLE ONLY keys ADD CONSTRAINT \"FK_keys_target_table\" FOREIGN KEY (target_table) REFERENCES tables(table_name)";
-                    log.debug("Executing query {}", queryString);
-                    statement.executeUpdate(queryString);
-                }
-
-                /////////////////////////////////////
-                //    CREATE key_columns TABLE     //
-                /////////////////////////////////////
-                querySb = new StringBuilder();
-
-                querySb.append("CREATE TABLE IF NOT EXISTS ");
-                querySb.append(tapSchemaNameEscaped);
-                querySb.append(".key_columns (\n");
-                querySb.append("from_column character varying(64) NOT NULL,\n");
-                querySb.append("target_column character varying(64) NOT NULL,\n");
-                if (TSMUtil.isIA2(version)) {
-                    querySb.append("key_columnid bigint,\n");
-                }
-                querySb.append("key_id character varying(64) NOT NULL)");
-
-                queryString = querySb.toString();
-                log.debug("Creating \"key_columns\" table");
-                log.debug("Executing query {}", queryString);
-                updateResult = statement.executeUpdate(queryString);
-
-                if (updateResult > 0) {
-                    log.debug("Adding constraints to \"key_columns\" table");
-                    queryString = "ALTER TABLE ONLY key_columns ADD CONSTRAINT key_columns_pkey PRIMARY KEY (from_column, target_column, key_id)";
-                    log.debug("Executing query {}", queryString);
-                    statement.executeUpdate(queryString);
-                    queryString = "ALTER TABLE ONLY key_columns ADD CONSTRAINT fk_key_columns_key_id FOREIGN KEY (key_id) REFERENCES keys(key_id)";
-                    log.debug("Executing query {}", queryString);
-                    statement.executeUpdate(queryString);
-                }
-            }
-        } else {
-            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-        }
-    }
-
-    protected static void save(DBWrapper dbWrapper, TapSchema tapSchema) throws SQLException {
-
-        log.debug("Saving TAP_SCHEMA");
-
-        DatabaseType dbType = dbWrapper.getTapSchemaDatabaseType();
-        DataSource dataSource = dbWrapper.getTapSchemaDataSource();
-
-        Connection connection = null;
-        PreparedStatement statement = null;
-        boolean transactionStarted = false;
-
-        try {
-            connection = dataSource.getConnection();
-
-            UpdateOperations operations = new UpdateOperations(tapSchema);
-
-            if (!tapSchema.exists()) {
-                createTapSchemaStructure(dbType, connection, tapSchema);
-            }
-
-            // Start update
-            connection.setAutoCommit(false); // start transaction
-            transactionStarted = true;
-
-            String tapSchemaNameEscaped = TSMUtil.escapeName(tapSchema.getName(), dbType);
-
-            // REMOVE ELEMENTS
-            if (tapSchema.exists()) {
-                for (Key key : operations.getKeysToRemove()) {
-                    String keyId = key.getId();
-
-                    String query = String.format("DELETE FROM %s.%s WHERE key_id = ?", tapSchemaNameEscaped, TSMUtil.escapeName("key_columns", dbType));
-                    statement = connection.prepareStatement(query);
-                    statement.setString(1, keyId);
-                    log.debug("Executing query {} [key_id={}]", query, keyId);
-                    statement.executeUpdate();
-
-                    query = String.format("DELETE FROM %s.%s WHERE key_id = ?", tapSchemaNameEscaped, TSMUtil.escapeName("keys", dbType));
-                    statement = connection.prepareStatement(query);
-                    statement.setString(1, keyId);
-                    log.debug("Executing query {} [key_id={}]", query, keyId);
-                    statement.executeUpdate();
-                }
-
-                for (Column column : operations.getColumnsToRemove()) {
-                    String query = String.format("DELETE FROM %s.%s WHERE table_name = ? AND column_name = ?", tapSchemaNameEscaped, TSMUtil.escapeName("columns", dbType));
-                    statement = connection.prepareStatement(query);
-                    String tableName = column.getTableCompleteName();
-                    String columnName = column.getName();
-                    statement.setString(1, tableName);
-                    statement.setString(2, columnName);
-                    log.debug("Executing query {} [table_name={}, column_name={}]", query, tableName, columnName);
-                    statement.executeUpdate();
-                }
-
-                for (Table table : operations.getTablesToRemove()) {
-                    String query = String.format("DELETE FROM %s.%s WHERE table_name = ?", tapSchemaNameEscaped, TSMUtil.escapeName("tables", dbType));
-                    statement = connection.prepareStatement(query);
-                    String tableCompleteName = table.getCompleteName();
-                    statement.setString(1, tableCompleteName);
-                    log.debug("Executing query {} [table_name={}]", query, tableCompleteName);
-                    statement.executeUpdate();
-                }
-
-                for (Schema schema : operations.getSchemasToRemove()) {
-                    String query = String.format("DELETE FROM %s.%s WHERE schema_name = ?", tapSchemaNameEscaped, TSMUtil.escapeName("schemas", dbType));
-                    statement = connection.prepareStatement(query);
-                    String schemaName = schema.getName();
-                    statement.setString(1, schemaName);
-                    log.debug("Executing query {} [schema_name={}]", query, schemaName);
-                    statement.executeUpdate();
-                }
-            }
-
-            // INSERT ELEMENTS
-            if (!operations.getSchemasToAdd().isEmpty()) {
-                log.debug("Inserting {} new schemas", operations.getSchemasToAdd().size());
-            }
-            for (Schema schema : operations.getSchemasToAdd()) {
-                DaoSchema.insertNewSchema(dbType, connection, tapSchema, schema);
-            }
-
-            if (!operations.getTablesToAdd().isEmpty()) {
-                log.debug("Inserting {} new tables", operations.getTablesToAdd().size());
-            }
-            for (Table table : operations.getTablesToAdd()) {
-                DaoTable.insertNewTable(dbType, connection, tapSchema, table);
-            }
-
-            if (!operations.getColumnsToAdd().isEmpty()) {
-                log.debug("Inserting {} new columns", operations.getColumnsToAdd().size());
-            }
-            for (Column column : operations.getColumnsToAdd()) {
-                DaoColumn.insertNewColumn(dbType, connection, tapSchema, column);
-            }
-
-            if (!operations.getKeysToAdd().isEmpty()) {
-                log.debug("Inserting {} new keys", operations.getKeysToAdd().size());
-            }
-            for (Key key : operations.getKeysToAdd()) {
-                // insert new keys and their key columns
-                DaoKey.insertNewKey(dbType, connection, tapSchema, key);
-            }
-
-            //UPDATE ELEMENTS
-            if (tapSchema.exists()) {
-                for (Key key : operations.getKeysToUpdate()) {
-                    // update keys and their key columns
-                    DaoKey.updateKey(dbType, connection, tapSchema, key);
-                }
-
-                for (Schema schema : operations.getSchemasToUpdate()) {
-                    DaoSchema.updateSchema(dbType, connection, tapSchema, schema);
-                }
-
-                for (Table table : operations.getTablesToUpdate()) {
-                    DaoTable.updateTable(dbType, connection, tapSchema, table);
-                }
-
-                for (Column column : operations.getColumnsToUpdate()) {
-                    DaoColumn.updateColumn(dbType, connection, tapSchema, column);
-                }
-            }
-
-            connection.commit();
-
-            // Status cleanup after commit
-            // added
-            for (Key key : operations.getKeysToAdd()) {
-                key.save();
-            }
-            for (Schema schema : operations.getSchemasToAdd()) {
-                schema.save();
-            }
-            for (Table table : operations.getTablesToAdd()) {
-                table.save();
-            }
-            for (Column column : operations.getColumnsToAdd()) {
-                column.save();
-            }
-
-            // removed
-            for (Key key : operations.getKeysToRemove()) {
-                key.initProperty(Key.ID_KEY, null);
-                for (KeyColumn keyColumn : key.getKeyColumns()) {
-                    keyColumn.initProperty(KeyColumn.KEY_ID_KEY, null);
-                }
-            }
-            for (Column column : operations.getColumnsToRemove()) {
-                column.setStatus(Status.LOADED);
-            }
-            for (Column column : operations.getColumnsToClean()) {
-                column.setStatus(Status.LOADED);
-            }
-            for (Table table : operations.getTablesToRemove()) {
-                Schema schema = tapSchema.getChild(table.getSchemaName());
-                if (schema != null) {
-                    ((SchemaImpl) schema).cleanTable(table.getName());
-                }
-            }
-            for (Table table : operations.getTablesToClean()) {
-                Schema schema = tapSchema.getChild(table.getSchemaName());
-                if (schema != null) {
-                    ((SchemaImpl) schema).cleanTable(table.getName());
-                }
-            }
-            for (Schema schema : operations.getSchemasToRemove()) {
-                ((TapSchemaImpl) tapSchema).cleanSchema(schema.getName());
-            }
-            for (Schema schema : operations.getSchemasToClean()) {
-                ((TapSchemaImpl) tapSchema).cleanSchema(schema.getName());
-            }
-
-            // updated
-            for (Key key : operations.getKeysToUpdate()) {
-                key.save();
-            }
-            for (Schema schema : operations.getSchemasToUpdate()) {
-                schema.save();
-            }
-            for (Table table : operations.getTablesToUpdate()) {
-                table.save();
-            }
-            for (Column column : operations.getColumnsToUpdate()) {
-                column.save();
-            }
-        } catch (SQLException e) {
-            log.error("Exception caught", e);
-            try {
-                if (connection != null && transactionStarted) {
-                    log.debug("Executing rollback");
-                    connection.rollback();
-                }
-            } catch (SQLException e2) {
-                log.error("Exception caught", e2);
-            }
-            throw e;
-        } finally {
-            if (connection != null) {
-                try {
-                    if (statement != null) {
-                        statement.close();
-                    }
-                    connection.close();
-                } catch (SQLException e2) {
-                    log.error("Exception caught", e2);
-                }
-            }
-        }
-    }
-
-    public static List<String> getAllTAPSchemasNames(Credentials credentials) throws SQLException {
-        DatabaseType dbType = credentials.getDatabaseType();
-        DataSource ds = TSMUtil.createDataSource(credentials);
-        List<String> allSchemas = DaoSchema.getAllSchemasNames(ds, dbType);
-        return getAllTAPSchemasNames(ds, dbType, allSchemas);
-    }
-
-    public static List<String> getAllTAPSchemasNames(DBWrapper dbs) throws SQLException {
-        List<String> allSchemas = DaoSchema.getAllSchemasNames(dbs.getTapSchemaDataSource(), dbs.getTapSchemaDatabaseType());
-        return getAllTAPSchemasNames(dbs, allSchemas);
-    }
-
-    public static List<String> getAllTAPSchemasNames(DBWrapper dbs, List<String> allSchemas) throws SQLException {
-        return getAllTAPSchemasNames(dbs.getTapSchemaDataSource(), dbs.getTapSchemaDatabaseType(), allSchemas);
-    }
-
-    /**
-     * Retrieve the list of all TAP_SCHEMA schemas names contained in the
-     * TAP_SCHEMA <code>DataSource</code>.<br>
-     * TAP_SCHEMA schemas are selected simply checking if they contains the
-     * TAP_SCHEMA standard tables. Currently no check on columns is performed.
-     *
-     * @param allSchemas usually the TAP_SCHEMA schemas list is loaded together
-     * the list of all schemas, so this list is passed by parameter to avoid
-     * repeating the query twice.
-     *
-     * @return list of all TAP_SCHEMA schemas names alphabetically and case
-     * insensitively ordered.
-     */
-    public static List<String> getAllTAPSchemasNames(DataSource dataSource, DatabaseType dbType, List<String> allSchemas) throws SQLException {
-
-        List<String> allTAPSchemas = new ArrayList<>();
-
-        for (String schemaName : allSchemas) {
-
-            boolean schemas = false,
-                    tables = false,
-                    columns = false,
-                    keys = false,
-                    keyColumns = false;
-
-            String query;
-            switch (dbType) {
-                case MYSQL:
-                    query = "SHOW TABLES FROM `" + schemaName + "`";
-                    break;
-                case POSTGRES:
-                    query = "SELECT tablename FROM pg_catalog.pg_tables where schemaname = '" + schemaName + "'";
-                    break;
-                default:
-                    throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-            }
-
-            log.debug("Executing query {}", query);
-
-            try (Connection connection = dataSource.getConnection();
-                    Statement statement = connection.createStatement();
-                    ResultSet resultSet = statement.executeQuery(query)) {
-                while (resultSet.next()) {
-                    String shortTableName = resultSet.getString(1);
-
-                    if (null != shortTableName) {
-                        switch (shortTableName) {
-                            case "schemas":
-                                schemas = true;
-                                break;
-                            case "tables":
-                                tables = true;
-                                break;
-                            case "columns":
-                                columns = true;
-                                break;
-                            case "keys":
-                                keys = true;
-                                break;
-                            case "key_columns":
-                                keyColumns = true;
-                                break;
-                        }
-                    }
-                }
-            }
-
-            if (schemas && tables && columns && keys && keyColumns) {
-                // the schema is a TAP_SCHEMA
-                allTAPSchemas.add(schemaName);
-            }
-        }
-
-        log.debug("{} TAP_SCHEMA schemas found", allTAPSchemas.size());
-
-        return TSMUtil.sortStringsList(allTAPSchemas);
-    }
-
-    /**
-     * Retrieve the list of the name of the schemas exposed by the TAP_SCHEMA
-     * specified by the <code>tapSchemaName</code> parameter.
-     *
-     * @return list of exposed schemas names alphabetically and case
-     * insensitively ordered.
-     */
-    public static List<String> getExposedSchemas(DBWrapper dbs, String tapSchemaName) throws SQLException {
-
-        final List<String> exposedSchemas = new ArrayList<>();
-
-        DatabaseType dbType = dbs.getTapSchemaDatabaseType();
-
-        String query;
-        if (dbType == DatabaseType.MYSQL) {
-            query = "SELECT schema_name FROM `" + tapSchemaName + "`.`schemas`";
-        } else if (dbType == DatabaseType.POSTGRES) {
-            query = "SELECT schema_name FROM \"" + tapSchemaName + "\".\"schemas\"";
-        } else {
-            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-        }
-
-        log.debug("Executing query " + query);
-
-        try (Connection connection = dbs.getTapSchemaConnection();
-                Statement statement = connection.createStatement();
-                ResultSet resultSet = statement.executeQuery(query)) {
-            while (resultSet.next()) {
-                exposedSchemas.add(resultSet.getString(1));
-            }
-        }
-
-        return exposedSchemas;
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoColumn.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoColumn.java
deleted file mode 100644
index eb93b08a4c1b010c49a65758ba2d53717028a67a..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoColumn.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
-import it.inaf.ia2.tsm.api.contract.Column;
-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 java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-import javax.sql.DataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Utility class that contains static methods for managing {@link Column}s into
- * the database.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public class DaoColumn {
-
-    private static final Logger log = LoggerFactory.getLogger(DaoColumn.class);
-
-    private static boolean equalsOneOf(String string, String... values) {
-        for (String value : values) {
-            if (string.equals(value)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns the list of all the columns names given a schema name and a table
-     * name, also if these objects have never been added into the TAP_SCHEMA.
-     * This can be useful to retrieve the source database structure.
-     */
-    public static List<String> getAllColumnsNames(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName, String tableSimpleName) throws SQLException {
-        final List<String> allColumns = new ArrayList<>();
-
-        DataSource dataSource = TSMUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName);
-        DatabaseType dbType = TSMUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName);
-
-        String query;
-        if (dbType == DatabaseType.MYSQL) {
-            query = String.format("SHOW COLUMNS FROM `%s`.`%s`", schemaName, tableSimpleName);
-        } else if (dbType == DatabaseType.POSTGRES) {
-            query = "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schemaName + "' AND table_name = '" + tableSimpleName + "'";
-        } else {
-            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-        }
-
-        log.debug("Executing query {}", query);
-
-        try (Connection connection = dataSource.getConnection();
-                Statement statement = connection.createStatement();
-                ResultSet resultSet = statement.executeQuery(query)) {
-
-            while (resultSet.next()) {
-
-                String columnName;
-                if (dbType == DatabaseType.MYSQL) {
-                    columnName = resultSet.getString("Field");
-                } else if (dbType == DatabaseType.POSTGRES) {
-                    columnName = resultSet.getString("column_name");
-                } else {
-                    throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-                }
-
-                allColumns.add(columnName);
-            }
-        }
-
-        return allColumns;
-    }
-
-    /**
-     * For performance reasons all columns of a {@link Table} are loaded
-     * together using this method. Columns {@link Status} is at first set as
-     * {@code LOADED}.
-     */
-    protected static List<Column> loadAllTableColumns(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName, Table table) throws SQLException {
-        String tableSimpleName = table.getName();
-        final List<Column> allColumns = new ArrayList<>();
-
-        DataSource dataSource = TSMUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName);
-        DatabaseType dbType = TSMUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName);
-
-        String query;
-        if (dbType == DatabaseType.MYSQL) {
-            query = String.format("SHOW COLUMNS FROM `%s`.`%s`", schemaName, tableSimpleName);
-        } else if (dbType == DatabaseType.POSTGRES) {
-            query = "SELECT c.column_name, c.data_type, r.contype AS column_type, c.character_maximum_length, c.numeric_precision\n" //, c.numeric_precision_radix
-                    + "FROM information_schema.columns c\n"
-                    + "JOIN pg_catalog.pg_tables t ON c.table_schema = t.schemaname AND c.table_name = t.tablename\n"
-                    + "LEFT JOIN pg_catalog.pg_constraint r ON c.ordinal_position = ANY(r.conkey) AND r.conrelid = (t.schemaname || '.' || t.tablename)::regclass::oid\n"
-                    + "WHERE t.schemaname = '" + schemaName + "' AND t.tablename = '" + tableSimpleName + "'";
-        } else {
-            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-        }
-
-        log.debug("Executing query {}", query);
-
-        try (Connection connection = dataSource.getConnection();
-                Statement statement = connection.createStatement();
-                ResultSet resultSet = statement.executeQuery(query)) {
-
-            while (resultSet.next()) {
-
-                String columnName;
-                if (dbType == DatabaseType.MYSQL) {
-                    columnName = resultSet.getString("Field");
-                } else if (dbType == DatabaseType.POSTGRES) {
-                    columnName = resultSet.getString("column_name");
-                } else {
-                    throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-                }
-
-                boolean indexed = false, primaryKey = false;
-
-                // Key type
-                if (dbType == DatabaseType.MYSQL) {
-                    String key = resultSet.getString("Key");
-                    primaryKey = key.equals("PRI");
-                    indexed = equalsOneOf(key, "PRI", "UNI", "MUL");
-                } else if (dbType == DatabaseType.POSTGRES) {
-                    String columnType = resultSet.getString("column_type");
-                    if (columnType != null) {
-                        primaryKey = "p".equals(columnType);
-                        indexed = equalsOneOf(columnType, "p", "f", "u");
-                    }
-                } else {
-                    throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-                }
-
-                // Datatype and Size
-                int size = 0;
-                String datatype;
-
-                if (dbType == DatabaseType.MYSQL) {
-                    String type = resultSet.getString("Type").toLowerCase();
-
-                    if (type.startsWith("int")) {
-                        datatype = "adql:INTEGER";
-                    } else if (type.startsWith("smallint")) {
-                        datatype = "adql:SMALLINT";
-                    } else if (type.startsWith("bigint")) {
-                        datatype = "adql:BIGINT";
-                    } else if (type.startsWith("float")) {
-                        datatype = "adql:REAL";
-                    } else if (type.startsWith("char")) {
-                        int beginIndex = type.indexOf('(');
-                        int endIndex = type.indexOf(')');
-                        size = Integer.parseInt(type.substring(beginIndex + 1, endIndex));
-                        datatype = "adql:CHAR";
-                    } else if (type.startsWith("varchar")) {
-                        int beginIndex = type.indexOf('(');
-                        int endIndex = type.indexOf(')');
-                        size = Integer.parseInt(type.substring(beginIndex + 1, endIndex));
-                        datatype = "adql:VARCHAR";
-                    } else if (type.contains("timestamp")) {
-                        datatype = "adql:TIMESTAMP";
-                    } else {
-                        datatype = "adql:" + type.toUpperCase();
-                    }
-                } else if (dbType == DatabaseType.POSTGRES) {
-                    String type = resultSet.getString("data_type");
-
-                    if (type.startsWith("int")) {
-                        datatype = "adql:INTEGER";
-                    } else if (type.startsWith("smallint")) {
-                        datatype = "adql:SMALLINT";
-                    } else if (type.startsWith("bigint")) {
-                        datatype = "adql:BIGINT";
-                    } else if (type.startsWith("double") || type.startsWith("real")) {
-                        datatype = "adql:REAL";
-                    } else if (type.startsWith("character varying")) {
-                        datatype = "adql:VARCHAR";
-                        size = resultSet.getInt("character_maximum_length");
-                    } else if (type.startsWith("char")) {
-                        datatype = "adql:CHAR";
-                        size = resultSet.getInt("character_maximum_length");
-                    } else if (type.contains("timestamp")) {
-                        datatype = "adql:TIMESTAMP";
-                    } else {
-                        datatype = "adql:" + type.toUpperCase();
-                    }
-                } else {
-                    throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-                }
-
-                Integer arraySize = null; // TODO (v 1.1)
-
-                Column column = new ColumnImpl(dbWrapper, tapSchema, table, columnName, indexed, primaryKey, datatype, size, arraySize);
-
-                allColumns.add(column);
-            }
-        }
-
-        return allColumns;
-    }
-
-    /**
-     * Retrieves saved {@code Column}s from the database and add them into the
-     * specified {@code TapSchema}.
-     */
-    protected static void fillSavedColumns(DBWrapper dbWrapper, final TapSchema tapSchema) throws SQLException {
-
-        log.debug("fillSavedColumns");
-
-        SelectQueryBuilder selectQueryBuilder = new SelectQueryBuilder(dbWrapper.getTapSchemaDatabaseType(), tapSchema, TapSchema.COLUMNS_TABLE) {
-
-            @Override
-            protected TapSchemaEntity getEntity(ResultSet rs) throws SQLException {
-                String tableCompleteName = rs.getString("table_name");
-                String columnName = rs.getString("column_name");
-
-                String[] tableNameSplit = tableCompleteName.split(Pattern.quote("."));
-                String schemaName = tableNameSplit[0];
-                String tableSimpleName = tableNameSplit[1];
-
-                Schema schema = tapSchema.getChild(schemaName);
-                if (schema == null) {
-                    return null;
-                }
-                Table table = schema.getChild(tableSimpleName);
-                if (table == null) {
-                    return null;
-                }
-                Column column = table.addChild(columnName);
-                if (column == null) {
-                    return null;
-                }
-                column.setStatus(Status.ADDED_PERSISTED);
-                return column;
-            }
-        };
-
-        selectQueryBuilder.executeQuery(dbWrapper.getTapSchemaConnection());
-    }
-
-    /**
-     * Save a new {@code Column} into the TAP_SCHEMA schema.
-     */
-    protected static void insertNewColumn(DatabaseType dbType, Connection connection, TapSchema tapSchema, Column column) throws SQLException {
-
-        log.debug("insertNewColumn");
-
-        InsertQueryBuilder insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, column, TapSchema.COLUMNS_TABLE);
-        insertQueryBuilder.executeQuery(connection);
-    }
-
-    /**
-     * Updates an existing {@code Column}.
-     */
-    protected static void updateColumn(DatabaseType dbType, Connection connection, TapSchema tapSchema, Column column) throws SQLException {
-
-        UpdateQueryBuilder updateQueryBuilder = new UpdateQueryBuilder(dbType, tapSchema, column, TapSchema.COLUMNS_TABLE, "column_name = ? AND table_name = ?");
-
-        String query = updateQueryBuilder.getQuery();
-
-        try (PreparedStatement statement = connection.prepareStatement(query)) {
-
-            log.debug("Executing query {}", query);
-
-            int i = updateQueryBuilder.addStatementValues(statement);
-            statement.setString(i, column.getName());
-            statement.setString(i + 1, column.getTableCompleteName());
-
-            statement.executeUpdate();
-        }
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoKey.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoKey.java
deleted file mode 100644
index 1824ce02de05d7a6cb18bdfce90ae3ac4ab50b78..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoKey.java
+++ /dev/null
@@ -1,494 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
-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.Table;
-import it.inaf.ia2.tsm.api.contract.TapSchema;
-import it.inaf.ia2.tsm.api.contract.TapSchemaEntity;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-import javax.sql.DataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Utility class that contains static methods for managing {@link Key}s and
- * {@link KeyColumn}s into the database.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public class DaoKey {
-
-    private static final Logger log = LoggerFactory.getLogger(DaoKey.class);
-
-    /**
-     * Generate list of KeyEntity for a given schema, specifying its
-     * <code>DataSource</code> and its name.<br>
-     * <strong>IMPORTANT</strong>: this keys are without id. The id has to be
-     * set when a table is added to a schema.
-     */
-    protected static List<Key> getSchemaKeys(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) throws SQLException {
-
-        log.debug("getSchemaKeys");
-
-        DataSource dataSource = TSMUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName);
-        DatabaseType dbType = TSMUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName);
-
-        if (dbType == DatabaseType.MYSQL) {
-
-            Map<String, Key> schemaKeys = new HashMap<>();
-
-            String query = "SELECT\n"
-                    + "c.`CONSTRAINT_NAME` AS constraint_name,\n"
-                    + "k.`TABLE_SCHEMA` AS from_schema,\n"
-                    + "k.`TABLE_NAME` AS from_table,\n"
-                    + "k.`COLUMN_NAME` AS from_column,\n"
-                    + "k.`REFERENCED_TABLE_SCHEMA` AS target_schema,\n"
-                    + "k.`REFERENCED_TABLE_NAME` AS target_table,\n"
-                    + "k.`REFERENCED_COLUMN_NAME` AS target_column\n"
-                    + "FROM information_schema.TABLE_CONSTRAINTS c \n"
-                    + "LEFT JOIN information_schema.KEY_COLUMN_USAGE k \n"
-                    + "ON c.`CONSTRAINT_NAME` = k.`CONSTRAINT_NAME` AND c.`TABLE_SCHEMA` = k.`TABLE_SCHEMA`\n"
-                    + "WHERE c.`CONSTRAINT_TYPE` = 'FOREIGN KEY' \n"
-                    + "AND k.`TABLE_SCHEMA` = '" + schemaName + "' OR k.`REFERENCED_TABLE_SCHEMA` = '" + schemaName + "'";
-
-            try (Connection connection = dataSource.getConnection();
-                    Statement statement = connection.createStatement();
-                    ResultSet resultSet = statement.executeQuery(query)) {
-
-                while (resultSet.next()) {
-                    String constraintName = resultSet.getString("constraint_name");
-
-                    Key key = schemaKeys.get(constraintName);
-                    if (key == null) {
-                        key = new KeyImpl(
-                                dbWrapper,
-                                tapSchema,
-                                resultSet.getString("from_schema"),
-                                resultSet.getString("from_table"),
-                                resultSet.getString("target_schema"),
-                                resultSet.getString("target_table")
-                        );
-                        schemaKeys.put(constraintName, key);
-                    }
-
-                    ((KeyImpl) key).addKeyColumn(resultSet.getString("from_column"), resultSet.getString("target_column"));
-                }
-            }
-
-            return new ArrayList<>(schemaKeys.values());
-
-        } else if (dbType == DatabaseType.POSTGRES) {
-
-            String databaseName
-                    = schemaName.equals(tapSchema.getName())
-                    ? dbWrapper.getTapSchemaCredentials().getDatabase()
-                    : dbWrapper.getSourceCredentials().getDatabase();
-
-            List<Key> schemaKeys = new ArrayList<>();
-
-            String queryKeys = "SELECT\n"
-                    + "conname AS constraint_name,\n"
-                    + "conrelid::regclass AS from_table, \n"
-                    + "confrelid::regclass AS target_table\n"
-                    + "FROM pg_catalog.pg_constraint\n"
-                    + "WHERE contype = 'f'\n"
-                    + "AND ((conrelid::regclass || '' LIKE '" + schemaName + ".%')\n"
-                    + "OR (confrelid::regclass || '' LIKE '" + schemaName + ".%'))";
-
-            try (Connection connection = dataSource.getConnection();
-                    Statement statement = connection.createStatement();
-                    ResultSet resultSet = statement.executeQuery(queryKeys)) {
-
-                log.debug("Executing query {}", queryKeys);
-
-                while (resultSet.next()) {
-
-                    String constraintName = resultSet.getString("constraint_name");
-
-                    String[] fromTableFullNameSplit = resultSet.getString("from_table").split(Pattern.quote("."));
-                    String fromSchema = fromTableFullNameSplit[0];
-                    String fromTable = fromTableFullNameSplit[1];
-
-                    String[] targetTableFullNameSplit = resultSet.getString("target_table").split(Pattern.quote("."));
-                    String targetSchema = targetTableFullNameSplit[0];
-                    String targetTable = targetTableFullNameSplit[1];
-
-                    Key key = new KeyImpl(dbWrapper, tapSchema, fromSchema, fromTable, targetSchema, targetTable);
-                    schemaKeys.add(key);
-
-                    // conkey conrelid
-                    String queryFromKC = "SELECT\n"
-                            + "c.column_name AS key_column\n"
-                            + "FROM information_schema.columns c\n"
-                            + "JOIN pg_catalog.pg_constraint r ON c.ordinal_position = ANY(r.conkey)\n"
-                            + "AND (c.table_schema || '.' || c.table_name) = (r.conrelid::regclass || '')\n"
-                            + "WHERE r.conname = '" + constraintName + "' AND r.contype = 'f'\n"
-                            + "AND c.table_schema = '" + fromSchema + "'\n"
-                            + "AND table_catalog = '" + databaseName + "'";
-
-                    // as above, but with confkey and confrelid and different c.table_schema where condition
-                    String queryTargetKC = "SELECT\n"
-                            + "c.column_name AS key_column\n"
-                            + "FROM information_schema.columns c\n"
-                            + "JOIN pg_catalog.pg_constraint r ON c.ordinal_position = ANY(r.confkey)\n"
-                            + "AND (c.table_schema || '.' || c.table_name) = (r.confrelid::regclass || '')\n"
-                            + "WHERE r.conname = '" + constraintName + "' AND r.contype = 'f'\n"
-                            + "AND c.table_schema = '" + targetSchema + "'\n"
-                            + "AND table_catalog = '" + databaseName + "'";
-
-                    try (Statement statFromKC = connection.createStatement();
-                            Statement statTargetKC = connection.createStatement()) {
-
-                        try (ResultSet rsFromKC = statFromKC.executeQuery(queryFromKC);
-                                ResultSet rsTargetKC = statTargetKC.executeQuery(queryTargetKC)) {
-
-                            log.debug("Executing query {}", queryFromKC);
-                            log.debug("Executing query {}", queryTargetKC);
-
-                            while (rsFromKC.next()) {
-                                if (rsTargetKC.next()) {
-                                    ((KeyImpl) key).addKeyColumn(
-                                            rsFromKC.getString("key_column"),
-                                            rsTargetKC.getString("key_column")
-                                    );
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-
-            return schemaKeys;
-        } else {
-            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-        }
-    }
-
-    /**
-     * Retrieves saved {@code Key}s from the database and add them into the
-     * specified {@code TapSchema}.
-     */
-    protected static void fillSavedKeys(DBWrapper dbWrapper, TapSchema tapSchema) throws SQLException {
-
-        log.debug("fillSavedKeys");
-
-        // We can decide to work only on from tables or target tables, because 
-        // the same key is contained on both.
-        // Schemas and tables have to be already added to the TAP_SCHEMA.
-        List<Key> allVisibleKeys = new ArrayList<>();
-
-        // Reset to null all generated keyId.
-        for (Key key : ((TapSchemaImpl) tapSchema).getAllKeys()) {
-            key.initProperty(Key.ID_KEY, null);
-
-            // Meanwhile we add all the visible keys to this list for 
-            // further checks
-            if (key.isVisible()) {
-                allVisibleKeys.add(key);
-            }
-        }
-
-        // Building query for the keys table
-        SelectQueryBuilder keysSelect = new SelectQueryBuilder(dbWrapper.getTapSchemaDatabaseType(), tapSchema, TapSchema.KEYS_TABLE) {
-            @Override
-            protected TapSchemaEntity getEntity(ResultSet rs) throws SQLException {
-                throw new UnsupportedOperationException();
-            }
-        };
-        String queryKeys = keysSelect.getQuery();
-        
-        // Building query for the key_columns table
-        SelectQueryBuilder keyColumnsSelect = new SelectQueryBuilder(dbWrapper.getTapSchemaDatabaseType(), tapSchema, TapSchema.KEY_COLUMNS_TABLE) {
-            @Override
-            protected TapSchemaEntity getEntity(ResultSet rs) throws SQLException {
-                throw new UnsupportedOperationException();
-            }
-        };
-        String queryKeyColumns = String.format("%s WHERE %s = ?",
-                keyColumnsSelect.getQuery(),
-                TSMUtil.escapeName(KeyColumn.KEY_ID_KEY, dbWrapper.getTapSchemaDatabaseType()));
-
-        boolean supportKeyID = EntityPropertyInfo.getEntityPropertyInfo(TapSchema.KEYS_TABLE, Key.KEY_ID_KEY).acceptVersion(tapSchema.getVersion());
-        boolean supportKeyColumnID = EntityPropertyInfo.getEntityPropertyInfo(TapSchema.KEY_COLUMNS_TABLE, KeyColumn.KEY_COLUMN_ID_KEY).acceptVersion(tapSchema.getVersion());
-
-        try (Connection conn = dbWrapper.getTapSchemaConnection()) {
-
-            log.debug("Executing query {}", queryKeys);
-
-            // ResultSet type and concurrency are necessary for PostgreSQL
-            try (Statement statementKeys = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
-                    ResultSet rsKeys = statementKeys.executeQuery(queryKeys)) {
-
-                while (rsKeys.next()) {
-                    // Searching the keys.
-
-                    String keyId = rsKeys.getString(Key.ID_KEY);
-                    String fromTableCompleteNameSplit[] = rsKeys.getString(Key.FROM_TABLE_KEY).split(Pattern.quote("."));
-                    String fromSchemaName = fromTableCompleteNameSplit[0];
-                    String fromTableName = fromTableCompleteNameSplit[1];
-
-                    Schema fromSchema = tapSchema.getChild(fromSchemaName);
-
-                    if (fromSchema == null) {
-                        tapSchema.getConsistencyChecks().addUnexistingKey(keyId);
-                    } else {
-                        Table fromTable = fromSchema.getChild(fromTableName);
-                        if (fromTable == null) {
-                            tapSchema.getConsistencyChecks().addUnexistingKey(keyId);
-                        } else {
-                            // ResultSet type and concurrency are necessary for PostgreSQL
-                            try (PreparedStatement statementKeyColumns = conn.prepareStatement(queryKeyColumns, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) {
-
-                                statementKeyColumns.setString(1, keyId);
-                                log.debug("Executing query {} [key_id={}]", queryKeyColumns, keyId);
-
-                                try (ResultSet rsKeyColumns = statementKeyColumns.executeQuery()) {
-                                    for (Key fromKey : fromTable.getAllFromKeys()) {
-
-                                        boolean columnsFound = false;
-
-                                        for (KeyColumn keyColumn : fromKey.getKeyColumns()) {
-                                            columnsFound = false;
-
-                                            rsKeyColumns.beforeFirst();
-                                            while (rsKeyColumns.next()) {
-                                                String fromColumn = rsKeyColumns.getString(KeyColumn.FROM_COLUMN_KEY);
-                                                String targetColumn = rsKeyColumns.getString(KeyColumn.TARGET_COLUMN_KEY);
-                                                if (keyColumn.getFromColumn().equals(fromColumn)
-                                                        && keyColumn.getTargetColumn().equals(targetColumn)) {
-                                                    columnsFound = true;
-                                                    break;
-                                                }
-                                            }
-                                            if (!columnsFound) {
-                                                break;
-                                            }
-                                        }
-
-                                        if (columnsFound) {
-                                            // all columns found --> key found!
-
-                                            // Updating key
-                                            String keyDescription = rsKeys.getString(Key.DESCRIPTION_KEY);
-                                            String keyUtype = rsKeys.getString(Key.UTYPE_KEY);
-
-                                            fromKey.initProperty(Key.ID_KEY, keyId);
-                                            fromKey.initProperty(Key.DESCRIPTION_KEY, keyDescription);
-                                            fromKey.initProperty(Key.UTYPE_KEY, keyUtype);
-                                            if (supportKeyID) {
-                                                fromKey.initProperty(Key.KEY_ID_KEY, TSMUtil.getObject(rsKeys, Key.KEY_ID_KEY, Long.class));
-                                            }
-                                            ((KeyImpl) fromKey).setVisible(true);
-
-                                            // Updating key columns
-                                            for (KeyColumn keyColumn : fromKey.getKeyColumns()) {
-                                                rsKeyColumns.beforeFirst();
-                                                while (rsKeyColumns.next()) {
-                                                    String fromColumn = rsKeyColumns.getString(KeyColumn.FROM_COLUMN_KEY);
-                                                    String targetColumn = rsKeyColumns.getString(KeyColumn.TARGET_COLUMN_KEY);
-                                                    if (keyColumn.getFromColumn().equals(fromColumn)
-                                                            && keyColumn.getTargetColumn().equals(targetColumn)) {
-                                                        keyColumn.initProperty(KeyColumn.KEY_ID_KEY, keyId);
-                                                        if (supportKeyColumnID) {
-                                                            keyColumn.initProperty(KeyColumn.KEY_COLUMN_ID_KEY, TSMUtil.getObject(rsKeyColumns, KeyColumn.KEY_COLUMN_ID_KEY, Long.class));
-                                                        }
-                                                        break;
-                                                    }
-                                                }
-                                            }
-
-                                            break;
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-
-                // Check if the saved TAP_SCHEMA contains keys that aren't loaded (fictitious keys).
-                List<Key> fictitiousKeys = new ArrayList<>();
-
-                rsKeys.beforeFirst();
-                while (rsKeys.next()) {
-                    String keyId = rsKeys.getString(Key.ID_KEY);
-                    boolean keyIdFound = false;
-                    for (Key key : allVisibleKeys) {
-                        if (keyId.equals(key.getId())) {
-                            keyIdFound = true;
-                            break;
-                        }
-                    }
-                    if (!keyIdFound && !tapSchema.getConsistencyChecks().getUnexistingKeys().contains(keyId)) {
-                        String fromTableCompleteName = rsKeys.getString(Key.FROM_TABLE_KEY);
-                        String targetTableCompleteName = rsKeys.getString(Key.TARGET_TABLE_KEY);
-                        KeyImpl key = new KeyImpl(dbWrapper, tapSchema, fromTableCompleteName, targetTableCompleteName);
-                        key.initProperty(Key.ID_KEY, keyId);
-                        if (supportKeyID) {
-                            key.initProperty(Key.KEY_ID_KEY, TSMUtil.getObject(rsKeys, Key.KEY_ID_KEY, Long.class));
-                        }
-                        key.setVisible(true);
-                        fictitiousKeys.add(key);
-
-                        tapSchema.getChild(key.getFromSchemaName()).getChild(key.getFromTableSimpleName()).addFromKey(key);
-                        tapSchema.getChild(key.getTargetSchemaName()).getChild(key.getTargetTableSimpleName()).addTargetKey(key);
-                    }
-                }
-
-                // filling fictitious keys columns
-                for (Key key : fictitiousKeys) {
-                    try (PreparedStatement statementKeyColumns = conn.prepareStatement(queryKeyColumns)) {
-
-                        String keyId = key.getId();
-                        statementKeyColumns.setString(1, keyId);
-                        log.debug("Executing query {} [key_id={}]", queryKeyColumns, keyId);
-
-                        try (ResultSet rsKeyColumns = statementKeyColumns.executeQuery()) {
-
-                            while (rsKeyColumns.next()) {
-                                String fromColumn = rsKeyColumns.getString(KeyColumn.FROM_COLUMN_KEY);
-                                String targetColumn = rsKeyColumns.getString(KeyColumn.TARGET_COLUMN_KEY);
-
-                                KeyColumn keyColumn = ((KeyImpl) key).addKeyColumn(fromColumn, targetColumn);
-                                if (supportKeyColumnID) {
-                                    keyColumn.initProperty(KeyColumn.KEY_COLUMN_ID_KEY, TSMUtil.getObject(rsKeyColumns, KeyColumn.KEY_COLUMN_ID_KEY, Long.class));
-                                }
-                            }
-                        }
-                    }
-
-                    // adding fictitious key to key set
-                    ((TapSchemaImpl) tapSchema).getAllKeys().add(key);
-                }
-
-                if (!fictitiousKeys.isEmpty()) {
-                    log.debug("{} fictitious keys found", fictitiousKeys.size());
-                    for (Key key : fictitiousKeys) {
-                        log.debug("   {}", key);
-                    }
-                }
-
-                // Check if there are remaining keys with keyId = null (valid keys
-                // that weren't saved into the TAP_SCHEMA).
-                int keyId = ((TapSchemaImpl) tapSchema).getMaxKeyId() + 1;
-                for (Key key : allVisibleKeys) {
-                    if (key.getId() == null) {
-                        key.setId(keyId + "");
-                        keyId++;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Save a new {@code Key} into the TAP_SCHEMA schema.
-     */
-    protected static void insertNewKey(DatabaseType dbType, Connection connection, TapSchema tapSchema, Key key) throws SQLException {
-        log.debug("insertNewKey");
-
-        InsertQueryBuilder insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, key, TapSchema.KEYS_TABLE);
-        insertQueryBuilder.executeQuery(connection);
-
-        for (KeyColumn keyColumn : key.getKeyColumns()) {
-            insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, keyColumn, TapSchema.KEY_COLUMNS_TABLE);
-            insertQueryBuilder.executeQuery(connection);
-        }
-    }
-
-    /**
-     * Updates an existing {@code Key}.
-     */
-    protected static void updateKey(DatabaseType dbType, Connection connection, TapSchema tapSchema, Key key) throws SQLException {
-        log.debug("updateKey");
-
-        if (key.getId() == null) {
-            throw new IllegalStateException("Unable to update key: key_id is null");
-        }
-
-        boolean keyIdChanged = key.isChanged(Key.ID_KEY);
-
-        if (keyIdChanged) {
-            // Deleting key columns to avoid problem with foreign key constraint failures
-
-            String tapSchemaNameEscaped = TSMUtil.escapeName(tapSchema.getName(), dbType);
-            String keyColumnsNameEscaped = TSMUtil.escapeName("key_columns", dbType);
-
-            String query = String.format("DELETE FROM %s.%s WHERE key_id = ?", tapSchemaNameEscaped, keyColumnsNameEscaped);
-
-            try (PreparedStatement statement = connection.prepareStatement(query)) {
-                String originalKey = key.getOriginalValue(Key.ID_KEY, String.class);
-                statement.setString(1, originalKey);
-                log.debug("Executing query {} [key_id={}]", query, originalKey);
-                statement.executeUpdate();
-            }
-        }
-
-        // Updating keys
-        UpdateQueryBuilder updateQueryBuilder = new UpdateQueryBuilder(dbType, tapSchema, key, TapSchema.KEYS_TABLE, "key_id = ?");
-        String query = updateQueryBuilder.getQuery();
-        try (PreparedStatement statement = connection.prepareStatement(query)) {
-            int i = updateQueryBuilder.addStatementValues(statement);
-            String keyId = key.getId();
-            statement.setString(i, keyId);
-            log.debug("Executing query {} [key_id={}]", query, keyId);
-            statement.executeUpdate();
-        }
-
-        if (keyIdChanged) {
-            // Re-insert deleted key columns
-            for (KeyColumn keyColumn : key.getKeyColumns()) {
-                InsertQueryBuilder insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, keyColumn, TapSchema.KEY_COLUMNS_TABLE);
-                insertQueryBuilder.executeQuery(connection);
-            }
-        } else {
-            // Update key columns
-            for (KeyColumn keyColumn : key.getKeyColumns()) {
-                if (keyColumn.isChanged()) {
-                    updateQueryBuilder = new UpdateQueryBuilder(dbType, tapSchema, keyColumn, TapSchema.KEY_COLUMNS_TABLE, "key_id = ?");
-                    query = updateQueryBuilder.getQuery();
-                    try (PreparedStatement statement = connection.prepareStatement(query)) {
-                        int i = updateQueryBuilder.addStatementValues(statement);
-                        String keyId = key.getId();
-                        statement.setString(i, keyId);
-                        log.debug("Executing query {} [key_id={}]", query, keyId);
-                        statement.executeUpdate();
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoSchema.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoSchema.java
deleted file mode 100644
index 32257b6ec90fafaef6f2dfec7357072053182168..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoSchema.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
-import it.inaf.ia2.tsm.api.contract.Schema;
-import it.inaf.ia2.tsm.api.contract.Status;
-import it.inaf.ia2.tsm.api.contract.TapSchema;
-import it.inaf.ia2.tsm.api.contract.TapSchemaEntity;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.List;
-import javax.sql.DataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Utility class that contains static methods for managing {@link Schema}s into
- * the database.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public class DaoSchema {
-
-    private static final Logger log = LoggerFactory.getLogger(DaoSchema.class);
-
-    public static List<String> getAllSchemasNames(Credentials credentials) throws SQLException {
-        DataSource ds = TSMUtil.createDataSource(credentials);
-        return getAllSchemasNames(ds, credentials.getDatabaseType());
-    }
-
-    /**
-     * Retrieve the list of the names of the all the schemas contained into the
-     * database specified by the <code>DataSource</code> parameter.
-     *
-     * @return list of schemas names alphabetically and case insensitively
-     * ordered.
-     */
-    public static List<String> getAllSchemasNames(DataSource dataSource, DatabaseType dbType) throws SQLException {
-
-        log.debug("getAllSchemasNames");
-
-        String query;
-        if (dbType == DatabaseType.MYSQL) {
-            query = "SHOW DATABASES";
-        } else if (dbType == DatabaseType.POSTGRES) {
-            query = "SELECT schema_name FROM information_schema.schemata";
-        } else {
-            throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-        }
-
-        log.debug("Executing query {}", query);
-
-        List<String> allSchemas = new ArrayList<>();
-
-        try (Connection connection = dataSource.getConnection();
-                Statement statement = connection.createStatement();
-                ResultSet resultSet = statement.executeQuery(query)) {
-            while (resultSet.next()) {
-                allSchemas.add(resultSet.getString(1));
-            }
-        }
-
-        log.debug("{} schemas found", allSchemas.size());
-
-        return TSMUtil.sortStringsList(allSchemas);
-    }
-
-    /**
-     * Retrieves saved {@code Schema}s from the database and add them into the
-     * specified {@code TapSchema}.
-     */
-    protected static void fillSavedSchemas(DBWrapper dbWrapper, final TapSchema tapSchema) throws SQLException {
-
-        log.debug("fillSavedSchemas");
-
-        SelectQueryBuilder selectQueryBuilder = new SelectQueryBuilder(dbWrapper.getTapSchemaDatabaseType(), tapSchema, TapSchema.SCHEMAS_TABLE) {
-
-            @Override
-            protected TapSchemaEntity getEntity(ResultSet rs) throws SQLException {
-                String schemaName = rs.getString("schema_name");
-                Schema schema = tapSchema.addChild(schemaName);
-                if (schema == null) {
-                    return null;
-                }
-                schema.setStatus(Status.ADDED_PERSISTED);
-                return schema;
-            }
-        };
-
-        selectQueryBuilder.executeQuery(dbWrapper.getTapSchemaConnection());
-    }
-
-    /**
-     * Save a new {@code Schema} into the TAP_SCHEMA schema.
-     */
-    protected static void insertNewSchema(DatabaseType dbType, Connection connection, TapSchema tapSchema, Schema schema) throws SQLException {
-
-        log.debug("insertNewSchema");
-
-        InsertQueryBuilder insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, schema, TapSchema.SCHEMAS_TABLE);
-        insertQueryBuilder.executeQuery(connection);
-    }
-
-    /**
-     * Updates an existing {@code Schema}.
-     */
-    protected static void updateSchema(DatabaseType dbType, Connection connection, TapSchema tapSchema, Schema schema) throws SQLException {
-
-        UpdateQueryBuilder updateQueryBuilder = new UpdateQueryBuilder(dbType, tapSchema, schema, TapSchema.SCHEMAS_TABLE, "schema_name = ?");
-
-        String query = updateQueryBuilder.getQuery();
-
-        try (PreparedStatement statement = connection.prepareStatement(query)) {
-
-            log.debug("Executing query {}", query);
-
-            int i = updateQueryBuilder.addStatementValues(statement);
-            statement.setString(i, schema.getName());
-
-            statement.executeUpdate();
-        }
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoTable.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoTable.java
deleted file mode 100644
index 90c21f245c13ed36e978c76c0222aa9eca5c033f..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DaoTable.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
-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 java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-import javax.sql.DataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Utility class that contains static methods for managing {@link Table}s into
- * the database.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public class DaoTable {
-
-    private static final Logger log = LoggerFactory.getLogger(DaoTable.class);
-
-    /**
-     * Retrieve the list of the names of all the tables contained in a schema,
-     * given its name, also if the schema has never been added into the
-     * TAP_SCHEMA.
-     *
-     * @return list of all tables names alphabetically and case insensitively
-     * ordered.
-     */
-    public static List<String> getAllTablesNames(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) throws SQLException {
-
-        DataSource dataSource = TSMUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName);
-        DatabaseType dbType = TSMUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName);
-
-        String query;
-        switch (dbType) {
-            case MYSQL:
-                query = "SHOW TABLES FROM `" + schemaName + "`";
-                break;
-            case POSTGRES:
-                query = "SELECT tablename FROM pg_catalog.pg_tables where schemaname = '" + schemaName + "'";
-                break;
-            default:
-                throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-        }
-
-        log.debug("Executing query {}", query);
-
-        List<String> allTables = new ArrayList<>();
-        try (Connection connection = dataSource.getConnection();
-                Statement statement = connection.createStatement();
-                ResultSet resultSet = statement.executeQuery(query)) {
-            while (resultSet.next()) {
-                allTables.add(resultSet.getString(1));
-            }
-        }
-
-        return TSMUtil.sortStringsList(allTables);
-    }
-
-    /**
-     * Retrieve the association between the tables names and their types
-     * (<code>table</code> or <code>view</code>), given a
-     * <code>DataSource</code> and a schema name.
-     *
-     * @return a map which has the tables names as keys and the table types as
-     * values.
-     */
-    protected static Map<String, String> getTablesTypes(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) throws SQLException {
-
-        log.debug("getTablesTypes");
-
-        final Map<String, String> tablesTypes = new HashMap<>();
-
-        DataSource dataSource = TSMUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName);
-        DatabaseType dbType = TSMUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName);
-
-        String query;
-        switch (dbType) {
-            case MYSQL:
-                query = "SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = '" + schemaName + "'";
-                break;
-            case POSTGRES:
-                query = "SELECT tablename AS table_name, 'table' AS table_type\n"
-                        + "FROM pg_catalog.pg_tables WHERE schemaname = '" + schemaName + "'\n"
-                        + "UNION\n"
-                        + "SELECT table_name AS table_name, 'view' AS table_type\n"
-                        + "FROM INFORMATION_SCHEMA.views\n"
-                        + "WHERE table_schema = '" + schemaName + "'";
-                break;
-            default:
-                throw new UnsupportedOperationException("Database type " + dbType + " not supported");
-        }
-
-        log.debug("Executing query {}", query);
-
-        try (Connection connection = dataSource.getConnection();
-                Statement statement = connection.createStatement();
-                ResultSet resultSet = statement.executeQuery(query)) {
-            while (resultSet.next()) {
-                String tableName = resultSet.getString("table_name");
-                String tableType = resultSet.getString("table_type").equalsIgnoreCase("VIEW") ? "view" : "table";
-                tablesTypes.put(tableName, tableType);
-            }
-        }
-
-        return tablesTypes;
-    }
-
-    /**
-     * Retrieves saved {@code Table}s from the database and add them into the
-     * specified {@code TapSchema}.
-     */
-    protected static void fillSavedTables(DBWrapper dbWrapper, final TapSchema tapSchema) throws SQLException {
-
-        log.debug("fillSavedTables");
-
-        SelectQueryBuilder selectQueryBuilder = new SelectQueryBuilder(dbWrapper.getTapSchemaDatabaseType(), tapSchema, TapSchema.TABLES_TABLE) {
-
-            @Override
-            protected TapSchemaEntity getEntity(ResultSet rs) throws SQLException {
-                String schemaName = rs.getString("schema_name");
-                String completeTableName = rs.getString("table_name");
-
-                Schema schema = tapSchema.getChild(schemaName);
-
-                if (schema != null) {
-                    Table table = schema.addChild(completeTableName.split(Pattern.quote("."))[1]);
-                    if (table == null) {
-                        return null;
-                    }
-                    table.setStatus(Status.ADDED_PERSISTED);
-                    return table;
-                }
-                // Schema was marked for removal in the ConsistencyChecks
-                return null;
-            }
-        };
-
-        selectQueryBuilder.executeQuery(dbWrapper.getTapSchemaConnection());
-    }
-
-    /**
-     * Save a new {@code Table} into the TAP_SCHEMA schema.
-     */
-    protected static void insertNewTable(DatabaseType dbType, Connection connection, TapSchema tapSchema, Table table) throws SQLException {
-
-        log.debug("insertNewTable");
-
-        InsertQueryBuilder insertQueryBuilder = new InsertQueryBuilder(dbType, tapSchema, table, TapSchema.TABLES_TABLE);
-        insertQueryBuilder.executeQuery(connection);
-    }
-
-    /**
-     * Updates an existing {@code Table}.
-     */
-    protected static void updateTable(DatabaseType dbType, Connection connection, TapSchema tapSchema, Table table) throws SQLException {
-
-        UpdateQueryBuilder updateQueryBuilder = new UpdateQueryBuilder(dbType, tapSchema, table, TapSchema.TABLES_TABLE, "table_name = ?");
-
-        String query = updateQueryBuilder.getQuery();
-
-        try (PreparedStatement statement = connection.prepareStatement(query)) {
-
-            log.debug("Executing query {}", query);
-
-            int i = updateQueryBuilder.addStatementValues(statement);
-            statement.setString(i, table.getCompleteName());
-
-            statement.executeUpdate();
-        }
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/EntityPropertyInfo.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/EntityPropertyInfo.java
deleted file mode 100644
index 37a590508ac6f156f3b231eaebea8b6c0ab5239c..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/EntityPropertyInfo.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-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.Table;
-import it.inaf.ia2.tsm.api.contract.TapSchema;
-import it.inaf.ia2.tsm.api.contract.TapSchemaVersion;
-import java.sql.Types;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Describes the mapping between the
- * {@link it.inaf.ia2.tsm.api.contract.TapSchemaEntity} instances
- * and their related table columns.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public class EntityPropertyInfo {
-
-    private static final Logger log = LoggerFactory.getLogger(EntityPropertyInfo.class);
-
-    private static final Map<String, List<EntityPropertyInfo>> propertiesMap = new HashMap<>();
-
-    static {
-        List<EntityPropertyInfo> schemaProperties = new ArrayList<>();
-        propertiesMap.put(TapSchema.SCHEMAS_TABLE, schemaProperties);
-        schemaProperties.add(new EntityPropertyInfo(Schema.SCHEMA_NAME_KEY, String.class, false));
-        schemaProperties.add(new EntityPropertyInfo(Schema.UTYPE_KEY, String.class, true));
-        schemaProperties.add(new EntityPropertyInfo(Schema.DESCRIPTION_KEY, String.class, true));
-        schemaProperties.add(new EntityPropertyInfo(Schema.SCHEMA_ID, Long.class, true, TapSchemaVersion.TAP_SCHEMA_1_IA2, TapSchemaVersion.TAP_SCHEMA_1_1_IA2));
-
-        List<EntityPropertyInfo> tableProperties = new ArrayList<>();
-        propertiesMap.put(TapSchema.TABLES_TABLE, tableProperties);
-        tableProperties.add(new EntityPropertyInfo(Table.SCHEMA_NAME_KEY, String.class, false));
-        tableProperties.add(new EntityPropertyInfo(Table.TABLE_NAME_KEY, String.class, false));
-        tableProperties.add(new EntityPropertyInfo(Table.TABLE_TYPE_KEY, String.class, false));
-        tableProperties.add(new EntityPropertyInfo(Table.UTYPE_KEY, String.class, true));
-        tableProperties.add(new EntityPropertyInfo(Table.DESCRIPTION_KEY, String.class, true));
-        tableProperties.add(new EntityPropertyInfo(Table.TABLE_INDEX, Integer.class, true, TapSchemaVersion.TAP_SCHEMA_1_1, TapSchemaVersion.TAP_SCHEMA_1_1_IA2));
-        tableProperties.add(new EntityPropertyInfo(Table.TABLE_ID, Long.class, true, TapSchemaVersion.TAP_SCHEMA_1_IA2, TapSchemaVersion.TAP_SCHEMA_1_1_IA2));
-
-        List<EntityPropertyInfo> columnProperties = new ArrayList<>();
-        propertiesMap.put(TapSchema.COLUMNS_TABLE, columnProperties);
-        columnProperties.add(new EntityPropertyInfo(Column.TABLE_NAME_KEY, String.class, false));
-        columnProperties.add(new EntityPropertyInfo(Column.COLUMN_NAME_KEY, String.class, false));
-        columnProperties.add(new EntityPropertyInfo(Column.DATATYPE_KEY, String.class, false));
-        columnProperties.add(new EntityPropertyInfo(Column.ARRAYSIZE_KEY, Integer.class, false, TapSchemaVersion.TAP_SCHEMA_1_1, TapSchemaVersion.TAP_SCHEMA_1_1_IA2));
-        columnProperties.add(new EntityPropertyInfo(Column.SIZE_KEY, Integer.class, false));
-        columnProperties.add(new EntityPropertyInfo(Column.DESCRIPTION_KEY, String.class, true));
-        columnProperties.add(new EntityPropertyInfo(Column.UTYPE_KEY, String.class, true));
-        columnProperties.add(new EntityPropertyInfo(Column.UNIT_KEY, String.class, true));
-        columnProperties.add(new EntityPropertyInfo(Column.UCD_KEY, String.class, true));
-        columnProperties.add(new EntityPropertyInfo(Column.INDEXED_KEY, Boolean.class, false));
-        columnProperties.add(new EntityPropertyInfo(Column.PRINCIPAL_KEY, Boolean.class, true));
-        columnProperties.add(new EntityPropertyInfo(Column.STD_KEY, Boolean.class, true));
-        columnProperties.add(new EntityPropertyInfo(Column.COLUMN_INDEX_KEY, Integer.class, true, TapSchemaVersion.TAP_SCHEMA_1_1, TapSchemaVersion.TAP_SCHEMA_1_1_IA2));
-        columnProperties.add(new EntityPropertyInfo(Column.ID_KEY, Integer.class, true, TapSchemaVersion.TAP_SCHEMA_1_IA2, TapSchemaVersion.TAP_SCHEMA_1_1_IA2));
-        columnProperties.add(new EntityPropertyInfo(Column.COLUMN_ID_KEY, Long.class, true, TapSchemaVersion.TAP_SCHEMA_1_IA2, TapSchemaVersion.TAP_SCHEMA_1_1_IA2));
-
-        List<EntityPropertyInfo> keyProperties = new ArrayList<>();
-        propertiesMap.put(TapSchema.KEYS_TABLE, keyProperties);
-        keyProperties.add(new EntityPropertyInfo(Key.ID_KEY, String.class, true));
-        keyProperties.add(new EntityPropertyInfo(Key.FROM_TABLE_KEY, String.class, false));
-        keyProperties.add(new EntityPropertyInfo(Key.TARGET_TABLE_KEY, String.class, false));
-        keyProperties.add(new EntityPropertyInfo(Key.DESCRIPTION_KEY, String.class, true));
-        keyProperties.add(new EntityPropertyInfo(Key.UTYPE_KEY, String.class, true));
-        keyProperties.add(new EntityPropertyInfo(Key.KEY_ID_KEY, Long.class, true, TapSchemaVersion.TAP_SCHEMA_1_IA2, TapSchemaVersion.TAP_SCHEMA_1_1_IA2));
-
-        List<EntityPropertyInfo> keyColumnProperties = new ArrayList<>();
-        propertiesMap.put(TapSchema.KEY_COLUMNS_TABLE, keyColumnProperties);
-        keyColumnProperties.add(new EntityPropertyInfo(KeyColumn.KEY_ID_KEY, String.class, true));
-        keyColumnProperties.add(new EntityPropertyInfo(KeyColumn.FROM_COLUMN_KEY, String.class, false));
-        keyColumnProperties.add(new EntityPropertyInfo(KeyColumn.TARGET_COLUMN_KEY, String.class, false));
-        keyColumnProperties.add(new EntityPropertyInfo(KeyColumn.KEY_COLUMN_ID_KEY, Long.class, true, TapSchemaVersion.TAP_SCHEMA_1_IA2, TapSchemaVersion.TAP_SCHEMA_1_1_IA2));
-    }
-
-    /**
-     * Obtains all the {@link EntityPropertyInfo} for a given TAP_SCHEMA table
-     * name.
-     */
-    public static List<EntityPropertyInfo> getEntityPropertiesInfo(String tapSchemaTable) {
-        return propertiesMap.get(tapSchemaTable);
-    }
-
-    /**
-     * Obtains the {@link EntityPropertyInfo} for a given TAP_SCHEMA table name
-     * and a given column name.
-     */
-    public static EntityPropertyInfo getEntityPropertyInfo(String tapSchemaTable, String key) {
-        for (EntityPropertyInfo propertyInfo : getEntityPropertiesInfo(tapSchemaTable)) {
-            if (propertyInfo.getPropertyKey().equals(key)) {
-                return propertyInfo;
-            }
-        }
-        log.debug("property {} not found for {} table", key, tapSchemaTable);
-        return null;
-    }
-
-    private final String propertyKey;
-    private final Class type;
-    private final int sqlType;
-    private final boolean updatable;
-    private final TapSchemaVersion[] versions;
-
-    protected EntityPropertyInfo(String propertyKey, Class type, boolean updatable, TapSchemaVersion... versions) {
-        this.propertyKey = propertyKey;
-        this.type = type;
-
-        if (type == String.class) {
-            sqlType = Types.VARCHAR;
-        } else if (type == Integer.class) {
-            sqlType = Types.INTEGER;
-        } else if (type == Long.class) {
-            sqlType = Types.BIGINT;
-        } else if (type == Boolean.class) {
-            sqlType = Types.BIT;
-        } else {
-            throw new IllegalArgumentException("EntityPropertyInfo doesn't support class type " + type.getCanonicalName());
-        }
-
-        this.updatable = updatable;
-        this.versions = versions;
-    }
-
-    /**
-     * The name of the property (the column name).
-     */
-    public String getPropertyKey() {
-        return propertyKey;
-    }
-
-    /**
-     * The class type of the property value (the value stored in a
-     * {@link EntityProperty}).
-     */
-    public Class getPropertyType() {
-        return type;
-    }
-
-    /**
-     * The {@link java.sql.Types} integer related to the class type of the
-     * property value.
-     */
-    public int getSqlType() {
-        return sqlType;
-    }
-
-    /**
-     * Returns true if the user can update the value of this property.
-     */
-    public boolean isUpdatable() {
-        return updatable;
-    }
-
-    /**
-     * Returns all the TAP_SCHEMA versions that uses this property.
-     */
-    public TapSchemaVersion[] getVersions() {
-        return versions;
-    }
-
-    /**
-     * Returns true if the specified {@link TapSchemaVersion} uses this
-     * property.
-     */
-    public boolean acceptVersion(TapSchemaVersion version) {
-        if (versions == null || versions.length == 0) {
-            return true;
-        }
-        for (TapSchemaVersion v : versions) {
-            if (v == version) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/InsertQueryBuilder.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/InsertQueryBuilder.java
deleted file mode 100644
index f62a1d5c8b9f53ca8a72b06087e9ecbc71b19f83..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/InsertQueryBuilder.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
-import it.inaf.ia2.tsm.api.contract.TapSchema;
-import it.inaf.ia2.tsm.api.contract.TapSchemaEntity;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Prepares an {@code INSERT} SQL query for a given {@link TapSchemaEntity} and
- * a given {@link TapSchema}.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public class InsertQueryBuilder {
-
-    private static final Logger log = LoggerFactory.getLogger(InsertQueryBuilder.class);
-
-    private final String query;
-    private final List<EntityPropertyInfo> addedProperties;
-    private final TapSchemaEntity tapSchemaEntity;
-
-    protected InsertQueryBuilder(DatabaseType dbType, TapSchema tapSchema, TapSchemaEntity tapSchemaEntity, String tapSchemaTableName) {
-
-        StringBuilder querySb = new StringBuilder("INSERT INTO ");
-        querySb.append(TSMUtil.escapeName(tapSchema.getName(), dbType));
-        querySb.append(".");
-        querySb.append(TSMUtil.escapeName(tapSchemaTableName, dbType));
-        querySb.append(" (");
-
-        addedProperties = new ArrayList<>();
-        this.tapSchemaEntity = tapSchemaEntity;
-
-        boolean first = true;
-        for (EntityPropertyInfo propertyInfo : EntityPropertyInfo.getEntityPropertiesInfo(tapSchemaTableName)) {
-            if (propertyInfo.acceptVersion(tapSchema.getVersion())) {
-
-                if (!first) {
-                    querySb.append(", ");
-                }
-                querySb.append(propertyInfo.getPropertyKey());
-                addedProperties.add(propertyInfo);
-                first = false;
-            }
-        }
-        querySb.append(") VALUES (");
-        for (int i = 0; i < addedProperties.size(); i++) {
-            if (i > 0) {
-                querySb.append(",");
-            }
-            querySb.append("?");
-        }
-        querySb.append(")");
-
-        query = querySb.toString();
-    }
-
-    protected void executeQuery(Connection connection) throws SQLException {
-
-        try (PreparedStatement statement = connection.prepareStatement(query)) {
-            log.debug("Executing query {}", query);
-            int i = 1;
-            for (EntityPropertyInfo property : addedProperties) {
-                Object value = tapSchemaEntity.getValue(property.getPropertyKey(), property.getPropertyType());
-                //log.debug("  [{}] {} ({})", i, value, property.getSqlType());
-                statement.setObject(i, value, property.getSqlType());
-                i++;
-            }
-            statement.executeUpdate();
-        }
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/SelectQueryBuilder.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/SelectQueryBuilder.java
deleted file mode 100644
index e17277dd3f970186d92c7f5892edc92c0bb2a4a4..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/SelectQueryBuilder.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
-import it.inaf.ia2.tsm.api.contract.TapSchema;
-import it.inaf.ia2.tsm.api.contract.TapSchemaEntity;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.List;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Prepares a {@code SELECT} SQL query for a given {@link TapSchemaEntity} and a
- * given {@link TapSchema}.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public abstract class SelectQueryBuilder {
-
-    private static final Logger log = LoggerFactory.getLogger(SelectQueryBuilder.class);
-
-    private final TapSchema tapSchema;
-    private final String query;
-    private final List<EntityPropertyInfo> addedProperties;
-
-    protected SelectQueryBuilder(DatabaseType dbType, TapSchema tapSchema, String tapSchemaTableName) {
-
-        this.tapSchema = tapSchema;
-
-        StringBuilder querySb = new StringBuilder("SELECT ");
-
-        addedProperties = new ArrayList<>();
-
-        boolean first = true;
-        for (EntityPropertyInfo propertyInfo : EntityPropertyInfo.getEntityPropertiesInfo(tapSchemaTableName)) {
-            if (propertyInfo.acceptVersion(tapSchema.getVersion())) {
-                if (!first) {
-                    querySb.append(", ");
-                }
-                querySb.append(propertyInfo.getPropertyKey());
-                addedProperties.add(propertyInfo);
-                first = false;
-            }
-        }
-
-        querySb.append(" FROM ");
-
-        querySb.append(TSMUtil.escapeName(tapSchema.getName(), dbType));
-        querySb.append(".");
-        querySb.append(TSMUtil.escapeName(tapSchemaTableName, dbType));
-
-        query = querySb.toString();
-    }
-
-    protected abstract TapSchemaEntity getEntity(ResultSet rs) throws SQLException;
-
-    protected void executeQuery(Connection connection) throws SQLException {
-
-        log.debug("Executing query {}", query);
-
-        try (Statement statement = connection.createStatement();
-                ResultSet rs = statement.executeQuery(query)) {
-
-            while (rs.next()) {
-
-                TapSchemaEntity entity = getEntity(rs);
-
-                if (entity != null) {
-                    for (EntityPropertyInfo property : addedProperties) {
-                        String key = property.getPropertyKey();
-                        Class type = property.getPropertyType();
-                        Object value = TSMUtil.getObject(rs, key, type);
-                        if (property.isUpdatable()) {
-                            entity.initProperty(key, value);
-                        } else {
-                            Object correctValue = entity.getValue(key, type);
-                            boolean changed = (correctValue == null && value != null) || (correctValue != null && !correctValue.equals(value));
-                            if (changed) {
-
-                                entity.amendProperty(key, correctValue);
-
-                                InconsistentValue inconsistentValue = new InconsistentValue(
-                                        TSMUtil.getNaturalLangueName(entity),
-                                        TSMUtil.getName(entity),
-                                        key,
-                                        value,
-                                        correctValue
-                                );
-
-                                tapSchema.getConsistencyChecks().addInconsistency(inconsistentValue);
-
-                                //throw new InconsistentTapSchemaException(debugInfo);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public String getQuery() {
-        return query;
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TableImpl.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TableImpl.java
deleted file mode 100644
index 629fb0de94db31ce927a993c931eb5ec974e2af3..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TableImpl.java
+++ /dev/null
@@ -1,339 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-import it.inaf.ia2.tsm.api.contract.Column;
-import it.inaf.ia2.tsm.api.contract.Key;
-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 java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.TreeMap;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The main implementation of {@link Table}.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public class TableImpl extends ChildEntityImpl<Schema> implements Table {
-    
-    private static final long serialVersionUID = 8265331530960896871L;
-    private static final Logger log = LoggerFactory.getLogger(TableImpl.class);
-    
-    private final Map<String, Column> columns;
-    private final List<Key> fromKeys;
-    private final List<Key> targetKeys;
-    
-    private String simpleName;
-    private Schema parentSchema;
-    
-    private TableImpl() {
-        // for serialization
-        super();
-        columns = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        fromKeys = new ArrayList<>();
-        targetKeys = new ArrayList<>();
-    }
-    
-    protected TableImpl(DBWrapper dbWrapper, TapSchema tapSchema, Schema schema, String tableSimpleName, String tableType) throws SQLException {
-        super(dbWrapper, tapSchema);
-        parentSchema = schema;
-        String schemaName = schema.getName();
-        this.simpleName = tableSimpleName;
-        columns = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        
-        addProperty(SCHEMA_NAME_KEY, new FixedEntityProperty<>(schemaName));
-        addProperty(TABLE_NAME_KEY, new FixedEntityProperty<>(schemaName + "." + tableSimpleName));
-        addProperty(TABLE_TYPE_KEY, new FixedEntityProperty<>(tableType));
-        
-        addProperty(UTYPE_KEY, new EditableProperty<String>());
-        addProperty(DESCRIPTION_KEY, new EditableProperty<String>());
-        addProperty(TABLE_INDEX, new EditableProperty<Integer>());
-        addProperty(TABLE_ID, new EditableProperty<Long>());
-        
-        fromKeys = new ArrayList<>();
-        targetKeys = new ArrayList<>();
-        
-        for (Column column : DaoColumn.loadAllTableColumns(dbWrapper, tapSchema, schemaName, (this))) {
-            columns.put(column.getName(), column);
-        }
-        
-        setStatus(Status.LOADED);
-    }
-
-    /**
-     * Only the table name.
-     */
-    @Override
-    public String getName() {
-        return simpleName;
-    }
-
-    /**
-     * {@code schema_name.table_name}.
-     */
-    @Override
-    public String getCompleteName() {
-        return getValue(TABLE_NAME_KEY, String.class);
-    }
-
-    /**
-     * {@inheritDoc }
-     */
-    @Override
-    public Column addChild(String columnName) {
-        String tableCompleteName = getCompleteName();
-        
-        log.debug("Adding column {} into table {}", columnName, tableCompleteName);
-        
-        if (!columns.containsKey(columnName)) {
-            //throw new IllegalArgumentException("Column " + columnName + " doesn't exists in table " + tableCompleteName);
-            tapSchema.getConsistencyChecks().addUnexistingColumn(getCompleteName(), columnName);
-            return null;
-        } else {
-            Column column = columns.get(columnName);
-            
-            switch (column.getStatus()) {
-                case LOADED:
-                    column.setStatus(Status.ADDED_NOT_PERSISTED);
-                    break;
-                case REMOVED_NOT_PERSISTED: // undo removal
-                    column.setStatus(Status.ADDED_NOT_PERSISTED);
-                    break;
-                case TO_REMOVE: // undo removal
-                    column.setStatus(Status.ADDED_PERSISTED);
-                    break;
-                default:
-                    throw new IllegalArgumentException("Cannot add column " + columnName + " in table " + tableCompleteName + ". Invalid column status: " + column.getStatus());
-            }
-            
-            ((TapSchemaImpl) tapSchema).checkKeys();
-            
-            return column;
-        }
-    }
-
-    /**
-     * {@inheritDoc }
-     */
-    @Override
-    public void removeChild(String columnName) {
-        String tableCompleteName = getCompleteName();
-        
-        log.debug("Removing column {} from table {}", columnName, tableCompleteName);
-        
-        if (!columns.containsKey(columnName)) {
-            throw new IllegalArgumentException("Column " + columnName + " doesn't exists in table " + tableCompleteName);
-        }
-        
-        Column column = columns.get(columnName);
-        
-        switch (column.getStatus()) {
-            case ADDED_NOT_PERSISTED:
-                column.setStatus(Status.REMOVED_NOT_PERSISTED);
-                break;
-            case ADDED_PERSISTED:
-                column.setStatus(Status.TO_REMOVE);
-                break;
-            default:
-                throw new IllegalArgumentException("Cannot remove column " + columnName + " in table " + tableCompleteName + ". Invalid column status: " + column.getStatus());
-        }
-        
-        ((TapSchemaImpl) tapSchema).checkKeys();
-    }
-
-    /**
-     * {@inheritDoc }
-     */
-    @Override
-    public Column getChild(String childName, Status... statuses) {
-        return TSMUtil.getChild(columns, childName, statuses);
-    }
-
-    /**
-     * {@inheritDoc }
-     */
-    @Override
-    public List<Column> getChildren(Status... statuses) {
-        return TSMUtil.getChildrenByStatus(columns.values(), statuses);
-    }
-
-    /**
-     * {@inheritDoc }
-     */
-    @Override
-    public List<String> getAddableChildrenNames() {
-        return TSMUtil.getAddableChildrenNames(columns);
-    }
-    
-    @Override
-    public List<Column> getAddedChildren() {
-        return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
-    }
-    
-    @Override
-    public List<Column> getAddedOrRemovedChildren() {
-        return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED, Status.TO_REMOVE, Status.REMOVED_NOT_PERSISTED);
-    }
-    
-    @Override
-    public String getTableType() {
-        return getValue(TABLE_TYPE_KEY, String.class);
-    }
-    
-    @Override
-    public Integer getTableIndex() {
-        return getValue(TABLE_INDEX, Integer.class);
-    }
-    
-    @Override
-    public void setTableIndex(Integer tableIndex) {
-        setValue(TABLE_INDEX, tableIndex);
-    }
-    
-    @Override
-    public Long getTableID() {
-        return getValue(TABLE_ID, Long.class);
-    }
-    
-    @Override
-    public void setTableID(Long tableID) {
-        setValue(TABLE_ID, tableID);
-    }
-    
-    @Override
-    public List<Key> getVisibleFromKeys() {
-        List<Key> ret = new ArrayList<>();
-        for (Key key : fromKeys) {
-            if (key.isVisible()) {
-                ret.add(key);
-            }
-        }
-        return Collections.unmodifiableList(ret);
-    }
-    
-    @Override
-    public List<Key> getAllFromKeys() {
-        return Collections.unmodifiableList(fromKeys);
-    }
-    
-    @Override
-    public List<Key> getVisibleTargetKeys() {
-        List<Key> ret = new ArrayList<>();
-        for (Key key : targetKeys) {
-            if (key.isVisible()) {
-                ret.add(key);
-            }
-        }
-        return Collections.unmodifiableList(ret);
-    }
-    
-    @Override
-    public List<Key> getAllTargetKeys() {
-        return Collections.unmodifiableList(targetKeys);
-    }
-    
-    @Override
-    public void addFromKey(Key key) {
-        if (!fromKeys.contains(key)) {
-            fromKeys.add(key);
-        }
-    }
-    
-    @Override
-    public void addTargetKey(Key key) {
-        if (!targetKeys.contains(key)) {
-            targetKeys.add(key);
-        }
-    }
-    
-    @Override
-    public int hashCode() {
-        int hash = 7;
-        hash = 29 * hash + Objects.hashCode(this.getCompleteName());
-        return hash;
-    }
-    
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final TableImpl other = (TableImpl) obj;
-        if (!Objects.equals(this.getCompleteName(), other.getCompleteName())) {
-            return false;
-        }
-        return true;
-    }
-    
-    @Override
-    public String getSchemaName() {
-        return getValue(SCHEMA_NAME_KEY, String.class);
-    }
-    
-    @Override
-    public String getUtype() {
-        return getValue(UTYPE_KEY, String.class);
-    }
-    
-    @Override
-    public void setUtype(String utype) {
-        setValue(UTYPE_KEY, utype);
-    }
-    
-    @Override
-    public String getDescription() {
-        return getValue(DESCRIPTION_KEY, String.class);
-    }
-    
-    @Override
-    public void setDescription(String description) {
-        setValue(DESCRIPTION_KEY, description);
-    }
-    
-    protected void afterUpdate() {
-        for (Column column : columns.values()) {
-            if (column.getStatus() == Status.ADDED_NOT_PERSISTED) {
-                column.setStatus(Status.ADDED_PERSISTED);
-            } else if (column.getStatus() != Status.ADDED_PERSISTED) {
-                column.setStatus(Status.LOADED);
-            }
-        }
-    }
-    
-    @Override
-    public Schema getParent() {
-        return parentSchema;
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TapSchemaEntityImpl.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TapSchemaEntityImpl.java
deleted file mode 100644
index 4696fee20de3d0dc22f03df5d8f18c72e04f5a3a..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TapSchemaEntityImpl.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-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.io.Serializable;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The main implementation of {@link TapSchemaEntity}.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public abstract class TapSchemaEntityImpl implements TapSchemaEntity, Serializable {
-    
-    private static final long serialVersionUID = 5515596028279668709L;
-    private static final Logger log = LoggerFactory.getLogger(TapSchemaEntityImpl.class);
-    
-    private final Map<String, EntityProperty> properties;
-    private final String tapSchemaEntityTable;
-    protected DBWrapper dbWrapper;
-    protected TapSchema tapSchema;
-    
-    protected TapSchemaEntityImpl() {
-        // for serialization
-        properties = new HashMap<>();
-        tapSchemaEntityTable = TSMUtil.getTapSchemaTableNameFromEntity((this));
-    }
-    
-    public TapSchemaEntityImpl(DBWrapper dbWrapper, TapSchema tapSchema) {
-        this();
-        this.dbWrapper = dbWrapper;
-        this.tapSchema = tapSchema;
-    }
-    
-    protected void addProperty(String key, EntityProperty property) {
-        if (EntityPropertyInfo.getEntityPropertyInfo(tapSchemaEntityTable, key).acceptVersion(tapSchema.getVersion())) {
-            properties.put(key, property);
-        }
-    }
-    
-    protected DBWrapper getDBWrapper() {
-        return dbWrapper;
-    }
-    
-    @Override
-    public <T> void initProperty(String key, T value) {
-        properties.get(key).init(value);
-    }
-    
-    protected TapSchemaVersion getVersion() {
-        return tapSchema.getVersion();
-    }
-    
-    @Override
-    public boolean isChanged() {
-        for (EntityProperty property : properties.values()) {
-            if (property.isChanged()) {
-                return true;
-            }
-        }
-        return false;
-    }
-    
-    @Override
-    public <T> T getValue(String key, Class<T> type) {
-        if (!EntityPropertyInfo.getEntityPropertyInfo(tapSchemaEntityTable, key).acceptVersion(tapSchema.getVersion())) {
-            throw TSMUtil.getUnsupportedOperationException(getVersion(), key + " property");
-        }
-        return properties.get(key).getValue(type);
-    }
-    
-    public <T> void setValue(String key, T value) {
-        EntityProperty property = properties.get(key);
-        if (property instanceof EditableProperty) {
-            if (!EntityPropertyInfo.getEntityPropertyInfo(tapSchemaEntityTable, key).acceptVersion(tapSchema.getVersion())) {
-                throw TSMUtil.getUnsupportedOperationException(getVersion(), key + " property");
-            }
-            ((EditableProperty) property).setValue(value);
-        } else {
-            throw new IllegalArgumentException("Property " + key + " isn't editable");
-        }
-    }
-    
-    @Override
-    public <T> T getOriginalValue(String key, Class<T> type) {
-        EntityProperty property = properties.get(key);
-        if (property instanceof EditableProperty) {
-            return ((EditableProperty<T>) property).getOriginalValue(type);
-        }
-        throw new IllegalArgumentException("Property " + key + " hasn't original value");
-    }
-    
-    @Override
-    public boolean isChanged(String key) {
-        return properties.get(key).isChanged();
-    }
-    
-    @Override
-    public List<String> getPropertiesKeys() {
-        return new ArrayList<>(properties.keySet());
-    }
-    
-    @Override
-    public void save() {
-        for (EntityProperty p : properties.values()) {
-            if (p instanceof EditableProperty) {
-                EditableProperty property = (EditableProperty) p;
-                property.save();
-            } else {
-                FixedEntityProperty property = (FixedEntityProperty) p;
-                property.setChanged(false);
-            }
-        }
-    }
-    
-    @Override
-    public <T> void amendProperty(String key, T value) {
-        FixedEntityProperty prop = (FixedEntityProperty) properties.get(key);
-        prop.init(value);
-        prop.setChanged(true);
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TapSchemaImpl.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TapSchemaImpl.java
deleted file mode 100644
index 5823d61322db9c585bb0f5e61dae4395c5a666b9..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TapSchemaImpl.java
+++ /dev/null
@@ -1,425 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-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.TapSchemaVersion;
-import java.io.Serializable;
-import java.sql.SQLException;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The main implementation of {@link TapSchema}.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public class TapSchemaImpl implements TapSchema, Serializable {
-
-    private static final long serialVersionUID = 1678083091602571256L;
-    private static final Logger log = LoggerFactory.getLogger(TapSchemaImpl.class);
-
-    private final Map<String, Schema> schemas;
-    private final Set<Key> allKeys;
-    private final ConsistencyChecks consistencyChecks;
-
-    private TapSchemaVersion version;
-    private DBWrapper dbWrapper;
-    private String tapSchemaName;
-    private boolean exists;
-
-    private TapSchemaImpl() {
-        // for serialization
-        schemas = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        allKeys = new HashSet<>();
-        consistencyChecks = new ConsistencyChecks();
-    }
-
-    protected TapSchemaImpl(TapSchemaVersion version, DBWrapper dbWrapper, String tapSchemaName, boolean exists) throws SQLException {
-        this.version = version;
-        this.dbWrapper = dbWrapper;
-        this.tapSchemaName = tapSchemaName;
-        this.exists = exists;
-
-        schemas = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-        allKeys = new HashSet<>();
-        consistencyChecks = new ConsistencyChecks();
-
-        // Initializing schemas map
-        for (String schemaName : DaoSchema.getAllSchemasNames(dbWrapper.getSourceDataSource(), dbWrapper.getSourceDatabaseType())) {
-            schemas.put(schemaName, null);
-        }
-        schemas.put(tapSchemaName, null); // the TAP_SCHEMA contains itself
-
-        if (exists) {
-            DaoSchema.fillSavedSchemas(dbWrapper, (this));
-            DaoTable.fillSavedTables(dbWrapper, (this));
-            DaoColumn.fillSavedColumns(dbWrapper, (this));
-            DaoKey.fillSavedKeys(dbWrapper, (this));
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getName() {
-        return tapSchemaName;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public TapSchemaVersion getVersion() {
-        return version;
-    }
-
-    private void loadSchemaKeys(String schemaName) throws SQLException {
-        for (Key key : DaoKey.getSchemaKeys(dbWrapper, this, schemaName)) {
-            if (!allKeys.contains(key)) {
-                allKeys.add(key);
-            }
-        }
-    }
-
-    protected Set<Key> getAllKeys() {
-        return allKeys;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Schema addChild(String schemaName) throws SQLException {
-        log.debug("Adding schema {}", schemaName);
-
-        Schema schema;
-        
-        if (!schemas.containsKey(schemaName)) {
-            
-            consistencyChecks.addUnexistingSchema(schemaName);
-            schema = null;
-        } else {
-
-            schema = schemas.get(schemaName);
-
-            if (schema == null) {
-                schema = new SchemaImpl(dbWrapper, this, schemaName);
-                schema.setStatus(Status.ADDED_NOT_PERSISTED);
-                schemas.put(schemaName, schema);
-                loadSchemaKeys(schemaName);
-            } else {
-                switch (schema.getStatus()) {
-                    case TO_REMOVE:
-                        schema.setStatus(Status.ADDED_PERSISTED);
-                        break;
-                    case REMOVED_NOT_PERSISTED:
-                        schema.setStatus(Status.ADDED_NOT_PERSISTED);
-                        break;
-                    default:
-                        throw new IllegalArgumentException("Cannot add the schema " + schemaName + ". Invalid status. Schema status is " + schema.getStatus());
-                }
-            }
-        }
-
-        checkKeys();
-
-        return schema;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void removeChild(String schemaName) {
-        log.debug("Removing schema {}", schemaName);
-
-        if (!schemas.containsKey(schemaName)) {
-            throw new IllegalArgumentException("The database doesn't contains a schema named " + schemaName);
-        }
-
-        Schema schema = schemas.get(schemaName);
-        if (schema == null || schema.getStatus() == Status.LOADED) {
-            throw new IllegalArgumentException("Cannot remove the schema " + schemaName + ". It has never been added.");
-        }
-
-        if (schema.getStatus() == Status.ADDED_NOT_PERSISTED) {
-            schema.setStatus(Status.REMOVED_NOT_PERSISTED);
-        } else if (schema.getStatus() == Status.ADDED_PERSISTED) {
-            schema.setStatus(Status.TO_REMOVE);
-        }
-
-        checkKeys();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Schema getChild(String childName, Status... statuses) {
-        return TSMUtil.getChild(schemas, childName, statuses);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public List<Schema> getChildren(Status... statuses) {
-        return TSMUtil.getChildrenByStatus(schemas.values(), statuses);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public List<String> getAddableChildrenNames() {
-        return TSMUtil.getAddableChildrenNames(schemas);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public List<Schema> getAddedChildren() {
-        return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public List<Schema> getAddedOrRemovedChildren() {
-        return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED, Status.TO_REMOVE, Status.REMOVED_NOT_PERSISTED);
-    }
-
-    /**
-     * This method has to be used after TAP_SCHEMA modifications are committed
-     * to the database, in order to remove from the memory the schemas with
-     * status {@code Status.TO_REMOVE} or {@code Status.REMOVED_NOT_PERSISTED}.
-     */
-    protected void cleanSchema(String schemaName) {
-        if (!schemas.containsKey(schemaName)) {
-            throw new IllegalArgumentException("The TAP_SCHEMA doesn't contain the schema " + schemaName);
-        }
-        schemas.put(schemaName, null);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void save() throws SQLException {
-
-        Dao.save(dbWrapper, this);
-
-        if (!exists) {
-            // Adding TAP_SCHEMA into TAP_SCHEMA
-            Schema tapSchemaSchema = addChild(tapSchemaName);
-            for (String tableName : tapSchemaSchema.getAddableChildrenNames()) {
-                Table table = tapSchemaSchema.addChild(tableName);
-                for (String columnName : table.getAddableChildrenNames()) {
-                    table.addChild(columnName);
-                }
-            }
-            log.debug(this.toString());
-            TSMUtil.putInfoIntoTapSchemaSchema(tapSchemaSchema);
-
-            exists = true; // important!
-
-            Dao.save(dbWrapper, this); // save again
-        }
-
-        exists = true;
-
-        consistencyChecks.getInconsistencies().clear();
-    }
-
-    /**
-     * Retrieve the maximum key id from all the schemas that are added into the
-     * TAP_SCHEMA.
-     *
-     * @return the maximum key, if it exists, zero otherwise.
-     */
-    public int getMaxKeyId() {
-        int maxKeyId = 0;
-        for (Key key : allKeys) {
-            if (key.getId() != null) {
-                int keyId = Integer.parseInt(key.getId());
-                if (keyId > maxKeyId) {
-                    maxKeyId = keyId;
-                }
-            }
-        }
-        return maxKeyId;
-    }
-
-    /**
-     * Set keys visibility based on other entities visibility (a key is visible
-     * if all schemas, tables and columns involved have
-     * {@link Status} {@code ADDED_PERSISTED} or {@code ADDED_NOT_PERSISTED}).
-     */
-    protected void checkKeys() {
-
-        int currentKey = getMaxKeyId() + 1;
-
-        for (Key key : allKeys) {
-
-            ((KeyImpl) key).setVisible(false);
-
-            Schema fromSchema = getChild(key.getFromSchemaName(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
-            Schema targetSchema = getChild(key.getTargetSchemaName(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
-            if (fromSchema != null && targetSchema != null) {
-
-                Table fromTable = fromSchema.getChild(key.getFromTableSimpleName(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
-                Table targetTable = targetSchema.getChild(key.getTargetTableSimpleName(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
-
-                if (fromTable != null && targetTable != null) {
-
-                    boolean allColumnsVisible = true;
-
-                    for (KeyColumn keyColumn : key.getKeyColumns()) {
-
-                        Column fromColumn = fromTable.getChild(keyColumn.getFromColumn(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
-                        Column targetColumn = targetTable.getChild(keyColumn.getTargetColumn(), Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED);
-
-                        if (fromColumn == null || targetColumn == null) {
-                            allColumnsVisible = false;
-                            break;
-                        }
-                    }
-
-                    if (allColumnsVisible) {
-                        ((KeyImpl) key).setVisible(true);
-                        if (key.getId() == null) {
-                            key.setId(currentKey + "");
-                            currentKey++;
-                        }
-                    }
-                }
-            }
-        }
-//        for (Key key : allKeys) {
-//            log.debug("{} [{}]", key, key.getStatus());
-//        }
-    }
-
-    public void addFictitiousKey(Table fromTable, String[] fromColumns, Table targetTable, String[] targetColumns) {
-        KeyImpl key = new KeyImpl(dbWrapper, this, fromTable.getCompleteName(), targetTable.getCompleteName());
-        key.setId((getMaxKeyId() + 1) + "");
-
-        for (int i = 0; i < fromColumns.length; i++) {
-            key.addKeyColumn(fromColumns[i], targetColumns[i]);
-        }
-
-        fromTable.addFromKey(key);
-        targetTable.addTargetKey(key);
-
-        allKeys.add(key);
-        checkKeys();
-    }
-
-    /**
-     * Print all TAP_SCHEMA tree (useful for debugging).
-     */
-    @Override
-    public String toString() {
-
-        StringBuilder sb = new StringBuilder("\n");
-
-        sb.append(String.format(">> TAP_SCHEMA %s <<\n", tapSchemaName));
-
-        for (Schema schema : getChildren()) {
-            sb.append("--");
-            sb.append(schema.getName());
-            sb.append(String.format(" [%s]", schema.getStatus()));
-            sb.append("\n");
-            List<Table> tables = schema.getChildren();
-            for (int i = 0; i < tables.size(); i++) {
-                Table table = tables.get(i);
-                sb.append("   |--");
-                sb.append(table.getName());
-                sb.append(String.format(" [%s]", table.getStatus()));
-                sb.append("\n");
-
-                String padder = i < tables.size() - 1 ? "   |   " : "       ";
-
-                for (Column column : table.getChildren()) {
-                    sb.append(padder);
-                    sb.append("|--");
-                    sb.append(column.getName());
-                    sb.append(String.format(" [%s]", column.getStatus()));
-                    sb.append("\n");
-                }
-
-                if (table.getAllFromKeys().size() > 0) {
-                    sb.append(padder);
-                    sb.append("** From keys **\n");
-                    for (Key fromKey : table.getAllFromKeys()) {
-                        sb.append(padder);
-                        sb.append("* ");
-                        sb.append(fromKey.toString());
-                        sb.append(String.format(" [visible=%s]", fromKey.isVisible()));
-                        sb.append("\n");
-                    }
-                }
-                if (table.getAllTargetKeys().size() > 0) {
-                    sb.append(padder);
-                    sb.append("** Target keys **\n");
-                    for (Key targetKey : table.getAllTargetKeys()) {
-                        sb.append(padder);
-                        sb.append("* ");
-                        sb.append(targetKey.toString());
-                        sb.append(String.format(" [visible=%s]", targetKey.isVisible()));
-                        sb.append("\n");
-                    }
-                }
-
-                sb.append("\n");
-            }
-        }
-
-        return sb.toString();
-    }
-
-    @Override
-    public boolean exists() {
-        return exists;
-    }
-
-    @Override
-    public ConsistencyChecks getConsistencyChecks() {
-        return consistencyChecks;
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/UpdateQueryBuilder.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/UpdateQueryBuilder.java
deleted file mode 100644
index 62d2cf0cf1e17f872a25d2f8992fd0790f046946..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/UpdateQueryBuilder.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api;
-
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
-import it.inaf.ia2.tsm.api.contract.TapSchema;
-import it.inaf.ia2.tsm.api.contract.TapSchemaEntity;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Prepares an {@code UPDATE } SQL query for a given {@link TapSchemaEntity} and
- * a given {@link TapSchema}.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public class UpdateQueryBuilder {
-
-    private static final Logger log = LoggerFactory.getLogger(UpdateQueryBuilder.class);
-
-    private final String query;
-    private final List<EntityPropertyInfo> addedProperties;
-    private final TapSchemaEntity tapSchemaEntity;
-
-    protected UpdateQueryBuilder(DatabaseType dbType, TapSchema tapSchema, TapSchemaEntity tapSchemaEntity, String tapSchemaTableName, String whereCondition) {
-
-        StringBuilder querySb = new StringBuilder("UPDATE ");
-        querySb.append(TSMUtil.escapeName(tapSchema.getName(), dbType));
-        querySb.append(".");
-        querySb.append(TSMUtil.escapeName(tapSchemaTableName, dbType));
-        querySb.append("\nSET");
-
-        addedProperties = new ArrayList<>();
-        this.tapSchemaEntity = tapSchemaEntity;
-
-        boolean first = true;
-        for (EntityPropertyInfo propertyInfo : EntityPropertyInfo.getEntityPropertiesInfo(tapSchemaTableName)) {
-            if (propertyInfo.acceptVersion(tapSchema.getVersion())
-                    && tapSchemaEntity.isChanged(propertyInfo.getPropertyKey())) {
-
-                if (!first) {
-                    querySb.append(",");
-                }
-                querySb.append(" ");
-                querySb.append(propertyInfo.getPropertyKey());
-                querySb.append(" = ?");
-                addedProperties.add(propertyInfo);
-                first = false;
-            }
-        }
-
-        querySb.append("\nWHERE ");
-        querySb.append(whereCondition);
-
-        query = querySb.toString();
-    }
-
-    public String getQuery() {
-        return query;
-    }
-
-    protected int addStatementValues(PreparedStatement statement) throws SQLException {
-        int i = 1;
-        for (EntityPropertyInfo property : addedProperties) {
-            Object value = tapSchemaEntity.getValue(property.getPropertyKey(), property.getPropertyType());
-            statement.setObject(i, value, property.getSqlType());
-            log.debug("\t[{}] {}", property.getPropertyKey(), value);
-            i++;
-        }
-        return i;
-    }
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Column.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Column.java
deleted file mode 100644
index 00b8441519684c84d492c01db5a084a111a10800..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Column.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api.contract;
-
-/**
- * {@link TapSchemaEntity} that represents the table {@code TAP_SCHEMA.columns}.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public interface Column extends ChildEntity<Table> {
-
-    final static String TABLE_NAME_KEY = "table_name";
-    final static String COLUMN_NAME_KEY = "column_name";
-    final static String DATATYPE_KEY = "datatype";
-    final static String SIZE_KEY = "size";
-    final static String ARRAYSIZE_KEY = "arraysize";
-    final static String DESCRIPTION_KEY = "description";
-    final static String UTYPE_KEY = "utype";
-    final static String UNIT_KEY = "unit";
-    final static String UCD_KEY = "ucd";
-    final static String INDEXED_KEY = "indexed";
-    final static String PRINCIPAL_KEY = "principal";
-    final static String STD_KEY = "std";
-    final static String COLUMN_INDEX_KEY = "column_index";
-    final static String ID_KEY = "id"; // IA2?
-    final static String COLUMN_ID_KEY = "columnID";
-
-    /**
-     * The complete table name: {@code &lt;schema-name&gt;.&lt;table-name&gt;}.
-     */
-    String getTableCompleteName();
-
-    /**
-     * Indicates if the column is a primary key (or a part of a primary key).
-     */
-    boolean isPrimaryKey();
-
-    /**
-     * Retrieve (if it exists) the key of which this column is a "from column".
-     */
-    Key getForeignKey();
-
-    /**
-     * The value in the {@code datatype} column.
-     */
-    String getDatatype();
-
-    Integer getArraySize();
-
-    /**
-     * The value in the {@code size} column.
-     */
-    Integer getSize();
-
-    /**
-     * The value in the {@code description} column.
-     */
-    String getDescription();
-
-    void setDescription(String description);
-
-    /**
-     * The value in the {@code utype} column.
-     */
-    String getUtype();
-
-    void setUtype(String utype);
-
-    /**
-     * The value in the {@code unit} column.
-     */
-    String getUnit();
-
-    void setUnit(String unit);
-
-    /**
-     * The value in the {@code ucd} column: represents the Unified Content
-     * Descriptor of the column.
-     */
-    String getUCD();
-
-    void setUCD(String ucd);
-
-    /**
-     * The value in the {@code indexed} column: indicates that the column is
-     * indexed.<br> It is an integer but should be treated as a boolean value.
-     */
-    boolean getIndexed();
-
-    /**
-     * The value in the {@code principal} column: indicates that the column is
-     * considered a core part the content.<br> It is an integer but should be
-     * treated as a boolean value.
-     */
-    boolean getPrincipal();
-
-    void setPrincipal(boolean principal);
-
-    /**
-     * The value in the {@code std} column: indicates that the column is defined
-     * by some standard.<br> It is an integer but should be treated as a boolean
-     * value.
-     */
-    boolean getStd();
-
-    void setStd(boolean std);
-
-    Integer getColumnIndex();
-
-    void setColumnIndex(Integer columnIndex);
-
-    /**
-     * The value in the {@code columnID} column: it represents [TODO]...
-     */
-    Long getColumnID();
-
-    void setColumnID(Long columnID);
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Key.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Key.java
deleted file mode 100644
index 40965887fb8367645806e31448803493edaf62b0..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Key.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api.contract;
-
-import java.util.List;
-
-/**
- * {@link TapSchemaEntity} that represents the table {@code TAP_SCHEMA.keys}.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public interface Key extends TapSchemaEntity {
-
-    static final String ID_KEY = "key_id";
-    static final String FROM_TABLE_KEY = "from_table";
-    static final String TARGET_TABLE_KEY = "target_table";
-    static final String DESCRIPTION_KEY = "description";
-    static final String UTYPE_KEY = "utype";
-    static final String KEY_ID_KEY = "keyID";
-
-    /**
-     * The value in the {@code key_id} column: represents the ID of the key (The
-     * TAP standard define the {@code key_id} as a {@code VARCHAR}, but in our
-     * implementation we assume it represents a numeric value).
-     */
-    String getId();
-
-    void setId(String keyId);
-
-    /**
-     * List of the {@code KeyColumnEntity} owned by this {@code KeyEntity}.
-     */
-    List<KeyColumn> getKeyColumns();
-
-    String getFromSchemaName();
-
-    String getFromTableSimpleName();
-
-    /**
-     * The value in the {@code from_table} column: it is the complete name of
-     * the table, as defined in the TAP standard: so it is
-     * {@code &lt;schema-name&gt;.&lt;table-name&gt;}.
-     */
-    String getFromTableCompleteName();
-
-    String getTargetSchemaName();
-
-    String getTargetTableSimpleName();
-
-    /**
-     * The value in the {@code target_table} column: it is the complete name of
-     * the table, as defined in the TAP standard: so it is
-     * {@code &lt;schema-name&gt;.&lt;table-name&gt;}.
-     */
-    String getTargetTableCompleteName();
-
-    /**
-     * The value in the {@code utype} column.
-     */
-    String getUtype();
-
-    void setUtype(String utype);
-
-    /**
-     * The value in the {@code description} column.
-     */
-    String getDescription();
-
-    void setDescription(String description);
-
-    /**
-     * The value in the {@code keyID} column: it represents [TODO]...
-     */
-    Long getKeyID();
-
-    void setKeyID(Long keyID);
-
-    /**
-     * A key is visible if all schemas, tables and columns involved with it have
-     * {@link Status} {@code ADDED_PERSISTED} or {@code ADDED_NOT_PERSISTED}.
-     */
-    boolean isVisible();
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/KeyColumn.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/KeyColumn.java
deleted file mode 100644
index c6f9c3870f3d134b72bcbed0e3eb2b21424e55bb..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/KeyColumn.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api.contract;
-
-/**
- * {@link TapSchemaEntity} that represents the table
- * {@code TAP_SCHEMA.key_columns}.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public interface KeyColumn extends TapSchemaEntity {
-
-    static final String KEY_ID_KEY = "key_id";
-    static final String FROM_COLUMN_KEY = "from_column";
-    static final String TARGET_COLUMN_KEY = "target_column";
-    static final String KEY_COLUMN_ID_KEY = "key_columnID";
-
-    Key getParent();
-    
-    /**
-     * The value in the {@code key_id} column.
-     */
-    String getKeyId();
-
-    void setKeyId(String keyId);
-
-    /**
-     * The value in the {@code from_column} column.
-     */
-    String getFromColumn();
-
-    /**
-     * The value in the {@code target_column} column.
-     */
-    String getTargetColumn();
-
-    /**
-     * The value in the {@code key_columnID} column: it represents [TODO]...
-     */
-    Long getKeyColumnID();
-
-    void setKeyColumnID(Long keyColumnID);
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Schema.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Schema.java
deleted file mode 100644
index af7c875d4da67b3875f52402c6cd500532f0ba59..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Schema.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api.contract;
-
-/**
- * {@link TapSchemaEntity} that represents the table {@code TAP_SCHEMA.schemas}.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public interface Schema extends EntitiesContainer<Table>, ChildEntity<TapSchema> {
-
-    final static String SCHEMA_NAME_KEY = "schema_name";
-    final static String UTYPE_KEY = "utype";
-    final static String DESCRIPTION_KEY = "description";
-    final static String SCHEMA_ID = "schemaID";
-
-    /**
-     * The value in the {@code utype} column.
-     */
-    String getUtype();
-
-    void setUtype(String utype);
-
-    /**
-     * The value in the {@code description} column.
-     */
-    String getDescription();
-
-    void setDescription(String description);
-
-    /**
-     * The value in the {@code schemaID} column: it represents [TODO]...
-     */
-    Long getSchemaID();
-
-    void setSchemaID(Long schemaID);
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Table.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Table.java
deleted file mode 100644
index 1d8abf66a04b18941f9e1466a8cc9c2100d7e0d5..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/Table.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api.contract;
-
-import java.util.List;
-
-/**
- * {@link TapSchemaEntity} that represents the table {@code TAP_SCHEMA.tables}.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public interface Table extends EntitiesContainer<Column>, ChildEntity<Schema> {
-
-    final static String SCHEMA_NAME_KEY = "schema_name";
-    final static String TABLE_NAME_KEY = "table_name";
-    final static String TABLE_TYPE_KEY = "table_type";
-    final static String UTYPE_KEY = "utype";
-    final static String DESCRIPTION_KEY = "description";
-    final static String TABLE_INDEX = "table_index";
-    final static String TABLE_ID = "tableID";
-
-    /**
-     * The value in the {@code schema_name} column.
-     */
-    String getSchemaName();
-
-    /**
-     * The value in the {@code table_name} column: it represents the complete
-     * table name: {@code schema_name.table_name}.
-     */
-    String getCompleteName();
-
-    /**
-     * The value in the {@code table_type} column: it could be {@code table} or
-     * {@code view}.
-     */
-    String getTableType();
-
-    Integer getTableIndex();
-
-    void setTableIndex(Integer tableIndex);
-
-    /**
-     * The value in the {@code tableID} column: it represents [TODO]...
-     */
-    Long getTableID();
-
-    void setTableID(Long tableID);
-
-    /**
-     * Retrieve the list of all the visible keys whose
-     * {@link Key#getFromTableCompleteName()} method returns the complete name
-     * of this table.
-     */
-    List<Key> getVisibleFromKeys();
-
-    /**
-     * Retrieve the list of all the keys (both visible and not visible) whose
-     * {@link Key#getFromTableCompleteName()} method returns the complete name
-     * of this table.
-     */
-    List<Key> getAllFromKeys();
-
-    /**
-     * Retrieve the list of all the visible keys whose
-     * {@link Key#getTargetTableCompleteName()} method returns the complete name
-     * of this table.
-     */
-    List<Key> getVisibleTargetKeys();
-
-    /**
-     * Retrieve the list of all the keys (both visible and not visible) whose
-     * {@link Key#getTargetTableCompleteName()} method returns the complete name
-     * of this table.
-     */
-    List<Key> getAllTargetKeys();
-
-    void addFromKey(Key key);
-
-    void addTargetKey(Key key);
-
-    /**
-     * The value in the {@code utype} column.
-     */
-    String getUtype();
-
-    void setUtype(String utype);
-
-    /**
-     * The value in the {@code description} column.
-     */
-    String getDescription();
-
-    void setDescription(String description);
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/TapSchema.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/TapSchema.java
deleted file mode 100644
index 2b658803264bda3d6785f3edd87fc6a6782f8294..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/TapSchema.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api.contract;
-
-import it.inaf.ia2.tsm.api.ConsistencyChecks;
-import java.sql.SQLException;
-
-/**
- * Represents a TAP_SCHEMA.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public interface TapSchema extends EntitiesContainer<Schema> {
-
-    public static final String TABLES_TABLE = "tables";
-    public static final String SCHEMAS_TABLE = "schemas";
-    public static final String COLUMNS_TABLE = "columns";
-    public static final String KEYS_TABLE = "keys";
-    public static final String KEY_COLUMNS_TABLE = "key_columns";
-
-    ConsistencyChecks getConsistencyChecks();
-
-    /**
-     * The name of the TAP_SCHEMA schema.
-     */
-    String getName();
-
-    /**
-     * The version selected for this TAP_SCHEMA.
-     */
-    TapSchemaVersion getVersion();
-
-    /**
-     * Save or update the TAP_SCHEMA changes into the database.
-     */
-    void save() throws SQLException;
-
-    /**
-     * Define if the TAP_SCHEMA schema was already written into the database.
-     */
-    boolean exists();
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/TapSchemaEntity.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/TapSchemaEntity.java
deleted file mode 100644
index 35895847f1eed32f698dff589c10bdc12e5d8cb2..0000000000000000000000000000000000000000
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/TapSchemaEntity.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/* 
- * _____________________________________________________________________________
- * 
- * 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.
- */
-package it.inaf.ia2.tsm.api.contract;
-
-import java.util.List;
-
-/**
- * Represents an object that is mapped on a table of the TAP_SCHEMA.
- *
- * A TapSchemaEntity has some properties that correspond to columns of the table
- * represented by the TapSchemaEntity.<br>
- * Property value can be changed but the original value has to be maintained
- * until the {@link #save()} method is called.
- *
- * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
- */
-public interface TapSchemaEntity {
-
-    /**
-     * Initializes the value of a property (store the original value).
-     */
-    <T> void initProperty(String key, T value);
-
-    /**
-     * Set the correct value for a fixed property that has inconsistent value in
-     * the TAP_SCHEMA.
-     */
-    <T> void amendProperty(String key, T value);
-
-    /**
-     * Returns true if one or more property values is changed (the current value
-     * is different from the original value).
-     */
-    boolean isChanged();
-
-    /**
-     * Returns true the value of property which key is passed as parameter is
-     * changed (the current value is different from the original value).
-     */
-    boolean isChanged(String key);
-
-    /**
-     * Retrieve the current value of the property (the last value set).
-     */
-    <T> T getValue(String key, Class<T> type);
-
-    /**
-     * Retrieve the original value of the property.
-     *
-     * @param key the name of the property (the name of the table column).
-     * @param type the class of the property value.
-     * @return
-     */
-    <T> T getOriginalValue(String key, Class<T> type);
-
-    /**
-     * Retrieve a list of all properties names (the names of the table columns).
-     */
-    List<String> getPropertiesKeys();
-
-    /**
-     * Marks the TapSchemaEntity as saved (all original values are set equals to
-     * current values).
-     */
-    void save();
-}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/EntityProperty.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/ADQL.java
similarity index 57%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/EntityProperty.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/ADQL.java
index 29afe97c5caef614aa1727cdd9924d2b0695e5e9..830e6f7d2f84523a6818532f24467d07795b7466 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/EntityProperty.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/ADQL.java
@@ -1,11 +1,11 @@
-/* 
+/*
  * _____________________________________________________________________________
  * 
  * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
  * Trieste INAF - IA2 Italian Center for Astronomical Archives
  * _____________________________________________________________________________
  * 
- * Copyright (C) 2016 Istituto Nazionale di Astrofisica
+ * Copyright (C) 2017 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
@@ -20,25 +20,26 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm.datalayer;
 
 /**
- * Store the value of an entity property (that corresponds to a column of the
- * mapped table).
- *
+ * ADQL data type constants.
+ * 
  * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
  */
-public interface EntityProperty {
-
-    /**
-     * Retrieve the current value.
-     */
-    <T> T getValue(Class<T> type);
+public class ADQL {
 
-    /**
-     * Initialize the value.
-     */
-    <T> void init(T initialValue);
+    private static final String ADQL_PREFIX = "adql:";
     
-    boolean isChanged();
+    public static final String INTEGER = ADQL_PREFIX + "INTEGER";
+    public static final String SMALLINT = ADQL_PREFIX + "SMALLINT";
+    public static final String BIGINT = ADQL_PREFIX + "BIGINT";
+    public static final String REAL = ADQL_PREFIX + "REAL";
+    public static final String CHAR = ADQL_PREFIX + "CHAR";
+    public static final String VARCHAR = ADQL_PREFIX + "VARCHAR";
+    public static final String TIMESTAMP = ADQL_PREFIX + "TIMESTAMP";
+
+    public static String getDataType(String dataType) {
+        return ADQL_PREFIX + dataType.toUpperCase();
+    }
 }
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/Credentials.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/Credentials.java
similarity index 98%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/Credentials.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/Credentials.java
index c3ad13438e3ad3bfafb188233c927820bf4383a8..7f8e342c4f33c37765fa423e5c07729e6ab65274 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/Credentials.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/Credentials.java
@@ -20,9 +20,9 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm.datalayer;
 
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
 import java.io.Serializable;
 import javax.xml.bind.annotation.XmlAttribute;
 import org.slf4j.Logger;
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBroker.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBroker.java
new file mode 100644
index 0000000000000000000000000000000000000000..48acab3be4aaa4f52775561e1de48c114ee7063e
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBroker.java
@@ -0,0 +1,65 @@
+/*
+ * _____________________________________________________________________________
+ * 
+ * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
+ * Trieste INAF - IA2 Italian Center for Astronomical Archives
+ * _____________________________________________________________________________
+ * 
+ * Copyright (C) 2017 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.
+ */
+package it.inaf.ia2.tsm.datalayer;
+
+import it.inaf.ia2.tsm.KeyMetadata;
+import it.inaf.ia2.tsm.TapSchema;
+import it.inaf.ia2.tsm.TapSchemaEntity;
+import it.inaf.ia2.tsm.xmlmodel.TableModel;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public interface DBBroker {
+
+    Map<String, Map<String, Object>> getColumnsInfo(String schemaName, String tableName) throws SQLException;
+
+    List<String> getAllSchemaNames() throws SQLException;
+
+    List<String> getAllTAPSchemaNames(List<String> allSchemas) throws SQLException;
+
+    List<String> getAllTablesNames(String schemaName) throws SQLException;
+
+    Map<String, String> getAllTableTypes(String schemaName) throws SQLException;
+
+    List<String> getAllColumnsNames(String schemaName, String tableName) throws SQLException;
+
+    Map<String, Map<String, Object>> getAllColumnsMetadata(String schemaName, String tableSimpleName) throws SQLException;
+
+    List<KeyMetadata> getKeysMetadata(String schemaName) throws SQLException;
+
+    List<Map<String, Object>> getSavedItems(String tapSchemaName, TableModel tableModel, String whereCondition, Object[] whereParams) throws SQLException;
+
+    List<Map<String, Object>> getSavedItems(String tapSchemaName, TableModel tableModel) throws SQLException;
+
+    void insertItem(String tapSchemaName, TapSchemaEntity entity, Connection conn) throws SQLException;
+
+    void updateItem(String tapSchemaName, TapSchemaEntity entity, Connection conn, String whereCondition, Object... whereParams) throws SQLException;
+
+    void save(TapSchema tapSchema) throws SQLException;
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/TapSchemaVersion.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBrokerFactory.java
similarity index 65%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/TapSchemaVersion.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBrokerFactory.java
index c91e790b202919cc39865246e41dbfc2e0d81560..7213c5632bc38be70cf680c92a1a3514bfd1805e 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/TapSchemaVersion.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBrokerFactory.java
@@ -1,11 +1,11 @@
-/* 
+/*
  * _____________________________________________________________________________
  * 
  * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
  * Trieste INAF - IA2 Italian Center for Astronomical Archives
  * _____________________________________________________________________________
  * 
- * Copyright (C) 2016 Istituto Nazionale di Astrofisica
+ * Copyright (C) 2017 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
@@ -20,24 +20,22 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api.contract;
+package it.inaf.ia2.tsm.datalayer;
+
+import it.inaf.ia2.tsm.datalayer.mysql.MySQLDBBroker;
 
 /**
- * Version of a TAP_SCHEMA schema. TAP_SCHEMA schemas with different versions
- * can use different columns in the database.
  *
  * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
  */
-public enum TapSchemaVersion {
-
-    TAP_SCHEMA_1("TAP_SCHEMA 1.0"),
-    TAP_SCHEMA_1_1("TAP_SCHEMA 1.1"),
-    TAP_SCHEMA_1_IA2("IA2 TAP_SCHEMA 1.0"),
-    TAP_SCHEMA_1_1_IA2("IA2 TAP_SCHEMA 1.1");
-
-    private final String name;
+public class DBBrokerFactory {
 
-    private TapSchemaVersion(String name) {
-        this.name = name;
+    public static DBBroker getDBBroker(DataSourceWrapper dataSourceWrapper) {
+        switch (dataSourceWrapper.getDatabaseType()) {
+            case MYSQL:
+                return new MySQLDBBroker(dataSourceWrapper.getDataSource());
+            default:
+                throw new UnsupportedOperationException(dataSourceWrapper.getDatabaseType() + " not supported yet");
+        }
     }
 }
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBrokerTemplate.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBrokerTemplate.java
new file mode 100644
index 0000000000000000000000000000000000000000..c283b39d59fcc53c80168dfeef12a793f051c25e
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBrokerTemplate.java
@@ -0,0 +1,631 @@
+/*
+ * _____________________________________________________________________________
+ * 
+ * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
+ * Trieste INAF - IA2 Italian Center for Astronomical Archives
+ * _____________________________________________________________________________
+ * 
+ * Copyright (C) 2017 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.
+ */
+package it.inaf.ia2.tsm.datalayer;
+
+import it.inaf.ia2.tsm.Column;
+import it.inaf.ia2.tsm.Key;
+import it.inaf.ia2.tsm.KeyColumn;
+import it.inaf.ia2.tsm.Schema;
+import it.inaf.ia2.tsm.Status;
+import it.inaf.ia2.tsm.TSMUtil;
+import it.inaf.ia2.tsm.Table;
+import it.inaf.ia2.tsm.TapSchema;
+import it.inaf.ia2.tsm.TapSchemaEntity;
+import it.inaf.ia2.tsm.UpdateOperations;
+import it.inaf.ia2.tsm.xmlmodel.PropertyModel;
+import it.inaf.ia2.tsm.xmlmodel.TableModel;
+import it.inaf.ia2.tsm.xmlmodel.TapSchemaModel;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.sql.DataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public abstract class DBBrokerTemplate implements DBBroker {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DBBrokerTemplate.class);
+
+    protected final DataSource dataSource;
+    private final char escapeCharacter;
+
+    public DBBrokerTemplate(DataSource dataSource, char escapeCharacter) {
+        this.dataSource = dataSource;
+        this.escapeCharacter = escapeCharacter;
+    }
+
+    protected List<String> getAllItemsNames(String query) throws SQLException {
+
+        List<String> allSchemas = new ArrayList<>();
+
+        LOG.debug("Executing query: {}", query);
+
+        try (Connection connection = dataSource.getConnection();
+                Statement statement = connection.createStatement();
+                ResultSet resultSet = statement.executeQuery(query)) {
+            while (resultSet.next()) {
+                allSchemas.add(resultSet.getString(1));
+            }
+        }
+
+        Collections.sort(allSchemas, String.CASE_INSENSITIVE_ORDER);
+        return allSchemas;
+    }
+
+    protected String buildColumnsList(String[] columns) {
+
+        StringBuilder sb = new StringBuilder();
+
+        boolean first = true;
+        for (String keyColumn : columns) {
+            if (!first) {
+                sb.append(",");
+            }
+            first = false;
+            sb.append(escape(keyColumn));
+        }
+
+        return sb.toString();
+    }
+
+    protected String escape(String name) {
+        return String.format("%s%s%s", escapeCharacter, name, escapeCharacter);
+    }
+
+    protected abstract void createTable(String tapSchemaName, TableModel tableModel, Connection conn) throws SQLException;
+
+    protected abstract void addPrimaryKey(String tapSchemaName, String tableName, String[] keyColumns, Connection conn) throws SQLException;
+
+    protected abstract void addForeignKey(String tapSchemaName, String tableName, String[] fromKeyColumns, String targetTableName, String[] toKeyColumns, Connection conn) throws SQLException;
+
+    private void addPrimaryKey(String tapSchemaName, String tableName, String keyColumn, Connection conn) throws SQLException {
+        addPrimaryKey(tapSchemaName, tableName, new String[]{keyColumn}, conn);
+    }
+
+    private void addForeignKey(String tapSchemaName, String tableName, String fromKeyColumn, String targetTableName, String toKeyColumn, Connection conn) throws SQLException {
+        addForeignKey(tapSchemaName, tableName, new String[]{fromKeyColumn}, targetTableName, new String[]{toKeyColumn}, conn);
+    }
+
+    protected abstract void createDatabase(String databaseName, Connection conn) throws SQLException;
+
+    private void createTapSchemaStructure(String tapSchemaName, TapSchemaModel tapSchemaModel) throws SQLException {
+
+        try (Connection conn = dataSource.getConnection()) {
+
+            createDatabase(tapSchemaName, conn);
+
+            for (TableModel tableModel : tapSchemaModel.getTables().values()) {
+                createTable(tapSchemaName, tableModel, conn);
+            }
+
+            // schemas keys
+            addPrimaryKey(tapSchemaName, TapSchema.SCHEMAS_TABLE, Schema.SCHEMA_NAME_KEY, conn);
+
+            // tables keys
+            addPrimaryKey(tapSchemaName, TapSchema.TABLES_TABLE, Table.TABLE_NAME_KEY, conn);
+            addForeignKey(tapSchemaName, TapSchema.TABLES_TABLE, Table.SCHEMA_NAME_KEY, TapSchema.SCHEMAS_TABLE, Schema.SCHEMA_NAME_KEY, conn);
+
+            // columns keys
+            addPrimaryKey(tapSchemaName, TapSchema.COLUMNS_TABLE, new String[]{Column.TABLE_NAME_KEY, Column.COLUMN_NAME_KEY}, conn);
+            addForeignKey(tapSchemaName, TapSchema.COLUMNS_TABLE, Column.TABLE_NAME_KEY, TapSchema.TABLES_TABLE, Table.TABLE_NAME_KEY, conn);
+
+            // keys keys
+            addPrimaryKey(tapSchemaName, TapSchema.KEYS_TABLE, Key.ID_KEY, conn);
+            addForeignKey(tapSchemaName, TapSchema.KEYS_TABLE, Key.FROM_TABLE_KEY, TapSchema.TABLES_TABLE, Table.TABLE_NAME_KEY, conn);
+            addForeignKey(tapSchemaName, TapSchema.KEYS_TABLE, Key.TARGET_TABLE_KEY, TapSchema.TABLES_TABLE, Table.TABLE_NAME_KEY, conn);
+
+            // key columns key
+            //addPrimaryKey(tapSchemaName, TapSchema.KEY_COLUMNS_TABLE, new String[]{KeyColumn.KEY_ID_KEY, KeyColumn.FROM_COLUMN_KEY, KeyColumn.TARGET_COLUMN_KEY}, conn);
+            addForeignKey(tapSchemaName, TapSchema.KEY_COLUMNS_TABLE, Key.ID_KEY, TapSchema.KEYS_TABLE, Key.ID_KEY, conn);
+            //addForeignKey(tapSchemaName, TapSchema.KEY_COLUMNS_TABLE, KeyColumn.FROM_COLUMN_KEY, TapSchema.COLUMNS_TABLE, Column.COLUMN_NAME_KEY, conn);
+            //addForeignKey(tapSchemaName, TapSchema.KEY_COLUMNS_TABLE, KeyColumn.TARGET_COLUMN_KEY, TapSchema.COLUMNS_TABLE, Column.COLUMN_NAME_KEY, conn);
+        }
+    }
+
+    @Override
+    public void save(TapSchema tapSchema) throws SQLException {
+
+        LOG.debug("Saving TAP_SCHEMA");
+
+        Connection connection = null;
+        PreparedStatement statement = null;
+        boolean transactionStarted = false;
+
+        try {
+
+            if (!tapSchema.exists()) {
+                createTapSchemaStructure(tapSchema.getName(), tapSchema.getTapSchemaModel());
+            }
+
+            connection = dataSource.getConnection();
+
+            UpdateOperations operations = new UpdateOperations(tapSchema);
+
+            // Start update
+            connection.setAutoCommit(false); // start transaction
+            transactionStarted = true;
+
+            String tapSchemaNameEscaped = escape(tapSchema.getName());
+
+            // REMOVE ELEMENTS
+            if (tapSchema.exists()) {
+                for (Key key : operations.getKeysToRemove()) {
+                    String keyId = key.getId();
+
+                    String query = String.format("DELETE FROM %s.%s WHERE key_id = ?", tapSchemaNameEscaped, escape("key_columns"));
+                    statement = connection.prepareStatement(query);
+                    statement.setString(1, keyId);
+                    LOG.debug("Executing query {} [key_id={}]", query, keyId);
+                    statement.executeUpdate();
+
+                    query = String.format("DELETE FROM %s.%s WHERE key_id = ?", tapSchemaNameEscaped, escape("keys"));
+                    statement = connection.prepareStatement(query);
+                    statement.setString(1, keyId);
+                    LOG.debug("Executing query {} [key_id={}]", query, keyId);
+                    statement.executeUpdate();
+                }
+
+                for (Column column : operations.getColumnsToRemove()) {
+                    String query = String.format("DELETE FROM %s.%s WHERE table_name = ? AND column_name = ?", tapSchemaNameEscaped, escape("columns"));
+                    statement = connection.prepareStatement(query);
+                    String tableName = column.getTableCompleteName();
+                    String columnName = column.getName();
+                    statement.setString(1, tableName);
+                    statement.setString(2, columnName);
+                    LOG.debug("Executing query {} [table_name={}, column_name={}]", query, tableName, columnName);
+                    statement.executeUpdate();
+                }
+
+                for (Table table : operations.getTablesToRemove()) {
+                    String query = String.format("DELETE FROM %s.%s WHERE table_name = ?", tapSchemaNameEscaped, escape("tables"));
+                    statement = connection.prepareStatement(query);
+                    String tableCompleteName = table.getCompleteName();
+                    statement.setString(1, tableCompleteName);
+                    LOG.debug("Executing query {} [table_name={}]", query, tableCompleteName);
+                    statement.executeUpdate();
+                }
+
+                for (Schema schema : operations.getSchemasToRemove()) {
+                    String query = String.format("DELETE FROM %s.%s WHERE schema_name = ?", tapSchemaNameEscaped, escape("schemas"));
+                    statement = connection.prepareStatement(query);
+                    String schemaName = schema.getName();
+                    statement.setString(1, schemaName);
+                    LOG.debug("Executing query {} [schema_name={}]", query, schemaName);
+                    statement.executeUpdate();
+                }
+            }
+
+            // INSERT ELEMENTS
+            if (!operations.getSchemasToAdd().isEmpty()) {
+                LOG.debug("Inserting {} new schemas", operations.getSchemasToAdd().size());
+            }
+            for (Schema schema : operations.getSchemasToAdd()) {
+                insertItem(tapSchema.getName(), schema, connection);
+            }
+
+            if (!operations.getTablesToAdd().isEmpty()) {
+                LOG.debug("Inserting {} new tables", operations.getTablesToAdd().size());
+            }
+            for (Table table : operations.getTablesToAdd()) {
+                insertItem(tapSchema.getName(), table, connection);
+            }
+
+            if (!operations.getColumnsToAdd().isEmpty()) {
+                LOG.debug("Inserting {} new columns", operations.getColumnsToAdd().size());
+            }
+            for (Column column : operations.getColumnsToAdd()) {
+                insertItem(tapSchema.getName(), column, connection);
+            }
+
+            if (!operations.getKeysToAdd().isEmpty()) {
+                LOG.debug("Inserting {} new keys", operations.getKeysToAdd().size());
+            }
+            for (Key key : operations.getKeysToAdd()) {
+                // insert new keys and their key columns
+                insertItem(tapSchema.getName(), key, connection);
+                // TODO: INSERT COLUMNS!!!
+            }
+
+            //UPDATE ELEMENTS
+            if (tapSchema.exists()) {
+                for (Key key : operations.getKeysToUpdate()) {
+                    // update keys and their key columns
+                    String whereCond = String.format("%s = ?", escape(Key.ID_KEY));
+                    updateItem(tapSchema.getName(), key, connection, whereCond, key.getId());
+                }
+
+                for (Schema schema : operations.getSchemasToUpdate()) {
+                    String whereCond = String.format("%s = ?", escape(Schema.SCHEMA_NAME_KEY));
+                    updateItem(tapSchema.getName(), schema, connection, whereCond, schema.getName());
+                }
+
+                for (Table table : operations.getTablesToUpdate()) {
+                    String whereCond = String.format("%s = ?", escape(Table.TABLE_NAME_KEY));
+                    updateItem(tapSchema.getName(), table, connection, whereCond, table.getCompleteName());
+                }
+
+                for (Column column : operations.getColumnsToUpdate()) {
+                    String whereCond = String.format("%s = ? AND %s = ?", escape(Column.TABLE_NAME_KEY), escape(Column.COLUMN_NAME_KEY));
+                    updateItem(tapSchema.getName(), column, connection, whereCond, column.getTableCompleteName(), column.getName());
+                }
+            }
+
+            connection.commit();
+
+            // Status cleanup after commit
+            // added
+            for (Key key : operations.getKeysToAdd()) {
+                key.save();
+            }
+            for (Schema schema : operations.getSchemasToAdd()) {
+                schema.save();
+            }
+            for (Table table : operations.getTablesToAdd()) {
+                table.save();
+            }
+            for (Column column : operations.getColumnsToAdd()) {
+                column.save();
+            }
+
+            // removed
+            for (Key key : operations.getKeysToRemove()) {
+                key.initProperty(Key.ID_KEY, null);
+                for (KeyColumn keyColumn : key.getKeyColumns()) {
+                    keyColumn.initProperty(KeyColumn.KEY_ID_KEY, null);
+                }
+            }
+            for (Column column : operations.getColumnsToRemove()) {
+                column.setStatus(Status.LOADED);
+            }
+            for (Column column : operations.getColumnsToClean()) {
+                column.setStatus(Status.LOADED);
+            }
+            for (Table table : operations.getTablesToRemove()) {
+                Schema schema = tapSchema.getChild(table.getParent().getName());
+                if (schema != null) {
+                    schema.cleanTable(table.getName());
+                }
+            }
+            for (Table table : operations.getTablesToClean()) {
+                Schema schema = tapSchema.getChild(table.getParent().getName());
+                if (schema != null) {
+                    schema.cleanTable(table.getName());
+                }
+            }
+            for (Schema schema : operations.getSchemasToRemove()) {
+                tapSchema.cleanSchema(schema.getName());
+            }
+            for (Schema schema : operations.getSchemasToClean()) {
+                tapSchema.cleanSchema(schema.getName());
+            }
+
+            // updated
+            for (Key key : operations.getKeysToUpdate()) {
+                key.save();
+            }
+            for (Schema schema : operations.getSchemasToUpdate()) {
+                schema.save();
+            }
+            for (Table table : operations.getTablesToUpdate()) {
+                table.save();
+            }
+            for (Column column : operations.getColumnsToUpdate()) {
+                column.save();
+            }
+        } catch (SQLException e) {
+            LOG.error("Exception caught", e);
+            try {
+                if (connection != null && transactionStarted) {
+                    LOG.debug("Executing rollback");
+                    connection.rollback();
+                }
+            } catch (SQLException e2) {
+                LOG.error("Exception caught", e2);
+            }
+            throw e;
+        } finally {
+            if (connection != null) {
+                try {
+                    if (statement != null) {
+                        statement.close();
+                    }
+                    connection.close();
+                } catch (SQLException e2) {
+                    LOG.error("Exception caught", e2);
+                }
+            }
+        }
+    }
+
+    @Override
+    public List<Map<String, Object>> getSavedItems(String tapSchemaName, TableModel tableModel, String whereCondition, Object[] whereParams) throws SQLException {
+
+        StringBuilder querySb = new StringBuilder("SELECT ");
+
+        boolean first = true;
+        for (PropertyModel pm : tableModel.getProperties().values()) {
+            if (!first) {
+                querySb.append(", ");
+            }
+            first = false;
+            querySb.append(escape(pm.getName()));
+        }
+
+        querySb.append(" FROM ");
+
+        querySb.append(escape(tapSchemaName));
+        querySb.append(".");
+        querySb.append(escape(tableModel.getName()));
+
+        // TODO: Manage where condition
+        String query = querySb.toString();
+
+        LOG.debug("Executing query {}", query);
+
+        try (Connection conn = dataSource.getConnection()) {
+            try (Statement statement = conn.createStatement();
+                    ResultSet rs = statement.executeQuery(query)) {
+
+                List<Map<String, Object>> items = new ArrayList<>();
+
+                while (rs.next()) {
+                    Map<String, Object> item = new HashMap<>();
+
+                    for (PropertyModel pm : tableModel.getProperties().values()) {
+                        Object value = rs.getObject(pm.getName(), pm.getType());
+                        item.put(pm.getName(), value);
+                    }
+
+                    items.add(item);
+                }
+
+                return items;
+            }
+        }
+    }
+
+    @Override
+    public List<Map<String, Object>> getSavedItems(String tapSchemaName, TableModel tableModel) throws SQLException {
+        return getSavedItems(tapSchemaName, tableModel, null, null);
+    }
+
+    private int getSQLType(Class type) {
+        if (type == String.class) {
+            return Types.VARCHAR;
+        } else if (type == Integer.class) {
+            return Types.INTEGER;
+        } else if (type == Long.class) {
+            return Types.BIGINT;
+        } else if (type == Boolean.class) {
+            return Types.BIT;
+        } else {
+            throw new UnsupportedOperationException("Class type " + type.getCanonicalName() + " not supported yet!");
+        }
+    }
+
+    @Override
+    public void insertItem(String tapSchemaName, TapSchemaEntity tapSchemaItem, Connection conn) throws SQLException {
+
+        StringBuilder querySb = new StringBuilder("INSERT INTO ");
+        querySb.append(escape(tapSchemaName));
+        querySb.append(".");
+        querySb.append(escape(tapSchemaItem.getTableModel().getName()));
+        querySb.append(" (");
+
+        boolean first = true;
+        for (String key : tapSchemaItem.getPropertiesKeys()) {
+            if (!first) {
+                querySb.append(", ");
+            }
+            first = false;
+            querySb.append(escape(key));
+        }
+
+        querySb.append(") VALUES (");
+        first = true;
+        for (String key : tapSchemaItem.getPropertiesKeys()) {
+            if (!first) {
+                querySb.append(",");
+            }
+            first = false;
+            querySb.append("?");
+        }
+        querySb.append(")");
+
+        String query = querySb.toString();
+
+        try (PreparedStatement statement = conn.prepareStatement(query)) {
+
+            List<Object> values = null;
+            if (LOG.isDebugEnabled()) {
+                values = new ArrayList<>();
+            }
+
+            int i = 1;
+            for (String key : tapSchemaItem.getPropertiesKeys()) {
+                Class type = tapSchemaItem.getTableModel().get(key).getType();
+                Object value = tapSchemaItem.getValue(key, type);
+                statement.setObject(i, value, getSQLType(type));
+                i++;
+
+                if (values != null) {
+                    values.add(value);
+                }
+            }
+
+            LOG.debug("Executing query {} [{}]", query, values);
+            statement.executeUpdate();
+        }
+    }
+
+    @Override
+    public void updateItem(String tapSchemaName, TapSchemaEntity tapSchemaItem, Connection conn, String whereCondition, Object... whereParams) throws SQLException {
+
+        StringBuilder querySb = new StringBuilder("UPDATE ");
+        querySb.append(escape(tapSchemaName));
+        querySb.append(".");
+        querySb.append(escape(tapSchemaItem.getTableModel().getName()));
+        querySb.append("\nSET");
+
+        boolean first = true;
+        for (String key : tapSchemaItem.getPropertiesKeys()) {
+            if (!first) {
+                querySb.append(",");
+            }
+            first = false;
+            querySb.append(" ");
+            querySb.append(escape(key));
+            querySb.append(" = ?");
+        }
+
+        querySb.append("\nWHERE ");
+        querySb.append(whereCondition);
+
+        String query = querySb.toString();
+
+        try (PreparedStatement ps = conn.prepareStatement(query)) {
+
+            int i = 0;
+
+            List<Object> statParams = null;
+            if (LOG.isDebugEnabled()) {
+                statParams = new ArrayList<>();
+            }
+            for (String key : tapSchemaItem.getPropertiesKeys()) {
+                Object value = tapSchemaItem.getValue(key);
+                ps.setObject(i, value, getSQLType(value.getClass()));
+                i++;
+                if (statParams != null) {
+                    statParams.add(value);
+                }
+            }
+            for (Object wp : whereParams) {
+                ps.setObject(i, wp, getSQLType(wp.getClass()));
+                i++;
+                if (statParams != null) {
+                    statParams.add(wp);
+                }
+            }
+
+            LOG.debug("Executing query: {} [{}]", query, statParams);
+
+            ps.executeUpdate();
+        }
+    }
+
+    protected abstract String getSchemaTablesQuery(String schemaName);
+
+    @Override
+    public List<String> getAllTAPSchemaNames(List<String> allSchemata) throws SQLException {
+
+        List<String> allTAPSchemas = new ArrayList<>();
+
+        for (String schemaName : allSchemata) {
+
+            boolean schemas = false,
+                    tables = false,
+                    columns = false,
+                    keys = false,
+                    keyColumns = false;
+
+            String query = getSchemaTablesQuery(schemaName);
+
+            LOG.debug("Executing query {}", query);
+
+            try (Connection connection = dataSource.getConnection();
+                    Statement statement = connection.createStatement();
+                    ResultSet resultSet = statement.executeQuery(query)) {
+                while (resultSet.next()) {
+                    String shortTableName = resultSet.getString(1);
+
+                    if (null != shortTableName) {
+                        switch (shortTableName) {
+                            case "schemas":
+                                schemas = true;
+                                break;
+                            case "tables":
+                                tables = true;
+                                break;
+                            case "columns":
+                                columns = true;
+                                break;
+                            case "keys":
+                                keys = true;
+                                break;
+                            case "key_columns":
+                                keyColumns = true;
+                                break;
+                        }
+                    }
+                }
+            }
+
+            if (schemas && tables && columns && keys && keyColumns) {
+                // the schema is a TAP_SCHEMA
+                allTAPSchemas.add(schemaName);
+            }
+        }
+
+        LOG.debug("{} TAP_SCHEMA schemas found", allTAPSchemas.size());
+
+        Collections.sort(allTAPSchemas, String.CASE_INSENSITIVE_ORDER);
+
+        return allTAPSchemas;
+    }
+
+    protected abstract String getTableTypesQuery(String schemaName);
+
+    @Override
+    public Map<String, String> getAllTableTypes(String schemaName) throws SQLException {
+        LOG.debug("getTablesTypes");
+
+        final Map<String, String> tablesTypes = new HashMap<>();
+
+        String query = getTableTypesQuery(schemaName);
+        LOG.debug("Executing query {}", query);
+
+        try (Connection connection = dataSource.getConnection();
+                Statement statement = connection.createStatement();
+                ResultSet resultSet = statement.executeQuery(query)) {
+            while (resultSet.next()) {
+                String tableName = resultSet.getString("table_name");
+                String tableType = resultSet.getString("table_type").equalsIgnoreCase("VIEW") ? "view" : "table";
+                tablesTypes.put(tableName, tableType);
+            }
+        }
+
+        return tablesTypes;
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DBWrapper.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBWrapper.java
similarity index 58%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DBWrapper.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBWrapper.java
index 4a81333ad7e358ea7a404ab06c6e34870f0e2d9c..bddca27e8cc149820dcca2bf7dcdfc0f108e90ea 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/DBWrapper.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBWrapper.java
@@ -20,9 +20,8 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm.datalayer;
 
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
 import java.io.Serializable;
 import java.sql.Connection;
 import java.sql.SQLException;
@@ -44,19 +43,16 @@ import org.slf4j.LoggerFactory;
 public class DBWrapper implements Serializable {
 
     private static final long serialVersionUID = 1721030677924066695L;
-    private final static Logger log = LoggerFactory.getLogger(DBWrapper.class);
+    private final static Logger LOG = LoggerFactory.getLogger(DBWrapper.class);
 
     // Same credentials
-    private Credentials credentials;
+    private DataSourceWrapper dataSourceWrapper;
 
     // Separated credentials
-    private Credentials sourceCredentials;
-    private Credentials tapSchemaCredentials;
-
-    private final DataSourcesWrapper dataSources;
+    private DataSourceWrapper sourceDataSourceWrapper;
+    private DataSourceWrapper tapSchemaDataSourceWrapper;
 
     private DBWrapper() {
-        dataSources = new DataSourcesWrapper();
     }
 
     /**
@@ -65,7 +61,7 @@ public class DBWrapper implements Serializable {
      */
     public DBWrapper(Credentials credentials) {
         this();
-        this.credentials = credentials;
+        dataSourceWrapper = new DataSourceWrapper(credentials);
     }
 
     /**
@@ -74,16 +70,30 @@ public class DBWrapper implements Serializable {
      */
     public DBWrapper(Credentials sourceCredentials, Credentials tapSchemaCredentials) {
         this();
-        this.sourceCredentials = sourceCredentials;
-        this.tapSchemaCredentials = tapSchemaCredentials;
+        sourceDataSourceWrapper = new DataSourceWrapper(sourceCredentials);
+        tapSchemaDataSourceWrapper = new DataSourceWrapper(tapSchemaCredentials);
+    }
+
+    public DataSourceWrapper getSourceDataSourceWrapper() {
+        if (dataSourceWrapper != null) {
+            return dataSourceWrapper;
+        }
+        return sourceDataSourceWrapper;
     }
 
     public DataSource getSourceDataSource() {
-        return dataSources.getSourceDataSource();
+        return getSourceDataSourceWrapper().getDataSource();
+    }
+
+    public DataSourceWrapper getTapSchemaDataSourceWrapper() {
+        if (dataSourceWrapper != null) {
+            return dataSourceWrapper;
+        }
+        return tapSchemaDataSourceWrapper;
     }
 
     public DataSource getTapSchemaDataSource() {
-        return dataSources.getTapSchemaDataSource();
+        return getTapSchemaDataSourceWrapper().getDataSource();
     }
 
     public Connection getSourceConnection() throws SQLException {
@@ -95,25 +105,27 @@ public class DBWrapper implements Serializable {
     }
 
     public Credentials getSourceCredentials() {
-        if (credentials != null) {
-            return credentials;
-        }
-        return sourceCredentials;
+        return getSourceDataSourceWrapper().getCredentials();
     }
 
     public Credentials getTapSchemaCredentials() {
-        if (credentials != null) {
-            return credentials;
-        }
-        return tapSchemaCredentials;
+        return getTapSchemaDataSourceWrapper().getCredentials();
     }
 
     public DatabaseType getSourceDatabaseType() {
-        return getSourceCredentials().getDatabaseType();
+        return getSourceDataSourceWrapper().getDatabaseType();
     }
 
     public DatabaseType getTapSchemaDatabaseType() {
-        return getTapSchemaCredentials().getDatabaseType();
+        return getTapSchemaDataSourceWrapper().getDatabaseType();
+    }
+
+    /**
+     * @return true if the TAP_SCHEMA <code>DataSource</code> is different from
+     * its source <code>DataSource</code>, false otherwise.
+     */
+    public boolean isSeparatedSources() {
+        return dataSourceWrapper == null;
     }
 
     /**
@@ -125,61 +137,15 @@ public class DBWrapper implements Serializable {
      */
     public void testConnections() throws SQLException {
         Connection connection;
-        if (credentials != null) {
-            connection = dataSources.getSourceDataSource().getConnection();
+
+        if (isSeparatedSources()) {
+            connection = getSourceDataSource().getConnection();
             connection.close();
-        } else {
-            connection = dataSources.getSourceDataSource().getConnection();
+            connection = getTapSchemaDataSource().getConnection();
             connection.close();
-            connection = dataSources.getTapSchemaDataSource().getConnection();
+        } else {
+            connection = getSourceDataSource().getConnection();
             connection.close();
         }
     }
-
-    /**
-     * @return true if the TAP_SCHEMA <code>DataSource</code> is different from
-     * its source <code>DataSource</code>, false otherwise.
-     */
-    public boolean isSeparatedSources() {
-        return dataSources.isSeparatedSources();
-    }
-
-    private class DataSourcesWrapper implements Serializable {
-
-        private static final long serialVersionUID = -7025255003212206748L;
-
-        private transient DataSource dataSource;
-        private transient DataSource sourceDataSource;
-        private transient DataSource tapSchemaDataSource;
-
-        public boolean isSeparatedSources() {
-            return dataSource == null;
-        }
-
-        public DataSource getTapSchemaDataSource() {
-            if (credentials != null) {
-                if (dataSource == null) {
-                    dataSource = TSMUtil.createDataSource(credentials);
-                }
-                return dataSource;
-            }
-            if (tapSchemaDataSource == null) {
-                tapSchemaDataSource = TSMUtil.createDataSource(tapSchemaCredentials);
-            }
-            return tapSchemaDataSource;
-        }
-
-        public DataSource getSourceDataSource() {
-            if (credentials != null) {
-                if (dataSource == null) {
-                    dataSource = TSMUtil.createDataSource(credentials);
-                }
-                return dataSource;
-            }
-            if (sourceDataSource == null) {
-                sourceDataSource = TSMUtil.createDataSource(sourceCredentials);
-            }
-            return sourceDataSource;
-        }
-    }
 }
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DataSourceWrapper.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DataSourceWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..266794a7083e3031673bc478aaf29bee85168de1
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DataSourceWrapper.java
@@ -0,0 +1,88 @@
+/*
+ * _____________________________________________________________________________
+ * 
+ * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
+ * Trieste INAF - IA2 Italian Center for Astronomical Archives
+ * _____________________________________________________________________________
+ * 
+ * Copyright (C) 2017 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.
+ */
+package it.inaf.ia2.tsm.datalayer;
+
+import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
+import java.io.Serializable;
+import javax.sql.DataSource;
+import org.postgresql.ds.PGPoolingDataSource;
+
+/**
+ * Serializable wrapper for a DataSource.
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class DataSourceWrapper implements Serializable {
+
+    private static final long serialVersionUID = -7658342136473761826L;
+
+    private Credentials credentials;
+    private transient DataSource dataSource;
+
+    private DataSourceWrapper() {
+    }
+
+    public DataSourceWrapper(Credentials credentials) {
+        this.credentials = credentials;
+    }
+
+    public DataSource getDataSource() {
+        if (dataSource == null) {
+            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.");
+            }
+        }
+        return dataSource;
+    }
+
+    public DatabaseType getDatabaseType() {
+        return credentials.getDatabaseType();
+    }
+
+    public Credentials getCredentials() {
+        return credentials;
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/DatabaseType.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DatabaseType.java
similarity index 96%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/DatabaseType.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DatabaseType.java
index cbf2cc51659e20e7e5545a14cebe1a41901a8c5b..9a21e6941f7b1458144287a58295cedfbf4f60a5 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/contract/DatabaseType.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DatabaseType.java
@@ -20,7 +20,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api.contract;
+package it.inaf.ia2.tsm.datalayer;
 
 /**
  * This enum lists the supported RDBMS.
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/mysql/MySQLDBBroker.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/mysql/MySQLDBBroker.java
new file mode 100644
index 0000000000000000000000000000000000000000..99a26ad7cf6191ad56c72b0626d3fdc1ec8d2f14
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/mysql/MySQLDBBroker.java
@@ -0,0 +1,290 @@
+/*
+ * _____________________________________________________________________________
+ * 
+ * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
+ * Trieste INAF - IA2 Italian Center for Astronomical Archives
+ * _____________________________________________________________________________
+ * 
+ * Copyright (C) 2017 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.
+ */
+package it.inaf.ia2.tsm.datalayer.mysql;
+
+import it.inaf.ia2.tsm.Column;
+import it.inaf.ia2.tsm.KeyMetadata;
+import it.inaf.ia2.tsm.datalayer.ADQL;
+import it.inaf.ia2.tsm.datalayer.DBBrokerTemplate;
+import it.inaf.ia2.tsm.xmlmodel.PropertyModel;
+import it.inaf.ia2.tsm.xmlmodel.TableModel;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.sql.DataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class MySQLDBBroker extends DBBrokerTemplate {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MySQLDBBroker.class);
+
+    public MySQLDBBroker(DataSource dataSource) {
+        super(dataSource, '`');
+    }
+
+    @Override
+    public Map<String, Map<String, Object>> getColumnsInfo(String schemaName, String tableName) {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    public List<String> getAllSchemaNames() throws SQLException {
+        List<String> allSchemas = super.getAllItemsNames("SHOW DATABASES");
+        LOG.debug("{} schemas found", allSchemas.size());
+        return allSchemas;
+    }
+
+    @Override
+    public List<String> getAllTablesNames(String schemaName) throws SQLException {
+        List<String> allTables = super.getAllItemsNames("SHOW TABLES FROM " + escape(schemaName));
+        LOG.debug("{} tables found", allTables.size());
+        return allTables;
+    }
+
+    @Override
+    public List<String> getAllColumnsNames(String schemaName, String tableName) throws SQLException {
+        String query = String.format("SHOW COLUMNS FROM %s.%s", escape(schemaName), escape(tableName));
+        List<String> allColumns = super.getAllItemsNames(query);
+        LOG.debug("{} columns found", allColumns.size());
+        return allColumns;
+    }
+
+    @Override
+    public Map<String, Map<String, Object>> getAllColumnsMetadata(String schemaName, String tableName) throws SQLException {
+
+        Map<String, Map<String, Object>> allColumnsMetadata = new HashMap<>();
+
+        String query = String.format("SHOW COLUMNS FROM %s.%s", escape(schemaName), escape(tableName));
+
+        LOG.debug("Executing query {}", query);
+
+        try (Connection connection = dataSource.getConnection();
+                Statement statement = connection.createStatement();
+                ResultSet resultSet = statement.executeQuery(query)) {
+
+            while (resultSet.next()) {
+
+                Map<String, Object> cm = new HashMap<>();
+
+                // Column name
+                String columnName = resultSet.getString("Field");
+                cm.put(Column.COLUMN_NAME_KEY, columnName);
+
+                // Key info
+                String keyType = resultSet.getString("Key");
+                if ("PRI".equals(keyType)) {
+                    cm.put(Column.PRIMARY_KEY, true);
+                }
+                if ("PRI".equals(keyType) || "UNI".equals(keyType) || "MUL".equals(keyType)) {
+                    cm.put(Column.INDEXED_KEY, true);
+                }
+
+                // Datatype and Size
+                String type = resultSet.getString("Type").toLowerCase();
+                String datatype;
+                Integer size = null;
+
+                if (type.startsWith("int")) {
+                    datatype = ADQL.INTEGER;
+                } else if (type.startsWith("smallint")) {
+                    datatype = ADQL.SMALLINT;
+                } else if (type.startsWith("bigint")) {
+                    datatype = ADQL.BIGINT;
+                } else if (type.startsWith("float")) {
+                    datatype = ADQL.REAL;
+                } else if (type.startsWith("char")) {
+                    int beginIndex = type.indexOf('(');
+                    int endIndex = type.indexOf(')');
+                    size = Integer.parseInt(type.substring(beginIndex + 1, endIndex));
+                    datatype = ADQL.CHAR;
+                } else if (type.startsWith("varchar")) {
+                    int beginIndex = type.indexOf('(');
+                    int endIndex = type.indexOf(')');
+                    size = Integer.parseInt(type.substring(beginIndex + 1, endIndex));
+                    datatype = ADQL.VARCHAR;
+                } else if (type.contains("timestamp")) {
+                    datatype = ADQL.TIMESTAMP;
+                } else {
+                    datatype = ADQL.getDataType(type);
+                }
+
+                cm.put(Column.DATATYPE_KEY, datatype);
+                cm.put(Column.SIZE_KEY, size);
+
+                Integer arraySize = null; // TODO (v 1.1)
+
+                allColumnsMetadata.put(columnName, cm);
+            }
+        }
+
+        return allColumnsMetadata;
+    }
+
+    @Override
+    protected void createTable(String tapSchemaName, TableModel tableModel, Connection conn) throws SQLException {
+
+        StringBuilder querySb = new StringBuilder();
+
+        querySb.append("CREATE TABLE IF NOT EXISTS ");
+        querySb.append(escape(tapSchemaName));
+        querySb.append(".");
+        querySb.append(escape(tableModel.getName()));
+        querySb.append(" (\n");
+
+        boolean first = true;
+        for (PropertyModel pm : tableModel.getProperties().values()) {
+            if (!first) {
+                querySb.append(",\n");
+            }
+            first = false;
+
+            querySb.append(pm.getName());
+            querySb.append(" ");
+
+            Class type = pm.getType();
+            if (type == String.class) {
+                querySb.append("VARCHAR(");
+                querySb.append(pm.getSize());
+                querySb.append(")");
+            } else if (type == Integer.class || type == Boolean.class) {
+                querySb.append("INTEGER");
+            } else if (type == Long.class) {
+                querySb.append("BIGINT");
+            } else {
+                throw new UnsupportedOperationException("Column type " + type.getCanonicalName() + " not supported yet!");
+            }
+
+            if (pm.isNullable()) {
+                querySb.append(" NULL");
+            } else {
+                querySb.append(" NOT NULL");
+            }
+        }
+
+        querySb.append(")");
+
+        String query = querySb.toString();
+
+        try (Statement stat = conn.createStatement()) {
+            LOG.debug("Executing query: {}", query);
+            stat.executeUpdate(query);
+        }
+    }
+
+    @Override
+    protected void addPrimaryKey(String tapSchemaName, String tableName, String[] keyColumns, Connection conn) throws SQLException {
+        String query = String.format("ALTER TABLE %s.%s ADD PRIMARY KEY(%s)", escape(tapSchemaName), escape(tableName), buildColumnsList(keyColumns));
+        try (Statement stat = conn.createStatement()) {
+            LOG.debug("Executing query: {}", query);
+            stat.executeUpdate(query);
+        }
+    }
+
+    @Override
+    protected void addForeignKey(String tapSchemaName, String tableName, String[] fromKeyColumns, String targetTableName, String[] toKeyColumns, Connection conn) throws SQLException {
+        String query = String.format("ALTER TABLE %s.%s ADD FOREIGN KEY (%s) REFERENCES %s.%s(%s)", escape(tapSchemaName), escape(tableName),
+                buildColumnsList(fromKeyColumns), escape(tapSchemaName), escape(targetTableName), buildColumnsList(toKeyColumns));
+        try (Statement stat = conn.createStatement()) {
+            LOG.debug("Executing query: {}", query);
+            stat.executeUpdate(query);
+        }
+    }
+
+    @Override
+    public List<KeyMetadata> getKeysMetadata(String schemaName) throws SQLException {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("SELECT\n");
+        sb.append("c.CONSTRAINT_NAME AS constraint_name,\n");
+        sb.append("k.TABLE_SCHEMA AS from_schema,\n");
+        sb.append("k.TABLE_NAME AS from_table,\n");
+        sb.append("k.COLUMN_NAME AS from_column,\n");
+        sb.append("k.REFERENCED_TABLE_SCHEMA AS target_schema,\n");
+        sb.append("k.REFERENCED_TABLE_NAME AS target_table,\n");
+        sb.append("k.REFERENCED_COLUMN_NAME AS target_column\n");
+        sb.append("FROM information_schema.TABLE_CONSTRAINTS c \n");
+        sb.append("LEFT JOIN information_schema.KEY_COLUMN_USAGE k \n");
+        sb.append("ON c.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND c.TABLE_SCHEMA = k.TABLE_SCHEMA\n");
+        sb.append("WHERE c.CONSTRAINT_TYPE = 'FOREIGN KEY' \n");
+        sb.append("AND k.TABLE_SCHEMA = '");
+        sb.append(schemaName);
+        sb.append("' OR k.REFERENCED_TABLE_SCHEMA = '");
+        sb.append(schemaName);
+        sb.append("'");
+
+        String query = sb.toString();
+
+        LOG.debug("Executing query: {}", query);
+
+        List<KeyMetadata> keysMetadata = new ArrayList<>();
+        try (Connection connection = dataSource.getConnection();
+                Statement statement = connection.createStatement();
+                ResultSet resultSet = statement.executeQuery(query)) {
+
+            while (resultSet.next()) {
+                //String constraintName = resultSet.getString("constraint_name");
+
+                String fromSchemaName = resultSet.getString("from_schema");
+                String fromTableName = resultSet.getString("from_table");
+                String targetSchemaName = resultSet.getString("target_schema");
+                String targetTableName = resultSet.getString("target_table");
+
+                KeyMetadata km = new KeyMetadata(fromSchemaName, fromTableName, targetSchemaName, targetTableName);
+                km.addKeyColumn(resultSet.getString("from_column"), resultSet.getString("target_column"));
+
+                keysMetadata.add(km);
+            }
+        }
+
+        return keysMetadata;
+    }
+
+    @Override
+    protected String getSchemaTablesQuery(String schemaName) {
+        return "SHOW TABLES FROM " + escape(schemaName);
+    }
+
+    @Override
+    protected void createDatabase(String databaseName, Connection conn) throws SQLException {
+        String queryString = "CREATE DATABASE IF NOT EXISTS " + escape(databaseName);
+        LOG.debug("Executing query: {}", queryString);
+        try (Statement stat = conn.createStatement()) {
+            stat.execute(queryString);
+        }
+    }
+
+    @Override
+    protected String getTableTypesQuery(String schemaName) {
+        return "SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = '" + schemaName + "'";
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/pgsql/PostgresDBBroker.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/pgsql/PostgresDBBroker.java
new file mode 100644
index 0000000000000000000000000000000000000000..94a41dfcfd58a039b6b85cd9e6110f837bcbbe25
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/pgsql/PostgresDBBroker.java
@@ -0,0 +1,119 @@
+/*
+ * _____________________________________________________________________________
+ * 
+ * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
+ * Trieste INAF - IA2 Italian Center for Astronomical Archives
+ * _____________________________________________________________________________
+ * 
+ * Copyright (C) 2017 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.
+ */
+package it.inaf.ia2.tsm.datalayer.pgsql;
+
+import it.inaf.ia2.tsm.KeyMetadata;
+import it.inaf.ia2.tsm.datalayer.DBBrokerTemplate;
+import it.inaf.ia2.tsm.xmlmodel.TableModel;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+import javax.sql.DataSource;
+
+/**
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class PostgresDBBroker extends DBBrokerTemplate {
+
+    public PostgresDBBroker(DataSource dataSource) {
+        super(dataSource, '\'');
+    }
+
+    @Override
+    protected void createTable(String tapSchemaName, TableModel tableModel, Connection conn) throws SQLException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    protected void addPrimaryKey(String tapSchemaName, String tableName, String[] keyColumns, Connection conn) throws SQLException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    protected void addForeignKey(String tapSchemaName, String tableName, String[] fromKeyColumns, String targetTableName, String[] toKeyColumns, Connection conn) throws SQLException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    protected void createDatabase(String databaseName, Connection conn) throws SQLException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    protected String getSchemaTablesQuery(String schemaName) {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    public Map<String, Map<String, Object>> getColumnsInfo(String schemaName, String tableName) throws SQLException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    public List<String> getAllSchemaNames() throws SQLException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    public List<String> getAllTablesNames(String schemaName) throws SQLException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    public Map<String, String> getAllTableTypes(String schemaName) throws SQLException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    public List<String> getAllColumnsNames(String schemaName, String tableName) throws SQLException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    public Map<String, Map<String, Object>> getAllColumnsMetadata(String schemaName, String tableSimpleName) throws SQLException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    public List<KeyMetadata> getKeysMetadata(String schemaName) throws SQLException {
+        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+    }
+
+    @Override
+    protected String getTableTypesQuery(String schemaName) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("SELECT tablename AS table_name, 'table' AS table_type\n");
+        sb.append("FROM pg_catalog.pg_tables WHERE schemaname = '");
+        sb.append(schemaName);
+        sb.append("'\n");
+        sb.append("UNION\n");
+        sb.append("SELECT table_name AS table_name, 'view' AS table_type\n");
+        sb.append("FROM INFORMATION_SCHEMA.views\n");
+        sb.append("WHERE table_schema = '");
+        sb.append(schemaName);
+        sb.append("'");
+        return sb.toString();
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/PropertyModel.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/PropertyModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..ca02f53b51a753093f7b44af9f0c7099dd848c21
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/PropertyModel.java
@@ -0,0 +1,83 @@
+/*
+ * _____________________________________________________________________________
+ * 
+ * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
+ * Trieste INAF - IA2 Italian Center for Astronomical Archives
+ * _____________________________________________________________________________
+ * 
+ * Copyright (C) 2017 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.
+ */
+package it.inaf.ia2.tsm.xmlmodel;
+
+import java.io.Serializable;
+
+/**
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class PropertyModel implements Serializable {
+
+    private static final long serialVersionUID = -3081516272534689428L;
+
+    private String name;
+    private Class type;
+    private Integer size;
+    private boolean updatable;
+    private boolean nullable;
+    private String loaderKey;
+
+    private PropertyModel() {
+    }
+
+    public PropertyModel(PropertyXMLModel propertyXMLModel) {
+        try {
+            name = propertyXMLModel.getName();
+            type = Class.forName(propertyXMLModel.getType());
+            size = propertyXMLModel.getSize();
+            updatable = propertyXMLModel.isUpdatable();
+            nullable = propertyXMLModel.isNullable();
+            loaderKey = propertyXMLModel.getLoaderKey();
+        } catch (ClassNotFoundException e) {
+            throw new ExceptionInInitializerError(
+                    "Invalid property type for property " + propertyXMLModel.getName()
+                    + ". ClassNotFoundException: " + propertyXMLModel.getType());
+        }
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Class getType() {
+        return type;
+    }
+
+    public Integer getSize() {
+        return size;
+    }
+
+    public boolean isUpdatable() {
+        return updatable;
+    }
+
+    public boolean isNullable() {
+        return nullable;
+    }
+
+    public String getLoaderKey() {
+        return loaderKey;
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/PropertyXMLModel.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/PropertyXMLModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..8558bf706c33d8fead8c498f7285428ab7626e9f
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/PropertyXMLModel.java
@@ -0,0 +1,109 @@
+/*
+ * _____________________________________________________________________________
+ * 
+ * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
+ * Trieste INAF - IA2 Italian Center for Astronomical Archives
+ * _____________________________________________________________________________
+ * 
+ * Copyright (C) 2017 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.
+ */
+package it.inaf.ia2.tsm.xmlmodel;
+
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class PropertyXMLModel {
+
+    private String name;
+    private String type;
+    private Integer size;
+    private boolean updatable;
+    private boolean nullable;
+    private String loaderKey;
+    private String description;
+
+    public PropertyXMLModel() {
+        // default values
+        updatable = true;
+        nullable = true;
+    }
+
+    @XmlElement(name = "name")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @XmlElement(name = "type")
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    @XmlElement(name = "size")
+    public Integer getSize() {
+        return size;
+    }
+
+    public void setSize(Integer size) {
+        this.size = size;
+    }
+
+    @XmlElement(name = "updatable", defaultValue = "true")
+    public boolean isUpdatable() {
+        return updatable;
+    }
+
+    public void setUpdatable(boolean updatable) {
+        this.updatable = updatable;
+    }
+
+    @XmlElement(name = "nullable", defaultValue = "true")
+    public boolean isNullable() {
+        return nullable;
+    }
+
+    public void setNullable(boolean nullable) {
+        this.nullable = nullable;
+    }
+
+    @XmlElement(name = "key")
+    public String getLoaderKey() {
+        return loaderKey;
+    }
+
+    public void setLoaderKey(String loaderMethod) {
+        this.loaderKey = loaderMethod;
+    }
+
+    @XmlElement(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TableModel.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TableModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..a0583421b47114ff14121ffd6b34a3d5962774e4
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TableModel.java
@@ -0,0 +1,60 @@
+/*
+ * _____________________________________________________________________________
+ * 
+ * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
+ * Trieste INAF - IA2 Italian Center for Astronomical Archives
+ * _____________________________________________________________________________
+ * 
+ * Copyright (C) 2017 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.
+ */
+package it.inaf.ia2.tsm.xmlmodel;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class TableModel implements Serializable {
+
+    private static final long serialVersionUID = 5142593924738484037L;
+
+    private final Map<String, PropertyModel> properties;
+    private String name;
+
+    private TableModel() {
+        this.properties = new HashMap<>();
+    }
+
+    public TableModel(String name) {
+        this();
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Map<String, PropertyModel> getProperties() {
+        return properties;
+    }
+
+    public PropertyModel get(String columnName) {
+        return properties.get(columnName);
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/FixedEntityProperty.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TableXMLModel.java
similarity index 53%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/FixedEntityProperty.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TableXMLModel.java
index b84bd9203f1b134ccfb6632e74c9d7fe689d1b86..b0118b4d1948cb41a3697dc805a2447b094d4588 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/FixedEntityProperty.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TableXMLModel.java
@@ -1,11 +1,11 @@
-/* 
+/*
  * _____________________________________________________________________________
  * 
  * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
  * Trieste INAF - IA2 Italian Center for Astronomical Archives
  * _____________________________________________________________________________
  * 
- * Copyright (C) 2016 Istituto Nazionale di Astrofisica
+ * Copyright (C) 2017 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
@@ -20,46 +20,48 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm.xmlmodel;
 
-import java.io.Serializable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
 
 /**
- * Represent an {@code EntityProperty} which value can't be modified by the
- * user.
  *
  * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
  */
-public class FixedEntityProperty<T> implements EntityProperty, Serializable {
+public class TableXMLModel {
 
-    private static final long serialVersionUID = -7009289405382798659L;
-    private static final Logger log = LoggerFactory.getLogger(EntityPropertyInfo.class);
+    private String name;
+    private String description;
+    private List<PropertyXMLModel> add;
 
-    private T value;
-    private boolean changed;
+    @XmlAttribute(name = "name")
+    public String getName() {
+        return name;
+    }
 
-    public FixedEntityProperty(T value) {
-        init(value);
+    public void setName(String name) {
+        this.name = name;
     }
 
-    @Override
-    public final <X> void init(X initialValue) {
-        this.value = (T) initialValue;
+    @XmlAttribute(name = "description")
+    public String getDescription() {
+        return description;
     }
 
-    @Override
-    public <X> X getValue(Class<X> type) {
-        return (X) value;
+    public void setDescription(String description) {
+        this.description = description;
     }
 
-    @Override
-    public boolean isChanged() {
-        return changed;
+    @XmlElementWrapper(name = "add")
+    @XmlElement(name = "property")
+    public List<PropertyXMLModel> getAdd() {
+        return add;
     }
 
-    public void setChanged(boolean changed) {
-        this.changed = changed;
+    public void setAdd(List<PropertyXMLModel> add) {
+        this.add = add;
     }
 }
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TapSchemaFactory.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TapSchemaModel.java
similarity index 57%
rename from TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TapSchemaFactory.java
rename to TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TapSchemaModel.java
index d926b92be473fe3ee05219160cefbe1b15ad6607..7c8ae31aa1c0fc5deb0ca4bc14f0d6f21383f3eb 100644
--- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/api/TapSchemaFactory.java
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TapSchemaModel.java
@@ -1,11 +1,11 @@
-/* 
+/*
  * _____________________________________________________________________________
  * 
  * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
  * Trieste INAF - IA2 Italian Center for Astronomical Archives
  * _____________________________________________________________________________
  * 
- * Copyright (C) 2016 Istituto Nazionale di Astrofisica
+ * Copyright (C) 2017 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
@@ -20,24 +20,41 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-package it.inaf.ia2.tsm.api;
+package it.inaf.ia2.tsm.xmlmodel;
 
-import it.inaf.ia2.tsm.api.contract.TapSchema;
-import it.inaf.ia2.tsm.api.contract.TapSchemaVersion;
-import java.sql.SQLException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
- * Factory for {@link TapSchema} instances.
  *
  * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
  */
-public class TapSchemaFactory {
+public class TapSchemaModel implements Serializable {
 
-    private final static Logger log = LoggerFactory.getLogger(TapSchemaFactory.class);
+    private static final long serialVersionUID = 1087876778125446000L;
 
-    public static TapSchema getTapSchema(TapSchemaVersion version, DBWrapper dbWrapper, String tapSchemaName, boolean exists) throws SQLException {
-        return new TapSchemaImpl(version, dbWrapper, tapSchemaName, exists);
+    private final Map<String, TableModel> tables;
+    private String version;
+
+    private TapSchemaModel() {
+        tables = new HashMap<>();
+    }
+
+    public TapSchemaModel(String version) {
+        this();
+        this.version = version;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public Map<String, TableModel> getTables() {
+        return tables;
+    }
+
+    public TableModel get(String tableName) {
+        return tables.get(tableName);
     }
 }
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TapSchemaModels.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TapSchemaModels.java
new file mode 100644
index 0000000000000000000000000000000000000000..7ab8dc4315013fdc85b766b4ec8e5e4e06a15f96
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TapSchemaModels.java
@@ -0,0 +1,102 @@
+/*
+ * _____________________________________________________________________________
+ * 
+ * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
+ * Trieste INAF - IA2 Italian Center for Astronomical Archives
+ * _____________________________________________________________________________
+ * 
+ * Copyright (C) 2017 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.
+ */
+package it.inaf.ia2.tsm.xmlmodel;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import javax.xml.bind.JAXB;
+
+/**
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+public class TapSchemaModels {
+
+    // Map keys are TS versions
+    private final static Map<String, TapSchemaModel> MODELS;
+
+    private TapSchemaModels() {
+    }
+
+    static {
+
+        try {
+            Map<String, TapSchemaXMLModel> xmlModels = getXmlModels();
+
+            MODELS = new HashMap<>();
+
+            for (TapSchemaXMLModel xmlModel : xmlModels.values()) {
+                TapSchemaModel model = new TapSchemaModel(xmlModel.getVersion());
+                loadTapSchemaModel(model, xmlModel, xmlModels);
+                MODELS.put(model.getVersion(), model);
+            }
+        } catch (URISyntaxException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    private static Map<String, TapSchemaXMLModel> getXmlModels() throws URISyntaxException {
+        Map<String, TapSchemaXMLModel> xmlModels = new HashMap<>();
+        File modelsDirectory = new File(TapSchemaModels.class.getClassLoader().getResource("tap_schema").toURI());
+        for (File modelFile : modelsDirectory.listFiles()) {
+            TapSchemaXMLModel model = JAXB.unmarshal(modelFile, TapSchemaXMLModel.class);
+            xmlModels.put(model.getVersion(), model);
+        }
+        return xmlModels;
+    }
+
+    private static void loadTapSchemaModel(TapSchemaModel model, TapSchemaXMLModel xmlModel, Map<String, TapSchemaXMLModel> xmlModels) {
+
+        for (TableXMLModel tableXmlModel : xmlModel.getTables()) {
+            String tableName = tableXmlModel.getName();
+            TableModel tableModel = model.get(tableName);
+            if (tableModel == null) {
+                tableModel = new TableModel(tableName);
+            }
+            for (PropertyXMLModel property : tableXmlModel.getAdd()) {
+                tableModel.getProperties().put(property.getName(), new PropertyModel(property));
+            }
+            model.getTables().put(tableName, tableModel);
+        }
+
+        if (xmlModel.getExtendsFrom() != null) {
+            TapSchemaXMLModel parentModel = xmlModels.get(xmlModel.getExtendsFrom());
+            loadTapSchemaModel(model, parentModel, xmlModels);
+        }
+    }
+
+    public static TapSchemaModel getTapSchemaModel(String version) {
+        return MODELS.get(version);
+    }
+
+    public static Iterator<TapSchemaModel> getIterator() {
+        return MODELS.values().iterator();
+    }
+
+    public static TableModel getTableModel(String tableName, String version) {
+        return getTapSchemaModel(version).getTables().get(tableName);
+    }
+}
diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TapSchemaXMLModel.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TapSchemaXMLModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..e320d16cb6fad1d1a361535eb975924c92f8d580
--- /dev/null
+++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/xmlmodel/TapSchemaXMLModel.java
@@ -0,0 +1,80 @@
+/*
+ * _____________________________________________________________________________
+ * 
+ * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
+ * Trieste INAF - IA2 Italian Center for Astronomical Archives
+ * _____________________________________________________________________________
+ * 
+ * Copyright (C) 2017 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.
+ */
+package it.inaf.ia2.tsm.xmlmodel;
+
+import java.util.List;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ *
+ * @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
+ */
+@XmlRootElement(name = "tap_schema")
+public class TapSchemaXMLModel {
+
+    private String version;
+    private String description;
+    private String extendsFrom;
+    private List<TableXMLModel> tables;
+
+    @XmlAttribute(name = "version")
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    @XmlAttribute(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @XmlAttribute(name = "extends")
+    public String getExtendsFrom() {
+        return extendsFrom;
+    }
+
+    public void setExtendsFrom(String extendsFrom) {
+        this.extendsFrom = extendsFrom;
+    }
+
+    @XmlElements({
+        @XmlElement(name = "table")
+    })
+    public List<TableXMLModel> getTables() {
+        return tables;
+    }
+
+    public void setTables(List<TableXMLModel> tables) {
+        this.tables = tables;
+    }
+}
diff --git a/TASMAN-core/src/main/resources/tap_schema/tap_schema-1-IA2.xml b/TASMAN-core/src/main/resources/tap_schema/tap_schema-1-IA2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..70e1638b275326fccd1aaa7afdd392dd0d2ae4a2
--- /dev/null
+++ b/TASMAN-core/src/main/resources/tap_schema/tap_schema-1-IA2.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+_____________________________________________________________________________
+
+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.
+-->
+<tap_schema version="1.0-IA2" extends="1.0">
+    <table name="schemas">
+        <add>
+            <property>
+                <name>schemaID</name>
+                <type>java.lang.Long</type>
+                <updatable>true</updatable>
+            </property>
+        </add>
+    </table>
+    <table name="tables">
+        <add>
+            <property>
+                <name>tableID</name>
+                <type>java.lang.Long</type>
+                <updatable>true</updatable>
+            </property>
+        </add>
+    </table>
+    <table name="columns">
+        <add>
+            <property>
+                <name>columnID</name>
+                <type>java.lang.Long</type>
+                <updatable>true</updatable>
+            </property>
+        </add>
+    </table>
+    <table name="keys">
+        <add>
+            <property>
+                <name>keyID</name>
+                <type>java.lang.Long</type>
+                <updatable>true</updatable>
+            </property>
+        </add>
+    </table>
+    <table name="key_columns">
+        <add>
+            <property>
+                <name>key_columnID</name>
+                <type>java.lang.Long</type>
+                <updatable>true</updatable>
+            </property>
+        </add>
+    </table>
+</tap_schema>
diff --git a/TASMAN-core/src/main/resources/tap_schema/tap_schema-1.xml b/TASMAN-core/src/main/resources/tap_schema/tap_schema-1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..89adc9c0b7585530e77a2dd0324d0a6702a4d95f
--- /dev/null
+++ b/TASMAN-core/src/main/resources/tap_schema/tap_schema-1.xml
@@ -0,0 +1,254 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+_____________________________________________________________________________
+
+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.
+-->
+<tap_schema version="1.0" description="a special schema to describe a TAP tableset">
+    <table name="schemas" description="description of schemas in this tableset">
+        <add>
+            <property>
+                <name>schema_name</name>
+                <type>java.lang.String</type>
+                <size>64</size>
+                <updatable>false</updatable>
+                <nullable>false</nullable>
+                <key>schema_name</key>
+                <description>schema name for reference to TAP_SCHEMA.schemas</description>
+            </property>
+            <property>
+                <name>utype</name>
+                <type>java.lang.String</type>
+                <size>255</size>
+                <updatable>true</updatable>
+                <description>lists the utypes of schemas in the tableset</description>
+            </property>
+            <property>
+                <name>description</name>
+                <type>java.lang.String</type>
+                <size>255</size>
+                <updatable>true</updatable>
+                <description>describes schemas in the tableset</description>
+            </property>
+        </add>
+    </table>
+    <table name="tables" description="description of tables in this tableset">
+        <add>
+            <property>
+                <name>schema_name</name>
+                <type>java.lang.String</type>
+                <size>64</size>
+                <updatable>false</updatable>
+                <nullable>false</nullable>
+                <key>schema_name</key>
+                <description>the schema this table belongs to</description>
+            </property>
+            <property>
+                <name>table_name</name>
+                <type>java.lang.String</type>
+                <size>128</size>
+                <updatable>false</updatable>
+                <nullable>false</nullable>
+                <key>table_name</key>
+                <description>the fully qualified table name</description>
+            </property>
+            <property>
+                <name>table_type</name>
+                <size>8</size>
+                <type>java.lang.String</type>
+                <updatable>false</updatable>
+                <key>table_type</key>
+                <description>one of: table view</description>
+            </property>
+            <property>
+                <name>utype</name>
+                <type>java.lang.String</type>
+                <size>255</size>
+                <updatable>true</updatable>
+                <description>lists the utype of tables in the tableset</description>
+            </property>
+            <property>
+                <name>description</name>
+                <type>java.lang.String</type>
+                <size>255</size>
+                <updatable>true</updatable>
+                <description>describes tables in the tableset</description>             
+            </property>
+        </add>
+    </table>
+    <table name="columns" description="description of columns in this tableset">
+        <add>
+            <property>
+                <name>table_name</name>
+                <required>true</required>
+                <type>java.lang.String</type>
+                <size>128</size>
+                <updatable>false</updatable>
+                <nullable>false</nullable>
+                <key>table_name</key>
+                <description>the table this column belongs to</description>
+            </property>
+            <property>
+                <name>column_name</name>
+                <required>true</required>
+                <type>java.lang.String</type>
+                <size>64</size>
+                <updatable>false</updatable>
+                <nullable>false</nullable>
+                <key>column_name</key>
+                <description>the column name</description>
+            </property>
+            <property>
+                <name>datatype</name>
+                <type>java.lang.String</type>
+                <size>64</size>
+                <updatable>false</updatable>
+                <key>datatype</key>
+                <description>lists the ADQL datatype of columns in the tableset</description>
+            </property>
+            <property>
+                <name>size</name>
+                <type>java.lang.Integer</type>
+                <updatable>false</updatable>
+                <key>size</key>
+                <description>lists the size of variable-length columns in the tableset</description>
+            </property>
+            <property>
+                <name>description</name>
+                <type>java.lang.String</type>
+                <size>255</size>
+                <updatable>true</updatable> 
+                <description>describes the columns in the tableset</description>  
+            </property>
+            <property>
+                <name>utype</name>
+                <type>java.lang.String</type>
+                <size>255</size>
+                <updatable>true</updatable>
+                <description>lists the utypes of columns in the tableset</description>
+            </property>
+            <property>
+                <name>unit</name>
+                <type>java.lang.String</type>
+                <size>64</size>
+                <updatable>true</updatable>
+                <description>lists the unit used for column values in the tableset</description>
+            </property>
+            <property>
+                <name>ucd</name>
+                <type>java.lang.String</type>
+                <size>64</size>
+                <updatable>true</updatable>
+                <description>lists the UCDs of columns in the tableset</description>
+            </property>
+            <property>
+                <name>indexed</name>
+                <type>java.lang.Boolean</type>
+                <updatable>false</updatable>
+                <key>indexed</key>
+                <description>an indexed column; 1 means 1, 0 means 0</description>
+            </property>
+            <property>
+                <name>principal</name>
+                <type>java.lang.Boolean</type>
+                <updatable>true</updatable>
+                <description>a principal column; 1 means 1, 0 means 0</description>   
+            </property>
+            <property>
+                <name>std</name>
+                <type>java.lang.Boolean</type>
+                <updatable>true</updatable> 
+                <description>a standard column; 1 means 1, 0 means 0</description>  
+            </property>
+        </add>
+    </table>
+    <table name="keys" description="description of foreign keys in this tableset">
+        <add>
+            <property>
+                <name>key_id</name>
+                <type>java.lang.String</type>
+                <size>64</size>
+                <updatable>true</updatable>
+                <key>key_id</key>
+                <nullable>false</nullable>
+                <description>unique key to join to TAP_SCHEMA.key_columns</description>
+            </property>
+            <property>
+                <name>from_table</name>
+                <type>java.lang.String</type>
+                <size>128</size>
+                <updatable>false</updatable>
+                <key>from_table</key>
+                <description>the table with the foreign key</description>
+            </property>
+            <property>
+                <name>target_table</name>
+                <type>java.lang.String</type>
+                <size>128</size>
+                <updatable>false</updatable>
+                <key>target_table</key>
+                <description>the table with the primary key</description>
+            </property>
+            <property>
+                <name>description</name>
+                <type>java.lang.String</type>
+                <size>255</size>
+                <updatable>true</updatable>
+                <description>describes keys in the tableset</description>
+            </property>
+            <property>
+                <name>utype</name>
+                <type>java.lang.String</type>
+                <size>255</size>
+                <updatable>true</updatable>
+                <description>lists the utype of keys in the tableset</description>
+            </property>
+        </add>
+    </table>
+    <table name="key_columns" description="description of foreign key columns in this tableset">
+        <add>
+            <property>
+                <name>key_id</name>
+                <type>java.lang.String</type>
+                <size>64</size>
+                <updatable>true</updatable>
+                <key>key_id</key>
+                <nullable>false</nullable>
+                <description>key to join to TAP_SCHEMA.keys</description>
+            </property>
+            <property>
+                <name>from_column</name>
+                <type>java.lang.String</type>
+                <size>64</size>
+                <updatable>false</updatable>
+                <key>from_column</key>
+                <description>column in the from_table</description>
+            </property>
+            <property>
+                <name>target_column</name>
+                <type>java.lang.String</type>
+                <size>64</size>
+                <updatable>false</updatable>
+                <key>target_column</key>
+                <description>column in the target_table</description>
+            </property>
+        </add>
+    </table>
+</tap_schema>
diff --git a/TASMAN-core/src/main/resources/tap_schema/tap_schema-1_1.xml b/TASMAN-core/src/main/resources/tap_schema/tap_schema-1_1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..74ae692d6a05b6f14149e2999d11dae029dccb2a
--- /dev/null
+++ b/TASMAN-core/src/main/resources/tap_schema/tap_schema-1_1.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+_____________________________________________________________________________
+
+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.
+-->
+<tap_schema version="1.1" extends="1.0">
+    <table name="tables">
+        <add>
+            <property>
+                <name>table_index</name>
+                <type>java.lang.Integer</type>
+                <updatable>true</updatable>                
+            </property>
+        </add>
+    </table>
+    <table name="columns">
+        <add>
+            <property>
+                <name>arraysize</name>
+                <type>java.lang.Integer</type>
+                <updatable>false</updatable> 
+                <key>arraysize</key>  
+            </property>
+            <property>
+                <name>column_index</name>
+                <type>java.lang.Integer</type>
+                <updatable>true</updatable>   
+            </property>
+        </add>
+    </table>
+</tap_schema>
diff --git a/TASMAN-core/src/test/java/it/inaf/ia2/tsm/api/TestAll.java b/TASMAN-core/src/test/java/it/inaf/ia2/tsm/api/TestAll.java
index 3295f4c08cf36c92aad4289f6618bd1805e8ab29..c85aaf4edf238ebab79b05201de091a55e38fbe2 100644
--- a/TASMAN-core/src/test/java/it/inaf/ia2/tsm/api/TestAll.java
+++ b/TASMAN-core/src/test/java/it/inaf/ia2/tsm/api/TestAll.java
@@ -22,15 +22,17 @@
  */
 package it.inaf.ia2.tsm.api;
 
-import it.inaf.ia2.tsm.api.contract.DatabaseType;
-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.TapSchemaVersion;
+import it.inaf.ia2.tsm.UpdateOperations;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
+import it.inaf.ia2.tsm.Table;
+import it.inaf.ia2.tsm.KeyColumn;
+import it.inaf.ia2.tsm.TapSchema;
+import it.inaf.ia2.tsm.Schema;
+import it.inaf.ia2.tsm.Column;
+import it.inaf.ia2.tsm.datalayer.DatabaseType;
+import it.inaf.ia2.tsm.datalayer.Credentials;
+import it.inaf.ia2.tsm.Status;
+import it.inaf.ia2.tsm.Key;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -233,29 +235,41 @@ public class TestAll {
         }
     }
 
-    private boolean allKeysHaveDifferentId(TapSchema tapSchema) {
-        boolean differentKeySameId = false;
-        Map<String, Key> keys = new HashMap<>();
+    @Test
+    public void test1() throws Exception {
 
-        for (Key key : ((TapSchemaImpl) tapSchema).getAllKeys()) {
-            if (key.getId() != null) {
-                if (keys.get(key.getId()) != null && !key.equals(keys.get(key.getId()))) {
-                    differentKeySameId = true;
-                }
-                keys.put(key.getId(), key);
-            }
-        }
+        setUpTestingDatabases();
 
-        if (differentKeySameId) {
-            log.debug("Found different keys with the same key_id!");
-            for (Key key : ((TapSchemaImpl) tapSchema).getAllKeys()) {
-                log.debug(key.toString());
-            }
+        for (DBWrapper dbWrapper : dbWrappers) {
+            TapSchema tapSchema = new TapSchema("1.0", dbWrapper, "test_tap_schema", false);
+            tapSchema.save();
         }
-
-        return !differentKeySameId;
     }
 
+//
+//    private boolean allKeysHaveDifferentId(TapSchema tapSchema) {
+//        boolean differentKeySameId = false;
+//        Map<String, Key> keys = new HashMap<>();
+//
+//        for (Key key : ((TapSchema) tapSchema).getAllKeys()) {
+//            if (key.getId() != null) {
+//                if (keys.get(key.getId()) != null && !key.equals(keys.get(key.getId()))) {
+//                    differentKeySameId = true;
+//                }
+//                keys.put(key.getId(), key);
+//            }
+//        }
+//
+//        if (differentKeySameId) {
+//            log.debug("Found different keys with the same key_id!");
+//            for (Key key : ((TapSchema) tapSchema).getAllKeys()) {
+//                log.debug(key.toString());
+//            }
+//        }
+//
+//        return !differentKeySameId;
+//    }
+//
     private void checkKey(Key key, String fromTableCompleteName, String[] fromColumns, String targetTableCompleteName, String[] targetColumns, boolean isVisible) {
         assertEquals(fromTableCompleteName, key.getFromTableCompleteName());
         assertEquals(targetTableCompleteName, key.getTargetTableCompleteName());
@@ -284,9 +298,9 @@ public class TestAll {
             setUpTestingDatabases();
 
             for (DBWrapper dbWrapper : dbWrappers) {
-                
+
                 // Initializing a not existing TAP_SCHEMA
-                TapSchema tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, "test_tap_schema", false);
+                TapSchema tapSchema = new TapSchema("1.0", dbWrapper, "test_tap_schema", false);
 
                 /////////////////////////////////////
                 //         ADDING A SCHEMA         //
@@ -295,12 +309,11 @@ public class TestAll {
                 Schema sch0 = tapSchema.addChild("sch0");
                 assertEquals(Status.ADDED_NOT_PERSISTED, sch0.getStatus());
 
-                Set<Key> allKeys = ((TapSchemaImpl) tapSchema).getAllKeys();
-                log.debug("ALL keys:");
-                for (Key key : allKeys) {
-                    log.debug(key.toString());
-                }
-
+//                Set<Key> allKeys = tapSchema.getAllKeys();
+//                log.debug("ALL keys:");
+//                for (Key key : allKeys) {
+//                    log.debug(key.toString());
+//                }
                 // In the testing schemas each numbered table references the id 
                 // of the previous table, except for the first table, so there
                 // should be "TABLES_COUNT - 1" keys for the numbered tables.
@@ -309,21 +322,20 @@ public class TestAll {
                 // - sch1.table0.sch0table0id -> sch0.table0.id
                 // - sch0.table_y.(idy1, idy2) -> sch0.table_x.(idyx, idx2)
                 // so we check for TABLES_COUNT + 2.
-                assertEquals(TABLES_COUNT + 2, allKeys.size());
-
-                // Checking that keys information has been filled correctly.
-                for (Key schemaKey : allKeys) {
-                    assertFalse(schemaKey.isVisible());
-                    assertNull(schemaKey.getId());
-                    assertEquals(schemaKey.getFromTableCompleteName(), schemaKey.getFromSchemaName() + "." + schemaKey.getFromTableSimpleName());
-                    assertEquals(schemaKey.getTargetTableCompleteName(), schemaKey.getTargetSchemaName() + "." + schemaKey.getTargetTableSimpleName());
-                    assertTrue(schemaKey.getKeyColumns().size() >= 1);
-                    for (KeyColumn keyColumn : schemaKey.getKeyColumns()) {
-                        assertNotNull(keyColumn.getFromColumn());
-                        assertNotNull(keyColumn.getTargetColumn());
-                    }
-                }
-
+//                assertEquals(TABLES_COUNT + 2, allKeys.size());
+//
+//                // Checking that keys information has been filled correctly.
+//                for (Key schemaKey : allKeys) {
+//                    assertFalse(schemaKey.isVisible());
+//                    assertNull(schemaKey.getId());
+//                    assertEquals(schemaKey.getFromTableCompleteName(), schemaKey.getFromSchemaName() + "." + schemaKey.getFromTableSimpleName());
+//                    assertEquals(schemaKey.getTargetTableCompleteName(), schemaKey.getTargetSchemaName() + "." + schemaKey.getTargetTableSimpleName());
+//                    assertTrue(schemaKey.getKeyColumns().size() >= 1);
+//                    for (KeyColumn keyColumn : schemaKey.getKeyColumns()) {
+//                        assertNotNull(keyColumn.getFromColumn());
+//                        assertNotNull(keyColumn.getTargetColumn());
+//                    }
+//                }
                 /////////////////////////////////////
                 //         ADDING A TABLE          //
                 /////////////////////////////////////
@@ -352,34 +364,18 @@ public class TestAll {
                 Table sch0table1 = sch0.addChild("table1");
                 assertEquals(2, sch0.getChildren().size());
 
-                assertTrue(sch0table0.getVisibleFromKeys().isEmpty());
-                assertTrue(sch0table0.getVisibleTargetKeys().isEmpty());
-                assertTrue(sch0table1.getVisibleFromKeys().isEmpty());
-                assertTrue(sch0table1.getVisibleTargetKeys().isEmpty());
-
+                assertTrue(tapSchema.getVisibileKeys().isEmpty());
                 sch0table1.addChild("table0_id");
-                // Now sch0table0.getVisibleTargetKeys() and sch0table1.getVisibleFromKeys()
-                // have to return the same Key object with id = 1
-
-                assertTrue(sch0table0.getVisibleFromKeys().isEmpty());
-                assertEquals(1, sch0table0.getVisibleTargetKeys().size());
-                assertEquals(1, sch0table1.getVisibleFromKeys().size());
-                assertTrue(sch0table1.getVisibleTargetKeys().isEmpty());
+                assertEquals(1, tapSchema.getVisibileKeys());
 
                 // Check if key and its columns have been properly initialized
-                Key sch0table0TargetKey = sch0table0.getVisibleTargetKeys().get(0);
-                Key sch0table1TargetKey = sch0table1.getVisibleFromKeys().get(0);
-                checkKey(sch0table0TargetKey, "sch0.table1", "table0_id", "sch0.table0", "id", true);
-                assertEquals("1", sch0table0TargetKey.getId());
-                assertEquals(sch0table0TargetKey, sch0table1TargetKey);
+                Key k1 = tapSchema.getVisibileKeys().get(0);
+                checkKey(k1, "sch0.table1", "table0_id", "sch0.table0", "id", true);
 
                 // Removing sch0.table1
-                assertEquals(1, sch0table0.getVisibleTargetKeys().size()); // sch0.table1.table0_id -> sch0.table0.id
                 sch0.removeChild("table1");
                 assertEquals(1, sch0.getAddedChildren().size());
-                assertTrue(sch0table0.getVisibleFromKeys().isEmpty());
-                assertTrue(sch0table0.getVisibleTargetKeys().isEmpty());
-                assertFalse(sch0table0TargetKey.isVisible());
+                assertTrue(tapSchema.getVisibileKeys().isEmpty());
 
                 //
                 // CASE 2: Foreign key between two tables in different schemas.
@@ -387,8 +383,8 @@ public class TestAll {
                 //
                 // Adding sch1
                 Schema sch1 = tapSchema.addChild("sch1");
-                allKeys = ((TapSchemaImpl) tapSchema).getAllKeys();
-                assertEquals(5, allKeys.size());
+//                allKeys = ((TapSchema) tapSchema).getAllKeys();
+//                assertEquals(5, allKeys.size());
 
                 // Adding sch1.table0
                 Table sch1table0 = sch1.addChild("table0");
@@ -397,113 +393,105 @@ public class TestAll {
                 sch1table0.addChild("sch0table0id"); // sch1.table0.sch0table0id -> sch0.table0.it obtains keyId = "1"
                 sch0table0.addChild("sch1table0id");// sch0.table0.sch1table0id -> sch1.table0.it obtains keyId = "2"
 
-                assertEquals(0, sch0table1.getVisibleFromKeys().size());
-                assertEquals(1, sch0table0.getVisibleFromKeys().size());
-                assertEquals(1, sch0table0.getVisibleTargetKeys().size());
-                assertEquals(1, sch1table0.getVisibleFromKeys().size());
-                assertEquals(1, sch1table0.getVisibleTargetKeys().size());
-
-                for (Key key : allKeys) {
-                    if (key.getId() == null) {
-                        assertFalse(key.isVisible());
-                    } else {
-                        switch (key.getId()) {
-                            case "1":
-                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", false);
-                                break;
-                            case "2":
-                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
-                                break;
-                            case "3":
-                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
-                                break;
-                        }
-                    }
-                }
-
-                assertTrue(allKeysHaveDifferentId(tapSchema));
-
+//                assertEquals(0, sch0table1.getVisibleFromKeys().size());
+//                assertEquals(1, sch0table0.getVisibleFromKeys().size());
+//                assertEquals(1, sch0table0.getVisibleTargetKeys().size());
+//                assertEquals(1, sch1table0.getVisibleFromKeys().size());
+//                assertEquals(1, sch1table0.getVisibleTargetKeys().size());
+//                for (Key key : allKeys) {
+//                    if (key.getId() == null) {
+//                        assertFalse(key.isVisible());
+//                    } else {
+//                        switch (key.getId()) {
+//                            case "1":
+//                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", false);
+//                                break;
+//                            case "2":
+//                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
+//                                break;
+//                            case "3":
+//                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
+//                                break;
+//                        }
+//                    }
+//                }
+//                assertTrue(allKeysHaveDifferentId(tapSchema));
                 // Removing sch1
                 tapSchema.removeChild("sch1");
                 assertEquals(Status.REMOVED_NOT_PERSISTED, sch1.getStatus());
-                assertTrue(sch0table0.getVisibleTargetKeys().isEmpty());
+//                assertTrue(sch0table0.getVisibleTargetKeys().isEmpty());
 
                 // Case 2B: Re-adding sch1
                 // sch1.table0 has not been removed from its schema, so the keys
                 // should be re-added.
                 tapSchema.addChild("sch1");
                 assertEquals(Status.ADDED_NOT_PERSISTED, sch1.getStatus());
-                assertEquals(1, sch0table0.getVisibleTargetKeys().size());
-                assertEquals(1, sch1table0.getVisibleFromKeys().size());
-
-                for (Key key : allKeys) {
-                    if (key.getId() == null) {
-                        assertFalse(key.isVisible());
-                    } else {
-                        switch (key.getId()) {
-                            case "1":
-                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", false);
-                                break;
-                            case "2":
-                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
-                                break;
-                            case "3":
-                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
-                                break;
-                        }
-                    }
-                }
-
+//                assertEquals(1, sch0table0.getVisibleTargetKeys().size());
+//                assertEquals(1, sch1table0.getVisibleFromKeys().size());
+
+//                for (Key key : allKeys) {
+//                    if (key.getId() == null) {
+//                        assertFalse(key.isVisible());
+//                    } else {
+//                        switch (key.getId()) {
+//                            case "1":
+//                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", false);
+//                                break;
+//                            case "2":
+//                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
+//                                break;
+//                            case "3":
+//                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
+//                                break;
+//                        }
+//                    }
+//                }
                 //
                 // CASE 3: foreign key with multiple columns
                 //
                 Table table_x = sch0.addChild("table_x");
                 Table table_y = sch0.addChild("table_y");
 
-                assertTrue(table_x.getVisibleFromKeys().isEmpty());
-                assertTrue(table_x.getVisibleTargetKeys().isEmpty());
-                assertTrue(table_y.getVisibleFromKeys().isEmpty());
-                assertTrue(table_y.getVisibleTargetKeys().isEmpty());
-
+//                assertTrue(table_x.getVisibleFromKeys().isEmpty());
+//                assertTrue(table_x.getVisibleTargetKeys().isEmpty());
+//                assertTrue(table_y.getVisibleFromKeys().isEmpty());
+//                assertTrue(table_y.getVisibleTargetKeys().isEmpty());
                 table_x.addChild("idx1");
                 table_x.addChild("idx2");
                 table_y.addChild("idy1");
 
-                assertTrue(table_x.getVisibleFromKeys().isEmpty());
-                assertTrue(table_x.getVisibleTargetKeys().isEmpty());
-                assertTrue(table_y.getVisibleFromKeys().isEmpty());
-                assertTrue(table_y.getVisibleTargetKeys().isEmpty());
-
+//                assertTrue(table_x.getVisibleFromKeys().isEmpty());
+//                assertTrue(table_x.getVisibleTargetKeys().isEmpty());
+//                assertTrue(table_y.getVisibleFromKeys().isEmpty());
+//                assertTrue(table_y.getVisibleTargetKeys().isEmpty());
                 table_y.addChild("idy2");
 
-                assertEquals(1, table_y.getVisibleFromKeys().size());
-                assertEquals(1, table_x.getVisibleTargetKeys().size());
-                assertTrue(table_x.getVisibleFromKeys().isEmpty());
-                assertTrue(table_y.getVisibleTargetKeys().isEmpty());
-
-                for (Key key : allKeys) {
-                    if (key.getId() == null) {
-                        assertFalse(key.isVisible());
-                    } else {
-                        switch (key.getId()) {
-                            case "1":
-                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", false);
-                                break;
-                            case "2":
-                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
-                                break;
-                            case "3":
-                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
-                                break;
-                            case "4":
-                                checkKey(key, "sch0.table_y", new String[]{"idy1", "idy2"}, "sch0.table_x", new String[]{"idx1", "idx2"}, true);
-                                break;
-                        }
-                    }
-                }
-
-                assertTrue(allKeysHaveDifferentId(tapSchema));
-
+//                assertEquals(1, table_y.getVisibleFromKeys().size());
+//                assertEquals(1, table_x.getVisibleTargetKeys().size());
+//                assertTrue(table_x.getVisibleFromKeys().isEmpty());
+//                assertTrue(table_y.getVisibleTargetKeys().isEmpty());
+//                for (Key key : allKeys) {
+//                    if (key.getId() == null) {
+//                        assertFalse(key.isVisible());
+//                    } else {
+//                        switch (key.getId()) {
+//                            case "1":
+//                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", false);
+//                                break;
+//                            case "2":
+//                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
+//                                break;
+//                            case "3":
+//                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
+//                                break;
+//                            case "4":
+//                                checkKey(key, "sch0.table_y", new String[]{"idy1", "idy2"}, "sch0.table_x", new String[]{"idx1", "idx2"}, true);
+//                                break;
+//                        }
+//                    }
+//                }
+//
+//                assertTrue(allKeysHaveDifferentId(tapSchema));
                 /////////////////////////////////////
                 //              SAVE               //
                 /////////////////////////////////////
@@ -512,31 +500,30 @@ public class TestAll {
                 Table sch0table2 = sch0.addChild("table2");
                 sch0table2.addChild("table1_id");
 
-                for (Key key : allKeys) {
-                    if (key.getId() == null) {
-                        assertFalse(key.isVisible());
-                    } else {
-                        switch (key.getId()) {
-                            case "1":
-                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", true);
-                                break;
-                            case "2":
-                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
-                                break;
-                            case "3":
-                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
-                                break;
-                            case "4":
-                                checkKey(key, "sch0.table_y", new String[]{"idy1", "idy2"}, "sch0.table_x", new String[]{"idx1", "idx2"}, true);
-                                break;
-                            case "5":
-                                checkKey(key, "sch0.table2", "table1_id", "sch0.table1", "id", true);
-                                break;
-                        }
-                    }
-                }
-                assertTrue(allKeysHaveDifferentId(tapSchema));
-
+//                for (Key key : allKeys) {
+//                    if (key.getId() == null) {
+//                        assertFalse(key.isVisible());
+//                    } else {
+//                        switch (key.getId()) {
+//                            case "1":
+//                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", true);
+//                                break;
+//                            case "2":
+//                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
+//                                break;
+//                            case "3":
+//                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
+//                                break;
+//                            case "4":
+//                                checkKey(key, "sch0.table_y", new String[]{"idy1", "idy2"}, "sch0.table_x", new String[]{"idx1", "idx2"}, true);
+//                                break;
+//                            case "5":
+//                                checkKey(key, "sch0.table2", "table1_id", "sch0.table1", "id", true);
+//                                break;
+//                        }
+//                    }
+//                }
+//                assertTrue(allKeysHaveDifferentId(tapSchema));
                 UpdateOperations operations = new UpdateOperations(tapSchema);
                 assertEquals(2, operations.getSchemasToAdd().size());
                 assertEquals(6, operations.getTablesToAdd().size());
@@ -545,13 +532,13 @@ public class TestAll {
 
                 tapSchema.save();
                 assertFalse(new UpdateOperations(tapSchema).getHasOperations());
-                assertTrue(allKeysHaveDifferentId(tapSchema));
+//                assertTrue(allKeysHaveDifferentId(tapSchema));
 
                 // reloading
                 log.debug("----- Reloading saved TAP_SCHEMA -----");
-                tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, "test_tap_schema", true);
-                allKeys = ((TapSchemaImpl) tapSchema).getAllKeys();
-                assertTrue(allKeysHaveDifferentId(tapSchema));
+//                tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, "test_tap_schema", true);
+//                allKeys = ((TapSchema) tapSchema).getAllKeys();
+//                assertTrue(allKeysHaveDifferentId(tapSchema));
                 log.debug(tapSchema.toString());
 
                 assertNotNull(sch0 = tapSchema.getChild("sch0", Status.ADDED_PERSISTED));
@@ -574,48 +561,47 @@ public class TestAll {
                 assertNotNull(sch1table0.getChild("id", Status.ADDED_PERSISTED));
                 assertNotNull(sch1table0.getChild("sch0table0id", Status.ADDED_PERSISTED));
 
-                for (Key key : allKeys) {
-                    if (key.getId() == null) {
-                        assertFalse(key.isVisible());
-                    } else {
-                        switch (key.getId()) {
-                            case "1":
-                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", true);
-                                break;
-                            case "2":
-                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
-                                break;
-                            case "3":
-                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
-                                break;
-                            case "4":
-                                checkKey(key, "sch0.table_y", new String[]{"idy1", "idy2"}, "sch0.table_x", new String[]{"idx1", "idx2"}, true);
-                                break;
-                            case "5":
-                                checkKey(key, "sch0.table2", "table1_id", "sch0.table1", "id", true);
-                                break;
-                        }
-                    }
-                }
-
-                List<Key> sch0table1FromKeys = sch0table1.getVisibleFromKeys();
-                assertEquals(1, sch0table1FromKeys.size());
-                assertEquals(1, sch0table1.getVisibleTargetKeys().size());
-
+//                for (Key key : allKeys) {
+//                    if (key.getId() == null) {
+//                        assertFalse(key.isVisible());
+//                    } else {
+//                        switch (key.getId()) {
+//                            case "1":
+//                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", true);
+//                                break;
+//                            case "2":
+//                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
+//                                break;
+//                            case "3":
+//                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
+//                                break;
+//                            case "4":
+//                                checkKey(key, "sch0.table_y", new String[]{"idy1", "idy2"}, "sch0.table_x", new String[]{"idx1", "idx2"}, true);
+//                                break;
+//                            case "5":
+//                                checkKey(key, "sch0.table2", "table1_id", "sch0.table1", "id", true);
+//                                break;
+//                        }
+//                    }
+//                }
+//                List<Key> sch0table1FromKeys = sch0table1.getVisibleFromKeys();
+//                assertEquals(1, sch0table1FromKeys.size());
+//                assertEquals(1, sch0table1.getVisibleTargetKeys().size());
+//
                 sch0.removeChild("table1");
-                assertEquals(0, sch0table1.getVisibleFromKeys().size());
-
-                for (Key key : allKeys) {
-                    if (key.getId() == null) {
-                        assertFalse(key.isVisible());
-                    } else {
-                        switch (key.getId()) {
-                            case "1":
-                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", false);
-                                break;
-                        }
-                    }
-                }
+//                assertEquals(0, sch0table1.getVisibleFromKeys().size());
+//
+//                for (Key key : allKeys) {
+//                    if (key.getId() == null) {
+//                        assertFalse(key.isVisible());
+//                    } else {
+//                        switch (key.getId()) {
+//                            case "1":
+//                                checkKey(key, "sch0.table1", "table0_id", "sch0.table0", "id", false);
+//                                break;
+//                        }
+//                    }
+//                }
 
                 operations = new UpdateOperations(tapSchema);
                 assertFalse(operations.getHasEntitiesToUpdate());
@@ -631,8 +617,8 @@ public class TestAll {
 
                 // reloading
                 log.debug("----- Reloading saved TAP_SCHEMA -----");
-                tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, "test_tap_schema", true);
-                allKeys = ((TapSchemaImpl) tapSchema).getAllKeys();
+                tapSchema = new TapSchema("1.0", dbWrapper, "test_tap_schema", false);
+//                allKeys = ((TapSchema) tapSchema).getAllKeys();
                 log.debug(tapSchema.toString());
 
                 assertNotNull(sch0 = tapSchema.getChild("sch0", Status.ADDED_PERSISTED));
@@ -652,51 +638,48 @@ public class TestAll {
                 assertNotNull(sch1table0.getChild("id", Status.ADDED_PERSISTED));
                 assertNotNull(sch1table0.getChild("sch0table0id", Status.ADDED_PERSISTED));
 
-                for (Key key : allKeys) {
-                    if (key.getId() == null) {
-                        assertFalse(key.isVisible());
-                    } else {
-                        assertNotNull(key.getOriginalValue(Key.ID_KEY, String.class)); // for reloaded keys
-                        switch (key.getId()) {
-                            case "2":
-                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
-                                break;
-                            case "3":
-                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
-                                break;
-                            case "4":
-                                checkKey(key, "sch0.table_y", new String[]{"idy1", "idy2"}, "sch0.table_x", new String[]{"idx1", "idx2"}, true);
-                                break;
-                            case "5":
-                                checkKey(key, "sch0.table2", "table1_id", "sch0.table1", "id", true);
-                                break;
-                        }
-                    }
-                }
-
+//                for (Key key : allKeys) {
+//                    if (key.getId() == null) {
+//                        assertFalse(key.isVisible());
+//                    } else {
+//                        assertNotNull(key.getOriginalValue(Key.ID_KEY, String.class)); // for reloaded keys
+//                        switch (key.getId()) {
+//                            case "2":
+//                                checkKey(key, "sch1.table0", "sch0table0id", "sch0.table0", "id", true);
+//                                break;
+//                            case "3":
+//                                checkKey(key, "sch0.table0", "sch1table0id", "sch1.table0", "id", true);
+//                                break;
+//                            case "4":
+//                                checkKey(key, "sch0.table_y", new String[]{"idy1", "idy2"}, "sch0.table_x", new String[]{"idx1", "idx2"}, true);
+//                                break;
+//                            case "5":
+//                                checkKey(key, "sch0.table2", "table1_id", "sch0.table1", "id", true);
+//                                break;
+//                        }
+//                    }
+//                }
                 // Test adding ficitious key
-                sch0table0.addChild("value1");
-                sch0table2.addChild("value1");
-                ((TapSchemaImpl) tapSchema).addFictitiousKey(sch0table2, new String[]{"value1"}, sch0table0, new String[]{"value1"});
-                operations = new UpdateOperations(tapSchema);
-                assertEquals(1, operations.getKeysToAdd().size());
-                tapSchema.save();
-
-                tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, "test_tap_schema", true);
-
-                sch0table2 = tapSchema.getChild("sch0").getChild("table2");
-                assertEquals(1, sch0table2.getVisibleFromKeys().size());
-                checkKey(sch0table2.getVisibleFromKeys().get(0), "sch0.table2", "value1", "sch0.table0", "value1", true);
-
-                tapSchema.removeChild("sch1");
-                assertEquals(1, tapSchema.getChildren(Status.TO_REMOVE).size());
-                tapSchema.save();
-                assertEquals(0, tapSchema.getChildren(Status.TO_REMOVE).size());
-                
+//                sch0table0.addChild("value1");
+//                sch0table2.addChild("value1");
+//                ((TapSchema) tapSchema).addFictitiousKey(sch0table2, new String[]{"value1"}, sch0table0, new String[]{"value1"});
+//                operations = new UpdateOperations(tapSchema);
+//                assertEquals(1, operations.getKeysToAdd().size());
+//                tapSchema.save();
+//
+//                tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, "test_tap_schema", true);
+//
+//                sch0table2 = tapSchema.getChild("sch0").getChild("table2");
+//                assertEquals(1, sch0table2.getVisibleFromKeys().size());
+//                checkKey(sch0table2.getVisibleFromKeys().get(0), "sch0.table2", "value1", "sch0.table0", "value1", true);
+//
+//                tapSchema.removeChild("sch1");
+//                assertEquals(1, tapSchema.getChildren(Status.TO_REMOVE).size());
+//                tapSchema.save();
+//                assertEquals(0, tapSchema.getChildren(Status.TO_REMOVE).size());
                 /////////////////////////////////////
                 //       CONSISTENCY CHECKS        //
                 /////////////////////////////////////
-                
             }
         } catch (SQLException e) {
             throw e;
@@ -709,7 +692,7 @@ public class TestAll {
     public void testTapSchemaSerialization() throws Exception {
         for (DBWrapper dbWrapper : dbWrappers) {
             if (dbWrapper.getTapSchemaDatabaseType() == DatabaseType.MYSQL) { // currently "tng_TAP_SCHEMA" exists in a MySQL instance
-                TapSchema tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, "test_tap_schema", true);
+                TapSchema tapSchema = new TapSchema("1.0", dbWrapper, "test_tap_schema", true);
 
                 File temp = File.createTempFile("test_tap_schema", ".ser");
 
diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/ConsistencyChecksBean.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/ConsistencyChecksBean.java
index da1d551dfa6297b57c4e93ffcbf0ad9eb3536139..abf6235ed6b462e347aee700dc6821ee6e8157ea 100644
--- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/ConsistencyChecksBean.java
+++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/ConsistencyChecksBean.java
@@ -22,7 +22,7 @@
  */
 package it.inaf.ia2.tsm.webapp;
 
-import it.inaf.ia2.tsm.api.DBWrapper;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
 import it.inaf.ia2.tsm.api.contract.TapSchema;
 import java.io.Serializable;
 import java.sql.SQLException;
diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/CredentialsEditing.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/CredentialsEditing.java
index 96f374ff9501fb0839f3001e75f1abb82e27e7d4..282015300807286f5213d187078afa5db9d2a661 100644
--- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/CredentialsEditing.java
+++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/CredentialsEditing.java
@@ -22,8 +22,8 @@
  */
 package it.inaf.ia2.tsm.webapp;
 
-import it.inaf.ia2.tsm.api.Credentials;
-import it.inaf.ia2.tsm.api.DBWrapper;
+import it.inaf.ia2.tsm.datalayer.Credentials;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
 import java.io.IOException;
 import java.io.Serializable;
 import java.sql.SQLException;
diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SchemaSelectionBean.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SchemaSelectionBean.java
index aa6b84174e7234478e9e7386ab8b4a76f6d65ce4..75d09874d10c4e313c9715bbb58e0ef639bd5a63 100644
--- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SchemaSelectionBean.java
+++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SchemaSelectionBean.java
@@ -24,10 +24,10 @@ package it.inaf.ia2.tsm.webapp;
 
 import it.inaf.ia2.tsm.api.contract.TapSchema;
 import it.inaf.ia2.tsm.api.contract.TapSchemaVersion;
-import it.inaf.ia2.tsm.api.DBWrapper;
-import it.inaf.ia2.tsm.api.Dao;
-import it.inaf.ia2.tsm.api.DaoSchema;
-import it.inaf.ia2.tsm.api.TapSchemaFactory;
+import it.inaf.ia2.tsm.datalayer.DBWrapper;
+import it.inaf.ia2.tsm.Dao;
+import it.inaf.ia2.tsm.DaoSchema;
+import it.inaf.ia2.tsm.TapSchemaFactory;
 import java.io.Serializable;
 import java.sql.SQLException;
 import java.util.ArrayList;
diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SeparateCredentials.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SeparateCredentials.java
index 16675f476af21caf89772aebb0875dd38e6b3150..f3c072c55822c9217052a05e33b2429b1c13468e 100644
--- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SeparateCredentials.java
+++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SeparateCredentials.java
@@ -22,7 +22,7 @@
  */
 package it.inaf.ia2.tsm.webapp;
 
-import it.inaf.ia2.tsm.api.Credentials;
+import it.inaf.ia2.tsm.datalayer.Credentials;
 import java.io.Serializable;
 import javax.xml.bind.annotation.XmlElement;
 
diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java
index a61ddc719d55994b95654be69424ce88480a0b0e..5a8c7844e45748e7e9f5af6ad07e5afdc4f5aaeb 100644
--- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java
+++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java
@@ -26,15 +26,15 @@ import it.inaf.ia2.tsm.webapp.env.CustomPartialResponseWriter;
 import it.inaf.ia2.tsm.webapp.env.JSUpdateHandler;
 import it.inaf.ia2.tsm.api.contract.ChildEntity;
 import it.inaf.ia2.tsm.api.contract.Column;
-import it.inaf.ia2.tsm.api.contract.EntitiesContainer;
+import it.inaf.ia2.tsm.EntitiesContainer;
 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.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.UpdateOperations;
+import it.inaf.ia2.tsm.TapSchemaEntity;
+import it.inaf.ia2.tsm.UpdateOperations;
 import java.io.Serializable;
 import java.sql.SQLException;
 import java.util.ArrayList;
diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/xmlconfig/UserConfiguration.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/xmlconfig/UserConfiguration.java
index 6300479c59789894624cb8208d95a38297ac9d7c..b7e7592c317fad11e9d63772b2e3c44a50162ca2 100644
--- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/xmlconfig/UserConfiguration.java
+++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/xmlconfig/UserConfiguration.java
@@ -22,7 +22,7 @@
  */
 package it.inaf.ia2.tsm.webapp.xmlconfig;
 
-import it.inaf.ia2.tsm.api.Credentials;
+import it.inaf.ia2.tsm.datalayer.Credentials;
 import it.inaf.ia2.tsm.webapp.SeparateCredentials;
 import java.io.Serializable;
 import java.util.ArrayList;
diff --git a/TASMAN-webapp/src/test/java/TapSchemaMangerTest.java b/TASMAN-webapp/src/test/java/TapSchemaMangerTest.java
index 3b754d72be2668b4eb633543100c996c8092bea1..a96059736392611cda45ee53160cdf13e37ff429 100644
--- a/TASMAN-webapp/src/test/java/TapSchemaMangerTest.java
+++ b/TASMAN-webapp/src/test/java/TapSchemaMangerTest.java
@@ -21,7 +21,7 @@
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 import it.inaf.ia2.tsm.webapp.SeparateCredentials;
-import it.inaf.ia2.tsm.api.Credentials;
+import it.inaf.ia2.tsm.datalayer.Credentials;
 import it.inaf.ia2.tsm.webapp.xmlconfig.UserConfiguration;
 import java.io.StringReader;
 import java.io.StringWriter;