Merge branch 'develop' into LibrAlign
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / store / CdmStoreConnector.java
index 5d1b7104a6d73912d36332c9b1e72b234f5c2364..88f204955d8a2e3850c9aeb7ceeed807d4dd00fa 100644 (file)
@@ -1,15 +1,16 @@
-// $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.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.sql.SQLException;
 import java.util.concurrent.CancellationException;
 
@@ -17,229 +18,346 @@ 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.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.common.DefinedTermBase;
 import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
-import eu.etaxonomy.cdm.model.metadata.CdmMetaData.MetaDataPropertyName;
+import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
+import eu.etaxonomy.cdm.model.name.Rank;
+import eu.etaxonomy.taxeditor.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.internal.TaxeditorStorePlugin;
 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(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);
+        }
+
+        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);
+                MessagingUtils.informationDialog(Messages.CdmStoreConnector_SUCCESS, Messages.CdmStoreConnector_DATA_MODEL_CREATION_SUCCESSFUL);
+                CdmDataSourceViewPart dataSourceView = (CdmDataSourceViewPart) AbstractUtility.getView("eu.etaxonomy.taxeditor.view.datasource", false);
+                if(dataSourceView!=null){
+                    dataSourceView.refresh();
+                }
+                return Status.OK_STATUS;
+            } catch (Exception e) {
+                if(! causeIsCancelationExceptionRecursive(e)){
+                    MessagingUtils.errorDialog(Messages.CdmStoreConnector_COULD_NOT_CREATE_DATAMODEL, CdmStoreConnector.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 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(Messages.CdmStoreConnector_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();
+                                        getInstance(Rank.class).resetTerms();
+                                        getInstance(NomenclaturalStatusType.class).resetTerms();
+                                        Rank.initDefaultTerms();
+                                        NomenclaturalStatusType.initDefaultTerms();
+                                    } 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());
+        }
+    }
+
+    /**
+     * Returns a new instance for the given class by using the default constructor.
+     * The constructor must be declared but can be unaccessible (e.g. private)
+     * @param termClass
+     * @return
+     */
+    private  <T extends DefinedTermBase> T getInstance(Class<? extends DefinedTermBase> termClass) {
+        try {
+            Constructor<T> c = ((Class<T>)termClass).getDeclaredConstructor();
+            c.setAccessible(true);
+            T termInstance = c.newInstance();
+            return termInstance;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    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(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);
+        }
+    }
+
+
 }