--- /dev/null
+/**
+ * Copyright (C) 2007 EDIT
+ * 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.webapp.server;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.CancellationException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+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.api.application.ICdmRepository;
+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.common.Language;
+import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
+import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
+import eu.etaxonomy.cdm.model.name.Rank;
+import eu.etaxonomy.cdm.model.term.init.TermLoader;
+import eu.etaxonomy.taxeditor.event.EventUtility;
+import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
+import eu.etaxonomy.taxeditor.l10n.Messages;
+import eu.etaxonomy.taxeditor.model.AbstractUtility;
+import eu.etaxonomy.taxeditor.model.CdmProgressMonitorAdapter;
+import eu.etaxonomy.taxeditor.model.MessagingUtils;
+import eu.etaxonomy.taxeditor.remoting.source.ICdmRemoteSource;
+import eu.etaxonomy.taxeditor.store.CdmAuthenticationException;
+import eu.etaxonomy.taxeditor.store.CdmStore;
+import eu.etaxonomy.taxeditor.store.LoginManager;
+import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
+
+
+/**
+ * @author n.hoffmann
+ * @created Dec 8, 2010
+ */
+public class CdmStoreConnectorLocal extends Job {
+ private final Display display;
+ private final ICdmSource cdmSource;
+ private DbSchemaValidation dbSchemaValidation;
+ private final Resource applicationContextBean;
+
+ public CdmStoreConnectorLocal(Display display,
+ ICdmSource cdmSource,
+ DbSchemaValidation dbSchemaValidation,
+ Resource applicationContextBean) {
+ super(String.format(Messages.CdmStoreConnector_CREATING_DATAMODEL, 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);
+ }
+
+ ICdmRepository 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);
+ MessagingUtils.informationDialog(Messages.CdmStoreConnector_SUCCESS, Messages.CdmStoreConnector_DATA_MODEL_CREATION_SUCCESSFUL);
+ //FIXME E4 migrate or delete because data source view is not used anymore
+// CdmDataSourceViewPartE4 dataSourceView = (CdmDataSourceViewPartE4) WorkbenchUtility.getE4WrappedPart(AbstractUtility.getView("eu.etaxonomy.taxeditor.view.datasource", false));
+// if(dataSourceView!=null){
+// dataSourceView.refresh();
+// }
+ EventUtility.postEvent(WorkbenchEventConstants.REFRESH_DATASOURCE, true);
+ return Status.OK_STATUS;
+ } catch (Exception e) {
+ if(! causeIsCancelationExceptionRecursive(e)){
+ MessagingUtils.errorDialog(Messages.CdmStoreConnector_COULD_NOT_CREATE_DATAMODEL, CdmStoreConnectorLocal.class,
+ String.format(Messages.CdmStoreConnector_ERROR_DURING_DATAMODEL_CREATION, cdmSource.getName()), TaxeditorStorePlugin.PLUGIN_ID, e, true);
+ return Status.CANCEL_STATUS;
+ }
+ } finally {
+ monitor.done();
+ Thread.currentThread().setPriority(oldPriority);
+ }
+ }
+ return Status.CANCEL_STATUS;
+ }
+
+ public void start(final RemotingLoginDialogLocal loginDialog) {
+ // hide login dialog and start connection dialog
+ loginDialog.setMessage(null);
+ loginDialog.hide(true);
+
+ ProgressMonitorDialog dialog = new ProgressMonitorDialog(AbstractUtility.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() {
+ @Override
+ public void run() {
+ // close the current context
+ CdmStore.close(monitor, false);
+ }
+ });
+
+ ICdmRepository applicationController = null;
+
+ if (!monitor.isCanceled()) {
+ CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
+ .CreateSubMonitor(monitor, 3);
+ // genrerate new application controller
+ applicationController = getApplicationController(cdmSource,subprogressMonitor);
+ }
+
+ if (!monitor.isCanceled()) {
+ CdmStoreLocal.setInstance(applicationController, cdmSource);
+ CdmStoreLocal.getTermManager().reset();
+ monitor.subTask(Messages.CdmStoreConnector_AUTHENTICATING_USER);
+ display.syncExec(()-> {
+ try {
+ // create new security context
+ CdmStore.getLoginManager().doAuthenticate(loginDialog.getUsername(), loginDialog.getPassword());
+ //loginDialog.onComplete();
+ CdmStore.getContextManager().notifyContextStart();
+ loginDialog.onComplete();
+ //TODO AM: is this necessary to be done on display thread?
+ new TermLoader().unloadAllTerms();
+ Rank.initDefaultTerms();
+ NomenclaturalStatusType.initDefaultTerms();
+ Language.getDefaultLanguage();
+ } catch(CdmAuthenticationException cae) {
+ loginDialog.hide(false);
+ loginDialog.setMessage(LoginManager.INCORRECT_CREDENTIALS_MESSAGE);
+ }
+ });
+ } 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 ICdmRepository 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 String getConnectionMessage() {
+ return cdmSource.getConnectionMessage();
+ }
+
+ private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
+ monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_EDITOR_IS_COMPATIBLE);
+ 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 = Messages.CdmStoreConnector_UPDATE_EDITOR_OR_CHOOSE_COMPATIBLE_DATASOURCE;
+ } else if (compareVersion < 0) {
+ message = Messages.CdmStoreConnector_UPDATE_DATASOUREC_OR_CHOOSE_NEW_DATASOURCE;
+ }
+ }
+ monitor.worked(1);
+ } catch (CdmSourceException e) {
+ //
+ }
+
+ if (message != null) {
+ // Show an error message
+ MessagingUtils
+ .messageDialog(
+ Messages.CdmStoreConnector_COMPATIBILITY_CHECK_FAILED,
+ this,
+ String.format(Messages.CdmStoreConnector_SCHEME_NOT_COMPATIBLE, cdmSource, message),
+ null);
+
+ monitor.setCanceled(true);
+ }
+ }
+
+ private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
+ monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_NON_EMPTY);
+ 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(Messages.CdmStoreConnector_CHECK_IF_REACHABLE);
+ cdmSource.checkConnection();
+ monitor.worked(1);
+ } catch (CdmSourceException e) {
+ MessagingUtils.messageDialog(Messages.CdmStoreConnector_COULD_NOT_CONNECT_TO_CHOSEN_DATASOURCE,
+ this, Messages.CdmStoreConnector_REASON + e.getMessage(), e);
+ monitor.setCanceled(true);
+ }
+ }
+}