Commit d58aff54 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

TAP_SCHEMA on webapp is loaded in an asychronous way to avoid connection...

TAP_SCHEMA on webapp is loaded in an asychronous way to avoid connection timeout issues when loading big TAP_SCHEMA schemas. Refactoring of JavaScript scripts
parent b9f7a2f7
......@@ -7,6 +7,9 @@
* **XML configuration format is changed: if you update from previous version you will lost your previous configuration.**
* Both new users and custom UCDs can now be added using the GUI.
* Added "Rebuild UCD" functionality on the UCD insertion dialog.
* Fixed bug on consistency checking when a schema is missing
* Added warning in case of possible wrong source credentials selection (this is shown when consistency checking detect only the TAP_SCHEMA itself).
* Avoided connection timeout on the webapp when loading big TAP_SCHEMA schemas.
## Version 1.0.4
......
......@@ -73,6 +73,9 @@ public class SchemaSelectionBean implements Serializable {
private String tapSchemaName;
private List<String> allSchemas;
private List<String> selectedSchemas;
private boolean loading;
private TapSchema loadedTapSchema;
private String loadingError;
@PostConstruct
public void init() {
......@@ -145,8 +148,10 @@ public class SchemaSelectionBean implements Serializable {
}
public void setSelectedTAPSchema(String selectedTAPSchema) {
this.selectedTAPSchema = selectedTAPSchema;
this.selectedTAPSchema = selectedTAPSchema;
}
public void selectedTAPSchemaChanged() {
try {
loadExposedSchemas();
} catch (SQLException e) {
......@@ -162,38 +167,58 @@ public class SchemaSelectionBean implements Serializable {
this.selectedSchemas = selectedSchemas;
}
private String loadTapSchema(TapSchema tapSchema) {
tapSchemaEditingBean.setTapSchema(tapSchema);
return "tapSchemaEditing.xhtml?faces-redirect=true";
public String openLoaded() {
if (loadedTapSchema.getConsistencyChecks().isInconsistent()) {
consistencyChecksBean.setDbWrapper(dbWrapper);
consistencyChecksBean.setTapSchema(loadedTapSchema);
return "consistencyChecks.xhtml?faces-redirect=true";
} else {
tapSchemaEditingBean.setTapSchema(loadedTapSchema);
return "tapSchemaEditing.xhtml?faces-redirect=true";
}
}
public String edit() {
try {
TapSchema tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, selectedTAPSchema, true);
if (tapSchema.getConsistencyChecks().isInconsistent()) {
consistencyChecksBean.setDbWrapper(dbWrapper);
consistencyChecksBean.setTapSchema(tapSchema);
return "consistencyChecks.xhtml?faces-redirect=true";
} else {
return loadTapSchema(tapSchema);
public void edit() {
loadedTapSchema = null;
loading = true;
loadingError = null;
new Thread(new Runnable() {
@Override
public void run() {
try {
loadedTapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, selectedTAPSchema, true);
} catch (Throwable e) {
loadingError = e.getMessage();
}
loading = false;
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}).start();
}
public String create() {
try {
TapSchema tapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, tapSchemaName, false);
for (String schemaName : selectedSchemas) {
tapSchema.addChild(schemaName);
public void create() {
loadedTapSchema = null;
loading = true;
loadingError = null;
new Thread(new Runnable() {
@Override
public void run() {
try {
loadedTapSchema = TapSchemaFactory.getTapSchema(TapSchemaVersion.TAP_SCHEMA_1_IA2, dbWrapper, tapSchemaName, false);
for (String schemaName : selectedSchemas) {
loadedTapSchema.addChild(schemaName);
}
} catch (Throwable e) {
loadingError = e.getMessage();
}
loading = false;
}
return loadTapSchema(tapSchema);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}).start();
}
public String getTapSchemaName() {
return tapSchemaName;
}
......@@ -226,4 +251,23 @@ public class SchemaSelectionBean implements Serializable {
throw new ValidatorException(new FacesMessage(validatorMessage));
}
}
/**
* This boolean is true when a TapSchema instance is loading.
*/
public boolean isLoading() {
return loading;
}
/**
* This String is not null when an error happens while a TapSchema is
* loading.
*/
public String getLoadingError() {
return loadingError;
}
public TapSchema getLoadedTapSchema() {
return loadedTapSchema;
}
}
......@@ -400,17 +400,18 @@ public class TapSchemaEditingBean implements Serializable {
});
}
public String reload() {
public void reload() {
if (schemaSelection.getSelectedRadioOption().equals("edit")) {
return schemaSelection.edit();
schemaSelection.edit();
} else {
if (tapSchema.exists()) {
schemaSelection.setSelectedRadioOption("edit");
schemaSelection.setSelectedTAPSchema(tapSchema.getName());
return schemaSelection.edit();
schemaSelection.selectedTAPSchemaChanged();
schemaSelection.edit();
} else {
return schemaSelection.create();
schemaSelection.create();
}
}
}
......
/*
* _____________________________________________________________________________
*
* INAF - OATS National Institute for Astrophysics - Astronomical Observatory of
* Trieste INAF - IA2 Italian Center for Astronomical Archives
* _____________________________________________________________________________
*
* Copyright (C) 2017 Istituto Nazionale di Astrofisica
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License Version 3 as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package it.inaf.ia2.tsm.webapp;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonObjectBuilder;
/**
* REST Web Service
*
* @author Sonia Zorba {@literal <zorba at oats.inaf.it>}
*/
@Path("tap_schema")
@RequestScoped
public class TapSchemaLoaderResource {
@Inject
private SchemaSelectionBean schemaSelection;
@GET
@Path("status")
public String getStatus() {
JsonObjectBuilder job = Json.createObjectBuilder();
job.add("loading", schemaSelection.isLoading());
if (schemaSelection.getLoadingError() != null) {
job.add("error", schemaSelection.getLoadingError());
}
return job.build().toString();
}
}
......@@ -46,6 +46,7 @@ public class ApplicationConfig extends Application {
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(it.inaf.ia2.tsm.webapp.CredentialsDialogResource.class);
resources.add(it.inaf.ia2.tsm.webapp.TapSchemaLoaderResource.class);
resources.add(it.inaf.ia2.tsm.webapp.env.KeepAliveResource.class);
}
}
......@@ -19,7 +19,8 @@
<h:outputStylesheet library="css" name="style.css"></h:outputStylesheet>
<h:outputScript library="js" name="lib/jquery-1.11.3.min.js"></h:outputScript>
<h:outputScript library="js" name="lib/bootstrap.min.js"></h:outputScript>
<h:outputScript library="js" name="script.js"></h:outputScript>
<h:outputScript library="js" name="common.js"></h:outputScript>
<script>TSM.init('${config.restPath}', '${keepalive.windowId}');</script>
<ui:insert name="scripts"></ui:insert>
</h:head>
......@@ -34,6 +35,31 @@
TASMAN ${config.version} &#8211; Powered by IA2
</footer>
<div class="modal fade" tabindex="-1" role="dialog" id="errorModal" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title text-danger">
<span class="glyphicon glyphicon-alert"></span>
Error
</h4>
</div>
<div class="modal-body">
<p>An error occurred. The page will be reloaded.</p>
<div class="alert alert-danger" role="alert">
<p><strong class="errorName"></strong></p>
<p class="errorMessage"></p>
</div>
</div>
<div class="modal-footer">
<h:form>
<h:commandLink class="btn btn-primary">Ok</h:commandLink>
</h:form>
</div>
</div>
</div>
</div>
<div class="loading hide">
<div class="icon-wrapper">
<span class="glyphicon glyphicon-refresh animate-spin"></span>
......
......@@ -6,10 +6,6 @@
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<ui:define name="title">Consistency problems for #{consistency.tapSchema.name}</ui:define>
<ui:define name="scripts">
<h:outputScript library="js" name="keepalive.js"></h:outputScript>
<script>startKeepAlive('${config.restPath}', '${keepalive.windowId}');</script>
</ui:define>
<ui:define name="content">
<f:event listener="#{loggedInChecker.checkFromNonIndex()}" type="preRenderView" />
<div class="container">
......
......@@ -9,7 +9,6 @@
<ui:define name="scripts">
<h:outputScript library="js" name="credentials.js"></h:outputScript>
<h:outputScript library="js" name="ucd-editor.js"></h:outputScript>
<script>credentials.init('#{config.restPath}', '#{keepalive.windowId}');</script>
</ui:define>
<ui:define name="content">
<f:event listener="#{loggedInChecker.checkFromNonIndex()}" type="preRenderView" />
......
(function ($, TSM) {
var loading;
function periodicCheck() {
showWaiting();
setTimeout(function () {
$.get(TSM.getRestPath('tap_schema/status'), function (res) {
var status = JSON.parse(res);
if (status.loading) {
periodicCheck();
} else {
if (status.error) {
hideWaiting();
TSM.showError(status.error);
} else {
// Perform redirect trick
$('#async-loader\\:open-loaded').click();
}
}
});
}, 500);
}
TSM.asyncLoader = {
init: function (l) {
loading = l;
},
startChecking: function (event) {
if (event.status === 'success') {
periodicCheck();
}
}
};
$(document).ready(function () {
if (loading) {
periodicCheck();
}
});
})(jQuery, window.TSM);
\ No newline at end of file
(function ($) {
window.showWaiting = function () {
$('.loading').removeClass('hide');
};
window.hideWaiting = function () {
$('.loading').addClass('hide');
};
var restPath, windowId;
TSM = {
init: function (path, wid) {
restPath = path;
windowId = wid;
},
getRestPath: function (action) {
path = restPath + '/' + action;
if (path.indexOf("?") !== -1) {
path += '&';
} else {
path += '?';
}
return path + 'dswid=' + windowId;
},
showError: function (errorMessage) {
$('#errorModal .errorName').text("");
$('#errorModal .errorMessage').text(errorMessage);
$('#errorModal').modal('show');
}
};
$(document).ready(function () {
// Starting keep alive
if (window.name && window.name !== '') {
setInterval(function () {
$.get(TSM.getRestPath('keepalive'));
}, 60000);
}
if (jsf) {
jsf.ajax.addOnError(function (error) {
$('#errorModal .errorName').text(error.errorName);
$('#errorModal .errorMessage').text(error.errorMessage);
if (error.errorName.indexOf('ViewExpiredException') !== -1) {
// If view has expired reload the page to display error message
location.reload();
} else {
$('#errorModal').modal('show');
}
});
// Setup loading animation
jsf.ajax.addOnEvent(function (data) {
if ($(data.source).is('input[type="text"]')) {
return; // special case
}
switch (data.status) {
case "begin":
showWaiting();
break;
case "complete":
hideWaiting();
break;
}
});
}
});
})(jQuery);
(function () {
var restPath, windowId;
window.credentials = {
init: function (path, wid) {
restPath = path;
windowId = wid;
},
editClicked: function (event) {
if (event.status === 'success') {
$('#credentials-modal').modal('show');
......@@ -23,10 +17,10 @@
$(document).ready(function () {
$('body').on('shown.bs.modal', '#credentials-modal', function ( ) {
$.post(restPath + "/credentialsDialog?opened=true&dswid=" + windowId);
$.post(TSM.getRestPath("credentialsDialog?opened=true"));
});
$('body').on('hidden.bs.modal', '#credentials-modal', function ( ) {
$.post(restPath + "/credentialsDialog?opened=false&dswid=" + windowId);
$.post(TSM.getRestPath("credentialsDialog?opened=false"));
});
$('body').on('keyup', '#credentials-modal input', function (event) {
......@@ -34,6 +28,6 @@
$('#main\\:save-credentials').click();
event.preventDefault();
}
})
});
});
})();
(function ($) {
(function ($, TSM) {
// Function factory to handle custom communications between the backing bean and JavaScript functions
function eventHandlerFactory(handler, componentId) {
......@@ -38,124 +38,95 @@
var COLUMNS_COMPONENT_ID = 'main:columns-list';
window.TSM = {
// validateManualUCD: function (event) {
// $clientValidationMessage = $('#ucd_search_form\\:ucd_validation_result');
//
// var valid = UCDRegExp.test(event.target.value);
// if (valid) {
// $clientValidationMessage.empty();
// } else {
// $clientValidationMessage.text('Invalid UCD!');
// }
//
// $('#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');
}
// Hide loading
TSM.displayUpdateOperations = eventHandlerFactory(function (srcElement, jsupdate) {
$('#updateOperationsModal').modal('show');
});
TSM.saveUCDCalled = eventHandlerFactory(function (srcElement, jsupdate) {
if (jsupdate !== null) {
$('#searchUCDModal').modal('hide');
}
// Hide loading
$('.loading').addClass('hide');
});
TSM.textInputChanged = eventHandlerFactory(function (srcElement, jsupdate) {
$(srcElement).toggleClass('changed', jsupdate === 'true');
});
TSM.stopPropagation = function (event) {
event.stopPropagation();
event.preventDefault();
return false;
};
TSM.columnChanged = function (event) {
if (event.status === 'success') {
var $li = $(event.source).closest('li');
$li.closest('ul').find('li').removeClass('active');
$li.addClass('active');
}
};
TSM.columnRemoved = eventHandlerFactory(function (srcElement, jsupdate, htmlupdate) {
jsupdate = JSON.parse(jsupdate);
var $ul = $(srcElement).closest('ul');
$(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');
}
}, COLUMNS_COMPONENT_ID);
TSM.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);
TSM.ucdTextKeyDown = function (event) {
if (event.keyCode === 13) {
$('#ucd_search_form\\:search_UCD_btn').click();
}
};
TSM.openAddablesModal = function (event) {
if (event.status === 'success') {
$('#addablesModal').modal('show');
}
};
TSM.entitiesAdded = function (event) {
if (event.status === 'success') {
$('#addablesModal').modal('hide');
}
};
TSM.openSearchUCDModal = function (event) {
if (event.status === 'success') {
$('.loading').addClass('hide');
}),
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');
$li.closest('ul').find('li').removeClass('active');
$li.addClass('active');
}
},
columnRemoved: eventHandlerFactory(function (srcElement, jsupdate, htmlupdate) {
jsupdate = JSON.parse(jsupdate);
var $ul = $(srcElement).closest('ul');
$(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');
}
}, 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');