From 286172b4768961459170426bff039dd5bcfdcac4 Mon Sep 17 00:00:00 2001 From: Sonia Zorba Date: Tue, 16 Aug 2016 16:54:03 +0200 Subject: [PATCH] Manage all without JPA; move some application logic into the datalayer (in order to rename it as TapSchemaManagerAPI); started management of multiple versions of TAP_SCHEMA added documentation --- .../businesslayer/Column.java | 154 --- .../businesslayer/EntityWrapper.java | 111 -- .../businesslayer/EntityWrapperContainer.java | 30 - .../businesslayer/Schema.java | 178 ---- .../businesslayer/Status.java | 11 - .../tapschemamanager/businesslayer/Table.java | 224 ---- .../businesslayer/TapSchema.java | 171 ---- .../tapschemamanager/businesslayer/Util.java | 28 - .../webapp/CredentialsBean.java | 5 +- .../CredentialsConfiguration.java | 14 +- .../webapp/CredentialsConfigurationBean.java | 51 - .../{businesslayer => webapp}/ParsedUCD.java | 2 +- .../webapp/SchemaSelectionBean.java | 34 +- .../{businesslayer => webapp}/SearchUCD.java | 27 +- .../webapp/SearchUCDDialog.java | 6 +- .../SeparateCredentials.java | 2 +- .../webapp/TapSchemaEditingBean.java | 224 +++- .../{businesslayer => webapp}/UCDInfo.java | 2 +- .../UCDServiceException.java | 2 +- .../webapp/WebAppConfigurationBean.java | 64 ++ .../main/resources/META-INF/persistence.xml | 10 - .../src/main/resources/webapp.properties | 3 + .../src/main/webapp/WEB-INF/web.xml | 14 +- .../webapp/resources/js/edit-tapschema.js | 39 +- .../src/main/webapp/tapSchemaEditing.xhtml | 326 ++++-- .../src/test/java/TapSchemaMangerTest.java | 46 +- TapSchemaManagerDL/pom.xml | 5 - .../contract/ChildEntity.java | 28 + .../ia2/tapschemamanager/contract/Column.java | 116 +++ .../contract/EntitiesContainer.java | 65 ++ .../ia2/tapschemamanager/contract/Key.java | 81 ++ .../tapschemamanager/contract/KeyColumn.java | 39 + .../ia2/tapschemamanager/contract/Schema.java | 35 + .../ia2/tapschemamanager/contract/Status.java | 37 + .../ia2/tapschemamanager/contract/Table.java | 93 ++ .../tapschemamanager/contract/TapSchema.java | 37 + .../contract/TapSchemaEntity.java | 58 ++ .../contract/TapSchemaVersion.java | 21 + .../datalayer/ChildEntityImpl.java | 43 + .../datalayer/ColumnEntity.java | 263 ----- .../datalayer/ColumnImpl.java | 283 +++++ .../tapschemamanager/datalayer/DLUtil.java | 274 +++-- .../ia2/tapschemamanager/datalayer/Dao.java | 969 +++++++++--------- .../tapschemamanager/datalayer/DaoColumn.java | 225 ++++ .../tapschemamanager/datalayer/DaoKey.java | 465 +++++++++ .../tapschemamanager/datalayer/DaoSchema.java | 117 +++ .../tapschemamanager/datalayer/DaoTable.java | 169 +++ .../datalayer/EditableProperty.java | 66 ++ .../datalayer/EntityProperty.java | 20 + .../datalayer/EntityPropertyInfo.java | 183 ++++ .../datalayer/FixedEntityProperty.java | 33 + .../InconsistentTapSchemaException.java | 14 + .../datalayer/InsertQueryBuilder.java | 76 ++ .../datalayer/KeyColumnEntity.java | 114 --- .../datalayer/KeyColumnImpl.java | 98 ++ .../tapschemamanager/datalayer/KeyEntity.java | 250 ----- .../tapschemamanager/datalayer/KeyImpl.java | 226 ++++ .../datalayer/SchemaEntity.java | 139 --- .../datalayer/SchemaImpl.java | 268 +++++ .../datalayer/SelectQueryBuilder.java | 88 ++ .../datalayer/TableEntity.java | 242 ----- .../tapschemamanager/datalayer/TableImpl.java | 315 ++++++ .../datalayer/TapSchemaEntity.java | 21 - .../datalayer/TapSchemaEntityImpl.java | 122 +++ .../datalayer/TapSchemaFactory.java | 21 + .../datalayer/TapSchemaHandler.java | 486 --------- .../datalayer/TapSchemaImpl.java | 385 +++++++ .../datalayer/UpdateOperations.java | 226 ++++ .../datalayer/UpdateQueryBuilder.java | 74 ++ .../tapschemamanager/datalayer/TestAll.java | 683 ++++++++++++ .../datalayer/test/TestQuery.java | 551 ---------- 71 files changed, 6087 insertions(+), 3815 deletions(-) delete mode 100644 TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Column.java delete mode 100644 TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/EntityWrapper.java delete mode 100644 TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/EntityWrapperContainer.java delete mode 100644 TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Schema.java delete mode 100644 TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Status.java delete mode 100644 TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Table.java delete mode 100644 TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/TapSchema.java delete mode 100644 TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Util.java rename TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/{businesslayer => webapp}/CredentialsConfiguration.java (78%) delete mode 100644 TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/CredentialsConfigurationBean.java rename TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/{businesslayer => webapp}/ParsedUCD.java (97%) rename TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/{businesslayer => webapp}/SearchUCD.java (89%) rename TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/{businesslayer => webapp}/SeparateCredentials.java (95%) rename TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/{businesslayer => webapp}/UCDInfo.java (93%) rename TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/{businesslayer => webapp}/UCDServiceException.java (82%) create mode 100644 TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/WebAppConfigurationBean.java delete mode 100644 TapSchemaManager/src/main/resources/META-INF/persistence.xml create mode 100644 TapSchemaManager/src/main/resources/webapp.properties create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/ChildEntity.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Column.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/EntitiesContainer.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Key.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/KeyColumn.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Schema.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Status.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Table.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchema.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchemaEntity.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchemaVersion.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ChildEntityImpl.java delete mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ColumnEntity.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ColumnImpl.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoColumn.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoKey.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoSchema.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoTable.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EditableProperty.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EntityProperty.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EntityPropertyInfo.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/FixedEntityProperty.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/InconsistentTapSchemaException.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/InsertQueryBuilder.java delete mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyColumnEntity.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyColumnImpl.java delete mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyEntity.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyImpl.java delete mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SchemaEntity.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SchemaImpl.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SelectQueryBuilder.java delete mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TableEntity.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TableImpl.java delete mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaEntity.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaEntityImpl.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaFactory.java delete mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaHandler.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaImpl.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/UpdateOperations.java create mode 100644 TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/UpdateQueryBuilder.java create mode 100644 TapSchemaManagerDL/src/test/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TestAll.java delete mode 100644 TapSchemaManagerDL/src/test/java/it/inaf/oats/ia2/tapschemamanager/datalayer/test/TestQuery.java diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Column.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Column.java deleted file mode 100644 index 07a9bc6..0000000 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Column.java +++ /dev/null @@ -1,154 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; - -import it.inaf.oats.ia2.tapschemamanager.datalayer.ColumnEntity; -import it.inaf.oats.ia2.tapschemamanager.datalayer.TapSchemaHandler; -import java.io.Serializable; - -/** - * - * @author Sonia Zorba {@literal } - */ -public class Column extends EntityWrapper implements Serializable { - - private static final long serialVersionUID = 2835969352471501746L; - - public static final String UTYPE = "utype"; - public static final String UCD = "ucd"; - public static final String UNIT = "unit"; - public static final String DESCRIPTION = "description"; - public static final String STD = "std"; - public static final String PRINCIPAL = "principal"; - - private final String datatype; - private final int size; - private final boolean primaryKey; - private final boolean indexed; - - private final String foreignKeyReference; - - private boolean hidden; - - public Column(TapSchemaHandler tapSchemaHandler, ColumnEntity columnEntity) { - super(columnEntity, UTYPE, UCD, UNIT, DESCRIPTION, STD, PRINCIPAL); - hidden = true; - this.primaryKey = columnEntity.isPrimaryKey(); - this.datatype = columnEntity.getDatatype(); - this.size = columnEntity.getSize(); - this.indexed = columnEntity.getIndexed() == 1; - - addValue(UTYPE, columnEntity.getUtype()); - addValue(UCD, columnEntity.getUcd()); - addValue(UNIT, columnEntity.getUnit()); - addValue(DESCRIPTION, columnEntity.getDescription()); - addValue(STD, columnEntity.getStd() + ""); - addValue(PRINCIPAL, columnEntity.getPrincipal() + ""); - - String tableName = columnEntity.getFullTableName(); - String schemaName = columnEntity.getTable().getSchemaName(); - foreignKeyReference = tapSchemaHandler.getForeignKeyReference(schemaName, tableName, columnEntity.getName()); - } - - @Override - protected void afterSetValue(String key, String value) { - ColumnEntity columnEntity = getEntity(); - switch (key) { - case UTYPE: - columnEntity.setUtype(value); - break; - case UCD: - columnEntity.setUcd(value); - break; - case UNIT: - columnEntity.setUnit(value); - break; - case DESCRIPTION: - columnEntity.setDescription(value); - break; - case STD: - columnEntity.setStd(Integer.parseInt(value)); - break; - case PRINCIPAL: - columnEntity.setPrincipal(Integer.parseInt(value)); - break; - } - } - - public boolean isHidden() { - return hidden; - } - - public void setHidden(boolean hidden) { - this.hidden = hidden; - if (hidden) { - undoChanges(); - } - } - - public String getDatatype() { - return datatype; - } - - public int getSize() { - return size; - } - - public boolean isPrimaryKey() { - return primaryKey; - } - - public String getForeignKey() { - return foreignKeyReference; - } - - public boolean isIndexed() { - return indexed; - } - - public boolean getStd() { - return getValue(STD).equals("1"); - } - - public void setStd(boolean std) { - setValue(STD, std ? "1" : "0"); - } - - public boolean getPrincipal() { - return getValue(PRINCIPAL).equals("1"); - } - - public void setPrincipal(boolean principal) { - setValue(PRINCIPAL, principal ? "1" : "0"); - } - - public String getUcd() { - return getValue(UCD); - } - - public void setUcd(String ucd) { - setValue(UCD, ucd); - } - - public String getUtype() { - return getValue(UTYPE); - } - - public void setUtype(String utype) { - setValue(UTYPE, utype); - } - - public String getUnit() { - return getValue(UNIT); - } - - public void setUnit(String unit) { - setValue(UNIT, unit); - } - - public String getDescription() { - return getValue(DESCRIPTION); - } - - public void setDescription(String description) { - setValue(DESCRIPTION, description); - } -} diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/EntityWrapper.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/EntityWrapper.java deleted file mode 100644 index 139758f..0000000 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/EntityWrapper.java +++ /dev/null @@ -1,111 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; - -import it.inaf.oats.ia2.tapschemamanager.datalayer.TapSchemaEntity; -import java.io.Serializable; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * - * @author Sonia Zorba {@literal } - * @param - */ -public abstract class EntityWrapper implements Serializable { - - private static final long serialVersionUID = -8399058826120891216L; - - private final T entity; - private final Map originalValues; - private final Map editedValues; - private final List supportedKeys; - private Status status; - - public EntityWrapper(T entity, String... supportedKeys) { - originalValues = new HashMap<>(); - editedValues = new HashMap<>(); - this.entity = entity; - this.supportedKeys = Arrays.asList(supportedKeys); - } - - public List getSupportedKeys() { - return supportedKeys; - } - - protected final void addValue(String key, String value) { - originalValues.put(key, value); - } - - public final String getValue(String key) { - String editedValue = editedValues.get(key); - if (editedValue != null) { - return editedValue; - } - return originalValues.get(key); - } - - protected abstract void afterSetValue(String key, String value); - - public final void setValue(String key, String value) { - if (originalValues.get(key) == null && value.isEmpty()) { - value = null; - } - editedValues.put(key, value); - afterSetValue(key, value); - } - - public final boolean isChanged(String key) { - String originalValue = originalValues.get(key); - String editedValue = editedValues.get(key); - if (originalValue == null) { - return editedValue != null; - } else { - if (editedValue != null && !originalValue.equals(editedValue)) { - return true; - } - } - return false; - } - - public final boolean isChanged() { - for (String key : editedValues.keySet()) { - if (isChanged(key)) { - return true; - } - } - return false; - } - - public Status getStatus() { - return status; - } - - public void setStatus(Status status) { - this.status = status; - } - - public T getEntity() { - return entity; - } - - public String getName() { - return entity.getName(); - } - - protected void setPersisted() { - setStatus(Status.ADDED_PERSISTED); - for (String key : editedValues.keySet()) { - originalValues.put(key, editedValues.get(key)); - } - editedValues.clear(); - } - - protected void undoChanges() { - editedValues.clear(); - } - - public boolean isToRemove() { - return status == Status.TO_REMOVE; - } -} diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/EntityWrapperContainer.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/EntityWrapperContainer.java deleted file mode 100644 index c191fe5..0000000 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/EntityWrapperContainer.java +++ /dev/null @@ -1,30 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; - -import java.sql.SQLException; -import java.util.List; - -/** - * - * @author Sonia Zorba {@literal } - * @param - */ -public interface EntityWrapperContainer { - - public T getEntity(String name); - - public T getSelectedEntity(); - - public void selectEntity(String entityName); - - public List getEntitiesNames(); - - public List getAddables(); - - public List getAllEntityWrappers(); - - public void addEntityWrapper(String name) throws SQLException; - - public void removeEntityWrapper(String name); - - public boolean hasChildren(); -} diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Schema.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Schema.java deleted file mode 100644 index 996227f..0000000 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Schema.java +++ /dev/null @@ -1,178 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; - -import it.inaf.oats.ia2.tapschemamanager.datalayer.SchemaEntity; -import it.inaf.oats.ia2.tapschemamanager.datalayer.TableEntity; -import it.inaf.oats.ia2.tapschemamanager.datalayer.TapSchemaHandler; -import java.io.Serializable; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -/** - * - * @author Sonia Zorba {@literal } - */ -public class Schema extends EntityWrapper implements EntityWrapperContainer, Serializable { - - private static final long serialVersionUID = -1564499229970697945L; - - public static final String UTYPE = "utype"; - public static final String DESCRIPTION = "description"; - - private final TapSchemaHandler tapSchemaHandler; - - private String selectedTable; - private final Map tables; - - public Schema(TapSchemaHandler tapSchemaHandler, SchemaEntity schemaEntity) throws SQLException { - super(schemaEntity, UTYPE, DESCRIPTION); - - this.tapSchemaHandler = tapSchemaHandler; - - addValue(UTYPE, schemaEntity.getUtype()); - addValue(DESCRIPTION, schemaEntity.getDescription()); - - tables = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - - for (TableEntity tableEntity : schemaEntity.getTables()) { - String tableName = tableEntity.getShortTableName(); - tables.put(tableName, new Table(tapSchemaHandler, getName(), tableName, tableEntity)); - } - - setStatus(Status.ADDED_PERSISTED); - } - - @Override - protected void afterSetValue(String key, String value) { - SchemaEntity schemaEntity = getEntity(); - switch (key) { - case UTYPE: - schemaEntity.setUtype(value); - break; - case DESCRIPTION: - schemaEntity.setDescription(value); - break; - } - } - - @Override - public List getEntitiesNames() { - return Util.setToList(tables.keySet()); - } - - @Override - public List getAddables() { - return Util.getAddables(tapSchemaHandler.getAllTables(getName()), tables.keySet()); - } - - @Override - public void addEntityWrapper(String name) throws SQLException { - Table table = tables.get(name); - if (table == null) { - // Add new - TableEntity tableEntity = tapSchemaHandler.getNewTable(getName(), name); - table = new Table(tapSchemaHandler, getName(), name, tableEntity); - tables.put(name, table); - table.setStatus(Status.ADDED_NOT_PERSISTED); - } else { - // Undo remove - table.setStatus(Status.ADDED_PERSISTED); - } - selectedTable = name; - - tapSchemaHandler.addTable(getName(), table.getEntity()); - } - - @Override - public void removeEntityWrapper(String name) { - String previousTable = null; - boolean changeSelection = false; - TableEntity tableEntity = null; - for (Table table : tables.values()) { - if (table.getName().equals(name)) { - if (table.getStatus() == Status.ADDED_NOT_PERSISTED) { - tables.remove(name); - changeSelection = true; - } else { - table.setStatus(Status.TO_REMOVE); - } - tableEntity = table.getEntity(); - break; - } - previousTable = table.getName(); - } - - if (changeSelection) { - if (tables.isEmpty()) { - selectedTable = null; - } else { - selectedTable = previousTable == null ? tables.keySet().iterator().next() : previousTable; - } - } - - tapSchemaHandler.removeTable(getEntity(), tableEntity); - } - - @Override - public Table getEntity(String name) { - return tables.get(name); - } - - @Override - protected void setPersisted() { - super.setPersisted(); - Iterator
iterator = tables.values().iterator(); - while (iterator.hasNext()) { - Table table = iterator.next(); - if (table.getStatus() == Status.TO_REMOVE) { - iterator.remove(); - } else { - table.setPersisted(); - } - } - } - - @Override - public boolean hasChildren() { - return !tables.isEmpty(); - } - - @Override - public List
getAllEntityWrappers() { - return new ArrayList(tables.values()); - } - - @Override - public void selectEntity(String entityName) { - selectedTable = entityName; - Table table = tables.get(entityName); - List columns = table.getEntitiesNames(); - if (!columns.isEmpty()) { - table.selectEntity(columns.get(0)); - } - } - - @Override - public Table getSelectedEntity() { - return selectedTable == null ? null : tables.get(selectedTable); - } - - public String getUtype() { - return getValue(UTYPE); - } - - public void setUtype(String utype) { - setValue(UTYPE, utype); - } - - public String getDescription() { - return getValue(DESCRIPTION); - } - - public void setDescription(String description) { - setValue(DESCRIPTION, description); - } -} diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Status.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Status.java deleted file mode 100644 index e04e7a6..0000000 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Status.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; - -/** - * - * @author Sonia Zorba {@literal } - */ -public enum Status { - ADDED_PERSISTED, - ADDED_NOT_PERSISTED, - TO_REMOVE -} diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Table.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Table.java deleted file mode 100644 index 3fcf9e6..0000000 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Table.java +++ /dev/null @@ -1,224 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; - -import it.inaf.oats.ia2.tapschemamanager.datalayer.ColumnEntity; -import it.inaf.oats.ia2.tapschemamanager.datalayer.DLUtil; -import it.inaf.oats.ia2.tapschemamanager.datalayer.TableEntity; -import it.inaf.oats.ia2.tapschemamanager.datalayer.TapSchemaHandler; -import java.io.Serializable; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -/** - * - * @author Sonia Zorba {@literal } - */ -public class Table extends EntityWrapper implements EntityWrapperContainer, Serializable { - - private static final long serialVersionUID = -9011881651746083862L; - - public static final String UTYPE = "utype"; - public static final String DESCRIPTION = "description"; - - private String selectedColumn; - private final Map columns; - - private final TapSchemaHandler tapSchemaHandler; - private final String schemaName; - private final String tableName; - - public Table(TapSchemaHandler tapSchemaHandler, String schemaName, String tableName, TableEntity tableEntity) throws SQLException { - super(tableEntity, UTYPE, DESCRIPTION); - - addValue(UTYPE, tableEntity.getUtype()); - addValue(DESCRIPTION, tableEntity.getDescription()); - - this.tapSchemaHandler = tapSchemaHandler; - this.schemaName = schemaName; - this.tableName = tableName; - - // Load all ColumnEntity map - columns = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - List alreadyLoadedColumns = DLUtil.getEntitiesNames(tableEntity.getColumns()); - for (ColumnEntity columnEntity : tapSchemaHandler.getColumnEntities(schemaName, tableName)) { - Column column = new Column(tapSchemaHandler, columnEntity); - columns.put(columnEntity.getName(), column); - - if (alreadyLoadedColumns.contains(columnEntity.getName())) { - column.setHidden(false); - column.setStatus(Status.ADDED_PERSISTED); - } - } - - setStatus(Status.ADDED_PERSISTED); - } - - public String getSchemaName() { - return schemaName; - } - - public String getFullName() { - return getEntity().getName(); - } - - @Override - protected void afterSetValue(String key, String value) { - TableEntity tableEntity = getEntity(); - switch (key) { - case UTYPE: - tableEntity.setUtype(value); - break; - case DESCRIPTION: - tableEntity.setDescription(value); - break; - } - } - - @Override - public List getAddables() { - List addables = new ArrayList<>(); - for (Column column : columns.values()) { - if (column.isHidden()) { - addables.add(column.getName()); - } - } - return addables; - } - - @Override - public void addEntityWrapper(String name) throws SQLException { - Column column = columns.get(name); - if (column.isHidden()) { - // Add new - column.setStatus(Status.ADDED_NOT_PERSISTED); - column.setHidden(false); - } else { - // Undo remove - column.setStatus(Status.ADDED_PERSISTED); - } - selectedColumn = name; - - tapSchemaHandler.addColumn(getEntity(), column.getEntity()); - } - - @Override - public void removeEntityWrapper(String name) { - String previousColumn = null; - String followingColumn = null; - boolean columnFound = false; - boolean changeSelection = false; - - // loop on visible columns - for (String columnName : getEntitiesNames()) { - if (columnFound) { - followingColumn = columnName; - break; - } else { - if (columnName.equals(name)) { - Column column = columns.get(name); - if (column.getStatus() == Status.ADDED_NOT_PERSISTED) { - column.setHidden(true); - changeSelection = true; - } else { - column.setStatus(Status.TO_REMOVE); - } - columnFound = true; - } else { - previousColumn = columnName; - } - } - } - - if (changeSelection) { - if (previousColumn == null && followingColumn == null) { - selectedColumn = null; // empty column list - } else { - selectedColumn = followingColumn == null ? previousColumn : followingColumn; - } - } - - tapSchemaHandler.removeColumn(getEntity(), name); - } - - @Override - public Column getEntity(String name) { - return columns.get(name); - } - - @Override - public List getEntitiesNames() { - List columnsNames = new ArrayList<>(); - for (Column column : columns.values()) { - if (!column.isHidden()) { - columnsNames.add(column.getName()); - } - } - return columnsNames; - } - - @Override - protected void setPersisted() { - super.setPersisted(); - for (Column column : columns.values()) { - if (column.getStatus() == Status.TO_REMOVE) { - column.setHidden(true); - } else { - column.setPersisted(); - } - } - } - - @Override - public boolean hasChildren() { - for (Column column : columns.values()) { - if (!column.isHidden()) { - return true; - } - } - return false; - } - - @Override - public List getAllEntityWrappers() { - List list = new ArrayList<>(); - for (Column column : columns.values()) { - if (!column.isHidden()) { - list.add(column); - } - } - return list; - } - - @Override - public void selectEntity(String entityName) { - selectedColumn = entityName; - } - - @Override - public String getName() { - return tableName; - } - - @Override - public Column getSelectedEntity() { - return selectedColumn == null ? null : columns.get(selectedColumn); - } - - public String getUtype() { - return getValue(UTYPE); - } - - public void setUtype(String utype) { - setValue(UTYPE, utype); - } - - public String getDescription() { - return getValue(DESCRIPTION); - } - - public void setDescription(String description) { - setValue(DESCRIPTION, description); - } -} diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/TapSchema.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/TapSchema.java deleted file mode 100644 index eff528c..0000000 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/TapSchema.java +++ /dev/null @@ -1,171 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; - -import it.inaf.oats.ia2.tapschemamanager.datalayer.DBWrapper; -import it.inaf.oats.ia2.tapschemamanager.datalayer.SchemaEntity; -import it.inaf.oats.ia2.tapschemamanager.datalayer.TapSchemaHandler; -import java.io.Serializable; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -/** - * - * @author Sonia Zorba {@literal } - */ -public class TapSchema implements EntityWrapperContainer, Serializable { - - private static final long serialVersionUID = 7607955740953928897L; - - private final TapSchemaHandler tapSchemaHandler; - - private final String name; - - private String selectedSchema; - private final Map schemas; - - public TapSchema(DBWrapper dbWrapper, String tapSchemaName, boolean exists) throws SQLException { - this.name = tapSchemaName; - schemas = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - - this.tapSchemaHandler = new TapSchemaHandler(dbWrapper, tapSchemaName, exists); - - if (exists) { - for (SchemaEntity schemaEntity : tapSchemaHandler.getSchemas()) { - if (!schemaEntity.getName().equals(tapSchemaName)) { - Schema schema = new Schema(tapSchemaHandler, schemaEntity); - schemas.put(schema.getName(), schema); - } - } - if (!schemas.isEmpty()) { - selectEntity(schemas.keySet().iterator().next()); // select first schema - } - } - } - - public String getName() { - return name; - } - - public void save() throws SQLException { - tapSchemaHandler.save(); - - Iterator iterator = schemas.values().iterator(); - while (iterator.hasNext()) { - Schema schema = iterator.next(); - if (schema.getStatus() == Status.TO_REMOVE) { - iterator.remove(); - } else { - schema.setPersisted(); - } - } - } - - public Table getSelectedTable() { - Schema schema = getSelectedEntity(); - return schema == null ? null : schema.getSelectedEntity(); - } - - public Column getSelectedColumn() { - Table table = getSelectedTable(); - return table == null ? null : table.getSelectedEntity(); - } - - @Override - public List getAddables() { - List addables = Util.getAddables(tapSchemaHandler.getAllSchemas(), schemas.keySet()); - if (addables.contains(name)) { - addables.remove(name); - } - return addables; - } - - @Override - public void addEntityWrapper(String name) throws SQLException { - Schema schema = schemas.get(name); - SchemaEntity schemaEntity; - if (schema == null) { - // Add new - schemaEntity = tapSchemaHandler.getNewSchema(name); - schema = new Schema(tapSchemaHandler, schemaEntity); - schemas.put(name, schema); - schema.setStatus(Status.ADDED_NOT_PERSISTED); - } else { - schemaEntity = schema.getEntity(); - // Undo remove - schema.setStatus(Status.ADDED_PERSISTED); - } - selectedSchema = name; - - tapSchemaHandler.addSchema(schemaEntity); - } - - @Override - public void removeEntityWrapper(String name) { - String previousSchema = null; - boolean changeSelection = false; - for (Schema schema : schemas.values()) { - if (schema.getName().equals(name)) { - if (schema.getStatus() == Status.ADDED_NOT_PERSISTED) { - schemas.remove(name); - changeSelection = true; - } else { - schema.setStatus(Status.TO_REMOVE); - } - break; - } - previousSchema = schema.getName(); - } - - if (changeSelection) { - if (schemas.isEmpty()) { - selectedSchema = null; - } else { - selectedSchema = previousSchema == null ? schemas.keySet().iterator().next() : previousSchema; - } - } - - tapSchemaHandler.removeSchema(name); - } - - @Override - public Schema getEntity(String name) { - return schemas.get(name); - } - - @Override - public List getEntitiesNames() { - return Util.setToList(schemas.keySet()); - } - - @Override - public final void selectEntity(String entityName) { - selectedSchema = entityName; - Schema schema = schemas.get(entityName); - List tables = schema.getEntitiesNames(); - if (!tables.isEmpty()) { - schema.selectEntity(tables.get(0)); - } - } - - @Override - public boolean hasChildren() { - return !schemas.isEmpty(); - } - - @Override - public List getAllEntityWrappers() { - return new ArrayList(schemas.values()); - } - - @Override - public Schema getSelectedEntity() { - return selectedSchema == null ? null : schemas.get(selectedSchema); - } - - public TapSchemaHandler getTapSchemaHandler() { - return tapSchemaHandler; - } -} diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Util.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Util.java deleted file mode 100644 index 446a9e0..0000000 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/Util.java +++ /dev/null @@ -1,28 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * - * @author Sonia Zorba {@literal } - */ -class Util { - - protected static List getAddables(List allElements, Set addedElements) { - List addables = new ArrayList<>(); - for (String elementName : allElements) { - if (!addedElements.contains(elementName)) { - addables.add(elementName); - } - } - return addables; - } - - protected static List setToList(Set set) { - List list = new ArrayList<>(); - list.addAll(set); - return list; - } -} diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/CredentialsBean.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/CredentialsBean.java index 7b674f1..60aea08 100644 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/CredentialsBean.java +++ b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/CredentialsBean.java @@ -1,6 +1,5 @@ package it.inaf.oats.ia2.tapschemamanager.webapp; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.SeparateCredentials; import it.inaf.oats.ia2.tapschemamanager.datalayer.Credentials; import it.inaf.oats.ia2.tapschemamanager.datalayer.DBWrapper; import java.io.IOException; @@ -30,7 +29,7 @@ public class CredentialsBean implements Serializable { private static final Logger log = LoggerFactory.getLogger(CredentialsBean.class); @Inject - CredentialsConfigurationBean ccBean; + WebAppConfigurationBean ccBean; @Inject Conversation conversation; @@ -60,7 +59,7 @@ public class CredentialsBean implements Serializable { } public void login() { - if (adminPassword != null && adminPassword.equals(ccBean.getConfig().getPassword())) { + if (adminPassword != null && adminPassword.equals(ccBean.getPassword())) { loggedIn = true; } else { FacesContext.getCurrentInstance().addMessage("main:password", new FacesMessage("Invalid credentials")); diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/CredentialsConfiguration.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/CredentialsConfiguration.java similarity index 78% rename from TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/CredentialsConfiguration.java rename to TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/CredentialsConfiguration.java index 8da2b29..247669f 100644 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/CredentialsConfiguration.java +++ b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/CredentialsConfiguration.java @@ -1,9 +1,8 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; +package it.inaf.oats.ia2.tapschemamanager.webapp; import it.inaf.oats.ia2.tapschemamanager.datalayer.Credentials; import java.util.ArrayList; 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; @@ -15,8 +14,6 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "credentials-config") public class CredentialsConfiguration { - private String password; - private List credentialsInfo; public CredentialsConfiguration() { @@ -42,13 +39,4 @@ public class CredentialsConfiguration { private void setCredentialsInfo(List credentialsInfo) { this.credentialsInfo = credentialsInfo; } - - @XmlAttribute(name = "password") - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } } diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/CredentialsConfigurationBean.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/CredentialsConfigurationBean.java deleted file mode 100644 index 8a84632..0000000 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/CredentialsConfigurationBean.java +++ /dev/null @@ -1,51 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.webapp; - -import it.inaf.oats.ia2.tapschemamanager.businesslayer.CredentialsConfiguration; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import javax.annotation.PostConstruct; -import javax.enterprise.context.ApplicationScoped; -import javax.naming.InitialContext; -import javax.naming.NamingException; -import javax.xml.bind.JAXB; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - * @author Sonia Zorba {@literal } - */ -@ApplicationScoped -public class CredentialsConfigurationBean { - - private static final Logger log = LoggerFactory.getLogger(CredentialsConfigurationBean.class); - - private String credentialsConfigPath; - private CredentialsConfiguration cc; - - @PostConstruct - public void init() { - try { - InitialContext ic = new InitialContext(); - credentialsConfigPath = (String) ic.lookup("java:comp/env/CREDENTIALS_CONFIG_PATH"); - - log.debug("CREDENTIALS_CONFIG_PATH={}", credentialsConfigPath); - - cc = JAXB.unmarshal(new File(credentialsConfigPath), CredentialsConfiguration.class); - - } catch (NamingException e) { - throw new RuntimeException(e); - } - } - - public CredentialsConfiguration getConfig() { - return cc; - } - - public void updateConfigurationFile() throws IOException { - FileWriter fw = new FileWriter(credentialsConfigPath); - JAXB.marshal(cc, fw); - fw.close(); - } -} diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/ParsedUCD.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/ParsedUCD.java similarity index 97% rename from TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/ParsedUCD.java rename to TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/ParsedUCD.java index 62dc9e4..3c84037 100644 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/ParsedUCD.java +++ b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/ParsedUCD.java @@ -1,4 +1,4 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; +package it.inaf.oats.ia2.tapschemamanager.webapp; import ari.ucd.UCD; import ari.ucd.UCDParser; diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SchemaSelectionBean.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SchemaSelectionBean.java index a30e6e8..42a7727 100644 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SchemaSelectionBean.java +++ b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SchemaSelectionBean.java @@ -1,8 +1,11 @@ package it.inaf.oats.ia2.tapschemamanager.webapp; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchemaVersion; import it.inaf.oats.ia2.tapschemamanager.datalayer.DBWrapper; import it.inaf.oats.ia2.tapschemamanager.datalayer.Dao; +import it.inaf.oats.ia2.tapschemamanager.datalayer.DaoSchema; +import it.inaf.oats.ia2.tapschemamanager.datalayer.TapSchemaFactory; import java.io.Serializable; import java.sql.SQLException; import java.util.ArrayList; @@ -36,8 +39,6 @@ public class SchemaSelectionBean implements Serializable { @Inject TapSchemaEditingBean tapSchemaEditingBean; -// private Credentials sourceCredentials; -// private Credentials tapSchemaCredentials; private DBWrapper dbWrapper; private String selectedRadioOption; @@ -67,7 +68,7 @@ public class SchemaSelectionBean implements Serializable { // Loading all schemas of the source database try { - allSchemas = Dao.getAllSchemasNames(dbWrapper.getSourceDataSource(), dbWrapper.getSourceDatabaseType()); + allSchemas = DaoSchema.getAllSchemasNames(dbWrapper.getSourceDataSource(), dbWrapper.getSourceDatabaseType()); setSelectedSchemas(new ArrayList()); } catch (SQLException e) { throw new RuntimeException(e); @@ -75,7 +76,7 @@ public class SchemaSelectionBean implements Serializable { // Loading all schemas of the TAP_SCHEMA database try { - allTAPSchemas = Dao.getAllTAPSchemasNames(dbWrapper, Dao.getAllSchemasNames(dbWrapper.getTapSchemaDataSource(), dbWrapper.getTapSchemaDatabaseType())); + allTAPSchemas = Dao.getAllTAPSchemasNames(dbWrapper, DaoSchema.getAllSchemasNames(dbWrapper.getTapSchemaDataSource(), dbWrapper.getTapSchemaDatabaseType())); if (!allTAPSchemas.isEmpty()) { this.selectedTAPSchema = allTAPSchemas.get(0); @@ -147,7 +148,8 @@ public class SchemaSelectionBean implements Serializable { public String edit() { try { - return loadTapSchema(new TapSchema(dbWrapper, selectedTAPSchema, true)); + TapSchema tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1, dbWrapper, selectedTAPSchema, true); + return loadTapSchema(tapSchema); } catch (SQLException e) { throw new RuntimeException(e); } @@ -155,10 +157,7 @@ public class SchemaSelectionBean implements Serializable { public String create() { try { - TapSchema tapSchema = new TapSchema(dbWrapper, tapSchemaName, false); - for (String selectedSchema : selectedSchemas) { - tapSchema.addEntityWrapper(selectedSchema); - } + TapSchema tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1, dbWrapper, tapSchemaName, false); return loadTapSchema(tapSchema); } catch (SQLException e) { throw new RuntimeException(e); @@ -173,21 +172,6 @@ public class SchemaSelectionBean implements Serializable { this.tapSchemaName = tapSchemaName; } -// public Credentials getSourceCredentials() { -// return sourceCredentials; -// } -// -// public void setSourceCredentials(Credentials sourceCredentials) { -// this.sourceCredentials = sourceCredentials; -// } -// -// public Credentials getTapSchemaCredentials() { -// return tapSchemaCredentials; -// } -// -// public void setTapSchemaCredentials(Credentials tapSchemaCredentials) { -// this.tapSchemaCredentials = tapSchemaCredentials; -// } public DBWrapper getDbWrapper() { return dbWrapper; } diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/SearchUCD.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SearchUCD.java similarity index 89% rename from TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/SearchUCD.java rename to TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SearchUCD.java index 076472e..4dbdfc6 100644 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/SearchUCD.java +++ b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SearchUCD.java @@ -1,7 +1,8 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; +package it.inaf.oats.ia2.tapschemamanager.webapp; import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; @@ -10,9 +11,8 @@ import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; +import java.util.Properties; import java.util.regex.Pattern; -import javax.naming.InitialContext; -import javax.naming.NamingException; /** * Collection of static methods for accessing to the UCD REST service and @@ -22,7 +22,7 @@ import javax.naming.NamingException; */ public class SearchUCD { - private static final String UCD_SERVICE_PATH; + private static final String UCD_SERVICE_URL; private static final String UCD_NOT_FOUND = "**** Could not find UCD ****"; public static final String REG_EXP_UCD; @@ -33,10 +33,13 @@ public class SearchUCD { static { try { - InitialContext ic = new InitialContext(); - UCD_SERVICE_PATH = (String) ic.lookup("java:comp/env/UCD_SERVICE_PATH"); - } catch (NamingException e) { - throw new RuntimeException("Unable to find UCD service path in web.xml configuration!"); + Properties prop = new Properties(); + try (InputStream in = SearchUCD.class.getClassLoader().getResourceAsStream("webapp.properties")) { + prop.load(in); + } + UCD_SERVICE_URL = prop.getProperty("ucd_service_url"); + } catch (IOException e) { + throw new RuntimeException("Unable to load UCD service URL from webapp.properties configuration!"); } String namespaceRegExpPart = "[a-zA-Z]+\\:"; // validate e.g. "mynamespace:" @@ -72,7 +75,7 @@ public class SearchUCD { public static String assign(String searchText) throws UCDServiceException { searchText = encodeText(searchText); - String urlStr = UCD_SERVICE_PATH + "assign?value=" + searchText; + String urlStr = UCD_SERVICE_URL + "assign?value=" + searchText; try { URL urlAssign = new URL(urlStr); @@ -104,7 +107,7 @@ public class SearchUCD { public static List suggest(String searchText) throws UCDServiceException { searchText = encodeText(searchText); - String urlStr = UCD_SERVICE_PATH + "suggest?value=" + searchText; + String urlStr = UCD_SERVICE_URL + "suggest?value=" + searchText; try { URL urlSuggest = new URL(urlStr); @@ -145,7 +148,7 @@ public class SearchUCD { public static void explain(UCDInfo ucdInfo) throws UCDServiceException { String searchText = encodeText(ucdInfo.getWord()); - String urlStr = UCD_SERVICE_PATH + "explain?value=" + searchText; + String urlStr = UCD_SERVICE_URL + "explain?value=" + searchText; try { URL url = new URL(urlStr); @@ -186,7 +189,7 @@ public class SearchUCD { return true; } else { String searchText = encodeText(inputText); - String urlStr = UCD_SERVICE_PATH + "validate?value=" + searchText; + String urlStr = UCD_SERVICE_URL + "validate?value=" + searchText; try { URL url = new URL(urlStr); diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SearchUCDDialog.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SearchUCDDialog.java index bdffb9d..de5a60c 100644 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SearchUCDDialog.java +++ b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SearchUCDDialog.java @@ -1,9 +1,5 @@ package it.inaf.oats.ia2.tapschemamanager.webapp; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.ParsedUCD; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.SearchUCD; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.UCDInfo; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.UCDServiceException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -139,7 +135,7 @@ public class SearchUCDDialog implements Serializable { } public void validateManualUCD() { - if (UCDManualText == null || UCDManualText.isEmpty()) { + if (UCDManualText == null || UCDManualText.isEmpty() || UCDManualText.trim().isEmpty()) { UCDValidationMessage = "UCD can't be null"; } else { parsedUCD = new ParsedUCD(UCDManualText); diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/SeparateCredentials.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SeparateCredentials.java similarity index 95% rename from TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/SeparateCredentials.java rename to TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SeparateCredentials.java index 74f16c7..b836e6d 100644 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/SeparateCredentials.java +++ b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/SeparateCredentials.java @@ -1,4 +1,4 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; +package it.inaf.oats.ia2.tapschemamanager.webapp; import it.inaf.oats.ia2.tapschemamanager.datalayer.Credentials; import javax.xml.bind.annotation.XmlElement; diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/TapSchemaEditingBean.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/TapSchemaEditingBean.java index 3d38fd3..d7a903d 100644 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/TapSchemaEditingBean.java +++ b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/TapSchemaEditingBean.java @@ -1,23 +1,27 @@ package it.inaf.oats.ia2.tapschemamanager.webapp; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.Column; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.EntityWrapper; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.EntityWrapperContainer; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.Status; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.Table; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.contract.ChildEntity; +import it.inaf.oats.ia2.tapschemamanager.contract.Column; +import it.inaf.oats.ia2.tapschemamanager.contract.EntitiesContainer; +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.KeyColumn; +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchemaEntity; +import it.inaf.oats.ia2.tapschemamanager.datalayer.UpdateOperations; import java.io.Serializable; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -import javax.annotation.PreDestroy; import javax.enterprise.context.Conversation; import javax.enterprise.context.ConversationScoped; import javax.faces.context.FacesContext; import javax.inject.Inject; import javax.inject.Named; -import javax.json.Json; -import javax.json.JsonObjectBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -28,6 +32,7 @@ import javax.json.JsonObjectBuilder; public class TapSchemaEditingBean implements Serializable { private static final long serialVersionUID = -6251004452688984277L; + private static final Logger log = LoggerFactory.getLogger(TapSchemaEditingBean.class); private static final String COLUMNS_COMPONENT_ID = "main:columns-list"; @@ -38,13 +43,79 @@ public class TapSchemaEditingBean implements Serializable { SchemaSelectionBean schemaSelection; private TapSchema tapSchema; + private Schema selectedSchema; + private Table selectedTable; + private Column selectedColumn; + private UpdateOperations updateOperations; - private EntityWrapperContainer currentAddingContainer; + private EntitiesContainer currentAddingContainer; private List currentAddables; @Inject private SearchUCDDialog searchUCDDialog; + public Schema getSelectedSchema() { + return selectedSchema; + } + + public Table getSelectedTable() { + return selectedTable; + } + + public Column getSelectedColumn() { + return selectedColumn; + } + + public void setSelectedSchema(Schema selectedSchema) { + this.selectedSchema = selectedSchema; + if (selectedSchema == null) { + setSelectedTable(null); + } else { + List
tables = selectedSchema.getAddedOrRemovedChildren(); + if (tables.isEmpty()) { + setSelectedTable(null); + } else { + setSelectedTable(tables.get(0)); + } + } + } + + public void setSelectedTable(Table selectedTable) { + this.selectedTable = selectedTable; + if (selectedTable == null) { + setSelectedColumn(null); + } else { + List columns = selectedTable.getAddedOrRemovedChildren(); + if (columns.isEmpty()) { + setSelectedColumn(null); + } else { + setSelectedColumn(columns.get(0)); + } + } + } + + public void setSelectedColumn(Column selectedColumn) { + this.selectedColumn = selectedColumn; + } + + public UpdateOperations getUpdateOperations() { + return updateOperations; + } + + public String getUpdatedValues(TapSchemaEntity entity) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (String key : entity.getPropertiesKeys()) { + if (entity.isChanged(key)) { + if (!first) { + sb.append(", "); + } + sb.append(key); + } + } + return sb.toString(); + } + public static class AddableItem implements Serializable { private static final long serialVersionUID = 2732253307571391962L; @@ -69,12 +140,69 @@ public class TapSchemaEditingBean implements Serializable { } } + public boolean toRemove(ChildEntity child) { + return child.getStatus() == Status.REMOVED_NOT_PERSISTED || child.getStatus() == Status.TO_REMOVE; + } + + public String getForeignKeyString(Column column) throws SQLException { + + Key foreignKey = column.getForeignKey(); + + if (foreignKey == null) { + return null; + } + + if (foreignKey.isVisible()) { + + String columnName = column.getName(); + + StringBuilder sb = new StringBuilder(); + + sb.append(foreignKey.getFromTableCompleteName()); + sb.append("."); + sb.append(columnName); + sb.append(" -> "); + for (KeyColumn keyColumn : foreignKey.getKeyColumns()) { + if (keyColumn.getFromColumn().equals(columnName)) { + sb.append(foreignKey.getTargetTableCompleteName()); + sb.append(keyColumn.getTargetColumn()); + break; + } + } + + return sb.toString(); + } + + return null; + } + public TapSchema getTapSchema() { return tapSchema; } + private void setupSelected() { + List schemas = tapSchema.getAddedOrRemovedChildren(); + if (!schemas.isEmpty()) { + selectedSchema = schemas.get(0); + List
tables = selectedSchema.getAddedOrRemovedChildren(); + if (!tables.isEmpty()) { + selectedTable = tables.get(0); + List columns = selectedTable.getChildren(); + if (!columns.isEmpty()) { + selectedColumn = columns.get(0); + } + } + } + } + public void setTapSchema(TapSchema tapSchema) { this.tapSchema = tapSchema; + setupSelected(); + } + + public void update() throws SQLException { + tapSchema.save(); + setupSelected(); } public SearchUCDDialog getSearchUCDDialog() { @@ -90,18 +218,19 @@ public class TapSchemaEditingBean implements Serializable { return "index.xhtml?faces-redirect=true"; } - public void undoRemove(EntityWrapperContainer ewc) { - ewc.getSelectedEntity().setStatus(Status.ADDED_PERSISTED); + public void undoRemove(ChildEntity entity) throws SQLException { + // re-add what was removed + entity.getParent().addChild(entity.getName()); } - public EntityWrapperContainer getCurrentAddingContainer() { + public EntitiesContainer getCurrentAddingContainer() { return currentAddingContainer; } - public void openAddablesModal(EntityWrapperContainer currentAddingContainer) { + public void openAddablesModal(EntitiesContainer currentAddingContainer) { this.currentAddingContainer = currentAddingContainer; - this.currentAddables = new ArrayList(); - for (String name : currentAddingContainer.getAddables()) { + this.currentAddables = new ArrayList<>(); + for (String name : currentAddingContainer.getAddableChildrenNames()) { currentAddables.add(new AddableItem(name)); } } @@ -113,9 +242,19 @@ public class TapSchemaEditingBean implements Serializable { } public void addSelected() throws SQLException { + TapSchemaEntity lastAddedEntity = null; for (AddableItem item : currentAddables) { if (item.isSelected()) { - currentAddingContainer.addEntityWrapper(item.getName()); + lastAddedEntity = currentAddingContainer.addChild(item.getName()); + } + } + if (lastAddedEntity != null) { + if (lastAddedEntity instanceof Schema) { + setSelectedSchema((Schema) lastAddedEntity); + } else if (lastAddedEntity instanceof Table) { + setSelectedTable((Table) lastAddedEntity); + } else if (lastAddedEntity instanceof Column) { + setSelectedColumn((Column) lastAddedEntity); } } } @@ -128,9 +267,9 @@ public class TapSchemaEditingBean implements Serializable { if (!FacesContext.getCurrentInstance().isValidationFailed()) { if (searchUCDDialog.isManualInsertion()) { - tapSchema.getSelectedColumn().setUcd(searchUCDDialog.getUCDManualText()); + selectedColumn.setUCD(searchUCDDialog.getUCDManualText()); } else { - tapSchema.getSelectedColumn().setUcd(searchUCDDialog.getSelectedUCD()); + selectedColumn.setUCD(searchUCDDialog.getSelectedUCD()); } // New UCD is set and we can notify the client to close the UCD Search modal dialog. @@ -144,21 +283,21 @@ public class TapSchemaEditingBean implements Serializable { } } - public void update() throws SQLException { - tapSchema.save(); + public void displayUpdateOperations() { + updateOperations = new UpdateOperations(tapSchema); } public void openUCDDialog() throws Exception { searchUCDDialog.setDefault(); - String description = tapSchema.getSelectedColumn().getDescription(); + String description = selectedColumn.getDescription(); if (description != null && !description.equals("")) { searchUCDDialog.setDescription(description); searchUCDDialog.search(description); } } - public void textInputChanged(EntityWrapper entityWrapper, String key) { - final boolean isChanged = entityWrapper.isChanged(key); + public void textInputChanged(TapSchemaEntity entity, String key) { + final boolean isChanged = entity.isChanged(key); CustomPartialResponseWriter.getCurrentInstance().addCustomJSUpdate(new JSUpdateHandler() { @Override @@ -169,14 +308,13 @@ public class TapSchemaEditingBean implements Serializable { } public void removeColumn(String name) { - tapSchema.getSelectedTable().removeEntityWrapper(name); + selectedTable.removeChild(name); - Column selectedColumn = tapSchema.getSelectedColumn(); Integer selectedColumnIndex = null; if (selectedColumn != null) { int index = 0; - for (String columnName : tapSchema.getSelectedTable().getEntitiesNames()) { - if (columnName.equals(selectedColumn.getName())) { + for (Column column : selectedTable.getAddedOrRemovedChildren()) { + if (column.getName().equals(selectedColumn.getName())) { selectedColumnIndex = index; break; } @@ -184,16 +322,9 @@ public class TapSchemaEditingBean implements Serializable { } } - Column removedColumn = tapSchema.getSelectedTable().getEntity(name); - CustomPartialResponseWriter writer = CustomPartialResponseWriter.getCurrentInstance(); - JsonObjectBuilder job = Json.createObjectBuilder(); - if (selectedColumnIndex != null) { - job.add("selectedColumn", selectedColumnIndex); - } - job.add("hideRemoved", removedColumn.isHidden()); - final String updateResult = job.build().toString(); + final String updateResult = selectedColumnIndex == null ? "{}" : "{\"selectedColumn\":" + selectedColumnIndex + "}"; writer.encodeComponent(COLUMNS_COMPONENT_ID); writer.addCustomJSUpdate(COLUMNS_COMPONENT_ID, new JSUpdateHandler() { @@ -205,12 +336,18 @@ public class TapSchemaEditingBean implements Serializable { }); } - public void undoRemoveColumn() { - Table selectedTable = tapSchema.getSelectedTable(); - this.undoRemove(selectedTable); + public void undoRemoveColumn() throws SQLException { + this.undoRemove(selectedColumn); - String selectedColumn = tapSchema.getSelectedColumn().getName(); - final int columnIndex = selectedTable.getEntitiesNames().indexOf(selectedColumn); + int i = 0; + for (Column column : selectedTable.getAddedOrRemovedChildren()) { + if (column.getName().equals(selectedColumn.getName())) { + break; + } + i++; + } + + final int columnIndex = i; CustomPartialResponseWriter writer = CustomPartialResponseWriter.getCurrentInstance(); writer.addCustomJSUpdate(COLUMNS_COMPONENT_ID, new JSUpdateHandler() { @@ -221,9 +358,4 @@ public class TapSchemaEditingBean implements Serializable { } }); } - - @PreDestroy - public void onDestroy() { - tapSchema.getTapSchemaHandler().close(); - } } diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/UCDInfo.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/UCDInfo.java similarity index 93% rename from TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/UCDInfo.java rename to TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/UCDInfo.java index ed6a7e2..e5be135 100644 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/UCDInfo.java +++ b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/UCDInfo.java @@ -1,4 +1,4 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; +package it.inaf.oats.ia2.tapschemamanager.webapp; import java.io.Serializable; diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/UCDServiceException.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/UCDServiceException.java similarity index 82% rename from TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/UCDServiceException.java rename to TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/UCDServiceException.java index daf9f54..8f8d86a 100644 --- a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/businesslayer/UCDServiceException.java +++ b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/UCDServiceException.java @@ -1,4 +1,4 @@ -package it.inaf.oats.ia2.tapschemamanager.businesslayer; +package it.inaf.oats.ia2.tapschemamanager.webapp; /** * diff --git a/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/WebAppConfigurationBean.java b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/WebAppConfigurationBean.java new file mode 100644 index 0000000..808c929 --- /dev/null +++ b/TapSchemaManager/src/main/java/it/inaf/oats/ia2/tapschemamanager/webapp/WebAppConfigurationBean.java @@ -0,0 +1,64 @@ +package it.inaf.oats.ia2.tapschemamanager.webapp; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import javax.xml.bind.JAXB; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author Sonia Zorba {@literal } + */ +@ApplicationScoped +public class WebAppConfigurationBean { + + private static final Logger log = LoggerFactory.getLogger(WebAppConfigurationBean.class); + + private File credentialsConfigFile; + private String password; + private CredentialsConfiguration cc; + + @PostConstruct + public void init() { + try { + Properties prop = new Properties(); + try (InputStream in = getClass().getClassLoader().getResourceAsStream("webapp.properties")) { + prop.load(in); + } + credentialsConfigFile = new File(prop.getProperty("credentials_config_path")); + password = prop.getProperty("password"); + + if (!credentialsConfigFile.exists()) { + log.debug("Configuration file doesn't exist: creating a new one at " + credentialsConfigFile.getAbsolutePath()); + credentialsConfigFile.getParentFile().mkdirs(); + credentialsConfigFile.createNewFile(); + cc = new CredentialsConfiguration(); + JAXB.marshal(cc, credentialsConfigFile); + } else { + cc = JAXB.unmarshal(credentialsConfigFile, CredentialsConfiguration.class); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public CredentialsConfiguration getConfig() { + return cc; + } + + public void updateConfigurationFile() throws IOException { + try (FileWriter fw = new FileWriter(credentialsConfigFile)) { + JAXB.marshal(cc, fw); + } + } + + public String getPassword() { + return password; + } +} diff --git a/TapSchemaManager/src/main/resources/META-INF/persistence.xml b/TapSchemaManager/src/main/resources/META-INF/persistence.xml deleted file mode 100644 index 10f7d6e..0000000 --- a/TapSchemaManager/src/main/resources/META-INF/persistence.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - jdbc/__TimerPool - false - - - - - diff --git a/TapSchemaManager/src/main/resources/webapp.properties b/TapSchemaManager/src/main/resources/webapp.properties new file mode 100644 index 0000000..9de6d7d --- /dev/null +++ b/TapSchemaManager/src/main/resources/webapp.properties @@ -0,0 +1,3 @@ +ucd_service_url=http://ia2-vo.oats.inaf.it:8080/ucd/ +credentials_config_path=/home/sonia/.tsm/config.xml +password=pippo \ No newline at end of file diff --git a/TapSchemaManager/src/main/webapp/WEB-INF/web.xml b/TapSchemaManager/src/main/webapp/WEB-INF/web.xml index 7b3bcad..e0954e0 100644 --- a/TapSchemaManager/src/main/webapp/WEB-INF/web.xml +++ b/TapSchemaManager/src/main/webapp/WEB-INF/web.xml @@ -1,15 +1,5 @@ - - UCD_SERVICE_PATH - java.lang.String - http://ia2-vo.oats.inaf.it:8080/ucd/ - - - CREDENTIALS_CONFIG_PATH - java.lang.String - /home/sonia/tsm-config.xml - javax.faces.PROJECT_STAGE Development @@ -22,6 +12,10 @@ javax.faces.WEBAPP_RESOURCES_DIRECTORY /resources + + javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL + true + eot application/vnd.ms-fontobject diff --git a/TapSchemaManager/src/main/webapp/resources/js/edit-tapschema.js b/TapSchemaManager/src/main/webapp/resources/js/edit-tapschema.js index 85d5205..4162c88 100644 --- a/TapSchemaManager/src/main/webapp/resources/js/edit-tapschema.js +++ b/TapSchemaManager/src/main/webapp/resources/js/edit-tapschema.js @@ -55,6 +55,9 @@ // // $('#ucd_search_form\\:save_ucd').prop('disabled', !valid); // }, + displayUpdateOperations: eventHandlerFactory(function (srcElement, jsupdate) { + $('#updateOperationsModal').modal('show'); + }), saveUCDCalled: eventHandlerFactory(function (srcElement, jsupdate) { if (jsupdate !== null) { $('#searchUCDModal').modal('hide'); @@ -65,6 +68,11 @@ textInputChanged: eventHandlerFactory(function (srcElement, jsupdate) { $(srcElement).toggleClass('changed', jsupdate === 'true'); }), + stopPropagation: function (event) { + event.stopPropagation(); + event.preventDefault(); + return false; + }, columnChanged: function (event) { if (event.status === 'success') { var $li = $(event.source).closest('li'); @@ -72,45 +80,22 @@ $li.addClass('active'); } }, - stopPropagation: function (event) { - event.stopPropagation(); - event.preventDefault(); - return false; - }, columnRemoved: eventHandlerFactory(function (srcElement, jsupdate, htmlupdate) { jsupdate = JSON.parse(jsupdate); var $ul = $(srcElement).closest('ul'); - if (jsupdate.hideRemoved) { - $(srcElement).closest('li').remove(); - } else { - $(srcElement).closest('a').find('span').addClass('strikeout'); - $(srcElement).prop('disabled', true); - } + $(srcElement).closest('a').find('span').addClass('strikeout'); + $(srcElement).prop('disabled', true); + if (jsupdate.selectedColumn !== undefined) { $ul.find('li').removeClass('active'); $ul.find('li:nth-child(' + (jsupdate.selectedColumn + 1) + ')').addClass('active'); } - if (jsupdate.hideRemoved) { - // Restore correct ids - $htmlUpdate = $(htmlupdate); - $htmlUpdate.find('li a'); - $htmlUpdate.find('li a input'); - - $htmlUpdate.find('li').each(function (index, element) { - var $this = $(element); - var $input = $this.find('input'); - - var $li = $('.columns-selector').find('li:nth-child(' + (index + 1) + ')'); - $li.attr('id', $this.attr('id')); - $li.find('a').attr('id', $this.find('a').attr('id')); - $li.find('input').attr('id', $input.attr('id')).attr('name', $input.attr('name')); - }); - } }, COLUMNS_COMPONENT_ID), columnRemovalUndo: eventHandlerFactory(function (srcElement, jsupdate) { var $a = $('#main\\:columns-list\\:' + jsupdate + '\\:column-selector'); $a.find('input').prop('disabled', false); $a.find('.strikeout').removeClass('strikeout'); + $a.removeClass('strikeout'); }, COLUMNS_COMPONENT_ID), ucdTextKeyDown: function (event) { if (event.keyCode === 13) { diff --git a/TapSchemaManager/src/main/webapp/tapSchemaEditing.xhtml b/TapSchemaManager/src/main/webapp/tapSchemaEditing.xhtml index 461f3f2..427f8c0 100644 --- a/TapSchemaManager/src/main/webapp/tapSchemaEditing.xhtml +++ b/TapSchemaManager/src/main/webapp/tapSchemaEditing.xhtml @@ -13,14 +13,19 @@ -

Editing #{tapSchemaEditing.tapSchema.name}

- + + + Display update operations + + +   + Update @@ -43,20 +48,20 @@
- +
This schema will be removed on TAP Schema Update. - + Undo @@ -78,7 +83,7 @@
- +
@@ -86,9 +91,9 @@
- + class="form-control #{tapSchemaEditing.selectedSchema.isChanged('utype') ? 'changed' : ''}" + value="#{tapSchemaEditing.selectedSchema.utype}"> +
@@ -97,9 +102,9 @@
- + class="form-control #{tapSchemaEditing.selectedSchema.isChanged('description') ? 'changed' : ''}" + value="#{tapSchemaEditing.selectedSchema.description}"> +
@@ -108,20 +113,20 @@ - +
- +
This table will be removed on TAP Schema Update. - + Undo @@ -144,7 +149,7 @@
- +
@@ -152,9 +157,9 @@
- + class="form-control #{tapSchemaEditing.selectedTable.isChanged('utype') ? 'changed' : ''}" + value="#{tapSchemaEditing.selectedTable.utype}"> +
@@ -163,9 +168,9 @@
- + class="form-control #{tapSchemaEditing.selectedTable.isChanged('description') ? 'changed' : ''}" + value="#{tapSchemaEditing.selectedTable.description}"> +
@@ -175,20 +180,20 @@
Columns - +
- - #{tapSchema.selectedColumn.name} - + + #{tapSchemaEditing.selectedColumn.name} + - - + + - + @@ -196,24 +201,24 @@
- - + +
This column will be removed on TAP Schema Update. @@ -233,18 +238,18 @@
- +
- #{tapSchema.selectedColumn.datatype} + #{tapSchemaEditing.selectedColumn.datatype}
- #{tapSchema.selectedColumn.size} + #{tapSchemaEditing.selectedColumn.size}
@@ -253,8 +258,8 @@
Description: - + class="form-control #{tapSchemaEditing.selectedColumn.isChanged('description') ? 'changed' : ''}" + value="#{tapSchemaEditing.selectedColumn.description}"> +
@@ -584,6 +589,187 @@
+ +
diff --git a/TapSchemaManager/src/test/java/TapSchemaMangerTest.java b/TapSchemaManager/src/test/java/TapSchemaMangerTest.java index b8c29f5..45228a3 100644 --- a/TapSchemaManager/src/test/java/TapSchemaMangerTest.java +++ b/TapSchemaManager/src/test/java/TapSchemaMangerTest.java @@ -1,9 +1,8 @@ -import it.inaf.oats.ia2.tapschemamanager.businesslayer.Column; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.CredentialsConfiguration; -import it.inaf.oats.ia2.tapschemamanager.businesslayer.SeparateCredentials; -import it.inaf.oats.ia2.tapschemamanager.datalayer.ColumnEntity; +import it.inaf.oats.ia2.tapschemamanager.webapp.CredentialsConfiguration; +import it.inaf.oats.ia2.tapschemamanager.webapp.SeparateCredentials; import it.inaf.oats.ia2.tapschemamanager.datalayer.Credentials; +import it.inaf.oats.ia2.tapschemamanager.webapp.CredentialsBean; import java.io.StringReader; import java.io.StringWriter; import javax.xml.bind.JAXB; @@ -14,6 +13,8 @@ import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; import org.junit.Ignore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -21,6 +22,8 @@ import org.junit.Ignore; */ public class TapSchemaMangerTest { + private static final Logger log = LoggerFactory.getLogger(TapSchemaMangerTest.class); + public TapSchemaMangerTest() { } @@ -40,38 +43,6 @@ public class TapSchemaMangerTest { public void tearDown() { } - @Ignore - @Test - public void testEditingFieldValue() { -// ColumnEntity columnEntity = new ColumnEntity("test"); -// columnEntity.setDescription("desc"); -// columnEntity.setUnit(null); -// columnEntity.setStd(0); -// -// Column column = new Column(columnEntity, false); -// -// String key = Column.DESCRIPTION; -// assertFalse(column.isChanged(key)); -// column.setValue(key, "mod"); -// assertTrue(column.isChanged(key)); -// column.setValue(key, "desc"); -// assertFalse(column.isChanged(key)); -// -// key = Column.UNIT; -// assertFalse(column.isChanged(key)); -// column.setValue(key, "xxx"); -// assertTrue(column.isChanged(key)); -// column.setValue(key, ""); -// assertFalse(column.isChanged(key)); -// -// key = Column.STD; -// assertFalse(column.isChanged(key)); -// column.setValue(key, "1"); -// assertTrue(column.isChanged(key)); -// column.setValue(key, "0"); -// assertFalse(column.isChanged(key)); - } - @Test public void testCredentialsConfigSerialization() throws Exception { CredentialsConfiguration cc = new CredentialsConfiguration(); @@ -92,6 +63,7 @@ public class TapSchemaMangerTest { sw = new StringWriter(); JAXB.marshal(cc, sw); - System.out.println(sw); + log.debug(sw.toString()); + sw.close(); } } diff --git a/TapSchemaManagerDL/pom.xml b/TapSchemaManagerDL/pom.xml index e070e57..ac98f02 100644 --- a/TapSchemaManagerDL/pom.xml +++ b/TapSchemaManagerDL/pom.xml @@ -11,11 +11,6 @@ 1.7 - - org.eclipse.persistence - eclipselink - 2.6.2 - mysql mysql-connector-java diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/ChildEntity.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/ChildEntity.java new file mode 100644 index 0000000..90c3883 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/ChildEntity.java @@ -0,0 +1,28 @@ +package it.inaf.oats.ia2.tapschemamanager.contract; + +/** + * A {@link TapSchemaEntity} that can be a child of an + * {@link EntitiesContainer}. + * + * @author Sonia Zorba {@literal } + */ +public interface ChildEntity extends TapSchemaEntity { + + /** + * Each child has a name that is univocal for a given parent, in this way + * the parent can search a child by name. + */ + String getName(); + + /** + * The {@link EntitiesContainer} that owns the {@link ChildEntity}. + */ + T getParent(); + + /** + * The persistence status of the {@link ChildEntity}. + */ + Status getStatus(); + + void setStatus(Status status); +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Column.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Column.java new file mode 100644 index 0000000..0fe39e3 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Column.java @@ -0,0 +1,116 @@ +package it.inaf.oats.ia2.tapschemamanager.contract; + +/** + * {@link TapSchemaEntity} that represents the table {@code TAP_SCHEMA.columns}. + * + * @author Sonia Zorba {@literal } + */ +public interface Column extends ChildEntity
{ + + 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 <schema-name>.<table-name>}. + */ + 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.
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.
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.
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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/EntitiesContainer.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/EntitiesContainer.java new file mode 100644 index 0000000..06c5a9d --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/EntitiesContainer.java @@ -0,0 +1,65 @@ +package it.inaf.oats.ia2.tapschemamanager.contract; + +import java.sql.SQLException; +import java.util.List; + +/** + * Objects of this class contain zero or more {@link ChildEntity} objects. + * + * @author Sonia Zorba {@literal } + */ +public interface EntitiesContainer { + + /** + * Returns a specific child of the container, selecting it by name and + * filtering it by a set of possible status: if the child doesn't have one + * of the status specified, this method returns null.
+ * If no status is specified it is assumed that all status are + * valid. + */ + T getChild(String childName, Status... status); + + /** + * Add a {@link ChildEntity} specifying its name. If the child entity has + * never been read from the database it is loaded when this method is + * called. If the entity was marked as removed, it will marked as added + * again. + */ + T addChild(String childName) throws SQLException; + + /** + * Remove a {@link ChildEntity} specifying its name.
+ * The child isn't really removed but only marked as removed (the removal + * will happen when the {@link TapSchema#save()} method will be called). + */ + void removeChild(String childName); + + /** + * Retrieve a list of names of child entities that can be added.
The + * list contains only names of entities that have never been added: entities + * which instance don't exist yet or entities having + * {@link Status} {@code LOADED}. + */ + List getAddableChildrenNames(); + + /** + * Retrieve a list of children filtering them by a set of possible + * status.
+ * If no status is specified it is assumed that all status are + * valid. + */ + List getChildren(Status... statuses); + + /** + * Retrieve all children having {@link Status} {@code ADDED_PERSISTED} or + * {@code ADDED_NOT_PERSISTED}. + */ + List getAddedChildren(); + + /** + * Retrieve all children having {@link Status} {@code ADDED_PERSISTED}, + * {@code ADDED_NOT_PERSISTED}, {@code TO_REMOVE} or + * {@code REMOVED_NOT_PERSISTED}. + */ + List getAddedOrRemovedChildren(); +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Key.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Key.java new file mode 100644 index 0000000..97a1238 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Key.java @@ -0,0 +1,81 @@ +package it.inaf.oats.ia2.tapschemamanager.contract; + +import java.util.List; + +/** + * {@link TapSchemaEntity} that represents the table {@code TAP_SCHEMA.keys}. + * + * @author Sonia Zorba {@literal } + */ +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 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 <schema-name>.<table-name>}. + */ + 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 <schema-name>.<table-name>}. + */ + 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/KeyColumn.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/KeyColumn.java new file mode 100644 index 0000000..774632d --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/KeyColumn.java @@ -0,0 +1,39 @@ +package it.inaf.oats.ia2.tapschemamanager.contract; + +/** + * {@link TapSchemaEntity} that represents the table + * {@code TAP_SCHEMA.key_columns}. + * + * @author Sonia Zorba {@literal } + */ +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"; + + /** + * 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Schema.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Schema.java new file mode 100644 index 0000000..f332991 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Schema.java @@ -0,0 +1,35 @@ +package it.inaf.oats.ia2.tapschemamanager.contract; + +/** + * {@link TapSchemaEntity} that represents the table {@code TAP_SCHEMA.schemas}. + * + * @author Sonia Zorba {@literal } + */ +public interface Schema extends EntitiesContainer
, ChildEntity { + + 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Status.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Status.java new file mode 100644 index 0000000..9911bf8 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Status.java @@ -0,0 +1,37 @@ +package it.inaf.oats.ia2.tapschemamanager.contract; + +/** + * Define the persistence status of a {@link ChildEntity}. + * + * @author Sonia Zorba {@literal } + */ +public enum Status { + + /** + * Information about the entity has been loaded from the database (e.g. for + * performance reason) but the entity hasn't been added to the TAP_SCHEMA. + * Currently only {@code Column}s uses this state. + */ + LOADED, + /** + * The entity was added to the TAP_SCHEMA and this fact is stored into the + * database. + */ + ADDED_PERSISTED, + /** + * The entity is marked as added, but it hasn't been saved to the database + * yet. + */ + ADDED_NOT_PERSISTED, + /** + * The entity is marked as removed but it is still written into the + * database, so it will be removed from it only when the + * {@link TapSchema#save()} method is called. + */ + TO_REMOVE, + /** + * The entity is marked as removed but it has never been written into the + * database. + */ + REMOVED_NOT_PERSISTED +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Table.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Table.java new file mode 100644 index 0000000..7becc0c --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/Table.java @@ -0,0 +1,93 @@ +package it.inaf.oats.ia2.tapschemamanager.contract; + +import java.util.List; + +/** + * {@link TapSchemaEntity} that represents the table {@code TAP_SCHEMA.tables}. + * + * @author Sonia Zorba {@literal } + */ +public interface Table extends EntitiesContainer, ChildEntity { + + 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 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 getAllFromKeys(); + + /** + * Retrieve the list of all the visible keys whose + * {@link Key#getTargetTableCompleteName()} method returns the complete name + * of this table. + */ + List 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 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchema.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchema.java new file mode 100644 index 0000000..b560828 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchema.java @@ -0,0 +1,37 @@ +package it.inaf.oats.ia2.tapschemamanager.contract; + +import java.sql.SQLException; + +/** + * Represents a TAP_SCHEMA. + * + * @author Sonia Zorba {@literal } + */ +public interface TapSchema extends EntitiesContainer { + + 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"; + + /** + * 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchemaEntity.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchemaEntity.java new file mode 100644 index 0000000..3e9282b --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchemaEntity.java @@ -0,0 +1,58 @@ +package it.inaf.oats.ia2.tapschemamanager.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.
+ * Property value can be changed but the original value has to be maintained + * until the {@link #save()} method is called. + * + * @author Sonia Zorba {@literal } + */ +public interface TapSchemaEntity { + + /** + * Initializes the value of a property (store the original value). + */ + void initProperty(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 getValue(String key, Class 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 getOriginalValue(String key, Class type); + + /** + * Retrieve a list of all properties names (the names of the table columns). + */ + List getPropertiesKeys(); + + /** + * Marks the TapSchemaEntity as saved (all original values are set equals to + * current values). + */ + void save(); +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchemaVersion.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchemaVersion.java new file mode 100644 index 0000000..7f9fa92 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/contract/TapSchemaVersion.java @@ -0,0 +1,21 @@ +package it.inaf.oats.ia2.tapschemamanager.contract; + +/** + * Version of a TAP_SCHEMA schema. TAP_SCHEMA schemas with different versions + * can use different columns in the database. + * + * @author Sonia Zorba {@literal } + */ +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; + + private TapSchemaVersion(String name) { + this.name = name; + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ChildEntityImpl.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ChildEntityImpl.java new file mode 100644 index 0000000..831e302 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ChildEntityImpl.java @@ -0,0 +1,43 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.ChildEntity; +import it.inaf.oats.ia2.tapschemamanager.contract.EntitiesContainer; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; + +/** + * The main implementation of {@link ChildEntity}. + * + * @author Sonia Zorba {@literal } + */ +public abstract class ChildEntityImpl extends TapSchemaEntityImpl implements ChildEntity { + + 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ColumnEntity.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ColumnEntity.java deleted file mode 100644 index 90a0ad3..0000000 --- a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ColumnEntity.java +++ /dev/null @@ -1,263 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.datalayer; - -import java.io.Serializable; -import java.math.BigInteger; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.IdClass; -import javax.persistence.ManyToOne; -import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.Table; -import javax.persistence.Transient; - -class ColumnId implements Serializable { - - private static final long serialVersionUID = 6943729649657196881L; - - String fullTableName; - String name; -} - -/** - * JPA entity for the table TAP_SCHEMA.columns. - * - * @author Sonia Zorba {@literal } - */ -@Entity -@IdClass(ColumnId.class) -@Table(name = "columns") -public class ColumnEntity implements Serializable, TapSchemaEntity { - - private static final long serialVersionUID = 3630294743516824359L; - - @Id - @Column(name = "table_name", length = 128) - private String fullTableName; - - @Id - @Column(name = "column_name", length = 64) - private String name; - - @ManyToOne(fetch = FetchType.EAGER) - @PrimaryKeyJoinColumn(name = "table_name", referencedColumnName = "table_name") - private TableEntity table; - - @Column(name = "utype", length = 512) - private String utype; - - @Column(name = "ucd", length = 64) - private String ucd; - - @Column(name = "unit", length = 64) - private String unit; - - @Column(name = "description", length = 512) - private String description; - - @Column(name = "datatype", length = 64) - private String datatype; - - @Column(name = "size") - private int size; - - @Column(name = "principal") - private int principal; - - @Column(name = "indexed") - private int indexed; - - @Column(name = "std") - private int std; - - @Column(name = "columnID") - private BigInteger columnID; - - @Column(name = "id") - private int id; - - @Transient - private boolean primaryKey; - - protected ColumnEntity() { - } - - protected ColumnEntity(String columnName) { - this(); - this.name = columnName; - } - - /** - * The complete table name: - * <schema-name>.<table-name>. - */ - public String getFullTableName() { - return fullTableName; - } - - protected void setFullTableName(String fullTableName) { - this.fullTableName = fullTableName; - } - - /** - * The value in the column_name column. - */ - @Override - public String getName() { - return name; - } - - protected void setName(String columnName) { - this.name = columnName; - } - - /** - * The value in the utype column. - */ - public String getUtype() { - return utype; - } - - public void setUtype(String utype) { - this.utype = utype; - } - - /** - * The value in the ucd column: represents the Unified Content - * Descriptor of the column. - */ - public String getUcd() { - return ucd; - } - - public void setUcd(String ucd) { - this.ucd = ucd; - } - - /** - * The value in the unit column. - */ - public String getUnit() { - return unit; - } - - public void setUnit(String unit) { - this.unit = unit; - } - - /** - * The value in the description column. - */ - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - /** - * The value in the datatype column. - */ - public String getDatatype() { - return datatype; - } - - public void setDatatype(String datatype) { - this.datatype = datatype; - } - - /** - * The value in the size column. - */ - public int getSize() { - return size; - } - - public void setSize(int size) { - this.size = size; - } - - /** - * The value in the principal column: indicates that the column - * is considered a core part the content.
It is an integer but should be - * treated as a boolean value. - */ - public int getPrincipal() { - return principal; - } - - public void setPrincipal(int principal) { - this.principal = principal; - } - - /** - * The value in the indexed column: indicates that the column - * is indexed.
It is an integer but should be treated as a boolean - * value. - */ - public int getIndexed() { - return indexed; - } - - public void setIndexed(int indexed) { - this.indexed = indexed; - } - - /** - * The value in the std column: indicates that the column is - * defined by some standard.
It is an integer but should be treated as a - * boolean value. - */ - public int getStd() { - return std; - } - - public void setStd(int std) { - this.std = std; - } - - /** - * The value in the columnID column: it represents [TODO]... - */ - protected BigInteger getColumnID() { - return columnID; - } - - protected void setColumnID(BigInteger columnID) { - this.columnID = columnID; - } - - /** - * The {@link TableEntity} that owns this ColumnEntity. - */ - public TableEntity getTable() { - return table; - } - - protected void setTable(TableEntity tableEntity) { - this.table = tableEntity; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - /** - * Indicates if the column is a primary key (or a part of a primary key). - * This information is not stored into the TAP_SCHEMA, so it will be - * reloaded from the source schema each time. - */ - public boolean isPrimaryKey() { - return primaryKey; - } - - public void setPrimaryKey(boolean primaryKey) { - this.primaryKey = primaryKey; - } -} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ColumnImpl.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ColumnImpl.java new file mode 100644 index 0000000..9029780 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/ColumnImpl.java @@ -0,0 +1,283 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Column; +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.KeyColumn; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The main implementation of {@link Column}. + * + * @author Sonia Zorba {@literal } + */ +public class ColumnImpl extends ChildEntityImpl
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()); + addProperty(UTYPE_KEY, new EditableProperty()); + addProperty(UNIT_KEY, new EditableProperty()); + addProperty(UCD_KEY, new EditableProperty()); + addProperty(PRINCIPAL_KEY, new EditableProperty<>(isPrimaryKey, false)); + addProperty(STD_KEY, new EditableProperty<>(false, false)); + addProperty(COLUMN_INDEX_KEY, new EditableProperty()); + addProperty(COLUMN_ID_KEY, new EditableProperty()); + + 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DLUtil.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DLUtil.java index d3f8240..e4d80f3 100644 --- a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DLUtil.java +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DLUtil.java @@ -1,9 +1,24 @@ package it.inaf.oats.ia2.tapschemamanager.datalayer; +import it.inaf.oats.ia2.tapschemamanager.contract.ChildEntity; +import it.inaf.oats.ia2.tapschemamanager.contract.Column; +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.KeyColumn; +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchemaEntity; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchemaVersion; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.List; +import java.util.Map; +import javax.sql.DataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Utility class that contains some static methods to manage various operations @@ -13,56 +28,179 @@ import java.util.List; */ public class DLUtil { - /** - * Retrieve a TapSchemaEntity from a list searching it by name. - */ - public static T getEntityByName(List entities, String name) { - for (T entity : entities) { - if (entity.getName().equals(name)) { - return entity; + private static final Logger log = LoggerFactory.getLogger(DLUtil.class); + + protected static List sortStringsList(List list) { + Collections.sort(list, String.CASE_INSENSITIVE_ORDER); + return list; + } + + protected static List getChildrenByStatus(Iterable entities, Status... statuses) { + List ret = new ArrayList<>(); + for (T child : entities) { + if (statuses == null || statuses.length == 0) { + if (child != null) { + ret.add(child); + } + } else { + for (Status status : statuses) { + if (child != null && child.getStatus().equals(status)) { + ret.add(child); + break; + } + } + } + } + return Collections.unmodifiableList(ret); + } + + protected static T getChild(Map children, String childName, Status... statuses) { + T child = children.get(childName); + if (child == null) { + return null; + } + if (statuses == null || statuses.length == 0) { + return child; + } + for (Status status : statuses) { + if (child.getStatus().equals(status)) { + return child; } } return null; } + protected static List getAddableChildrenNames(Map children) { + List list = new ArrayList<>(); + + for (Map.Entry entry : children.entrySet()) { + T entity = entry.getValue(); + if (entity == null || entity.getStatus() == Status.LOADED) { + list.add(entry.getKey()); + } + } + return Collections.unmodifiableList(list); + } + /** - * Given a list of TapSchemaEntity objects returns a list - * containing their names. + * This method is thought for avoiding various problem encountered using the + * standard {@code ResultSet} {@code getObject()} method. * - * @return list of entities names alphabetically and case insensitively - * ordered. + * In particular: + *
    + *
  • In some cases the {@code getObject()} method (e.g. with + * {@code Integer.class}) returns 0 instead of null. + *
  • + *
  • + * Method + * {@code org.postgresql.jdbc4.Jdbc4ResultSet.getObject(int, Class)} is + * not yet implemented. + *
  • + *
*/ - public static List getEntitiesNames(List entities) { - List entitiesNames = new ArrayList<>(); - for (T entity : entities) { - entitiesNames.add(entity.getName()); + protected static T getObject(ResultSet rs, String key, Class type) throws SQLException { + T ret; + if (type == String.class) { + ret = (T) rs.getString(key); + } else if (type == Integer.class) { + ret = (T) (Integer) rs.getInt(key); + } else if (type == Long.class) { + ret = (T) (Long) rs.getLong(key); + } else if (type == Boolean.class) { + ret = (T) (Boolean) rs.getBoolean(key); + } else { + throw new UnsupportedOperationException("Type " + type.getCanonicalName() + " not supported by " + DLUtil.class.getCanonicalName() + " getObject() method"); } - Collections.sort(entitiesNames, String.CASE_INSENSITIVE_ORDER); - return entitiesNames; + + if (rs.wasNull()) { + return null; + } + return ret; } /** - * Remove an entity from a list of TapSchemaEntity instances - * searching it by name. - * - * This method is protected because this operation should be performed by - * the entity that contains the list. + * Same as {@link DLUtil.getObject(ResultSet, String, Class)}. */ - protected static void removeEntity(List entities, String entityName) { - Iterator iterator = entities.iterator(); - while (iterator.hasNext()) { - T entity = iterator.next(); - if (entity.getName().equals(entityName)) { - iterator.remove(); - return; - } + protected static T getObject(ResultSet rs, int i, Class type) throws SQLException { + T ret; + if (type == String.class) { + ret = (T) rs.getString(i); + } else if (type == Integer.class) { + ret = (T) (Integer) rs.getInt(i); + } else if (type == Long.class) { + ret = (T) (Long) rs.getLong(i); + } else if (type == Boolean.class) { + ret = (T) (Boolean) rs.getBoolean(i); + } else { + throw new UnsupportedOperationException("Type " + type.getCanonicalName() + " not supported by " + DLUtil.class.getCanonicalName() + " getObject() method"); } + + if (rs.wasNull()) { + return null; + } + return ret; + } + + protected static DataSource getSchemaDataSource(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) { + return schemaName.equals(tapSchema.getName()) ? dbWrapper.getTapSchemaDataSource() : dbWrapper.getSourceDataSource(); + } + + protected static DatabaseType getSchemaDatabaseType(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) { + return schemaName.equals(tapSchema.getName()) ? dbWrapper.getTapSchemaDatabaseType() : dbWrapper.getSourceDatabaseType(); + } + + protected static boolean isTapSchema(TapSchema tapSchema, String schemaName) { + return schemaName.equals(tapSchema.getName()); + } + + protected static UnsupportedOperationException getUnsupportedOperationException(TapSchemaVersion version, String unsupportedFeature) { + return new UnsupportedOperationException("Version \"" + version.name() + "\" doesn't support " + unsupportedFeature); + } + + protected static boolean is1_1(TapSchemaVersion version) { + return version == TapSchemaVersion.TAP_SCHEMA_1_1 || version == TapSchemaVersion.TAP_SCHEMA_1_1_IA2; + } + + protected static boolean isIA2(TapSchemaVersion version) { + return version == TapSchemaVersion.TAP_SCHEMA_1_IA2 || version == TapSchemaVersion.TAP_SCHEMA_1_1_IA2; + } + + protected static String escapeName(String name, DatabaseType dbType) { + char escapeChar; + switch (dbType) { + case MYSQL: + escapeChar = '`'; + break; + case POSTGRES: + escapeChar = '"'; + break; + default: + throw new UnsupportedOperationException("Database type " + dbType + " not supported"); + } + + return String.format("%s%s%s", escapeChar, name, escapeChar); + } + + protected static String getTapSchemaTableNameFromEntity(TapSchemaEntity entity) { + if (entity instanceof Schema) { + return TapSchema.SCHEMAS_TABLE; + } else if (entity instanceof Table) { + return TapSchema.TABLES_TABLE; + } else if (entity instanceof Column) { + return TapSchema.COLUMNS_TABLE; + } else if (entity instanceof Key) { + return TapSchema.KEYS_TABLE; + } else if (entity instanceof KeyColumn) { + return TapSchema.KEY_COLUMNS_TABLE; + } + log.warn("getTapSchemaTableNameFromEntity returns null for {}" + entity.getClass().getCanonicalName()); + return null; } - private static void setColumnDescription(TableEntity tableEntity, String columnName, String description) { - ColumnEntity columnEntity = getEntityByName(tableEntity.getColumns(), columnName); - columnEntity.setDescription(description); - columnEntity.setStd(1); + private static void setTSColumnDescription(Table table, String columnName, String description) { + Column column = table.getChild(columnName); + column.setDescription(description); + column.setStd(true); } /** @@ -70,60 +208,60 @@ public class DLUtil { * * @param schema the TAP_SCHEMA schema SchemaEntity. */ - protected static void putInfoIntoTapSchemaSchema(SchemaEntity schema) { + protected static void putInfoIntoTapSchemaSchema(Schema schema) { schema.setDescription("a special schema to describe a TAP tableset"); // SCHEMAS - TableEntity schemasTable = schema.getTableByShortName("schemas"); + Table schemasTable = schema.getChild("schemas"); schemasTable.setDescription("description of schemas in this tableset"); - setColumnDescription(schemasTable, "schema_name", "schema name for reference to TAP_SCHEMA.schemas"); - setColumnDescription(schemasTable, "utype", "lists the utypes of schemas in the tableset"); - setColumnDescription(schemasTable, "description", "describes schemas in the 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 - TableEntity tablesTable = schema.getTableByShortName("tables"); + Table tablesTable = schema.getChild("tables"); tablesTable.setDescription("description of tables in this tableset"); - setColumnDescription(tablesTable, "schema_name", "the schema this table belongs to"); - setColumnDescription(tablesTable, "table_name", "the fully qualified table name"); - setColumnDescription(tablesTable, "table_type", "one of: table view"); - setColumnDescription(tablesTable, "utype", "lists the utype of tables in the tableset"); - setColumnDescription(tablesTable, "description", "describes tables in the 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 - TableEntity columnsTable = schema.getTableByShortName("columns"); + Table columnsTable = schema.getChild("columns"); columnsTable.setDescription("description of columns in this tableset"); - setColumnDescription(columnsTable, "table_name", "the table this column belongs to"); - setColumnDescription(columnsTable, "column_name", "the column name"); - setColumnDescription(columnsTable, "utype", "lists the utypes of columns in the tableset"); - setColumnDescription(columnsTable, "ucd", "lists the UCDs of columns in the tableset"); - setColumnDescription(columnsTable, "unit", "lists the unit used for column values in the tableset"); - setColumnDescription(columnsTable, "description", "describes the columns in the tableset"); - setColumnDescription(columnsTable, "datatype", "lists the ADQL datatype of columns in the tableset"); - setColumnDescription(columnsTable, "size", "lists the size of variable-length columns in the tableset"); - setColumnDescription(columnsTable, "principal", "a principal column; 1 means 1, 0 means 0"); - setColumnDescription(columnsTable, "indexed", "an indexed column; 1 means 1, 0 means 0"); - setColumnDescription(columnsTable, "std", "a standard column; 1 means 1, 0 means 0"); + 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 - TableEntity keysTable = schema.getTableByShortName("keys"); + Table keysTable = schema.getChild("keys"); keysTable.setDescription("description of foreign keys in this tableset"); - setColumnDescription(keysTable, "key_id", "unique key to join to TAP_SCHEMA.key_columns"); - setColumnDescription(keysTable, "from_table", "the table with the foreign key"); - setColumnDescription(keysTable, "target_table", "the table with the primary key"); - setColumnDescription(keysTable, "utype", "lists the utype of keys in the tableset"); - setColumnDescription(keysTable, "description", "describes keys in the 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 - TableEntity keyColumnsTable = schema.getTableByShortName("key_columns"); + Table keyColumnsTable = schema.getChild("key_columns"); keyColumnsTable.setDescription("description of foreign key columns in this tableset"); - setColumnDescription(keyColumnsTable, "key_id", "key to join to TAP_SCHEMA.keys"); - setColumnDescription(keyColumnsTable, "from_column", "column in the from_table"); - setColumnDescription(keyColumnsTable, "target_column", "column in the target_table"); + 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/Dao.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/Dao.java index cdbf8c2..9943584 100644 --- a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/Dao.java +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/Dao.java @@ -1,27 +1,26 @@ package it.inaf.oats.ia2.tapschemamanager.datalayer; +import it.inaf.oats.ia2.tapschemamanager.contract.Column; +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.KeyColumn; +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.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.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; -import javax.persistence.Persistence; import javax.sql.DataSource; -import org.postgresql.ds.PGPoolingDataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility class that contains static methods for interacting with databases. - * All the specific SQL clauses of the application are encapsulated in this - * class. All the other datalayer operations are performed using the JPA. * * @author Sonia Zorba {@literal } */ @@ -29,48 +28,526 @@ public class Dao { private static final Logger log = LoggerFactory.getLogger(Dao.class); - private static List sortStringsList(List list) { - Collections.sort(list, String.CASE_INSENSITIVE_ORDER); - return list; - } - /** - * Retrieve the list of the names of the all the schemas contained into the - * database specified by the DataSource parameter. - * - * @return list of schemas names alphabetically and case insensitively - * ordered. + * Creates the TAP_SCHEMA schema and its tables. */ - public static List getAllSchemasNames(DataSource dataSource, DatabaseType dbType) throws SQLException { + private static void createTapSchemaStructure(DatabaseType dbType, Connection conn, TapSchema tapSchema) throws SQLException { + + String tapSchemaName = tapSchema.getName(); + TapSchemaVersion version = tapSchema.getVersion(); - String query; if (dbType == DatabaseType.MYSQL) { - query = "SHOW DATABASES"; + 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 (DLUtil.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 (DLUtil.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 (DLUtil.isIA2(version)) { + 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 (DLUtil.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 (DLUtil.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) { - query = "SELECT schema_name FROM information_schema.schemata"; + try (Statement statement = conn.createStatement()) { + String tapSchemaNameEscaped = DLUtil.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 (DLUtil.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 (DLUtil.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 (DLUtil.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 (DLUtil.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 (DLUtil.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"); } + } - log.debug("Executing query {}", query); + protected static void save(DBWrapper dbWrapper, TapSchema tapSchema) throws SQLException { - List allSchemas = new ArrayList<>(); + log.debug("Saving TAP_SCHEMA"); - try (Connection connection = dataSource.getConnection(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery(query)) { - while (resultSet.next()) { - allSchemas.add(resultSet.getString(1)); + 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); } - } - log.debug("{} schemas found", allSchemas.size()); + // Start update + connection.setAutoCommit(false); // start transaction + transactionStarted = true; + + String tapSchemaNameEscaped = DLUtil.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, DLUtil.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, DLUtil.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, DLUtil.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, DLUtil.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, DLUtil.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); + } - return sortStringsList(allSchemas); + 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 (Table table : operations.getTablesToRemove()) { + Schema schema = tapSchema.getChild(table.getSchemaName()); + if (schema != null) { + ((SchemaImpl) schema).cleanTable(table.getName()); + } + } + for (Schema schema : operations.getSchemasToRemove()) { + ((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 getAllTAPSchemasNames(DBWrapper dbs) throws SQLException { - List allSchemas = getAllSchemasNames(dbs.getTapSchemaDataSource(), dbs.getTapSchemaDatabaseType()); + List allSchemas = DaoSchema.getAllSchemasNames(dbs.getTapSchemaDataSource(), dbs.getTapSchemaDatabaseType()); return getAllTAPSchemasNames(dbs, allSchemas); } @@ -148,7 +625,7 @@ public class Dao { log.debug("{} TAP_SCHEMA schemas found", allTAPSchemas.size()); - return sortStringsList(allTAPSchemas); + return DLUtil.sortStringsList(allTAPSchemas); } /** @@ -185,424 +662,4 @@ public class Dao { return exposedSchemas; } - - /** - * Retrieve the JPA entity manager for given TAP_SCHEMA name and - * credentials. - */ - protected static EntityManager getEntityManager(Credentials tapSchemaCredentials, String tapSchemaName) { - Map persistenceMap = new HashMap<>(); - - DatabaseType dbType = tapSchemaCredentials.getDatabaseType(); - - String jdbcUrl; - if (dbType == DatabaseType.MYSQL) { - jdbcUrl = String.format("jdbc:mysql://%s:%s/%s", tapSchemaCredentials.getHostname(), tapSchemaCredentials.getPort(), tapSchemaName); - } else if (dbType == DatabaseType.POSTGRES) { - jdbcUrl = String.format("jdbc:postgresql://%s:%s/%s?currentSchema=%s", tapSchemaCredentials.getHostname(), tapSchemaCredentials.getPort(), tapSchemaCredentials.getDatabase(), tapSchemaName); - } else { - throw new UnsupportedOperationException("Database type " + dbType + " not supported"); - } - - persistenceMap.put("javax.persistence.jdbc.url", jdbcUrl); - persistenceMap.put("javax.persistence.jdbc.user", tapSchemaCredentials.getUsername()); - persistenceMap.put("javax.persistence.jdbc.password", tapSchemaCredentials.getPassword()); - persistenceMap.put("javax.persistence.jdbc.driver", tapSchemaCredentials.getDatabaseDriverClass()); - - EntityManagerFactory managerFactory = Persistence.createEntityManagerFactory("pu", persistenceMap); - - try { - Class.forName(tapSchemaCredentials.getDatabaseDriverClass()); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - EntityManager em = managerFactory.createEntityManager(); - -// if (dbType == DatabaseType.POSTGRES) { -// ((EntityManagerImpl) em).getSession().getLogin().setTableQualifier(tapSchemaName); -// } - return em; - } - - /** - * Create the TAP_SCHEMA schema into the database. - */ - protected static void createTapSchemaSchema(DBWrapper dbs, String tapSchemaName) throws SQLException { - - DatabaseType dbType = dbs.getTapSchemaDatabaseType(); - - try (Connection connection = dbs.getTapSchemaConnection(); - Statement statement = connection.createStatement()) { - - if (dbType == DatabaseType.MYSQL) { - statement.executeUpdate("CREATE DATABASE IF NOT EXISTS `" + tapSchemaName + "`"); - } else if (dbType == DatabaseType.POSTGRES) { - statement.executeUpdate("CREATE SCHEMA IF NOT EXISTS \"" + tapSchemaName + "\""); - } else { - throw new UnsupportedOperationException("Database type " + dbType + " not supported"); - } - } - } - - /** - * Retrieve the list of the names of all the tables contained in a schema, - * given their related DataSource and schema name. - * - * @return list of all tables names alphabetically and case insensitively - * ordered. - */ - protected static List getAllTablesNames(DataSource dataSource, DatabaseType dbType, String schemaName) throws SQLException { - - String query; - if (dbType == DatabaseType.MYSQL) { - query = "SHOW TABLES FROM `" + schemaName + "`"; - } else if (dbType == DatabaseType.POSTGRES) { - query = "SELECT tablename FROM pg_catalog.pg_tables where schemaname = '" + schemaName + "'"; - } else { - throw new UnsupportedOperationException("Database type " + dbType + " not supported"); - } - - log.debug("Executing query {}", query); - - List 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 sortStringsList(allTables); - } - - /** - * Retrieve the association between the tables names and their types - * (table or view), given a - * DataSource and a schema name. - * - * @return a map which has the tables names as keys and the table types as - * values. - */ - protected static Map getTablesTypes(DataSource dataSource, DatabaseType dbType, String schemaName) throws SQLException { - final Map tablesTypes = new HashMap<>(); - - String query; - if (dbType == DatabaseType.MYSQL) { - query = "SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = '" + schemaName + "'"; - } else if (dbType == DatabaseType.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 + "'"; - } 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 tableName = resultSet.getString("table_name"); - String tableType = resultSet.getString("table_type").equalsIgnoreCase("VIEW") ? "view" : "table"; - tablesTypes.put(tableName, tableType); - } - } - - return tablesTypes; - } - - /** - * Generate list of KeyEntity for a given schema, specifying its - * DataSource and its name.
- * IMPORTANT: this keys are without id. The id has to be - * set when a table is added to a schema. - */ - protected static List getSchemaKeys(DataSource dataSource, DatabaseType dbType, String schemaName) throws SQLException { - - if (dbType == DatabaseType.MYSQL) { - - Map schemaKeysMap = 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"); - - KeyEntity key = schemaKeysMap.get(constraintName); - if (key == null) { - key = new KeyEntity( - resultSet.getString("from_schema"), - resultSet.getString("from_table"), - resultSet.getString("target_schema"), - resultSet.getString("target_table") - ); - schemaKeysMap.put(constraintName, key); - } - - KeyColumnEntity keyColumnEntity = new KeyColumnEntity(); - keyColumnEntity.setFromColumn(resultSet.getString("from_column")); - keyColumnEntity.setTargetColumn(resultSet.getString("target_column")); - } - } - - return new ArrayList<>(schemaKeysMap.values()); - - } else if (dbType == DatabaseType.POSTGRES) { - - String databaseName = ((PGPoolingDataSource) dataSource).getDatabaseName(); - - List 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[] fromTableFullNameSplitted = resultSet.getString("from_table").split(Pattern.quote(".")); - String fromSchema = fromTableFullNameSplitted[0]; - String fromTable = fromTableFullNameSplitted[1]; - - String[] targetTableFullNameSplitted = resultSet.getString("target_table").split(Pattern.quote(".")); - String targetSchema = targetTableFullNameSplitted[0]; - String targetTable = targetTableFullNameSplitted[1]; - - KeyEntity key = new KeyEntity(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()) { - KeyColumnEntity keyColumn = new KeyColumnEntity(); - keyColumn.setFromColumn(rsFromKC.getString("key_column")); - keyColumn.setTargetColumn(rsTargetKC.getString("key_column")); - key.getKeyColumns().add(keyColumn); - } - } - } - } - } - } - - return schemaKeys; - } else { - throw new UnsupportedOperationException("Database type " + dbType + " not supported"); - } - } - - private static boolean equalsOneOf(String string, String... values) { - for (String value : values) { - if (string.equals(value)) { - return true; - } - } - return false; - } - - /** - * A list of ALL the possible {@link ColumnEntity} for a - * given DataSource and a given {@link TableEntity}.
- * IMPORTANT: this list includes also the - * ColumnEntity instances that aren't exposed by the - * TAP_SCHEMA. This choice was done for performance reasons, to avoid - * repeating the query for adding new columns. A ColumnEntity - * will be persisted to the TAP_SCHEMA if it was added to its - * TableEntity using the methods - * {@link TableEntity.addColumn()}. - */ - protected static List getAllColumns(DataSource dataSource, DatabaseType dbType, TableEntity table) throws SQLException { - final List allColumns = new ArrayList<>(); - - String query; - if (dbType == DatabaseType.MYSQL) { - query = String.format("SHOW COLUMNS FROM `%s`.`%s`", table.getSchemaName(), table.getShortTableName()); - } 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 = '" + table.getSchemaName() + "' AND t.tablename = '" + table.getShortTableName() + "'"; - } 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"); - } - - ColumnEntity columnEntity = DLUtil.getEntityByName(table.getColumns(), columnName); - boolean alreadyLoaded = columnEntity != null; - - if (columnEntity == null) { - columnEntity = new ColumnEntity(columnName); - } - - columnEntity.setFullTableName(table.getName()); - columnEntity.setTable(table); - - // Key type - if (dbType == DatabaseType.MYSQL) { - String key = resultSet.getString("Key"); - columnEntity.setPrimaryKey(key.equals("PRI")); - columnEntity.setIndexed(equalsOneOf(key, "PRI", "UNI", "MUL") ? 1 : 0); - if (!alreadyLoaded) { - columnEntity.setPrincipal(key.equals("PRI") ? 1 : 0); - } - } else if (dbType == DatabaseType.POSTGRES) { - String columnType = resultSet.getString("column_type"); - if (columnType != null) { - columnEntity.setPrimaryKey("p".equals(columnType)); - columnEntity.setIndexed(equalsOneOf(columnType, "p", "f", "u") ? 1 : 0); - } - if (!alreadyLoaded) { - columnEntity.setPrincipal("p".equals(columnType) ? 1 : 0); - } - } 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"); - } - - columnEntity.setDatatype(datatype); - columnEntity.setSize(size); - - if (!alreadyLoaded) { - columnEntity.setStd(0); - } - - allColumns.add(columnEntity); - } - } - - return allColumns; - } } diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoColumn.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoColumn.java new file mode 100644 index 0000000..e5d47f8 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoColumn.java @@ -0,0 +1,225 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Column; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.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 } + */ +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; + } + + /** + * 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 loadAllTableColumns(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName, Table table) throws SQLException { + String tableSimpleName = table.getName(); + final List allColumns = new ArrayList<>(); + + DataSource dataSource = DLUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName); + DatabaseType dbType = DLUtil.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]; + + Table table = tapSchema.getChild(schemaName).getChild(tableSimpleName); + Column column = table.addChild(columnName); + 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoKey.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoKey.java new file mode 100644 index 0000000..05627b3 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoKey.java @@ -0,0 +1,465 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.KeyColumn; +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.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.postgresql.ds.PGPoolingDataSource; +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 } + */ +public class DaoKey { + + private static final Logger log = LoggerFactory.getLogger(DaoKey.class); + + /** + * Generate list of KeyEntity for a given schema, specifying its + * DataSource and its name.
+ * IMPORTANT: this keys are without id. The id has to be + * set when a table is added to a schema. + */ + protected static List getSchemaKeys(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) throws SQLException { + + log.debug("getSchemaKeys"); + + DataSource dataSource = DLUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName); + DatabaseType dbType = DLUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName); + + if (dbType == DatabaseType.MYSQL) { + + Map 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 = ((PGPoolingDataSource) dataSource).getDatabaseName(); + + List 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 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); + } + } + + 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(); + 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(), + DLUtil.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 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) { + throw new InconsistentTapSchemaException("Saved TAP_SCHEMA contains a key that is referred to a schema that wasn't added to that TAP_SCHEMA."); + } + + Table fromTable = fromSchema.getChild(fromTableName); + if (fromTable == null) { + throw new InconsistentTapSchemaException("Saved TAP_SCHEMA contains a key that is referred to a table that wasn't added to that TAP_SCHEMA."); + } + + String keyId = rsKeys.getString(Key.ID_KEY); + // 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, DLUtil.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, DLUtil.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 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) { + 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, DLUtil.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); + } + } + + if (!fictitiousKeys.isEmpty()) { + log.debug("{} fictitious keys found", fictitiousKeys.size()); + for (Key key : fictitiousKeys) { + log.debug(" {}", 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); + + KeyColumnImpl keyColumn = new KeyColumnImpl(dbWrapper, tapSchema, key, fromColumn, targetColumn); + if (supportKeyColumnID) { + keyColumn.initProperty(KeyColumn.KEY_COLUMN_ID_KEY, DLUtil.getObject(rsKeyColumns, KeyColumn.KEY_COLUMN_ID_KEY, Long.class)); + } + } + } + } + + // adding fictitious key to key set + ((TapSchemaImpl) tapSchema).getAllKeys().add(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 = DLUtil.escapeName(tapSchema.getName(), dbType); + String keyColumnsNameEscaped = DLUtil.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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoSchema.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoSchema.java new file mode 100644 index 0000000..d74629a --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoSchema.java @@ -0,0 +1,117 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.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 } + */ +public class DaoSchema { + + private static final Logger log = LoggerFactory.getLogger(DaoSchema.class); + + /** + * Retrieve the list of the names of the all the schemas contained into the + * database specified by the DataSource parameter. + * + * @return list of schemas names alphabetically and case insensitively + * ordered. + */ + public static List 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 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 DLUtil.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); + 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoTable.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoTable.java new file mode 100644 index 0000000..0de8b5f --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/DaoTable.java @@ -0,0 +1,169 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.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 } + */ +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 their related DataSource and schema name. + * + * @return list of all tables names alphabetically and case insensitively + * ordered. + */ + protected static List getAllTablesNames(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) throws SQLException { + + DataSource dataSource = DLUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName); + DatabaseType dbType = DLUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName); + + String query; + if (dbType == DatabaseType.MYSQL) { + query = "SHOW TABLES FROM `" + schemaName + "`"; + } else if (dbType == DatabaseType.POSTGRES) { + query = "SELECT tablename FROM pg_catalog.pg_tables where schemaname = '" + schemaName + "'"; + } else { + throw new UnsupportedOperationException("Database type " + dbType + " not supported"); + } + + log.debug("Executing query {}", query); + + List 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 DLUtil.sortStringsList(allTables); + } + + /** + * Retrieve the association between the tables names and their types + * (table or view), given a + * DataSource and a schema name. + * + * @return a map which has the tables names as keys and the table types as + * values. + */ + protected static Map getTablesTypes(DBWrapper dbWrapper, TapSchema tapSchema, String schemaName) throws SQLException { + + log.debug("getTablesTypes"); + + final Map tablesTypes = new HashMap<>(); + + DataSource dataSource = DLUtil.getSchemaDataSource(dbWrapper, tapSchema, schemaName); + DatabaseType dbType = DLUtil.getSchemaDatabaseType(dbWrapper, tapSchema, schemaName); + + String query; + if (dbType == DatabaseType.MYSQL) { + query = "SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = '" + schemaName + "'"; + } else if (dbType == DatabaseType.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 + "'"; + } 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 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); + + Table table = schema.addChild(completeTableName.split(Pattern.quote("."))[1]); + table.setStatus(Status.ADDED_PERSISTED); + return table; + } + }; + + 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EditableProperty.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EditableProperty.java new file mode 100644 index 0000000..83c8d78 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EditableProperty.java @@ -0,0 +1,66 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import java.io.Serializable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represent an {@code EntityProperty} which value can be modified by the user. + * + * @author Sonia Zorba {@literal } + */ +public class EditableProperty implements EntityProperty, Serializable { + + private static final long serialVersionUID = 4896192667771442640L; + private static final Logger log = LoggerFactory.getLogger(EditableProperty.class); + + private final T defaultValue; + private final boolean allowsNull; + private T originalValue; + private T value; + + public EditableProperty() { + this.defaultValue = null; + this.allowsNull = true; + this.init(defaultValue); + } + + public EditableProperty(T defaultValue, boolean allowsNull) { + this.defaultValue = defaultValue; + this.allowsNull = allowsNull; + this.init(defaultValue); + } + + @Override + public X getValue(Class type) { + return (X) value; + } + + public X getOriginalValue(Class type) { + return (X) originalValue; + } + + public void setValue(X value) { + if (value == null && !allowsNull) { + throw new IllegalArgumentException("This EditableProperty instance doesn't allow null values"); + } + this.value = (T) value; + } + + public boolean isChanged() { + if (originalValue == null) { + return value != null; + } + return !originalValue.equals(value); + } + + @Override + public final void init(X initialValue) { + setValue(initialValue); + this.originalValue = (T) initialValue; + } + + public void save() { + this.originalValue = value; + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EntityProperty.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EntityProperty.java new file mode 100644 index 0000000..e8dcbee --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EntityProperty.java @@ -0,0 +1,20 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +/** + * Store the value of an entity property (that corresponds to a column of the + * mapped table). + * + * @author Sonia Zorba {@literal } + */ +public interface EntityProperty { + + /** + * Retrieve the current value. + */ + T getValue(Class type); + + /** + * Initialize the value. + */ + void init(T initialValue); +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EntityPropertyInfo.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EntityPropertyInfo.java new file mode 100644 index 0000000..f73bdc2 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/EntityPropertyInfo.java @@ -0,0 +1,183 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Column; +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.KeyColumn; +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.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.oats.ia2.tapschemamanager.contract.TapSchemaEntity} instances + * and their related table columns. + * + * @author Sonia Zorba {@literal } + */ +public class EntityPropertyInfo { + + private static final Logger log = LoggerFactory.getLogger(EntityPropertyInfo.class); + + private static final Map> propertiesMap = new HashMap<>(); + + static { + List 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 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 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.COLUMN_ID_KEY, Long.class, true, TapSchemaVersion.TAP_SCHEMA_1_IA2, TapSchemaVersion.TAP_SCHEMA_1_1_IA2)); + + List 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 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 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/FixedEntityProperty.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/FixedEntityProperty.java new file mode 100644 index 0000000..07664be --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/FixedEntityProperty.java @@ -0,0 +1,33 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import java.io.Serializable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represent an {@code EntityProperty} which value can't be modified by the + * user. + * + * @author Sonia Zorba {@literal } + */ +public class FixedEntityProperty implements EntityProperty, Serializable { + + private static final long serialVersionUID = -7009289405382798659L; + private static final Logger log = LoggerFactory.getLogger(EntityPropertyInfo.class); + + private T value; + + public FixedEntityProperty(T value) { + init(value); + } + + @Override + public final void init(X initialValue) { + this.value = (T) initialValue; + } + + @Override + public X getValue(Class type) { + return (X) value; + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/InconsistentTapSchemaException.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/InconsistentTapSchemaException.java new file mode 100644 index 0000000..d0d5b8d --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/InconsistentTapSchemaException.java @@ -0,0 +1,14 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +/** + * + * @author Sonia Zorba {@literal } + */ +public class InconsistentTapSchemaException extends RuntimeException { + + private static final long serialVersionUID = 2722256809774917529L; + + public InconsistentTapSchemaException(String message) { + super(message); + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/InsertQueryBuilder.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/InsertQueryBuilder.java new file mode 100644 index 0000000..d01972a --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/InsertQueryBuilder.java @@ -0,0 +1,76 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.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 } + */ +public class InsertQueryBuilder { + + private static final Logger log = LoggerFactory.getLogger(InsertQueryBuilder.class); + + private final String query; + private final List addedProperties; + private final TapSchemaEntity tapSchemaEntity; + + protected InsertQueryBuilder(DatabaseType dbType, TapSchema tapSchema, TapSchemaEntity tapSchemaEntity, String tapSchemaTableName) { + + StringBuilder querySb = new StringBuilder("INSERT INTO "); + querySb.append(DLUtil.escapeName(tapSchema.getName(), dbType)); + querySb.append("."); + querySb.append(DLUtil.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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyColumnEntity.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyColumnEntity.java deleted file mode 100644 index 5633ff0..0000000 --- a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyColumnEntity.java +++ /dev/null @@ -1,114 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.datalayer; - -import java.io.Serializable; -import java.math.BigInteger; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.IdClass; -import javax.persistence.ManyToOne; -import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.Table; - -class KeyColumn implements Serializable { - - private static final long serialVersionUID = 1244476100879775193L; - - String keyId; - String fromColumn; - String targetColumn; -} - -/** - * JPA entity for the table TAP_SCHEMA.key_columns. - * - * @author Sonia Zorba {@literal } - */ -@Entity -@IdClass(KeyColumn.class) -@Table(name = "key_columns") -public class KeyColumnEntity implements Serializable { - - private static final long serialVersionUID = -1841850907719547336L; - - @Id - @Column(name = "key_id", length = 64) - private String keyId; - - @Id - @Column(name = "from_column", length = 64) - private String fromColumn; - - @Id - @Column(name = "target_column", length = 64) - private String targetColumn; - - @Column(name = "key_columnID") - private BigInteger keyColumnID; - - @ManyToOne(fetch = FetchType.EAGER) - @PrimaryKeyJoinColumn(name = "key_id", referencedColumnName = "key_id") - private KeyEntity key; - - /** - * The value in the key_id column. - */ - public String getKeyId() { - return keyId; - } - - public void setKeyId(String keyId) { - this.keyId = keyId; - } - - /** - * The value in the from_column column. - */ - public String getFromColumn() { - return fromColumn; - } - - public void setFromColumn(String fromColumn) { - this.fromColumn = fromColumn; - } - - /** - * The value in the target_column column. - */ - public String getTargetColumn() { - return targetColumn; - } - - public void setTargetColumn(String targetColumn) { - this.targetColumn = targetColumn; - } - - /** - * The value in the key_columnID column: it represents - * [TODO]... - */ - public BigInteger getKeyColumnID() { - return keyColumnID; - } - - public void setKeyColumnID(BigInteger keyColumnID) { - this.keyColumnID = keyColumnID; - } - - /** - * The KeyEntity that owns this KeyColumnEntity. - */ - public KeyEntity getKey() { - return key; - } - - public void setKey(KeyEntity key) { - this.key = key; - } - - @Override - public String toString() { - return String.format("%s->%s", fromColumn, targetColumn); - } -} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyColumnImpl.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyColumnImpl.java new file mode 100644 index 0000000..9ec3565 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyColumnImpl.java @@ -0,0 +1,98 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.KeyColumn; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import java.util.Objects; + +/** + * The main implementation of {@link KeyColumn}. + * + * @author Sonia Zorba {@literal } + */ +public class KeyColumnImpl extends TapSchemaEntityImpl implements KeyColumn { + + private static final long serialVersionUID = -3681677723432728327L; + + private Key key; + + private KeyColumnImpl() { + // for serialization + super(); + } + + protected KeyColumnImpl(DBWrapper dbWrapper, TapSchema tapSchema, Key key, String fromColumn, String targetColumn) { + super(dbWrapper, tapSchema); + 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()); + } + + @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; + hash = 97 * hash + Objects.hashCode(this.key.getFromTableCompleteName()); + hash = 97 * hash + Objects.hashCode(this.getFromColumn()); + hash = 97 * hash + Objects.hashCode(this.key.getTargetTableCompleteName()); + hash = 97 * hash + Objects.hashCode(this.getTargetColumn()); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final KeyColumnImpl other = (KeyColumnImpl) obj; + if (!Objects.equals(this.key.getFromTableCompleteName(), other.key.getFromTableCompleteName())) { + return false; + } + if (!Objects.equals(this.getFromColumn(), other.getFromColumn())) { + return false; + } + if (!Objects.equals(this.key.getTargetTableCompleteName(), other.key.getTargetTableCompleteName())) { + return false; + } + if (!Objects.equals(this.getTargetColumn(), other.getTargetColumn())) { + return false; + } + return true; + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyEntity.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyEntity.java deleted file mode 100644 index 08d367a..0000000 --- a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyEntity.java +++ /dev/null @@ -1,250 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.datalayer; - -import java.io.Serializable; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.Table; -import javax.persistence.Transient; - -/** - * JPA entity for the table TAP_SCHEMA.keys. - * - * @author Sonia Zorba {@literal } - */ -@Entity -@Table(name = "\"keys\"") -public class KeyEntity implements Serializable { - - private static final long serialVersionUID = 4321901642780866919L; - - @Id - @Column(name = "key_id", length = 64) - private String keyId; - - @Column(name = "from_table", length = 128) - private String fromTableFullName; - - @Column(name = "target_table", length = 128) - private String targetTableFullName; - - @Column(name = "utype", length = 512) - private String utype; - - @Column(name = "description", length = 512) - private String description; - - @Column(name = "keyID") - private BigInteger keyID; - - @ManyToOne(fetch = FetchType.EAGER) - @PrimaryKeyJoinColumn(name = "from_table", referencedColumnName = "table_name") - private TableEntity fromTable; - - @ManyToOne(fetch = FetchType.EAGER) - @PrimaryKeyJoinColumn(name = "target_table", referencedColumnName = "table_name") - private TableEntity targetTable; - - @OneToMany(mappedBy = "key", cascade = CascadeType.ALL, orphanRemoval = true) - private final List keyColumns; - - @Transient - private String fromSchemaName; - @Transient - private String targetSchemaName; - - public KeyEntity() { - keyColumns = new ArrayList<>(); - } - - public KeyEntity(String fromSchema, String fromTable, String targetSchema, String targetTable) { - this(); - this.fromSchemaName = fromSchema; - this.fromTableFullName = fromSchema + "." + fromTable; - this.targetSchemaName = targetSchema; - this.targetTableFullName = targetSchema + "." + targetTable; - } - - /** - * The TAP standard define the key ID as a VARCHAR, but in our - * implementation we assume it represents a numeric value - * - * @param keyId - ID of the key - */ - public KeyEntity(int keyId) { - this(); - this.keyId = keyId + ""; - } - - /** - * The value in the key_id column: represents the ID of the key - * (in our implementation we assume it represents a numeric value). - */ - public String getKeyId() { - return keyId; - } - - public void setKeyId(String keyId) { - this.keyId = keyId; - } - - /** - * The value in the from_table column: it is the complete name - * of the table, as defined in the TAP standard: so it is - * <schema-name>.<table-name>. - */ - public String getFromTableFullName() { - return fromTableFullName; - } - - public void setFromTableFullName(String fromTableFullName) { - this.fromTableFullName = fromTableFullName; - } - - /** - * The value in the target_table column: it is the complete - * name of the table, as defined in the TAP standard: so it is - * <schema-name>.<table-name>. - */ - public String getTargetTableFullName() { - return targetTableFullName; - } - - public void setTargetTableFullName(String targetTableFullName) { - this.targetTableFullName = targetTableFullName; - } - - /** - * The value in the utype column. - */ - public String getUtype() { - return utype; - } - - public void setUtype(String utype) { - this.utype = utype; - } - - /** - * The value in the description column. - */ - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - /** - * The value in the keyID column: it represents [TODO]... - */ - public BigInteger getKeyID() { - return keyID; - } - - public void setKeyID(BigInteger keyID) { - this.keyID = keyID; - } - - /** - * @return the {@link TableEntity} related to the from_table - * field - */ - public TableEntity getFromTable() { - return fromTable; - } - - public void setFromTable(TableEntity fromTable) { - this.fromTable = fromTable; - } - - /** - * @return the {@link TableEntity} related to the target_table - * field - */ - public TableEntity getTargetTable() { - return targetTable; - } - - public void setTargetTable(TableEntity targetTable) { - this.targetTable = targetTable; - } - - /** - * List of the KeyColumnEntity owned by this - * KeyEntity. - */ - public List getKeyColumns() { - return keyColumns; - } - - public String getFromSchemaName() { - return fromSchemaName; - } - - public void setFromSchemaName(String fromSchemaName) { - this.fromSchemaName = fromSchemaName; - } - - public String getTargetSchemaName() { - return targetSchemaName; - } - - public void setTargetSchemaName(String targetSchemaName) { - this.targetSchemaName = targetSchemaName; - } - - protected void reset() { - this.keyId = null; - for (KeyColumnEntity keyColumn : keyColumns) { - keyColumn.setKeyId(null); - keyColumn.setKey(null); - } - } - - @Override - public int hashCode() { - int hash = 5; - hash = 83 * hash + Objects.hashCode(this.keyId); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final KeyEntity other = (KeyEntity) obj; - - if (this.keyId == null || other.keyId == null) { - throw new UnsupportedOperationException("Cannot compare KeyEntity instances with null keyId"); - } - - return this.keyId.equals(other.keyId); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(String.format("key_id=%s\n", keyId)); - for (KeyColumnEntity keyColumn : keyColumns) { - sb.append("\t"); - sb.append(keyColumn.toString()); - sb.append("\n"); - } - return sb.toString(); - } -} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyImpl.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyImpl.java new file mode 100644 index 0000000..8d3cb7f --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/KeyImpl.java @@ -0,0 +1,226 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.KeyColumn; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +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 } + */ +public class KeyImpl extends TapSchemaEntityImpl implements Key { + + private static final long serialVersionUID = -8783695875831579336L; + + private final List keyColumns; + + private String fromSchema; + private String fromTable; + private String targetSchema; + private String targetTable; + private boolean visible; + + private KeyImpl() { + // for serialization + 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()); + addProperty(UTYPE_KEY, new EditableProperty()); + addProperty(DESCRIPTION_KEY, new EditableProperty()); + addProperty(KEY_ID_KEY, new EditableProperty()); + + 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 boolean isVisible() { + return visible; + } + + protected void setVisible(boolean visible) { + 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) { + keyColumn.setKeyId(id); + } + } + + @Override + public List getKeyColumns() { + return Collections.unmodifiableList(keyColumns); + } + + @Override + public String getFromSchemaName() { + return fromSchema; + } + + @Override + public String getFromTableSimpleName() { + return fromTable; + } + + @Override + public String getFromTableCompleteName() { + return getValue(FROM_TABLE_KEY, String.class); + } + + @Override + public String getTargetSchemaName() { + return targetSchema; + } + + @Override + public String getTargetTableSimpleName() { + return targetTable; + } + + @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); + keyColumns.add(keyColumn); + return keyColumn; + } + + @Override + public void save() { + super.save(); + for (KeyColumn keyColumn : keyColumns) { + keyColumn.save(); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append(String.format("[%s] %s.%s(", getId(), fromSchema, fromTable)); + + boolean first = true; + for (KeyColumn keyColumn : keyColumns) { + if (!first) { + sb.append(","); + } + first = false; + sb.append(keyColumn.getFromColumn()); + } + + sb.append(String.format(") -> %s.%s(", targetSchema, targetTable)); + + first = true; + for (KeyColumn keyColumn : keyColumns) { + if (!first) { + sb.append(","); + } + first = false; + sb.append(keyColumn.getTargetColumn()); + } + + sb.append(")"); + + return sb.toString(); + } + + @Override + public int hashCode() { + int hash = 7; + for (KeyColumn keyColumn : keyColumns) { + hash = 23 * hash + Objects.hashCode(keyColumn); + } + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + + final KeyImpl other = (KeyImpl) obj; + List otherKeyColumns = other.getKeyColumns(); + + // Comparing each key column + if (keyColumns.size() != otherKeyColumns.size()) { + return false; + } + for (int i = 0; i < keyColumns.size(); i++) { + if (!keyColumns.get(i).equals(otherKeyColumns.get(i))) { + return false; + } + } + + return true; + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SchemaEntity.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SchemaEntity.java deleted file mode 100644 index e072768..0000000 --- a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SchemaEntity.java +++ /dev/null @@ -1,139 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.datalayer; - -import java.io.Serializable; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.MapKeyColumn; -import javax.persistence.OneToMany; -import javax.persistence.Table; - -/** - * JPA entity for the table TAP_SCHEMA.schemas. - * - * @author Sonia Zorba {@literal } - */ -@Entity -@Table(name = "\"schemas\"") -public class SchemaEntity implements Serializable, TapSchemaEntity { - - private static final long serialVersionUID = -1058919664128696098L; - - @Id - @Column(name = "schema_name", length = 64) - private String name; - - @Column(name = "utype", length = 512) - private String utype; - - @Column(name = "description", length = 512) - private String description; - - @Column(name = "schemaID") - private BigInteger schemaID; - - @OneToMany(mappedBy = "schema", cascade = CascadeType.ALL, orphanRemoval = true) - @MapKeyColumn(name = "table_name", insertable = false, updatable = false) - private final List tables; - - protected SchemaEntity() { - this.tables = new ArrayList<>(); - } - - protected SchemaEntity(String schemaName) { - this(); - this.name = schemaName; - } - - /** - * The value in the schema_name column. - */ - @Override - public String getName() { - return name; - } - - protected void setName(String schemaName) { - this.name = schemaName; - } - - /** - * The value in the utype column. - */ - public String getUtype() { - return utype; - } - - public void setUtype(String utype) { - this.utype = utype; - } - - /** - * The value in the description column. - */ - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - /** - * The value in the schemaID column: it represents [TODO]... - */ - protected BigInteger getSchemaID() { - return schemaID; - } - - protected void setSchemaID(BigInteger schemaID) { - this.schemaID = schemaID; - } - - /** - * The list of TableEntity owned by this - * SchemaEntity. - * - * @return an unmodifiable list - */ - public List getTables() { - return Collections.unmodifiableList(tables); - } - - /** - * Find the TableEntity owned by this SchemaEntity - * using its short name (the table name without the schema name). - * - * @return the TableEntity instance if it exists, null - * otherwise. - */ - public TableEntity getTableByShortName(String shortTableName) { - return getTable(name + "." + shortTableName); - } - - /** - * Find the TableEntity owned by this SchemaEntity - * using its complete name (schema_name.table_name). - * - * @return the TableEntity instance if it exists, null - * otherwise. - */ - public TableEntity getTable(String fullTableName) { - return DLUtil.getEntityByName(tables, fullTableName); - } - - protected void addTable(TableEntity table) { - tables.add(table); - table.setSchemaName(name); - table.setSchema(this); - } - - protected void removeTable(String fullTableName) { - DLUtil.removeEntity(tables, fullTableName); - } -} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SchemaImpl.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SchemaImpl.java new file mode 100644 index 0000000..40eed71 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SchemaImpl.java @@ -0,0 +1,268 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +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 Schema}. + * + * @author Sonia Zorba {@literal } + */ +public class SchemaImpl extends ChildEntityImpl implements Schema { + + private static final long serialVersionUID = 8828583158332877855L; + private static final Logger log = LoggerFactory.getLogger(SchemaImpl.class); + + private final Map tables; + private Map tablesTypes; + + private SchemaImpl() { + // for serialization + super(); + tables = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + } + + public SchemaImpl(DBWrapper dbWrapper, TapSchema tapSchema, String name) throws SQLException { + super(dbWrapper, tapSchema); + + tables = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + tablesTypes = DaoTable.getTablesTypes(dbWrapper, tapSchema, name); + + for (String tableName : DaoTable.getAllTablesNames(dbWrapper, tapSchema, 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()); + addProperty(DESCRIPTION_KEY, new EditableProperty()); + addProperty(SCHEMA_ID, new EditableProperty()); + + setStatus(Status.LOADED); + } + + /** + * {@inheritDoc} + * The value in the {@code schema_name} column. + */ + @Override + public String getName() { + return getValue(SCHEMA_NAME_KEY, String.class); + } + + /** + * @param tableSimpleName the name of the table, without the schema name. + * @return + */ + @Override + public Table addChild(String tableSimpleName) throws SQLException { + String schemaName = getName(); + + 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?"); + } + + 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); + } + } + + tables.put(tableSimpleName, table); + table.setStatus(Status.ADDED_NOT_PERSISTED); + } else { + switch (table.getStatus()) { + case TO_REMOVE: + table.setStatus(Status.ADDED_PERSISTED); + break; + case REMOVED_NOT_PERSISTED: + table.setStatus(Status.ADDED_NOT_PERSISTED); + break; + default: + throw new IllegalArgumentException("Invalid table status. The status for " + table.getCompleteName() + " is " + table.getStatus()); + } + } + + ((TapSchemaImpl) tapSchema).checkKeys(); + + return table; + } + + /** + * {@inheritDoc} + */ + @Override + public void removeChild(String tableSimpleName) { + String schemaName = getName(); + + 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?"); + } + + Table table = tables.get(tableSimpleName); + + if (table == null) { + throw new IllegalArgumentException("The table " + tableSimpleName + " has never been loaded into the schema " + schemaName + ". Are you sure you are using the simple table name?"); + } + + if (table.getStatus() == Status.LOADED || table.getStatus() == Status.TO_REMOVE) { + throw new IllegalArgumentException("Invalid table status. The status for " + table.getCompleteName() + " is " + table.getStatus()); + } + + if (table.getStatus() == Status.ADDED_NOT_PERSISTED) { + table.setStatus(Status.REMOVED_NOT_PERSISTED); + } else if (table.getStatus() == Status.ADDED_PERSISTED) { + table.setStatus(Status.TO_REMOVE); + } + + ((TapSchemaImpl) tapSchema).checkKeys(); + } + + /** + * {@inheritDoc} + */ + @Override + public Table getChild(String childName, Status... statuses) { + return DLUtil.getChild(tables, childName, statuses); + } + + /** + * {@inheritDoc} + */ + @Override + public List
getChildren(Status... statuses) { + return DLUtil.getChildrenByStatus(tables.values(), statuses); + } + + /** + * {@inheritDoc} + */ + @Override + public List getAddableChildrenNames() { + return DLUtil.getAddableChildrenNames(tables); + } + + /** + * {@inheritDoc} + */ + @Override + public List
getAddedChildren() { + return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED); + } + + /** + * {@inheritDoc} + */ + @Override + public List
getAddedOrRemovedChildren() { + 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; + hash = 53 * hash + Objects.hashCode(this.getName()); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final SchemaImpl other = (SchemaImpl) obj; + if (!Objects.equals(this.getName(), other.getName())) { + return false; + } + return true; + } + + /** + * This method has to be used after TAP_SCHEMA modifications are committed + * 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) { + if (!tables.containsKey(tableSimpleName)) { + throw new IllegalArgumentException("Schema " + getName() + "doesn't contain the table " + tableSimpleName); + } + tables.put(tableSimpleName, null); + } + + /** + * {@inheritDoc} + */ + @Override + public TapSchema getParent() { + return tapSchema; + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SelectQueryBuilder.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SelectQueryBuilder.java new file mode 100644 index 0000000..32ca24d --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/SelectQueryBuilder.java @@ -0,0 +1,88 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.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 } + */ +public abstract class SelectQueryBuilder { + + private static final Logger log = LoggerFactory.getLogger(SelectQueryBuilder.class); + + private final String query; + private final List addedProperties; + + protected SelectQueryBuilder(DatabaseType dbType, TapSchema tapSchema, String tapSchemaTableName) { + + 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(DLUtil.escapeName(tapSchema.getName(), dbType)); + querySb.append("."); + querySb.append(DLUtil.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); + + for (EntityPropertyInfo property : addedProperties) { + String key = property.getPropertyKey(); + Class type = property.getPropertyType(); + Object value = DLUtil.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) { + throw new InconsistentTapSchemaException("Property " + key + " has " + value + " in TAP_SCHEMA but it should be " + correctValue); + } + } + } + } + } + } + + public String getQuery() { + return query; + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TableEntity.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TableEntity.java deleted file mode 100644 index 92525c7..0000000 --- a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TableEntity.java +++ /dev/null @@ -1,242 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.datalayer; - -import java.io.Serializable; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.regex.Pattern; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.ManyToOne; -import javax.persistence.MapKeyColumn; -import javax.persistence.OneToMany; -import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.Table; - -/** - * JPA entity for the table TAP_SCHEMA.tables. - * - * @author Sonia Zorba {@literal } - */ -@Entity -@Table(name = "tables") -public class TableEntity implements Serializable, TapSchemaEntity { - - private static final long serialVersionUID = 5386350231967268073L; - - @Id - @Column(name = "table_name", length = 128) - private String name; - - @Column(name = "schema_name", length = 64) - private String schemaName; - - @Column(name = "table_type", length = 8) - private String tableType; - - @Column(name = "utype", length = 512) - private String utype; - - @Column(name = "description", length = 512) - private String description; - - @Column(name = "tableID") - private BigInteger tableID; - - @ManyToOne(fetch = FetchType.EAGER) - @PrimaryKeyJoinColumn(name = "schema_name", referencedColumnName = "schema_name") - private SchemaEntity schema; - - @OneToMany(mappedBy = "table", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) - @MapKeyColumn(name = "column_name", insertable = false, updatable = false) - private final List columns; - - @OneToMany(mappedBy = "fromTable", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) - private final List fromKeys; - - @OneToMany(mappedBy = "targetTable", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) - private final List targetKeys; - - protected TableEntity() { - columns = new ArrayList<>(); - fromKeys = new ArrayList<>(); - targetKeys = new ArrayList<>(); - } - - protected TableEntity(SchemaEntity schemaEntity, String shortTableName) { - this(); - this.schema = schemaEntity; - this.schemaName = schemaEntity.getName(); - this.name = schemaName + "." + shortTableName; - } - - /** - * The value in the table_name column: it represents the - * complete table name: schema_name.table_name. - */ - @Override - public String getName() { - return name; - } - - /** - * The table name without the schema name. - */ - public String getShortTableName() { - return name.split(Pattern.quote("."))[1]; - } - - protected void setName(String fullTableName) { - this.name = fullTableName; - } - - /** - * The value in the schema_name column. - */ - public String getSchemaName() { - return schemaName; - } - - protected void setSchemaName(String schemaName) { - this.schemaName = schemaName; - } - - /** - * The value in the table_type column: it could be - * table or view. - */ - public String getTableType() { - return tableType; - } - - public void setTableType(String tableType) { - this.tableType = tableType; - } - - /** - * The value in the utype column. - */ - public String getUtype() { - return utype; - } - - public void setUtype(String utype) { - this.utype = utype; - } - - /** - * The value in the description column. - */ - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - /** - * The value in the tableID column: it represents [TODO]... - */ - protected BigInteger getTableID() { - return tableID; - } - - protected void setTableID(BigInteger tableID) { - this.tableID = tableID; - } - - /** - * The {@link SchemaEntity} that owns this TableEntity. - */ - public SchemaEntity getSchema() { - return schema; - } - - protected void setSchema(SchemaEntity schemaEntity) { - this.schema = schemaEntity; - } - - /** - * The list of ColumnEntity owned by this - * TableEntity. - * - * @return an unmodifiable list - */ - public List getColumns() { - return Collections.unmodifiableList(columns); - } - - /** - * The list of KeyEntity which from_table column - * is the complete name of this TableEntity. - * - * @return an unmodifiable list - */ - public List getFromKeys() { - return Collections.unmodifiableList(fromKeys); - } - - /** - * The list of KeyEntity which target_table column - * is the complete name of this TableEntity. - * - * @return an unmodifiable list - */ - public List getTargetKeys() { - return Collections.unmodifiableList(targetKeys); - } - - protected void addColumn(ColumnEntity column) { - columns.add(column); - column.setFullTableName(name); - column.setTable(this); - } - - protected void removeColumn(String columnName) { - DLUtil.removeEntity(columns, columnName); - } - - public void addFromKey(KeyEntity key) { - if (!fromKeys.contains(key)) { - fromKeys.add(key); - } - } - - public void removeFromKey(KeyEntity key) { - fromKeys.remove(key); - } - - public void addTargetKey(KeyEntity key) { - if (!targetKeys.contains(key)) { - targetKeys.add(key); - } - } - - public void removeTargetKey(KeyEntity key) { - targetKeys.remove(key); - } - - public void removeKeys() { - Iterator iteFromKeys = fromKeys.iterator(); - while (iteFromKeys.hasNext()) { - KeyEntity keyEntity = iteFromKeys.next(); - keyEntity.getTargetTable().removeTargetKey(keyEntity); - iteFromKeys.remove(); - keyEntity.reset(); - } - - Iterator iteTargetKeys = targetKeys.iterator(); - while (iteTargetKeys.hasNext()) { - KeyEntity keyEntity = iteTargetKeys.next(); - keyEntity.getFromTable().removeFromKey(keyEntity); - iteTargetKeys.remove(); - keyEntity.reset(); - } - } -} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TableImpl.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TableImpl.java new file mode 100644 index 0000000..9da946e --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TableImpl.java @@ -0,0 +1,315 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Column; +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.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 } + */ +public class TableImpl extends ChildEntityImpl implements Table { + + private static final long serialVersionUID = 8265331530960896871L; + private static final Logger log = LoggerFactory.getLogger(TableImpl.class); + + private final Map columns; + private final List fromKeys; + private final List 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()); + addProperty(DESCRIPTION_KEY, new EditableProperty()); + addProperty(TABLE_INDEX, new EditableProperty()); + addProperty(TABLE_ID, new EditableProperty()); + + 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); + } + + 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 DLUtil.getChild(columns, childName, statuses); + } + + /** + * {@inheritDoc } + */ + @Override + public List getChildren(Status... statuses) { + return DLUtil.getChildrenByStatus(columns.values(), statuses); + } + + /** + * {@inheritDoc } + */ + @Override + public List getAddableChildrenNames() { + return DLUtil.getAddableChildrenNames(columns); + } + + @Override + public List getAddedChildren() { + return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED); + } + + @Override + public List 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 getVisibleFromKeys() { + List ret = new ArrayList<>(); + for (Key key : fromKeys) { + if (key.isVisible()) { + ret.add(key); + } + } + return Collections.unmodifiableList(ret); + } + + @Override + public List getAllFromKeys() { + return Collections.unmodifiableList(fromKeys); + } + + @Override + public List getVisibleTargetKeys() { + List ret = new ArrayList<>(); + for (Key key : targetKeys) { + if (key.isVisible()) { + ret.add(key); + } + } + return Collections.unmodifiableList(ret); + } + + @Override + public List 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/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaEntity.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaEntity.java deleted file mode 100644 index e157ca8..0000000 --- a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaEntity.java +++ /dev/null @@ -1,21 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.datalayer; - -/** - * Interface that represents one of the principal entities of the TAP_SCHEMA, so - * it can be an instance of {@link SchemaEntity}, {@link TableEntity} or - * {@link ColumnEntity}. - * - * {@link KeyEntity} and {@link KeyColumnEntity} aren't included because their - * management is different. - * - * @author Sonia Zorba {@literal } - */ -public interface TapSchemaEntity { - - /** - * It can be the schema name, the table name or the column name. - * - * @return the name of the entity - */ - String getName(); -} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaEntityImpl.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaEntityImpl.java new file mode 100644 index 0000000..f32e146 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaEntityImpl.java @@ -0,0 +1,122 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchemaEntity; +import it.inaf.oats.ia2.tapschemamanager.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 } + */ +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 properties; + private final String tapSchemaEntityTable; + protected DBWrapper dbWrapper; + protected TapSchema tapSchema; + + protected TapSchemaEntityImpl() { + // for serialization + properties = new HashMap<>(); + tapSchemaEntityTable = DLUtil.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 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 instanceof EditableProperty && ((EditableProperty) property).isChanged()) { + return true; + } + } + return false; + } + + @Override + public T getValue(String key, Class type) { + if (!EntityPropertyInfo.getEntityPropertyInfo(tapSchemaEntityTable, key).acceptVersion(tapSchema.getVersion())) { + throw DLUtil.getUnsupportedOperationException(getVersion(), key + " property"); + } + return properties.get(key).getValue(type); + } + + public void setValue(String key, T value) { + EntityProperty property = properties.get(key); + if (property instanceof EditableProperty) { + if (!EntityPropertyInfo.getEntityPropertyInfo(tapSchemaEntityTable, key).acceptVersion(tapSchema.getVersion())) { + throw DLUtil.getUnsupportedOperationException(getVersion(), key + " property"); + } + ((EditableProperty) property).setValue(value); + } else { + throw new IllegalArgumentException("Property " + key + " isn't editable"); + } + } + + @Override + public T getOriginalValue(String key, Class type) { + EntityProperty property = properties.get(key); + if (property instanceof EditableProperty) { + return ((EditableProperty) property).getOriginalValue(type); + } + throw new IllegalArgumentException("Property " + key + " hasn't original value"); + } + + @Override + public boolean isChanged(String key) { + EntityProperty property = properties.get(key); + if (property instanceof EditableProperty) { + return ((EditableProperty) property).isChanged(); + } + return false; + } + + @Override + public List 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(); + } + } + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaFactory.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaFactory.java new file mode 100644 index 0000000..cc00106 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaFactory.java @@ -0,0 +1,21 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchemaVersion; +import java.sql.SQLException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Factory for {@link TapSchema} instances. + * + * @author Sonia Zorba {@literal } + */ +public class TapSchemaFactory { + + private final static Logger log = LoggerFactory.getLogger(TapSchemaFactory.class); + + public static TapSchema getTapSchema(TapSchemaVersion version, DBWrapper dbWrapper, String tapSchemaName, boolean exists) throws SQLException { + return new TapSchemaImpl(version, dbWrapper, tapSchemaName, exists); + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaHandler.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaHandler.java deleted file mode 100644 index 1cf499c..0000000 --- a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaHandler.java +++ /dev/null @@ -1,486 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.datalayer; - -import java.io.Closeable; -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.sql.DataSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class SchemaInfo implements Serializable { - - private static final long serialVersionUID = 2835388936102349727L; - - private final List allSchemaTables; - private final List schemaKeys; - private final Map tablesType; - - SchemaInfo(DataSource dataSource, DatabaseType dbType, String schemaName) throws SQLException { - allSchemaTables = Dao.getAllTablesNames(dataSource, dbType, schemaName); - schemaKeys = Dao.getSchemaKeys(dataSource, dbType, schemaName); - tablesType = Dao.getTablesTypes(dataSource, dbType, schemaName); - } - - public List getAllSchemaTables() { - return allSchemaTables; - } - - public List getSchemaKeys() { - return schemaKeys; - } - - public Map getTablesType() { - return tablesType; - } -} - -class ColumnsInfo implements Serializable { - - private static final long serialVersionUID = -3407052226160044192L; - - private final String tapSchemaName; - private final Map>> columnsInfo; - - ColumnsInfo(String tapSchemaName) { - this.tapSchemaName = tapSchemaName; - this.columnsInfo = new HashMap<>(); - } - - void addColumnsInfo(DBWrapper dbWrapper, TableEntity tableEntity) throws SQLException { - String schemaName = tableEntity.getSchemaName(); - Map> map = columnsInfo.get(schemaName); - if (map == null) { - map = new HashMap<>(); - columnsInfo.put(schemaName, map); - } - - List allColumns; - if (schemaName.equals(tapSchemaName)) { - allColumns = Dao.getAllColumns(dbWrapper.getTapSchemaDataSource(), dbWrapper.getTapSchemaDatabaseType(), tableEntity); - } else { - allColumns = Dao.getAllColumns(dbWrapper.getSourceDataSource(), dbWrapper.getSourceDatabaseType(), tableEntity); - } - map.put(tableEntity.getShortTableName(), allColumns); - } - - List getColumnEntities(String schemaName, String shortTableName) { - return columnsInfo.get(schemaName).get(shortTableName); - } -} - -/** - * This class manage load of TAP_SCHEMA entities and other database schemas - * informations. IMPORTANT: If you use this class inside - * another object remember to call the close method to release the occupied - * resources. - * - * @author Sonia Zorba {@literal } - */ -public class TapSchemaHandler implements Serializable, Closeable { - - private static final long serialVersionUID = 1193743698810532785L; - private static final Logger log = LoggerFactory.getLogger(TapSchemaHandler.class); - - private final DBWrapper dbWrapper; - - private final String tapSchemaName; - private boolean exists; - - private final List allSchemas; - private final List schemas; - private final List persistedSchemas; - private final List toRemoveSchemas; - - private final Map allSchemaInfos; - - private final ColumnsInfo columnsInfo; - - private transient EntityManager entityManager; - - public TapSchemaHandler(DBWrapper dbWrapper, String tapSchemaName, boolean exists) throws SQLException { - this.dbWrapper = dbWrapper; - this.tapSchemaName = tapSchemaName; - this.exists = exists; - - this.allSchemas = Dao.getAllSchemasNames(dbWrapper.getSourceDataSource(), dbWrapper.getSourceDatabaseType()); - - this.schemas = new ArrayList<>(); - this.persistedSchemas = new ArrayList<>(); - this.toRemoveSchemas = new ArrayList<>(); - - this.allSchemaInfos = new HashMap<>(); - - this.columnsInfo = new ColumnsInfo(tapSchemaName); - - if (exists) { - loadEntityManager(); - CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(SchemaEntity.class); - - // Load all SchemaEntities saved into the TAP_SCHEMA - //List savedSchemas = - for (SchemaEntity schemaEntity : entityManager.createQuery(cq).getResultList()) { - String schemaName = schemaEntity.getName(); - addSchema(schemaEntity); - - persistedSchemas.add(schemaName); - for (TableEntity tableEntity : schemaEntity.getTables()) { - columnsInfo.addColumnsInfo(dbWrapper, tableEntity); - } - } - } - } - - /** - * Retrieve the SchemaInfo object for a given schema name. The schema - * doesn't need to be already added into the TAP_SCHEMA. This method - * retrieves information about an arbitrary schema. The information is - * lazy-loaded into the {@code allSchemaInfos} map. - */ - private SchemaInfo getSchemaInfo(String schemaName) throws SQLException { - SchemaInfo schemaInfo = allSchemaInfos.get(schemaName); - if (schemaInfo == null) { - if (schemaName.equals(tapSchemaName)) { - schemaInfo = new SchemaInfo(dbWrapper.getTapSchemaDataSource(), dbWrapper.getTapSchemaDatabaseType(), schemaName); - } else { - schemaInfo = new SchemaInfo(dbWrapper.getSourceDataSource(), dbWrapper.getSourceDatabaseType(), schemaName); - } - allSchemaInfos.put(schemaName, schemaInfo); - } - return schemaInfo; - } - - /** - * Create a {@code SchemaEntity} that is not already added into the - * TAP_SCHEMA. - * - * @param schemaName the name of the schema - */ - public SchemaEntity getNewSchema(String schemaName) throws SQLException { - return new SchemaEntity(schemaName); - } - - /** - * Add an existing {@code SchemaEntity} to the TAP_SCHEMA. The - * {@code SchemaEntity} needs to be created using the - * {@link #getNewSchema(String)} method. - * - * @param schemaEntity the {@code SchemaEntity} to add - */ - public final void addSchema(SchemaEntity schemaEntity) throws SQLException { - schemas.add(schemaEntity); - - for (TableEntity tableEntity : schemaEntity.getTables()) { - addTableKeys(schemaEntity, tableEntity); - } - } - - /** - * Remove a {@link SchemaEntity} from the TAP_SCHEMA. - * - * @param schemaName the name of the schema to remove - */ - public final void removeSchema(String schemaName) { - for (TableEntity tableEntity : DLUtil.getEntityByName(schemas, schemaName).getTables()) { - tableEntity.removeKeys(); - } - - if (persistedSchemas.contains(schemaName)) { - toRemoveSchemas.add(getSchema(schemaName)); - persistedSchemas.remove(schemaName); - } - DLUtil.removeEntity(schemas, schemaName); - } - - public List getSchemas() { - return schemas; - } - - /** - * Return the list of the names of all schemas that are inside the source - * database. - */ - public List getAllSchemas() { - return allSchemas; - } - - /** - * Return the list of the names of all the tables that are inside a given - * schema.
This returns both the tables that were added into the - * TAP_SCHEMA and the tables that weren't. - */ - public List getAllTables(String schemaName) throws SQLException { - return getSchemaInfo(schemaName).getAllSchemaTables(); - } - - public List getColumnEntities(String schemaName, String shortTableName) { - return columnsInfo.getColumnEntities(schemaName, shortTableName); - } - - /** - * 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 getMaxKey() { - int maxKey = 0; - for (SchemaEntity schemaEntity : schemas) { - for (TableEntity tableEntity : schemaEntity.getTables()) { - for (KeyEntity keyEntity : tableEntity.getFromKeys()) { - int key = Integer.parseInt(keyEntity.getKeyId()); - if (key > maxKey) { - maxKey = key; - } - } - for (KeyEntity keyEntity : tableEntity.getTargetKeys()) { - int key = Integer.parseInt(keyEntity.getKeyId()); - if (key > maxKey) { - maxKey = key; - } - } - } - } - return maxKey; - } - - /** - * Create a {@code TableEntity} that isn't already added into a - * {@code SchemaEntity}.
The {@code SchemaEntity} needs to exists and to - * be already added into the TAP_SCHEMA (loaded from the beginning or - * created with the {@link #getNewSchema(String)} method and then added - * using the {@link #addSchema(SchemaEntity)} method). - * - * @param schemaEntity the {@code SchemaEntity} that owns the table - * @param shortTableName the name of the table (without the schema name) - */ - public TableEntity getNewTable(SchemaEntity schemaEntity, String shortTableName) throws SQLException { - TableEntity table = new TableEntity(schemaEntity, shortTableName); - - table.setTableType(getSchemaInfo(schemaEntity.getName()).getTablesType().get(shortTableName)); - - // Add columns info - // For performance reasons all possible column entities are loaded together - columnsInfo.addColumnsInfo(dbWrapper, table); - - return table; - } - - /** - * See {@link #getNewTable(SchemaEntity, String)}. - * - * @param schemaName the name of the schema that owns the table - * @param shortTableName the name of the table (without the schema name) - */ - public TableEntity getNewTable(String schemaName, String shortTableName) throws SQLException { - return getNewTable(getSchema(schemaName), shortTableName); - } - - private void addTableKeys(SchemaEntity schemaEntity, TableEntity tableEntity) throws SQLException { - int currentKey = getMaxKey() + 1; - for (KeyEntity keyEntity : getAllSchemaKeys(schemaEntity.getName())) { - - SchemaEntity fromSchema = null; - SchemaEntity targetSchema = null; - - for (SchemaEntity s : getSchemas()) { - if (fromSchema != null && targetSchema != null) { - break; - } - if (s.getName().equals(keyEntity.getFromSchemaName())) { - fromSchema = s; - } - if (s.getName().equals(keyEntity.getTargetSchemaName())) { - targetSchema = s; - } - } - - // If both schemas are exposed it is possible to add the key - if (fromSchema != null && targetSchema != null) { - String fromTableName = keyEntity.getFromTableFullName(); - String targetTableName = keyEntity.getTargetTableFullName(); - TableEntity fromTable = null, targetTable = null; - if (tableEntity.getName().equals(fromTableName)) { - fromTable = tableEntity; - targetTable = targetSchema.getTable(targetTableName); - } else if (tableEntity.getName().equals(targetTableName)) { - targetTable = tableEntity; - fromTable = fromSchema.getTable(fromTableName); - } - if (fromTable != null && targetTable != null) { - String key = currentKey + ""; - keyEntity.setKeyId(key); - keyEntity.setFromTable(fromTable); - keyEntity.setTargetTable(targetTable); - for (KeyColumnEntity keyColumn : keyEntity.getKeyColumns()) { - keyColumn.setKey(keyEntity); - keyColumn.setKeyId(key); - } - - fromTable.addFromKey(keyEntity); - targetTable.addTargetKey(keyEntity); - - currentKey++; - } - } - } - } - - /** - * Add a {@code TableEntity} to a {@code SchemaEntity}.
The - * {@code SchemaEntity} needs to be already added to the TAP_SCHEMA and the - * {@code TableEntity} has to be created with the - * {@link #getNewTable(SchemaEntity, String)} method. - * - * @param schemaEntity the {@code SchemaEntity} that owns the table to add - * @param tableEntity the {@code TableEntity} to add - * @throws SQLException - */ - public void addTable(SchemaEntity schemaEntity, TableEntity tableEntity) throws SQLException { - schemaEntity.addTable(tableEntity); - addTableKeys(schemaEntity, tableEntity); - } - - /** - * See {@link #addTable(SchemaEntity, TableEntity)}. - * - * @param schemaName the name of the schema that owns the table to add - * @param tableEntity the {@code TableEntity} to add - * @throws SQLException - */ - public void addTable(String schemaName, TableEntity tableEntity) throws SQLException { - addTable(getSchema(schemaName), tableEntity); - } - - public void removeTable(SchemaEntity schemaEntity, TableEntity tableEntity) { - tableEntity.removeKeys(); - schemaEntity.removeTable(tableEntity.getName()); - } - - public void addColumn(TableEntity tableEntity, ColumnEntity columnEntity) { - tableEntity.addColumn(columnEntity); - } - - public void removeColumn(TableEntity tableEntity, String columnName) { - tableEntity.removeColumn(columnName); - } - - public String getForeignKeyReference(String schemaName, String fullTableName, String columnName) throws SQLException { - for (KeyEntity key : getAllSchemaKeys(schemaName)) { - if (key.getFromTableFullName().equals(fullTableName)) { - for (KeyColumnEntity keyColumn : key.getKeyColumns()) { - if (keyColumn.getFromColumn().equals(columnName)) { - return key.getTargetTableFullName().split(Pattern.quote("."))[1] + "." + keyColumn.getTargetColumn(); - } - } - } - } - - return null; - } - - /** - * Retrieve a schema that is currently into the TAP_SCHEMA. - * - * @return the {@code SchemaEntity} if it exists, null otherwise. - */ - public SchemaEntity getSchema(String schemaName) { - return DLUtil.getEntityByName(schemas, schemaName); - } - - public List getAllSchemaKeys(String schemaName) throws SQLException { - return getSchemaInfo(schemaName).getSchemaKeys(); - } - - public void save() throws SQLException { - if (exists) { - log.info("Saving existing TAP_SCHEMA {}", tapSchemaName); - - loadEntityManager(); - - entityManager.getTransaction().begin(); - for (SchemaEntity toRemoveSchema : toRemoveSchemas) { - entityManager.remove(toRemoveSchema); - } - for (SchemaEntity schemaEntity : schemas) { - entityManager.merge(schemaEntity); - } - entityManager.getTransaction().commit(); - } else { - log.info("Saving TAP_SCHEMA {} for the first time", tapSchemaName); - Dao.createTapSchemaSchema(dbWrapper, tapSchemaName); - - loadEntityManager(); - - entityManager.getTransaction().begin(); - for (SchemaEntity schemaEntity : schemas) { - entityManager.persist(schemaEntity); - } - entityManager.getTransaction().commit(); - - // Adding TAP_SCHEMA into TAP_SCHEMA - log.info("Adding TAP_SCHEMA into TAP_SCHEMA"); - SchemaEntity tapSchemaSchema; - tapSchemaSchema = getNewSchema(tapSchemaName); - addSchema(tapSchemaSchema); - - for (String shortTableName : getSchemaInfo(tapSchemaName).getAllSchemaTables()) { - TableEntity tableEntity = getNewTable(tapSchemaName, shortTableName); - addTable(tapSchemaName, tableEntity); - for (ColumnEntity ce : columnsInfo.getColumnEntities(tapSchemaName, shortTableName)) { - addColumn(tableEntity, ce); - } - } - - DLUtil.putInfoIntoTapSchemaSchema(tapSchemaSchema); - - entityManager.getTransaction().begin(); - entityManager.merge(tapSchemaSchema); - entityManager.getTransaction().commit(); - - exists = true; - } - } - - private void loadEntityManager() { - if (entityManager == null) { - entityManager = Dao.getEntityManager(dbWrapper.getTapSchemaCredentials(), tapSchemaName); - } - } - - @Override - public void close() { - - if (entityManager != null && entityManager.isOpen()) { - EntityManagerFactory efFactory = entityManager.getEntityManagerFactory(); - - entityManager.close(); - - if (efFactory.isOpen()) { - efFactory.close(); - } - } - } - - /** - * Automatic closing on serialization - * - * @param stream - * @throws IOException - */ - private void writeObject(ObjectOutputStream stream) throws IOException { - close(); - stream.defaultWriteObject(); - } -} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaImpl.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaImpl.java new file mode 100644 index 0000000..8e5f517 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TapSchemaImpl.java @@ -0,0 +1,385 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Column; +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.KeyColumn; +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.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 } + */ +public class TapSchemaImpl implements TapSchema, Serializable { + + private static final long serialVersionUID = 1678083091602571256L; + private static final Logger log = LoggerFactory.getLogger(TapSchemaImpl.class); + + private final Map schemas; + private final Set allKeys; + + 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<>(); + } + + 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<>(); + + // 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 getAllKeys() { + return allKeys; + } + + /** + * {@inheritDoc} + */ + @Override + public Schema addChild(String schemaName) throws SQLException { + log.debug("Adding 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 = 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 DLUtil.getChild(schemas, childName, statuses); + } + + /** + * {@inheritDoc} + */ + @Override + public List getChildren(Status... statuses) { + return DLUtil.getChildrenByStatus(schemas.values(), statuses); + } + + /** + * {@inheritDoc} + */ + @Override + public List getAddableChildrenNames() { + return DLUtil.getAddableChildrenNames(schemas); + } + + /** + * {@inheritDoc} + */ + @Override + public List getAddedChildren() { + return getChildren(Status.ADDED_PERSISTED, Status.ADDED_NOT_PERSISTED); + } + + /** + * {@inheritDoc} + */ + @Override + public List 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()); + DLUtil.putInfoIntoTapSchemaSchema(tapSchemaSchema); + + exists = true; // important! + + Dao.save(dbWrapper, this); // save again + } + + exists = true; + } + + /** + * 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 (Schema schema : getChildren()) { + for (Table table : schema.getChildren()) { + for (Key key : table.getAllFromKeys()) { + if (key.getId() != null) { + int keyId = Integer.parseInt(key.getId()); + if (keyId > maxKeyId) { + maxKeyId = keyId; + } + } + } + for (Key key : table.getAllTargetKeys()) { + 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()); +// } + } + + /** + * 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
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; + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/UpdateOperations.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/UpdateOperations.java new file mode 100644 index 0000000..9910563 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/UpdateOperations.java @@ -0,0 +1,226 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Column; +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import java.util.ArrayList; +import java.util.List; +import org.slf4j.Logger; +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.oats.ia2.tapschemamanager.contract.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 } + */ +public class UpdateOperations { + + private static final Logger log = LoggerFactory.getLogger(UpdateOperations.class); + + private final List schemasToRemove; + private final List schemasToAdd; + private final List schemasToUpdate; + private final List
tablesToRemove; + private final List
tablesToAdd; + private final List
tablesToUpdate; + private final List columnsToRemove; + private final List columnsToAdd; + private final List columnsToUpdate; + private final List keysToRemove; + private final List keysToAdd; + private final List keysToUpdate; + + private void manageAddedNotPersistedTable(Table table) { + tablesToAdd.add(table); + + // children columns can have only the following status: + // ADDED_NOT_PERSISTED, REMOVED_NOT_PERSISTED, LOADED + columnsToAdd.addAll(table.getChildren(Status.ADDED_NOT_PERSISTED)); + } + + public UpdateOperations(TapSchema tapSchema) { + schemasToRemove = new ArrayList<>(); + schemasToAdd = new ArrayList<>(); + schemasToUpdate = new ArrayList<>(); + tablesToRemove = new ArrayList<>(); + tablesToAdd = new ArrayList<>(); + tablesToUpdate = new ArrayList<>(); + columnsToRemove = new ArrayList<>(); + columnsToAdd = new ArrayList<>(); + columnsToUpdate = new ArrayList<>(); + keysToRemove = new ArrayList<>(); + keysToAdd = new ArrayList<>(); + keysToUpdate = new ArrayList<>(); + + for (Key key : ((TapSchemaImpl) tapSchema).getAllKeys()) { + + if (key.getId() != null) { + + if (key.isVisible()) { + String originalKeyId = key.getOriginalValue(Key.ID_KEY, String.class); + if (originalKeyId == null) { + keysToAdd.add(key); + } else if (key.isChanged()) { + keysToUpdate.add(key); + } + } else { + keysToRemove.add(key); + } + } + } + + for (Schema schema : tapSchema.getChildren()) { + + switch (schema.getStatus()) { + case ADDED_NOT_PERSISTED: + + schemasToAdd.add(schema); + + for (Table table : schema.getChildren()) { + + // children tables can have the following status: + // ADDED_NOT_PERSISTED, REMOVED_NOT_PERSISTED, LOADED + if (table.getStatus() == Status.ADDED_NOT_PERSISTED) { + manageAddedNotPersistedTable(table); + } + } + + break; + + case ADDED_PERSISTED: + + if (schema.isChanged()) { + schemasToUpdate.add(schema); + } + + // children tables can have any status! + for (Table table : schema.getChildren()) { + switch (table.getStatus()) { + case ADDED_NOT_PERSISTED: + manageAddedNotPersistedTable(table); + break; + case ADDED_PERSISTED: + if (table.isChanged()) { + tablesToUpdate.add(table); + } + // children columns can have any status! + for (Column column : table.getChildren()) { + switch (column.getStatus()) { + case ADDED_NOT_PERSISTED: + columnsToAdd.add(column); + break; + case ADDED_PERSISTED: + if (column.isChanged()) { + columnsToUpdate.add(column); + } + break; + case TO_REMOVE: + columnsToRemove.add(column); + break; + } + } + break; + case TO_REMOVE: + tablesToRemove.add(table); + for (Column column : table.getChildren()) { + if (column.getStatus() == Status.ADDED_PERSISTED) { + columnsToRemove.add(column); + } + } + break; + } + } + + break; + + case TO_REMOVE: + + schemasToRemove.add(schema); + for (Table table : schema.getChildren()) { + if (table.getStatus() == Status.ADDED_PERSISTED) { + tablesToRemove.add(table); + for (Column column : table.getChildren()) { + if (column.getStatus() == Status.ADDED_PERSISTED) { + columnsToRemove.add(column); + } + } + } + } + + break; + } + } + } + + public List getSchemasToRemove() { + return schemasToRemove; + } + + public List getSchemasToAdd() { + return schemasToAdd; + } + + public List getSchemasToUpdate() { + return schemasToUpdate; + } + + public List
getTablesToRemove() { + return tablesToRemove; + } + + public List
getTablesToAdd() { + return tablesToAdd; + } + + public List
getTablesToUpdate() { + return tablesToUpdate; + } + + public List getColumnsToRemove() { + return columnsToRemove; + } + + public List getColumnsToAdd() { + return columnsToAdd; + } + + public List getColumnsToUpdate() { + return columnsToUpdate; + } + + public List getKeysToRemove() { + return keysToRemove; + } + + public List getKeysToAdd() { + return keysToAdd; + } + + public List getKeysToUpdate() { + return keysToUpdate; + } + + public boolean getHasEntitiesToAdd() { + return !(schemasToAdd.isEmpty() && tablesToAdd.isEmpty() && columnsToAdd.isEmpty() && keysToAdd.isEmpty()); + } + + public boolean getHasEntitiesToRemove() { + return !(schemasToRemove.isEmpty() && tablesToRemove.isEmpty() && columnsToRemove.isEmpty() && keysToRemove.isEmpty()); + } + + public boolean getHasEntitiesToUpdate() { + return !(schemasToUpdate.isEmpty() && tablesToUpdate.isEmpty() && columnsToUpdate.isEmpty() && keysToUpdate.isEmpty()); + } + + public boolean getHasOperations() { + return getHasEntitiesToAdd() || getHasEntitiesToRemove() || getHasEntitiesToUpdate(); + } +} diff --git a/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/UpdateQueryBuilder.java b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/UpdateQueryBuilder.java new file mode 100644 index 0000000..d804b75 --- /dev/null +++ b/TapSchemaManagerDL/src/main/java/it/inaf/oats/ia2/tapschemamanager/datalayer/UpdateQueryBuilder.java @@ -0,0 +1,74 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.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 } + */ +public class UpdateQueryBuilder { + + private static final Logger log = LoggerFactory.getLogger(UpdateQueryBuilder.class); + + private final String query; + private final List addedProperties; + private final TapSchemaEntity tapSchemaEntity; + + protected UpdateQueryBuilder(DatabaseType dbType, TapSchema tapSchema, TapSchemaEntity tapSchemaEntity, String tapSchemaTableName, String whereCondition) { + + StringBuilder querySb = new StringBuilder("UPDATE "); + querySb.append(DLUtil.escapeName(tapSchema.getName(), dbType)); + querySb.append("."); + querySb.append(DLUtil.escapeName(tapSchemaTableName, dbType)); + querySb.append("\nSET"); + + addedProperties = new ArrayList<>(); + this.tapSchemaEntity = tapSchemaEntity; + + boolean first = true; + for (EntityPropertyInfo propertyInfo : EntityPropertyInfo.getEntityPropertiesInfo(tapSchemaTableName)) { + if (propertyInfo.isUpdatable() + && (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/TapSchemaManagerDL/src/test/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TestAll.java b/TapSchemaManagerDL/src/test/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TestAll.java new file mode 100644 index 0000000..2ef3833 --- /dev/null +++ b/TapSchemaManagerDL/src/test/java/it/inaf/oats/ia2/tapschemamanager/datalayer/TestAll.java @@ -0,0 +1,683 @@ +package it.inaf.oats.ia2.tapschemamanager.datalayer; + +import it.inaf.oats.ia2.tapschemamanager.contract.Column; +import it.inaf.oats.ia2.tapschemamanager.contract.Key; +import it.inaf.oats.ia2.tapschemamanager.contract.KeyColumn; +import it.inaf.oats.ia2.tapschemamanager.contract.Schema; +import it.inaf.oats.ia2.tapschemamanager.contract.Status; +import it.inaf.oats.ia2.tapschemamanager.contract.Table; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchema; +import it.inaf.oats.ia2.tapschemamanager.contract.TapSchemaVersion; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +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 java.util.Set; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; +import org.junit.Ignore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author Sonia Zorba {@literal } + */ +public class TestAll { + + private static final Logger log = LoggerFactory.getLogger(TestAll.class); + + private static final int SCHEMAS_COUNT = 2; // minimum value: 2 + private static final int TABLES_COUNT = 3; + + private static List dbWrappers; + + public TestAll() { + } + + @BeforeClass + public static void setUpClass() throws SQLException { + + dbWrappers = new ArrayList<>(); + + // MYSQL + Credentials mysqlCredentials = new Credentials(DatabaseType.MYSQL); + mysqlCredentials.setHostname("localhost"); + mysqlCredentials.setUsername("root"); + mysqlCredentials.setPassword("root"); + + // POSTGRES + Credentials postgresCredentials = new Credentials(DatabaseType.POSTGRES); + postgresCredentials.setHostname("localhost"); + postgresCredentials.setUsername("postgres"); + postgresCredentials.setPassword("pippo"); + + DBWrapper dbWrapper = new DBWrapper(mysqlCredentials); + dbWrapper.testConnections(); + dbWrappers.add(dbWrapper); + + dbWrapper = new DBWrapper(postgresCredentials); + dbWrapper.testConnections(); + //dbWrappers.add(dbWrapper); + + // Mix! + //dbWrappers.add(new DBWrapper(mysqlCredentials, postgresCredentials)); + //dbWrappers.add(new DBWrapper(postgresCredentials, mysqlCredentials)); + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + private void removeTestingDatabases() throws SQLException { + for (DBWrapper dbWrapper : dbWrappers) { + try (Connection sourceConnection = dbWrapper.getSourceConnection(); + Statement statement = sourceConnection.createStatement()) { + DatabaseType dbType = dbWrapper.getSourceDatabaseType(); + + // Removing keys between schema1 and schema0 + if (dbType == DatabaseType.MYSQL) { + try (ResultSet rs = statement.executeQuery("SHOW DATABASES WHERE `Database` = 'sch1'")) { + // The constraint can be removed only if sch1 exists + if (rs.next()) { + statement.executeUpdate("ALTER TABLE sch1.table0 DROP FOREIGN KEY sch0table0id_constraint"); + } + } + } else if (dbType == DatabaseType.POSTGRES) { + try (ResultSet rs = statement.executeQuery("SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'sch1'")) { + // The constraint can be removed only if sch1 exists + if (rs.next()) { + statement.executeUpdate("ALTER TABLE sch1.table0 DROP CONSTRAINT sch0table0id_constraint"); + } + } + } else { + throw new UnsupportedOperationException("Database type " + dbType + " not supported"); + } + + for (int i = 0; i < SCHEMAS_COUNT; i++) { + if (dbType == DatabaseType.MYSQL) { + statement.executeUpdate("DROP DATABASE IF EXISTS sch" + i); + } else if (dbType == DatabaseType.POSTGRES) { + statement.executeUpdate("DROP SCHEMA IF EXISTS sch" + i + " CASCADE"); + } else { + throw new UnsupportedOperationException("Database type " + dbType + " not supported"); + } + } + } + try (Connection tapSchemaConnection = dbWrapper.getTapSchemaConnection(); + Statement statement = tapSchemaConnection.createStatement()) { + DatabaseType dbType = dbWrapper.getTapSchemaDatabaseType(); + if (dbType == DatabaseType.MYSQL) { + statement.executeUpdate("DROP DATABASE IF EXISTS test_tap_schema"); + } else if (dbType == DatabaseType.POSTGRES) { + statement.executeUpdate("DROP SCHEMA IF EXISTS test_tap_schema CASCADE"); + } else { + throw new UnsupportedOperationException("Database type " + dbType + " not supported"); + } + } + } + } + + private void setUpTestingDatabases() throws SQLException { + removeTestingDatabases(); + + for (DBWrapper dbWrapper : dbWrappers) { + + DatabaseType dbType = dbWrapper.getSourceDatabaseType(); + + try (Connection connection = dbWrapper.getSourceConnection()) { + + try (Statement statement = connection.createStatement()) { + + if (dbType == DatabaseType.MYSQL) { + for (int i = 0; i < SCHEMAS_COUNT; i++) { + statement.executeUpdate("CREATE DATABASE sch" + i); + for (int j = 0; j < TABLES_COUNT; j++) { + statement.executeUpdate("CREATE TABLE sch" + i + ".table" + j + " (\n" + + "id INT PRIMARY KEY AUTO_INCREMENT,\n" + + "value1 VARCHAR(255),\n" + + "value2 FLOAT\n" + + ");"); + } + } + } else if (dbType == DatabaseType.POSTGRES) { + for (int i = 0; i < SCHEMAS_COUNT; i++) { + statement.executeUpdate("CREATE SCHEMA sch" + i); + for (int j = 0; j < TABLES_COUNT; j++) { + statement.executeUpdate("CREATE TABLE sch" + i + ".table" + j + " (\n" + + "id BIGSERIAL PRIMARY KEY,\n" + + "value1 VARCHAR(255),\n" + + "value2 FLOAT\n" + + ");"); + } + } + } else { + throw new UnsupportedOperationException("Database type " + dbType + " not supported"); + } + } + + log.info("dbs created"); + + try (Statement statement = connection.createStatement()) { + for (int j = 0; j < TABLES_COUNT - 1; j++) { + String update1 = "ALTER TABLE sch0.table" + (j + 1) + " ADD COLUMN table" + j + "_id INT"; + statement.executeUpdate(update1); + String update2; + if (dbType == DatabaseType.MYSQL || dbType == DatabaseType.POSTGRES) { + update2 = "ALTER TABLE sch0.table" + (j + 1) + " ADD CONSTRAINT id_constraint_" + (j + 1) + " FOREIGN KEY (table" + j + "_id) REFERENCES sch0.table" + j + "(id)"; + } else { + throw new UnsupportedOperationException("Database type " + dbType + " not supported"); + } + + statement.executeUpdate(update2); + } + + // Foreign key with multiple columns + statement.executeUpdate("CREATE TABLE sch0.table_x (idx1 INT, idx2 INT)"); + statement.executeUpdate("ALTER TABLE sch0.table_x ADD CONSTRAINT pkx PRIMARY KEY (idx1, idx2)"); + statement.executeUpdate("CREATE TABLE sch0.table_y (idy1 INT, idy2 INT)"); + statement.executeUpdate("ALTER TABLE sch0.table_y ADD CONSTRAINT pky PRIMARY KEY (idy1, idy2)"); + statement.executeUpdate("ALTER TABLE sch0.table_y ADD CONSTRAINT fky FOREIGN KEY(idy1, idy2) REFERENCES sch0.table_x(idx1, idx2)"); + + // Foreign keys between different schemas + statement.executeUpdate("ALTER TABLE sch0.table0 ADD COLUMN sch1table0id INT"); + statement.executeUpdate("ALTER TABLE sch0.table0 ADD CONSTRAINT sch1table0id_constraint FOREIGN KEY(sch1table0id) REFERENCES sch1.table0(id)"); + statement.executeUpdate("ALTER TABLE sch1.table0 ADD COLUMN sch0table0id INT"); + statement.executeUpdate("ALTER TABLE sch1.table0 ADD CONSTRAINT sch0table0id_constraint FOREIGN KEY(sch0table0id) REFERENCES sch0.table0(id)"); + } + } + } + } + + @Test + 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); + + File temp = File.createTempFile("test_tap_schema", ".ser"); + + try (FileOutputStream fileOut = new FileOutputStream(temp); + ObjectOutputStream out = new ObjectOutputStream(fileOut)) { + out.writeObject(tapSchema); + } + + try (FileInputStream fileIn = new FileInputStream(temp); + ObjectInputStream in = new ObjectInputStream(fileIn)) { + tapSchema = (TapSchema) in.readObject(); + } + + log.debug(tapSchema.toString()); + } + } + } + + private boolean allKeysHaveDifferentId(TapSchema tapSchema) { + boolean differentKeySameId = false; + Map keys = new HashMap<>(); + + 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); + } + } + + if (differentKeySameId) { + log.debug("Found different keys with the same key_id!"); + for (Key key : ((TapSchemaImpl) 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()); + for (int i = 0; i < key.getKeyColumns().size(); i++) { + KeyColumn keyColumn = key.getKeyColumns().get(i); + assertEquals(fromColumns[i], keyColumn.getFromColumn()); + assertEquals(targetColumns[i], keyColumn.getTargetColumn()); + } + assertEquals(isVisible, key.isVisible()); + for (KeyColumn keyColumn : key.getKeyColumns()) { + assertEquals(key.getId(), keyColumn.getKeyId()); + } + } + + private void checkKey(Key key, String fromTableCompleteName, String fromColumn, String targetTableCompleteName, String targetColumn, boolean isVisible) { + checkKey(key, fromTableCompleteName, new String[]{fromColumn}, targetTableCompleteName, new String[]{targetColumn}, isVisible); + } + + @Test + public void createNewAndUpdate2() throws SQLException { + log.info("TEST createNewAndUpdate2 STARTED"); + + try { + removeTestingDatabases(); + + 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); + + ///////////////////////////////////// + // ADDING A SCHEMA // + ///////////////////////////////////// + // + Schema sch0 = tapSchema.addChild("sch0"); + assertEquals(Status.ADDED_NOT_PERSISTED, sch0.getStatus()); + + Set allKeys = ((TapSchemaImpl) 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. + // Moreover, there are also the following keys: + // - sch0.table0.sch1table0id -> sch1.table0.id + // - 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()); + } + } + + ///////////////////////////////////// + // ADDING A TABLE // + ///////////////////////////////////// + // + Table sch0table0 = sch0.addChild("table0"); + assertEquals(Status.ADDED_NOT_PERSISTED, sch0table0.getStatus()); + assertEquals("sch0.table0", sch0table0.getCompleteName()); + assertEquals(1, sch0.getChildren().size()); + + assertEquals(4, sch0table0.getAddableChildrenNames().size()); + + Column sch0table0id = sch0table0.addChild("id"); + assertEquals(Status.ADDED_NOT_PERSISTED, sch0table0id.getStatus()); + + // Primary key check + assertTrue(sch0table0id.isPrimaryKey()); + + ///////////////////////////////////// + // KEYS MANAGEMENT // + ///////////////////////////////////// + // + // CASE 1: Foreign key between two tables in the same schema. + // sch0.table1.t0id -> sch0.table0.id + // + // Adding sch0.table1 + 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()); + + 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()); + + // 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); + + // 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()); + + // + // CASE 2: Foreign key between two tables in different schemas. + // sch1.table0.sch0table0id -> sch0.table0.id + // + // Adding sch1 + Schema sch1 = tapSchema.addChild("sch1"); + allKeys = ((TapSchemaImpl) tapSchema).getAllKeys(); + assertEquals(5, allKeys.size()); + + // Adding sch1.table0 + Table sch1table0 = sch1.addChild("table0"); + + sch1table0.addChild("id"); + 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)); + + // Removing sch1 + tapSchema.removeChild("sch1"); + assertEquals(Status.REMOVED_NOT_PERSISTED, sch1.getStatus()); + 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; + } + } + } + + // + // 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()); + + 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()); + + 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)); + + ///////////////////////////////////// + // SAVE // + ///////////////////////////////////// + sch0table1 = sch0.addChild("table1"); + sch0table1.addChild("id"); + 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)); + + UpdateOperations operations = new UpdateOperations(tapSchema); + assertEquals(2, operations.getSchemasToAdd().size()); + assertEquals(6, operations.getTablesToAdd().size()); + assertEquals(11, operations.getColumnsToAdd().size()); + assertEquals(5, operations.getKeysToAdd().size()); + + tapSchema.save(); + assertFalse(new UpdateOperations(tapSchema).getHasOperations()); + 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)); + log.debug(tapSchema.toString()); + + assertNotNull(sch0 = tapSchema.getChild("sch0", Status.ADDED_PERSISTED)); + assertNotNull(sch1 = tapSchema.getChild("sch1", Status.ADDED_PERSISTED)); + assertNotNull(sch0table0 = sch0.getChild("table0", Status.ADDED_PERSISTED)); + assertNotNull(sch0table1 = sch0.getChild("table1", Status.ADDED_PERSISTED)); + assertNotNull(sch0table2 = sch0.getChild("table2", Status.ADDED_PERSISTED)); + assertNotNull(table_x = sch0.getChild("table_x", Status.ADDED_PERSISTED)); + assertNotNull(table_y = sch0.getChild("table_y", Status.ADDED_PERSISTED)); + assertNotNull(sch1table0 = sch1.getChild("table0", Status.ADDED_PERSISTED)); + assertNotNull(sch0table0.getChild("id", Status.ADDED_PERSISTED)); + assertNotNull(sch0table0.getChild("sch1table0id", Status.ADDED_PERSISTED)); + assertNotNull(sch0table1.getChild("id", Status.ADDED_PERSISTED)); + assertNotNull(sch0table1.getChild("table0_id", Status.ADDED_PERSISTED)); + assertNotNull(sch0table2.getChild("table1_id", Status.ADDED_PERSISTED)); + assertNotNull(table_x.getChild("idx1", Status.ADDED_PERSISTED)); + assertNotNull(table_x.getChild("idx2", Status.ADDED_PERSISTED)); + assertNotNull(table_y.getChild("idy1", Status.ADDED_PERSISTED)); + assertNotNull(table_y.getChild("idy2", Status.ADDED_PERSISTED)); + 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 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; + } + } + } + + operations = new UpdateOperations(tapSchema); + assertFalse(operations.getHasEntitiesToUpdate()); + assertFalse(operations.getHasEntitiesToAdd()); + assertEquals(0, operations.getSchemasToRemove().size()); + assertEquals(1, operations.getTablesToRemove().size()); + assertEquals(2, operations.getColumnsToRemove().size()); + assertEquals(2, operations.getKeysToRemove().size()); + + tapSchema.save(); + log.debug(tapSchema.toString()); + assertFalse(new UpdateOperations(tapSchema).getHasOperations()); + + // reloading + log.debug("----- Reloading saved TAP_SCHEMA -----"); + tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, "test_tap_schema", true); + allKeys = ((TapSchemaImpl) tapSchema).getAllKeys(); + log.debug(tapSchema.toString()); + + assertNotNull(sch0 = tapSchema.getChild("sch0", Status.ADDED_PERSISTED)); + assertNotNull(sch1 = tapSchema.getChild("sch1", Status.ADDED_PERSISTED)); + assertNotNull(sch0table0 = sch0.getChild("table0", Status.ADDED_PERSISTED)); + assertNotNull(sch0table2 = sch0.getChild("table2", Status.ADDED_PERSISTED)); + assertNotNull(table_x = sch0.getChild("table_x", Status.ADDED_PERSISTED)); + assertNotNull(table_y = sch0.getChild("table_y", Status.ADDED_PERSISTED)); + assertNotNull(sch1table0 = sch1.getChild("table0", Status.ADDED_PERSISTED)); + assertNotNull(sch0table0.getChild("id", Status.ADDED_PERSISTED)); + assertNotNull(sch0table0.getChild("sch1table0id", Status.ADDED_PERSISTED)); + assertNotNull(sch0table2.getChild("table1_id", Status.ADDED_PERSISTED)); + assertNotNull(table_x.getChild("idx1", Status.ADDED_PERSISTED)); + assertNotNull(table_x.getChild("idx2", Status.ADDED_PERSISTED)); + assertNotNull(table_y.getChild("idy1", Status.ADDED_PERSISTED)); + assertNotNull(table_y.getChild("idy2", Status.ADDED_PERSISTED)); + 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; + } + } + } + } + } catch (SQLException e) { + throw e; + } finally { + //removeTestingDatabases(credentials); + } + } +} diff --git a/TapSchemaManagerDL/src/test/java/it/inaf/oats/ia2/tapschemamanager/datalayer/test/TestQuery.java b/TapSchemaManagerDL/src/test/java/it/inaf/oats/ia2/tapschemamanager/datalayer/test/TestQuery.java deleted file mode 100644 index 211fd84..0000000 --- a/TapSchemaManagerDL/src/test/java/it/inaf/oats/ia2/tapschemamanager/datalayer/test/TestQuery.java +++ /dev/null @@ -1,551 +0,0 @@ -package it.inaf.oats.ia2.tapschemamanager.datalayer.test; - -import it.inaf.oats.ia2.tapschemamanager.datalayer.ColumnEntity; -import it.inaf.oats.ia2.tapschemamanager.datalayer.Credentials; -import it.inaf.oats.ia2.tapschemamanager.datalayer.DBWrapper; -import it.inaf.oats.ia2.tapschemamanager.datalayer.DLUtil; -import it.inaf.oats.ia2.tapschemamanager.datalayer.DatabaseType; -import it.inaf.oats.ia2.tapschemamanager.datalayer.KeyColumnEntity; -import it.inaf.oats.ia2.tapschemamanager.datalayer.KeyEntity; -import it.inaf.oats.ia2.tapschemamanager.datalayer.SchemaEntity; -import it.inaf.oats.ia2.tapschemamanager.datalayer.TableEntity; -import it.inaf.oats.ia2.tapschemamanager.datalayer.TapSchemaHandler; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -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.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.*; -import org.junit.Ignore; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - * @author Sonia Zorba {@literal } - */ -public class TestQuery { - - private static final Logger log = LoggerFactory.getLogger(TestQuery.class); - - private static final int SCHEMAS_COUNT = 2; // minimum value: 2 - private static final int TABLES_COUNT = 3; - - private static List dbWrappers; - - public TestQuery() { - } - - @BeforeClass - public static void setUpClass() throws SQLException { - - dbWrappers = new ArrayList<>(); - - // MYSQL - Credentials mysqlCredentials = new Credentials(DatabaseType.MYSQL); - mysqlCredentials.setHostname("localhost"); - mysqlCredentials.setUsername("root"); - mysqlCredentials.setPassword("root"); - - // POSTGRES - Credentials postgresCredentials = new Credentials(DatabaseType.POSTGRES); - postgresCredentials.setHostname("localhost"); - postgresCredentials.setUsername("postgres"); - postgresCredentials.setPassword("pippo"); - - DBWrapper dbWrapper = new DBWrapper(mysqlCredentials); - dbWrapper.testConnections(); - //dbWrappers.add(dbWrapper); - - dbWrapper = new DBWrapper(postgresCredentials); - dbWrapper.testConnections(); - dbWrappers.add(dbWrapper); - - // Mix! - //dbWrappers.add(new DBWrapper(mysqlCredentials, postgresCredentials)); - //dbWrappers.add(new DBWrapper(postgresCredentials, mysqlCredentials)); - } - - @AfterClass - public static void tearDownClass() { - } - - @Before - public void setUp() { - } - - @After - public void tearDown() { - } - - private void removeTestingDatabases() throws SQLException { - for (DBWrapper dbWrapper : dbWrappers) { - try (Connection sourceConnection = dbWrapper.getSourceConnection(); - Statement statement = sourceConnection.createStatement()) { - DatabaseType dbType = dbWrapper.getSourceDatabaseType(); - - // Removing keys between schema1 and schema0 - if (dbType == DatabaseType.MYSQL) { - try (ResultSet rs = statement.executeQuery("SHOW DATABASES WHERE `Database` = 'sch1'")) { - // The constraint can be removed only if sch1 exists - if (rs.next()) { - statement.executeUpdate("ALTER TABLE sch1.table0 DROP FOREIGN KEY sch0table0id_constraint"); - } - } - } else if (dbType == DatabaseType.POSTGRES) { - try (ResultSet rs = statement.executeQuery("SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'sch1'")) { - // The constraint can be removed only if sch1 exists - if (rs.next()) { - statement.executeUpdate("ALTER TABLE sch1.table0 DROP CONSTRAINT sch0table0id_constraint"); - } - } - } else { - throw new UnsupportedOperationException("Database type " + dbType + " not supported"); - } - - for (int i = 0; i < SCHEMAS_COUNT; i++) { - if (dbType == DatabaseType.MYSQL) { - statement.executeUpdate("DROP DATABASE IF EXISTS sch" + i); - } else if (dbType == DatabaseType.POSTGRES) { - statement.executeUpdate("DROP SCHEMA IF EXISTS sch" + i + " CASCADE"); - } else { - throw new UnsupportedOperationException("Database type " + dbType + " not supported"); - } - } - } - try (Connection tapSchemaConnection = dbWrapper.getTapSchemaConnection(); - Statement statement = tapSchemaConnection.createStatement()) { - DatabaseType dbType = dbWrapper.getTapSchemaDatabaseType(); - if (dbType == DatabaseType.MYSQL) { - statement.executeUpdate("DROP DATABASE IF EXISTS test_tap_schema"); - } else if (dbType == DatabaseType.POSTGRES) { - statement.executeUpdate("DROP SCHEMA IF EXISTS test_tap_schema CASCADE"); - } else { - throw new UnsupportedOperationException("Database type " + dbType + " not supported"); - } - } - } - } - - private void setUpTestingDatabases() throws SQLException { - removeTestingDatabases(); - - for (DBWrapper dbWrapper : dbWrappers) { - - DatabaseType dbType = dbWrapper.getSourceDatabaseType(); - - try (Connection connection = dbWrapper.getSourceConnection()) { - - try (Statement statement = connection.createStatement()) { - - if (dbType == DatabaseType.MYSQL) { - for (int i = 0; i < SCHEMAS_COUNT; i++) { - statement.executeUpdate("CREATE DATABASE sch" + i); - for (int j = 0; j < TABLES_COUNT; j++) { - statement.executeUpdate("CREATE TABLE sch" + i + ".table" + j + " (\n" - + "id INT PRIMARY KEY AUTO_INCREMENT,\n" - + "value1 VARCHAR(255),\n" - + "value2 FLOAT\n" - + ");"); - } - } - } else if (dbType == DatabaseType.POSTGRES) { - for (int i = 0; i < SCHEMAS_COUNT; i++) { - statement.executeUpdate("CREATE SCHEMA sch" + i); - for (int j = 0; j < TABLES_COUNT; j++) { - statement.executeUpdate("CREATE TABLE sch" + i + ".table" + j + " (\n" - + "id BIGSERIAL PRIMARY KEY,\n" - + "value1 VARCHAR(255),\n" - + "value2 FLOAT\n" - + ");"); - } - } - } else { - throw new UnsupportedOperationException("Database type " + dbType + " not supported"); - } - } - - log.info("dbs created"); - - try (Statement statement = connection.createStatement()) { - for (int j = 0; j < TABLES_COUNT - 1; j++) { - String update1 = "ALTER TABLE sch0.table" + (j + 1) + " ADD COLUMN table" + j + "_id INT"; - statement.executeUpdate(update1); - String update2; - if (dbType == DatabaseType.MYSQL || dbType == DatabaseType.POSTGRES) { - update2 = "ALTER TABLE sch0.table" + (j + 1) + " ADD CONSTRAINT id_constraint_" + (j + 1) + " FOREIGN KEY (table" + j + "_id) REFERENCES sch0.table" + j + "(id)"; - } else { - throw new UnsupportedOperationException("Database type " + dbType + " not supported"); - } - - statement.executeUpdate(update2); - } - - // Foreign key with multiple columns - statement.executeUpdate("CREATE TABLE sch0.table_x (idx1 INT, idx2 INT)"); - statement.executeUpdate("ALTER TABLE sch0.table_x ADD CONSTRAINT pkx PRIMARY KEY (idx1, idx2)"); - statement.executeUpdate("CREATE TABLE sch0.table_y (idy1 INT, idy2 INT)"); - statement.executeUpdate("ALTER TABLE sch0.table_y ADD CONSTRAINT pky PRIMARY KEY (idy1, idy2)"); - statement.executeUpdate("ALTER TABLE sch0.table_y ADD CONSTRAINT fky FOREIGN KEY(idy1, idy2) REFERENCES sch0.table_x(idx1, idx2)"); - - // Foreign keys between different schemas - statement.executeUpdate("ALTER TABLE sch0.table0 ADD COLUMN sch1table0id INT"); - statement.executeUpdate("ALTER TABLE sch0.table0 ADD CONSTRAINT sch1table0id_constraint FOREIGN KEY(sch1table0id) REFERENCES sch1.table0(id)"); - statement.executeUpdate("ALTER TABLE sch1.table0 ADD COLUMN sch0table0id INT"); - statement.executeUpdate("ALTER TABLE sch1.table0 ADD CONSTRAINT sch0table0id_constraint FOREIGN KEY(sch0table0id) REFERENCES sch0.table0(id)"); - } - } - } - } - - @Test - public void testTapSchemaSerialization() throws Exception { - for (DBWrapper dbWrapper : dbWrappers) { - if (dbWrapper.getTapSchemaDatabaseType() == DatabaseType.MYSQL) { // currently "tng_TAP_SCHEMA" exists in a MySQL instance - TapSchemaHandler tapSchemaHandler = new TapSchemaHandler(dbWrapper, "tng_TAP_SCHEMA", true); - - log.info("schemas size = {}", tapSchemaHandler.getSchemas().size()); - - try (FileOutputStream fileOut = new FileOutputStream("/home/sonia/test.ser"); - ObjectOutputStream out = new ObjectOutputStream(fileOut)) { - out.writeObject(tapSchemaHandler); - } - - try (FileInputStream fileIn = new FileInputStream("/home/sonia/test.ser"); - ObjectInputStream in = new ObjectInputStream(fileIn)) { - tapSchemaHandler = (TapSchemaHandler) in.readObject(); - } - - tapSchemaHandler.save(); - log.info("schemas size = {}", tapSchemaHandler.getSchemas().size()); - } - } - } - - //@Ignore - @Test - public void loadSchema() throws SQLException { - for (DBWrapper dbWrapper : dbWrappers) { - if (dbWrapper.getTapSchemaDatabaseType() == DatabaseType.MYSQL) { // currently "tng_TAP_SCHEMA" exists in a MySQL instance - TapSchemaHandler tapSchemaHandler = new TapSchemaHandler(dbWrapper, "tng_TAP_SCHEMA", true); - assertTrue(!tapSchemaHandler.getSchemas().isEmpty()); - - // Testing alphabetical order loading - for (SchemaEntity schemaEntity : tapSchemaHandler.getSchemas()) { - TableEntity previousTable = null; - for (TableEntity table : schemaEntity.getTables()) { - if (previousTable != null) { - //assertTrue("Table=" + table.getName() + ", Previous Table=" + previousTable.getName(), - // previousTable.getName().compareToIgnoreCase(table.getName()) < 1); - } - previousTable = table; - - ColumnEntity previousColumn = null; - for (ColumnEntity column : table.getColumns()) { - if (previousColumn != null) { - //assertTrue("Column=" + column.getName() + ", Previous Column=" + previousColumn.getName(), - // previousColumn.getName().compareToIgnoreCase(column.getName()) < 1); - } - previousColumn = column; - } - -// if(previousTable == null) { -// previousTable = table; -// } else { -// } - } - } - } - } - - } - - private void printKeys(String message, List keys) { - log.info("{}: Found {} keys", message, keys.size()); - int index = 0; - for (KeyEntity key : keys) { - for (KeyColumnEntity keyColumn : key.getKeyColumns()) { - log.info("[{}] {}.{} -> {}.{}", index, key.getFromTableFullName(), keyColumn.getFromColumn(), key.getTargetTableFullName(), keyColumn.getTargetColumn()); - } - index++; - } - } - - //@Ignore - @Test - public void createNewAndUpdate() throws SQLException { - log.info("TEST createNewAndUpdate STARTED"); - - try { - removeTestingDatabases(); - - setUpTestingDatabases(); - - for (DBWrapper dbWrapper : dbWrappers) { - - // Initializing a not existing TAP_SCHEMA - TapSchemaHandler tsh = new TapSchemaHandler(dbWrapper, "test_tap_schema", false); - - ///////////////////////////////////// - // ADDING A SCHEMA // - ///////////////////////////////////// - // - SchemaEntity sch0 = tsh.getNewSchema("sch0"); - tsh.addSchema(sch0); - - List sch0Keys = tsh.getAllSchemaKeys("sch0"); - printKeys("ALL sch0 keys", sch0Keys); - - // 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. - // Moreover, there are also the following keys: - // - sch0.table0.sch1table0id -> sch1.table0.id - // - sch1.table0.sch0table0id -> sch0.table0.id - // - sch0.table_y.(idy1, idy2) -> sch0.table_x.(idyx, idx2) - // so we check for TABLES_COUNT + 2. - assertEquals(sch0Keys.size(), TABLES_COUNT + 2); - - // Checking that keys information has been filled. - for (KeyEntity schemaKey : sch0Keys) { - assertNotNull(schemaKey.getFromTableFullName()); - assertNotNull(schemaKey.getTargetTableFullName()); - for (KeyColumnEntity keyColumn : schemaKey.getKeyColumns()) { - assertNotNull(keyColumn.getFromColumn()); - assertNotNull(keyColumn.getTargetColumn()); - } - } - - ///////////////////////////////////// - // ADDING A TABLE // - ///////////////////////////////////// - // - TableEntity sch0table0 = tsh.getNewTable("sch0", "table0"); - assertEquals(sch0table0.getName(), "sch0.table0"); - tsh.addTable("sch0", sch0table0); - assertEquals(sch0.getTables().size(), 1); - - // Checking that columns information has been filled. - List sch0table0Columns = tsh.getColumnEntities("sch0", "table0"); - for (ColumnEntity ce : sch0table0Columns) { - assertNotNull(ce.getTable()); - } - // Primary key check - assertTrue(DLUtil.getEntityByName(sch0table0Columns, "id").isPrimaryKey()); - - ///////////////////////////////////// - // KEYS MANAGEMENT // - ///////////////////////////////////// - // - // CASE 1: Foreign key between two tables in the same schema. - // sch0.table1.t0id -> sch0.table0.id - // - // Adding sch0.table1 - TableEntity sch0table1 = tsh.getNewTable("sch0", "table1"); - tsh.addTable("sch0", sch0table1); - assertEquals(sch0.getTables().size(), 2); - - printKeys("sch0table0 fromKeys", sch0table0.getFromKeys()); - assertTrue(sch0table0.getFromKeys().isEmpty()); - - assertEquals(sch0table0.getTargetKeys().size(), 1); - KeyEntity sch0table0TargetKey = sch0table0.getTargetKeys().get(0); - - assertEquals(sch0table0TargetKey.getFromTableFullName(), "sch0.table1"); - assertEquals(sch0table0TargetKey.getTargetTableFullName(), "sch0.table0"); - assertEquals(sch0table0TargetKey.getKeyColumns().size(), 1); - - assertEquals(sch0table1.getFromKeys().size(), 1); - KeyEntity sch0table0FromKey = sch0table0.getTargetKeys().get(0); - - assertEquals(sch0table0FromKey.getFromTableFullName(), "sch0.table1"); - assertEquals(sch0table0FromKey.getTargetTableFullName(), "sch0.table0"); - assertEquals(sch0table0FromKey.getKeyColumns().size(), 1); - assertTrue(sch0table1.getTargetKeys().isEmpty()); - - // Removing sch0.table1 - assertEquals(sch0table0.getTargetKeys().size(), 1); // sch0.table1.table0_id -> sch0.table0.id - tsh.removeTable(sch0, sch0table1); - assertEquals(sch0.getTables().size(), 1); - assertTrue(sch0table0.getFromKeys().isEmpty()); - assertTrue(sch0table0.getTargetKeys().isEmpty()); - - // - // CASE 2: Foreign key between two tables in different schemas. - // sch1.table0.sch0table0id -> sch0.table0.id - // - // Adding sch1 - SchemaEntity sch1 = tsh.getNewSchema("sch1"); - tsh.addSchema(sch1); - List sch1Keys = tsh.getAllSchemaKeys("sch1"); - assertEquals(sch1Keys.size(), 2); - for (KeyEntity keyEntity : sch1Keys) { - String fromSchemaName = keyEntity.getFromSchemaName(); - String targetSchemaName = keyEntity.getTargetSchemaName(); - assertTrue(fromSchemaName.equals("sch0") || fromSchemaName.equals("sch1")); - assertTrue(targetSchemaName.equals("sch0") || targetSchemaName.equals("sch1")); - assertEquals(keyEntity.getKeyColumns().size(), 1); - switch (fromSchemaName) { - case "sch0": - assertEquals(targetSchemaName, "sch1"); - assertEquals(keyEntity.getKeyColumns().get(0).getFromColumn(), "sch1table0id"); - assertEquals(keyEntity.getKeyColumns().get(0).getTargetColumn(), "id"); - break; - case "sch1": - assertEquals(targetSchemaName, "sch0"); - assertEquals(keyEntity.getKeyColumns().get(0).getFromColumn(), "sch0table0id"); - assertEquals(keyEntity.getKeyColumns().get(0).getTargetColumn(), "id"); - break; - } - } - - // Adding sch1.table0 - TableEntity sch1table0 = tsh.getNewTable("sch1", "table0"); - tsh.addTable("sch1", sch1table0); - - assertEquals(sch0table0.getTargetKeys().size(), 1); // sch1.table0.sch0table0id -> sch0.table0.id - KeyEntity sch0Table0Key = sch0table0.getTargetKeys().get(0); - assertEquals(sch0Table0Key.getFromTableFullName(), "sch1.table0"); - assertEquals(sch0Table0Key.getTargetTableFullName(), "sch0.table0"); - assertEquals(sch0Table0Key.getKeyColumns().size(), 1); - KeyColumnEntity sch0Table0KeyColumn = sch0Table0Key.getKeyColumns().get(0); - assertEquals(sch0Table0KeyColumn.getFromColumn(), "sch0table0id"); - assertEquals(sch0Table0KeyColumn.getTargetColumn(), "id"); - - assertEquals(sch0table0.getTargetKeys().get(0).getFromTableFullName(), "sch1.table0"); - assertEquals(sch0table0.getTargetKeys().get(0).getTargetTableFullName(), "sch0.table0"); - assertEquals(sch1table0.getFromKeys().size(), 1); - assertEquals(sch1table0.getFromKeys().get(0).getFromTableFullName(), "sch1.table0"); - assertEquals(sch1table0.getFromKeys().get(0).getTargetTableFullName(), "sch0.table0"); - - // Removing sch1 - tsh.removeSchema("sch1"); - assertTrue(sch0table0.getTargetKeys().isEmpty()); - assertTrue(sch1table0.getFromKeys().isEmpty()); - - // Case 2B: Re-adding the same instance of sch1 - // sch1.table0 has not been removed from its schema, so the keys - // should be re-added. - tsh.addSchema(sch1); - assertEquals(sch0table0.getTargetKeys().size(), 1); - assertEquals(sch1table0.getFromKeys().size(), 1); - - // Case 2C: removing sch1 and re-adding a new instance of sch1 - // In this case the sch1.table0 it isn't in sch1 instance, so - // there shouldn't be any keys to add. - tsh.removeSchema("sch1"); - sch1 = tsh.getNewSchema("sch1"); - tsh.addSchema(sch1); - assertTrue(sch0table0.getTargetKeys().isEmpty()); - assertTrue(sch1table0.getFromKeys().isEmpty()); - - // - // CASE 3: foreign key with multiple columns - // - TableEntity table_x = tsh.getNewTable("sch0", "table_x"); - tsh.addTable("sch0", table_x); - TableEntity table_y = tsh.getNewTable("sch0", "table_y"); - tsh.addTable("sch0", table_y); - - assertTrue(table_x.getFromKeys().isEmpty()); - assertEquals(table_x.getTargetKeys().size(), 1); - for (KeyColumnEntity keyColumn : table_x.getTargetKeys().get(0).getKeyColumns()) { - String fromColumn = keyColumn.getFromColumn(); - String targetColumn = keyColumn.getTargetColumn(); - assertTrue(fromColumn.equals("idy1") || fromColumn.equals("idy2")); - assertTrue(targetColumn.equals("idx1") || targetColumn.equals("idx2")); - } - - assertTrue(table_y.getTargetKeys().isEmpty()); - assertEquals(table_y.getFromKeys().size(), 1); - for (KeyColumnEntity keyColumn : table_y.getFromKeys().get(0).getKeyColumns()) { - String fromColumn = keyColumn.getFromColumn(); - String targetColumn = keyColumn.getTargetColumn(); - assertTrue(fromColumn.equals("idy1") || fromColumn.equals("idy2")); - assertTrue(targetColumn.equals("idx1") || targetColumn.equals("idx2")); - } - - // - // CASE 4: reset of key ids - // - // Adding sch0.table1 - int maxKey = tsh.getMaxKey(); - tsh.addTable(sch0, sch0table1); - String sch0table1keyId = (maxKey + 1) + ""; - KeyEntity sch0table1key = sch0table1.getFromKeys().get(0); - KeyColumnEntity sch0table1keyColumn = sch0table1key.getKeyColumns().get(0); - assertEquals(sch0table1key.getKeyId(), sch0table1keyId); - assertNotNull(sch0table1keyColumn.getKey()); - assertEquals(sch0table1keyColumn.getKeyId(), sch0table1keyId); - assertEquals(tsh.getMaxKey(), maxKey + 1); - - // Removing sch0.table1 - tsh.removeTable(sch0, sch0table1); - assertEquals(tsh.getMaxKey(), maxKey); - assertNull(sch0table1key.getKeyId()); - assertNull(sch0table1keyColumn.getKey()); - assertNull(sch0table1keyColumn.getKeyId()); - - // Re-adding sch0.table1 - tsh.addTable(sch0, sch0table1); - assertEquals(sch0table1key.getKeyId(), sch0table1keyId); - assertNotNull(sch0table1keyColumn.getKey()); - assertEquals(sch0table1keyColumn.getKeyId(), sch0table1keyId); - assertEquals(tsh.getMaxKey(), maxKey + 1); - - // Adding sch0.table2 - TableEntity sch0table2 = tsh.getNewTable(sch0, "table2"); - tsh.addTable(sch0, sch0table2); - String sch0table2keyId = (maxKey + 2) + ""; - KeyEntity sch0table2key = sch0table2.getFromKeys().get(0); - KeyColumnEntity sch0table2keyColumn = sch0table2key.getKeyColumns().get(0); - assertEquals(sch0table2key.getKeyId(), sch0table2keyId); - assertNotNull(sch0table2keyColumn.getKey()); - assertEquals(sch0table2keyColumn.getKeyId(), sch0table2keyId); - assertEquals(tsh.getMaxKey(), maxKey + 2); - - ///////////////////////////////////// - // ADDING A COLUMN // - ///////////////////////////////////// - ColumnEntity columnEntity = tsh.getColumnEntities("sch0", "table1").get(0); - tsh.addColumn(sch0table1, columnEntity); - assertNotNull(columnEntity.getTable()); - - ///////////////////////////////////// - // SAVE // - ///////////////////////////////////// - tsh.save(); - assertNotNull(sch0.getTable("sch0.table0")); - - ///////////////////////////////////// - // LOAD SAVED // - ///////////////////////////////////// - tsh = new TapSchemaHandler(dbWrapper, "test_tap_schema", true); - sch0 = tsh.getSchema("sch0"); - tsh.removeTable(sch0, sch0.getTable("sch0.table0")); - assertNull(sch0.getTable("sch0.table0")); - tsh.save(); - - tsh = new TapSchemaHandler(dbWrapper, "test_tap_schema", true); - sch0 = tsh.getSchemas().iterator().next(); - assertNull(sch0.getTable("sch0.table0")); - - tsh.addTable("sch0", sch0table0); - } - } catch (SQLException e) { - throw e; - } finally { - //removeTestingDatabases(credentials); - } - } -} -- GitLab