// $Id$
/**
* Copyright (C) 2007 EDIT
- * European Distributed Institute of Taxonomy
+ * European Distributed Institute of Taxonomy
* http://www.e-taxonomy.eu
- *
+ *
* The contents of this file are subject to the Mozilla Public License Version 1.1
* See LICENSE.TXT at the top of this package for the full license terms.
*/
package eu.etaxonomy.taxeditor.store;
+import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.concurrent.CancellationException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import org.springframework.core.io.Resource;
import eu.etaxonomy.cdm.api.application.CdmApplicationController;
import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteController;
-import eu.etaxonomy.cdm.database.DatabaseTypeEnum;
+import eu.etaxonomy.cdm.api.application.ICdmApplicationConfiguration;
+import eu.etaxonomy.cdm.config.CdmSourceException;
+import eu.etaxonomy.cdm.config.ICdmSource;
import eu.etaxonomy.cdm.database.DbSchemaValidation;
import eu.etaxonomy.cdm.database.ICdmDataSource;
import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
-import eu.etaxonomy.cdm.model.metadata.CdmMetaData.MetaDataPropertyName;
import eu.etaxonomy.taxeditor.model.CdmProgressMonitorAdapter;
+import eu.etaxonomy.taxeditor.model.MessagingUtils;
+import eu.etaxonomy.taxeditor.remoting.source.ICdmRemoteSource;
import eu.etaxonomy.taxeditor.ui.dialog.LoginDialog;
+import eu.etaxonomy.taxeditor.ui.dialog.RemotingLoginDialog;
import eu.etaxonomy.taxeditor.view.datasource.CdmDataSourceViewPart;
+
/**
* @author n.hoffmann
* @created Dec 8, 2010
* @version 1.0
*/
class CdmStoreConnector extends Job {
- private final Display display;
- private final ICdmDataSource dataSource;
- private DbSchemaValidation dbSchemaValidation;
- private final Resource applicationContextBean;
-
- /**
- * @param datasource
- * @param dbSchemaValidation
- * @param applicationContextBean
- */
- public CdmStoreConnector(Display display, ICdmDataSource datasource,
- DbSchemaValidation dbSchemaValidation,
- Resource applicationContextBean) {
- super("Connecting to datasource: " + datasource);
- this.display = display;
- this.dataSource = datasource;
- this.dbSchemaValidation = dbSchemaValidation;
- this.applicationContextBean = applicationContextBean;
- }
-
- @Override
- public IStatus run(final IProgressMonitor monitor) {
-
- monitor.beginTask(getConnectionMessage(), 10);
-
- // check if database is up and running
- checkDatabaseReachable(monitor);
-
- if (!monitor.isCanceled()) {
- // check if the datasource actually holds data
- checkIsNonEmptyCdmDatabase(monitor);
- }
-
- if (dbSchemaValidation != DbSchemaValidation.CREATE
- && !monitor.isCanceled()) {
- // if we do not create the datasource, we want to check if the
- // datasource is compatible with this editor
- checkDbSchemaVersionCompatibility(monitor);
- }
-
- // we are done with our low level checking and will free resources now
- dataSource.closeOpenConnections();
-
- if (!monitor.isCanceled()) {
- CdmStore.close(monitor);
- }
-
- CdmApplicationRemoteController applicationController = null;
-
- if (!monitor.isCanceled()) {
- CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
- .CreateSubMonitor(monitor, 7);
- // This is where we instantiate the application controller
- try {
- applicationController = CdmApplicationRemoteController.NewInstance();
- } catch (Exception e) {
- if(! causeIsCancelationExceptionRecursive(e)){
- return new Status(IStatus.ERROR, "Could not connect to CDM Store", "An error occurred while trying to connect to datasource: " + dataSource.getName(), e);
- }
- } finally {
- monitor.done();
- }
- }
-
-
-
- if (!monitor.isCanceled()) {
- CdmStore.setInstance(applicationController, dataSource);
-
- display.asyncExec(new Runnable() {
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run() {
- authenticate();
-
- startContext();
- }
- });
-
- StoreUtil.info("Application context initialized.");
- return Status.OK_STATUS;
- } else {
- // Show datasource view if not shown yet
- display.asyncExec(new Runnable() {
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Runnable#run()
- */
- @Override
- public void run() {
- StoreUtil.showView(CdmDataSourceViewPart.ID);
- }
- });
- return Status.CANCEL_STATUS;
- }
-
- }
-
- private void authenticate() {
- LoginDialog loginDialog = new LoginDialog(StoreUtil.getShell());
- loginDialog.open();
- }
-
- private void startContext() {
- CdmStore.getContextManager().notifyContextStart();
- }
-
- /**
- * @return
- */
- private String getConnectionMessage() {
- String message = "";
- if (dataSource.getDatabaseType().equals(DatabaseTypeEnum.H2)) {
- message = " local CDM Store ";
- } else {
- message = " CDM Community Store ";
- }
- message += "'" + dataSource.getName() + "'";
-
- message = "Connecting to" + message + ".";
-
- return message;
- }
-
- /**
- * @return
- * @throws SQLException
- */
- private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
- monitor.subTask("Checking if datasource is compatible with this editor.");
- String dbSchemaVersion;
- boolean result = false;
- try {
- dbSchemaVersion = (String) dataSource
- .getSingleValue(MetaDataPropertyName.DB_SCHEMA_VERSION
- .getSqlQuery());
- // we assume that empty dbSchemaVersion means an empty database and
- // skip version checking
- result = dbSchemaVersion == null ? true : CdmMetaData
- .isDbSchemaVersionCompatible(dbSchemaVersion);
- monitor.worked(1);
- } catch (SQLException e) {
- //
- }
-
- if (!result) {
- // Show an error message
- StoreUtil
- .errorDialog(
- "DatabaseCompatibilityCheck failed",
- this,
- "The database schema for the chosen "
- + "datasource '"
- + dataSource
- + "' \n is not valid for this version of the taxonomic editor. \n"
- + "Please update the chosen datasource or choose a new data source to connect to in the Datasource View.",
- null);
-
- monitor.setCanceled(true);
- }
-
- }
-
- private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
- monitor.subTask("Checking if datasource is a non empty CDM database.");
-
- try {
- dataSource.getSingleValue(MetaDataPropertyName.DB_SCHEMA_VERSION
- .getSqlQuery());
- } catch (SQLException e1) {
- dbSchemaValidation = DbSchemaValidation.CREATE;
- }
- }
-
- private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
- if(throwable == null){
- return false;
- }else if(throwable instanceof CancellationException){
- return true;
- }else{
- return causeIsCancelationExceptionRecursive(throwable.getCause());
- }
- }
-
- private void checkDatabaseReachable(IProgressMonitor monitor) {
- try {
- monitor.subTask("Checking if datasource is reachable.");
- dataSource.testConnection();
- monitor.worked(1);
- } catch (ClassNotFoundException e) {
- StoreUtil.errorDialog("Could not connect to chosen datasource",
- this, "Reason: " + e.getMessage(), e);
- monitor.setCanceled(true);
- } catch (SQLException e) {
- StoreUtil.errorDialog("Could not connect to chosen datasource",
- this, "Reason: " + e.getMessage(), e);
- monitor.setCanceled(true);
- }
-
- }
+ private final Display display;
+ private final ICdmSource cdmSource;
+ private DbSchemaValidation dbSchemaValidation;
+ private final Resource applicationContextBean;
+
+
+ /**
+ * @param datasource
+ * @param dbSchemaValidation
+ * @param applicationContextBean
+ */
+ public CdmStoreConnector(Display display,
+ ICdmSource cdmSource,
+ DbSchemaValidation dbSchemaValidation,
+ Resource applicationContextBean) {
+ super("Connecting to datasource: " + cdmSource);
+ this.display = display;
+ this.cdmSource = cdmSource;
+ this.dbSchemaValidation = dbSchemaValidation;
+ this.applicationContextBean = applicationContextBean;
+ }
+
+
+
+ @Override
+ public IStatus run(final IProgressMonitor monitor) {
+
+ monitor.beginTask(getConnectionMessage(), 10);
+
+ // check if database is up and running
+ checkDatabaseReachable(monitor);
+
+ if (!monitor.isCanceled()) {
+ // check if the datasource actually holds data
+ checkIsNonEmptyCdmDatabase(monitor);
+ }
+
+ if (dbSchemaValidation != DbSchemaValidation.CREATE
+ && !monitor.isCanceled()) {
+ // if we do not create the datasource, we want to check if the
+ // datasource is compatible with this editor
+ checkDbSchemaVersionCompatibility(monitor);
+ }
+
+ // we are done with our low level checking and will free resources now
+ cdmSource.closeOpenConnections();
+
+ if (!monitor.isCanceled()) {
+ CdmStore.close(monitor);
+ }
+
+ ICdmApplicationConfiguration applicationController = null;
+
+ if (!monitor.isCanceled()) {
+ CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
+ .CreateSubMonitor(monitor, 7);
+ // This is where we instantiate the application controller
+ int oldPriority = Thread.currentThread().getPriority();
+ try {
+ Thread.currentThread().setPriority(10);
+ applicationController = getApplicationController(cdmSource,subprogressMonitor);
+ } catch (Exception e) {
+ if(! causeIsCancelationExceptionRecursive(e)){
+ return new Status(IStatus.ERROR, "Could not connect to CDM Store", "An error occurred while trying to connect to datasource: " + cdmSource.getName(), e);
+ }
+ } finally {
+ monitor.done();
+ Thread.currentThread().setPriority(oldPriority);
+ }
+ }
+
+
+
+ if (!monitor.isCanceled()) {
+ CdmStore.setInstance(applicationController, cdmSource);
+
+ display.asyncExec(new Runnable() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ authenticate();
+
+ startContext();
+ }
+ });
+
+ MessagingUtils.info("Application context initialized.");
+ return Status.OK_STATUS;
+ } else {
+ // Show datasource view if not shown yet
+ display.asyncExec(new Runnable() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ StoreUtil.showView(CdmDataSourceViewPart.ID);
+ }
+ });
+ return Status.CANCEL_STATUS;
+ }
+
+ }
+
+ public void start(final RemotingLoginDialog loginDialog) {
+ // hide login dialog and start connection dialog
+ loginDialog.setMessage(null);
+ loginDialog.hide(true);
+
+
+ ProgressMonitorDialog dialog = new ProgressMonitorDialog(StoreUtil.getShell());
+
+ try {
+ dialog.run(true, true, new IRunnableWithProgress() {
+ @Override
+ public void run(final IProgressMonitor monitor) {
+ try {
+ monitor.beginTask(getConnectionMessage(), 7);
+
+ // check if database is up and running
+ checkDatabaseReachable(monitor);
+
+ // check if the datasource actually holds data
+ checkIsNonEmptyCdmDatabase(monitor);
+
+ if (dbSchemaValidation != DbSchemaValidation.CREATE) {
+ // if we do not create the datasource, we want to check if the
+ // datasource is compatible with this editor
+ checkDbSchemaVersionCompatibility(monitor);
+ }
+
+ // we are done with our low level checking and will free resources now
+ cdmSource.closeOpenConnections();
+
+ display.syncExec(new Runnable() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ // close the current context
+ CdmStore.close(monitor, false);
+ }
+ });
+
+ ICdmApplicationConfiguration applicationController = null;
+
+ if (!monitor.isCanceled()) {
+ CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
+ .CreateSubMonitor(monitor, 3);
+ // genrerate new application controller
+ applicationController = getApplicationController(cdmSource,subprogressMonitor);
+ }
+
+
+ if (!monitor.isCanceled()) {
+ CdmStore.setInstance(applicationController, cdmSource);
+ monitor.subTask("Authenticating user");
+ display.syncExec(new Runnable() {
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+
+ try {
+ // create new security context
+ CdmStore.getLoginManager().doAuthenticate(loginDialog.getUsername(), loginDialog.getPassword());
+ loginDialog.onComplete();
+ CdmStore.getContextManager().notifyContextStart();
+ } catch(CdmAuthenticationException cae) {
+ loginDialog.hide(false);
+ loginDialog.setMessage(cae.getMessage());
+ }
+
+ }
+ });
+ } else {
+ throw new RuntimeException("Login cancelled");
+ }
+ } finally {
+ monitor.done();
+ }
+ }
+ });
+ } catch (InvocationTargetException e) {
+ loginDialog.hide(false);
+ loginDialog.setMessage(e.getMessage());
+ } catch (InterruptedException e) {
+ loginDialog.hide(false);
+ loginDialog.setMessage(e.getMessage());
+ }
+ }
+
+
+ private ICdmApplicationConfiguration getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
+ if(cdmSource instanceof ICdmDataSource) {
+ return CdmApplicationController.NewInstance(applicationContextBean,
+ (ICdmDataSource)cdmSource,
+ dbSchemaValidation,
+ false,
+ subprogressMonitor);
+ } else if(cdmSource instanceof ICdmRemoteSource) {
+ return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
+ subprogressMonitor,
+ null);
+ } else {
+ throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
+ }
+ }
+
+ private void authenticate() {
+ LoginDialog saloginDialog = new LoginDialog(StoreUtil.getShell());
+ saloginDialog.open();
+ }
+
+ private void startContext() {
+ CdmStore.getContextManager().notifyContextStart();
+ }
+
+ /**
+ * @return
+ */
+ private String getConnectionMessage() {
+ return cdmSource.getConnectionMessage();
+ }
+
+ /**
+ * @return
+ * @throws SQLException
+ */
+ private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
+ monitor.subTask("Checking if datasource is compatible with this editor.");
+ String dbSchemaVersion;
+
+ String message = null;
+ try {
+ dbSchemaVersion = cdmSource.getDbSchemaVersion();
+ // we assume that empty dbSchemaVersion means an empty database and
+ // skip version checking
+
+ if(dbSchemaVersion != null) {
+ int compareVersion = CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
+ // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
+ // be updated else the datasource needs to be updated
+ if(compareVersion > 0) {
+ message = "Please update the Taxonomic Editor (Help->Check for Updates) or choose a compatible datasource";
+ } else if (compareVersion < 0) {
+ message = "Please update the chosen datasource or choose a new data source to connect to in the Datasource View.";
+ }
+ }
+ monitor.worked(1);
+ } catch (CdmSourceException e) {
+ //
+ }
+
+ if (message != null) {
+ // Show an error message
+ MessagingUtils
+ .messageDialog(
+ "Datasource Compatibility Check failed",
+ this,
+ "The database schema for the chosen "
+ + "datasource '"
+ + cdmSource
+ + "' \n is not compatible for this version of the taxonomic editor. \n\n"
+ + message,
+ null);
+
+ monitor.setCanceled(true);
+ }
+
+ }
+
+ private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
+ monitor.subTask("Checking if datasource is a non empty CDM database.");
+ boolean isDbEmpty = false;
+ try {
+ isDbEmpty = cdmSource.isDbEmpty();
+ } catch (CdmSourceException e) {
+ isDbEmpty = true;
+ }
+ if(isDbEmpty) {
+ dbSchemaValidation = DbSchemaValidation.CREATE;
+ }
+ }
+
+ private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
+ if(throwable == null){
+ return false;
+ }else if(throwable instanceof CancellationException){
+ return true;
+ }else{
+ return causeIsCancelationExceptionRecursive(throwable.getCause());
+ }
+ }
+
+ private void checkDatabaseReachable(IProgressMonitor monitor) {
+ try {
+ monitor.subTask("Checking if datasource is reachable.");
+ cdmSource.checkConnection();
+ monitor.worked(1);
+ } catch (CdmSourceException e) {
+ MessagingUtils.messageDialog("Could not connect to chosen datasource",
+ this, "Reason: " + e.getMessage(), e);
+ monitor.setCanceled(true);
+ }
+ }
+
+
}