diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TSMUtil.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TSMUtil.java index f0639af4d5ea161f0929455f38a59871ca7c1e19..abde2e34f44a4a14840f8b79da4e868928972ca3 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TSMUtil.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TSMUtil.java @@ -306,4 +306,38 @@ public class TSMUtil { return sb.toString(); } + + /** + * Utility class for joining a collection of object properties. + */ + public static class StringJoiner<T> { + + private final Iterable<T> values; + private final String separator; + + public StringJoiner(Iterable<T> values, String separator) { + this.values = values; + this.separator = separator; + } + + public final String getString() { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (T value : values) { + if (!first) { + sb.append(separator); + } + sb.append(getStringValue(value)); + first = false; + } + return sb.toString(); + } + + public String getStringValue(T value) { + if (value instanceof String) { + return (String) value; + } + return null; + } + } } diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchema.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchema.java index 54574983c673265ef74e5ab91d504f581ec07995..e4385711c77d278f5540820743bdbd0fd132c1c7 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchema.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchema.java @@ -463,7 +463,8 @@ public class TapSchema implements EntitiesContainer<Schema>, Serializable { if (obscore) { SchemaModel ivoaSchemaModel = getIvoaSchemaModel(); - broker.createIvoaSchemaStructure(ivoaSchemaModel); + // ivoa schema has to be created into source database + getSourceDBBroker().createIvoaSchemaStructure(ivoaSchemaModel); // Initializing ivoa schema slot in schemata maps schemas.put(ivoaSchemaModel.getName(), null); diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/mysql/MySQLDBBroker.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/mysql/MySQLDBBroker.java index b7d4cbd7b9f0c839d3434567c5e8848bc330168e..f3b8475b490a605e83cabf016c60a583ce5638fd 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/mysql/MySQLDBBroker.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/mysql/MySQLDBBroker.java @@ -74,7 +74,11 @@ public class MySQLDBBroker extends DBBrokerTemplate { if (beginIndex != -1) { int endIndex = typeWithSize.indexOf(')'); if (endIndex != -1) { - return Integer.parseInt(typeWithSize.substring(beginIndex + 1, endIndex)); + try { + return Integer.parseInt(typeWithSize.substring(beginIndex + 1, endIndex)); + } catch (NumberFormatException e) { + return null; + } } } return null; diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SearchUCDDialog.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SearchUCDDialog.java index f42170632062ff77b20d528c48e672b65b2ea51b..55039c5fb0180141a8d58c94966ed5a2dd0ba261 100644 --- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SearchUCDDialog.java +++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/SearchUCDDialog.java @@ -107,6 +107,9 @@ public class SearchUCDDialog implements Serializable { String assignResponse = SearchUCD.assign(description); if (assignResponse == null) { UCDnotFound = true; + selectedUCD = null; + suggestedUCD = null; + suggestedUCDs.clear(); } else { selectedUCD = assignResponse; suggestedUCD = assignResponse; diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java index bedc26fd1a9ecf0486186f81be8f672fd7bc16ad..0bbac7f52aaf8d16bf140343223d1f5cdbcfa4e8 100644 --- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java +++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java @@ -30,6 +30,7 @@ import it.inaf.ia2.tsm.Key; import it.inaf.ia2.tsm.KeyColumn; import it.inaf.ia2.tsm.Schema; import it.inaf.ia2.tsm.Status; +import it.inaf.ia2.tsm.TSMUtil; import it.inaf.ia2.tsm.Table; import it.inaf.ia2.tsm.TapSchema; import it.inaf.ia2.tsm.TapSchemaEntity; @@ -67,6 +68,7 @@ public class TapSchemaEditingBean implements Serializable { private EntitiesContainer currentAddingContainer; private List<AddableItem> currentAddables; + private boolean addAlsoAllChildren; private VOUnitValidator voUnitValidator; @Inject @@ -259,6 +261,7 @@ public class TapSchemaEditingBean implements Serializable { } public void openAddablesModal(EntitiesContainer<?> currentAddingContainer) { + this.addAlsoAllChildren = false; this.currentAddingContainer = currentAddingContainer; this.currentAddables = new ArrayList<>(); for (String name : currentAddingContainer.getAddableChildrenNames()) { @@ -277,11 +280,30 @@ public class TapSchemaEditingBean implements Serializable { } } + private void addAllChildren(TapSchemaEntity childEntity) throws SQLException { + if (childEntity instanceof Schema) { + Schema schema = (Schema) childEntity; + for (String tableName : schema.getAddableChildrenNames()) { + Table table = schema.addChild(tableName); + addAllChildren(table); + } + } else if (childEntity instanceof Table) { + Table table = (Table) childEntity; + for (String column : table.getAddableChildrenNames()) { + table.addChild(column); + } + } + } + public void addSelected() throws SQLException { TapSchemaEntity lastAddedEntity = null; + boolean canAddChildren = isCanAddChildren(); for (AddableItem item : currentAddables) { if (item.isSelected()) { lastAddedEntity = currentAddingContainer.addChild(item.getName()); + if (lastAddedEntity != null && canAddChildren) { + addAllChildren(lastAddedEntity); + } } } if (lastAddedEntity != null) { @@ -299,6 +321,22 @@ public class TapSchemaEditingBean implements Serializable { return currentAddables; } + public boolean isCanAddChildren() { + if (currentAddingContainer == null) { + return false; + } + return currentAddingContainer instanceof TapSchema + || currentAddingContainer instanceof Schema; + } + + public boolean isAddAlsoAllChildren() { + return addAlsoAllChildren; + } + + public void setAddAlsoAllChildren(boolean addAlsoAllChildren) { + this.addAlsoAllChildren = addAlsoAllChildren; + } + public void saveUCD() { if (!FacesContext.getCurrentInstance().isValidationFailed()) { @@ -402,4 +440,32 @@ public class TapSchemaEditingBean implements Serializable { column.setValue("principal", value ? 1 : 0); } } + + public List<Key> getVisibleKeys() { + List<Key> keys = new ArrayList<>(); + for (Key key : tapSchema.getAllKeys()) { + if (key.isVisible()) { + keys.add(key); + } + } + return keys; + } + + public String formatFromColumns(Key key) { + return (new TSMUtil.StringJoiner<KeyColumn>(key.getKeyColumns(), ", ") { + @Override + public String getStringValue(KeyColumn kc) { + return kc.getFromColumn(); + } + }).getString(); + } + + public String formatTargetColumns(Key key) { + return (new TSMUtil.StringJoiner<KeyColumn>(key.getKeyColumns(), ", ") { + @Override + public String getStringValue(KeyColumn kc) { + return kc.getTargetColumn(); + } + }).getString(); + } } diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/UCDEditor.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/UCDEditor.java index 1e1555a06f53f35a8c314c761f78a4e3b072ffa7..6a36cfd42b74278c3200670f70b7c331b3a27dae 100644 --- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/UCDEditor.java +++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/UCDEditor.java @@ -6,7 +6,6 @@ import it.inaf.ia2.tsm.webapp.xmlconfig.UCDConfiguration; import java.io.IOException; import java.io.Serializable; import java.util.List; -import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.inject.Named; import org.apache.deltaspike.core.api.scope.WindowScoped; @@ -30,7 +29,7 @@ public class UCDEditor implements Serializable { private boolean viewExisting; private UCDConfiguration newUCDConfiguration; private String invalidUCDMessage; - + public void openDialog() { viewExisting = true; newUCDConfiguration = new UCDConfiguration(user.getUsername()); @@ -76,11 +75,20 @@ public class UCDEditor implements Serializable { invalidUCDMessage = "Invalid UCD word syntax"; return; } -// -// newUCDConfiguration = new UCDConfiguration(user.getUsername()); -// if(config.addUCD(newUCDConfiguration)) { -// ne -// } + + if (!newUCDConfiguration.getWord().contains(":")) { + invalidUCDMessage = "Custom UCDs must have a namespace"; + return; + } + + boolean inserted = config.addUCD(newUCDConfiguration); + if (!inserted) { + invalidUCDMessage = "Specified UCD already exists"; + return; + } + + newUCDConfiguration = new UCDConfiguration(user.getUsername()); + invalidUCDMessage = null; } public void removeUCD(UCDConfiguration ucd) { diff --git a/TASMAN-webapp/src/main/webapp/resources/js/edit-tapschema.js b/TASMAN-webapp/src/main/webapp/resources/js/edit-tapschema.js index 34cdd9c3a1e586c8baf8b0512c4db1ae0398def9..0146318691ec33efa70c1c4a78b39a00b7f79f20 100644 --- a/TASMAN-webapp/src/main/webapp/resources/js/edit-tapschema.js +++ b/TASMAN-webapp/src/main/webapp/resources/js/edit-tapschema.js @@ -4,6 +4,10 @@ $('#updateOperationsModal').modal('show'); }); + TSM.displayKeysModal = TSM.eventHandlerFactory(function (srcElement, jsupdate) { + $('#keysModal').modal('show'); + }); + TSM.saveUCDCalled = TSM.eventHandlerFactory(function (srcElement, jsupdate) { if (jsupdate !== null) { $('#searchUCDModal').modal('hide'); diff --git a/TASMAN-webapp/src/main/webapp/resources/tsm_components/ucd_editor.xhtml b/TASMAN-webapp/src/main/webapp/resources/tsm_components/ucd_editor.xhtml index 9ed13bd898dd6a12f8bd1260a7314fbd42367d72..d65ef2837ab0c7e44d828363905f04cca0878b61 100644 --- a/TASMAN-webapp/src/main/webapp/resources/tsm_components/ucd_editor.xhtml +++ b/TASMAN-webapp/src/main/webapp/resources/tsm_components/ucd_editor.xhtml @@ -31,12 +31,12 @@ <ul> <ui:repeat value="#{ucdEditor.customUCDs}" var="ucd" varStatus="loop"> <li> - <h:commandLink class="text-danger" action="#{ucdEditor.removeUCD(ucd)}"> + <h:commandLink class="text-danger" action="#{ucdEditor.removeUCD(ucd)}" rendered="#{ucdEditor.isEditable(ucd)}"> × <ui:remove> <!-- Note: due to a strange JSF bug following render attribute needs complete component id reference --> </ui:remove> - <f:ajax execute="ucd-editor-body" render="main:ucd-editor:ucd-editor-body" /> + <f:ajax execute="ucd-editor-body" render=":main:ucd-editor:ucd-editor-body" /> </h:commandLink> [#{ucd.code}] <span title="#{ucd.description}">#{ucd.word}</span> </li> diff --git a/TASMAN-webapp/src/main/webapp/tapSchemaEditing.xhtml b/TASMAN-webapp/src/main/webapp/tapSchemaEditing.xhtml index bfe98e778e9e8a62a31e98e387cf199e183b2d01..b7a428bfd230bbe90e99e1df0fbff689fdb6433b 100644 --- a/TASMAN-webapp/src/main/webapp/tapSchemaEditing.xhtml +++ b/TASMAN-webapp/src/main/webapp/tapSchemaEditing.xhtml @@ -25,11 +25,31 @@ </h1> <div class="col-sm-6 vpadding text-center"> - <h:commandLink class="btn btn-info" action="#{tapSchemaEditing.displayUpdateOperations()}"> - <span class="glyphicon glyphicon-info-sign"></span> - Display update operations - <f:ajax execute="@form" render="update-operations-form" onevent="TSM.displayUpdateOperations"/> - </h:commandLink> + <div class="btn-group"> + <button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + <span class="glyphicon glyphicon-info-sign"></span> + Show <span class="caret"></span> + </button> + <ul class="dropdown-menu"> + <li> + <h:commandLink action="#{tapSchemaEditing.displayUpdateOperations()}"> + <span class="glyphicon glyphicon-cog"></span> + Update operations + <f:ajax execute="@form" render="update-operations-form" onevent="TSM.displayUpdateOperations"/> + </h:commandLink> + </li> + <li> + <h:commandLink> + <span class="icon-key"></span> + Keys + <ui:remove> + <!-- Very important: execute="@this", otherwise wrong values will be updated --> + </ui:remove> + <f:ajax execute="@this" render="keys-panel" onevent="TSM.displayKeysModal"/> + </h:commandLink> + </li> + </ul> + </div>   <h:commandLink class="btn btn-success" action="#{tapSchemaEditing.update()}" id="update-btn"> <span class="icon-save"></span> @@ -366,6 +386,16 @@ <f:ajax event="keyup" execute="@form" listener="#{tapSchemaEditing.textInputChanged(tapSchemaEditing.selectedColumn, 'description')}" onevent="TSM.textInputChanged" /> </h:inputText> </div> + <h:panelGroup class="form-group" layout="block" rendered="#{tapSchemaEditing.selectedColumn.getProperty('xtype') ne null}"> + <h:outputLabel for="column_xtype" class="control-label">Xtype:</h:outputLabel> + <h:inputText + id="column_xtype" + class="form-control #{tapSchemaEditing.selectedColumn.isChanged('xtype') ? 'changed' : ''}" + value="#{tapSchemaEditing.selectedColumn.getProperty('xtype').value}"> + <f:converter converterId="it.inaf.ia2.NullOrEmptyConverter" /> + <f:ajax event="keyup" execute="@form" listener="#{tapSchemaEditing.textInputChanged(tapSchemaEditing.selectedColumn, 'xtype')}" onevent="TSM.textInputChanged" /> + </h:inputText> + </h:panelGroup> </h:panelGroup> </h:panelGroup> </h:panelGroup> @@ -380,7 +410,7 @@ <div class="modal fade" tabindex="-1" role="dialog" id="addablesModal"> <div class="modal-dialog modal-lg"> - <div class="modal-content"> + <h:panelGroup class="modal-content" id="addables_modal_content" layout="block"> <div class="modal-header"> <div class="pull-right"> <h:commandLink class="btn btn-default btn-sm" action="#{tapSchemaEditing.checkAllEntities(false)}"> @@ -400,27 +430,85 @@ </div> <div class="modal-body"> <div class="addables"> - <h:panelGroup id="addables_modal_content"> - <h:panelGroup rendered="#{tapSchemaEditing.currentAddingContainer ne null}"> - <ui:repeat value="#{tapSchemaEditing.currentAddables}" var="item"> - <div class="checkbox"> - <label> - <h:selectBooleanCheckbox value="#{item.selected}"/> - #{item.name} - </label> - </div> - </ui:repeat> - </h:panelGroup> + <h:panelGroup rendered="#{tapSchemaEditing.currentAddingContainer ne null}"> + <ui:repeat value="#{tapSchemaEditing.currentAddables}" var="item"> + <div class="checkbox"> + <label> + <h:selectBooleanCheckbox value="#{item.selected}"/> + #{item.name} + </label> + </div> + </ui:repeat> </h:panelGroup> </div> </div> <div class="modal-footer"> + <h:panelGroup class="checkbox pull-left" layout="block" rendered="#{tapSchemaEditing.canAddChildren}"> + <label> + <h:selectBooleanCheckbox value="#{tapSchemaEditing.addAlsoAllChildren}" /> Add also all children + </label> + </h:panelGroup> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> <h:commandLink class="btn btn-primary" action="#{tapSchemaEditing.addSelected}"> Add <f:ajax execute="@form" render=":main:main_panel" onevent="TSM.entitiesAdded" /> </h:commandLink> </div> + </h:panelGroup> + </div> + </div> + + <div class="modal fade" tabindex="-1" role="dialog" id="keysModal"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title">Keys</h4> + </div> + <h:panelGroup class="modal-body" layout="block" id="keys-panel"> + <table class="table table-striped"> + <thead> + <tr> + <th>Id</th> + <th>From table</th> + <th>From columns</th> + <th>Target table</th> + <th>Target columns</th> + <th>Utype</th> + <th>Description</th> + </tr> + </thead> + <tbody> + <ui:repeat value="#{tapSchemaEditing.visibleKeys}" var="key"> + <tr> + <td>#{key.id}</td> + <td>#{key.fromTableCompleteName}</td> + <td>#{tapSchemaEditing.formatFromColumns(key)}</td> + <td>#{key.targetTableCompleteName}</td> + <td>#{tapSchemaEditing.formatTargetColumns(key)}</td> + <td> + <h:inputText + id="key_utype" + class="form-control #{key.isChanged('utype') ? 'changed' : ''}" + value="#{key.getProperty('utype').value}"> + <f:converter converterId="it.inaf.ia2.NullOrEmptyConverter" /> + <f:ajax event="keyup" execute="@form" listener="#{tapSchemaEditing.textInputChanged(key, 'utype')}" onevent="TSM.textInputChanged" /> + </h:inputText> + </td> + <td> + <h:inputText + id="key_description" + class="form-control #{key.isChanged('description') ? 'changed' : ''}" + value="#{key.getProperty('description').value}"> + <f:converter converterId="it.inaf.ia2.NullOrEmptyConverter" /> + <f:ajax event="keyup" execute="@form" listener="#{tapSchemaEditing.textInputChanged(key, 'description')}" onevent="TSM.textInputChanged" /> + </h:inputText> + </td> + </tr> + </ui:repeat> + </tbody> + </table> + </h:panelGroup> </div> </div> </div>