Project

General

Profile

Download (13.7 KB) Statistics
| Branch: | Tag: | Revision:
1
// $Id$
2
/**
3
 * Copyright (C) 2007 EDIT
4
 * European Distributed Institute of Taxonomy
5
 * http://www.e-taxonomy.eu
6
 *
7
 * The contents of this file are subject to the Mozilla Public License Version 1.1
8
 * See LICENSE.TXT at the top of this package for the full license terms.
9
 */
10

    
11
package eu.etaxonomy.taxeditor.store;
12

    
13
import java.lang.reflect.InvocationTargetException;
14
import java.sql.SQLException;
15
import java.util.concurrent.CancellationException;
16

    
17
import org.eclipse.core.runtime.IProgressMonitor;
18
import org.eclipse.core.runtime.IStatus;
19
import org.eclipse.core.runtime.Status;
20
import org.eclipse.core.runtime.jobs.Job;
21
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
22
import org.eclipse.jface.operation.IRunnableWithProgress;
23
import org.eclipse.swt.widgets.Display;
24
import org.springframework.core.io.Resource;
25

    
26
import eu.etaxonomy.cdm.api.application.CdmApplicationController;
27
import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteController;
28
import eu.etaxonomy.cdm.api.application.ICdmApplicationConfiguration;
29
import eu.etaxonomy.cdm.config.CdmSourceException;
30
import eu.etaxonomy.cdm.config.ICdmSource;
31
import eu.etaxonomy.cdm.database.DbSchemaValidation;
32
import eu.etaxonomy.cdm.database.ICdmDataSource;
33
import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
34
import eu.etaxonomy.taxeditor.model.CdmProgressMonitorAdapter;
35
import eu.etaxonomy.taxeditor.model.MessagingUtils;
36
import eu.etaxonomy.taxeditor.remoting.source.ICdmRemoteSource;
37
import eu.etaxonomy.taxeditor.ui.dialog.LoginDialog;
38
import eu.etaxonomy.taxeditor.ui.dialog.RemotingLoginDialog;
39
import eu.etaxonomy.taxeditor.view.datasource.CdmDataSourceViewPart;
40

    
41

    
42
/**
43
 * @author n.hoffmann
44
 * @created Dec 8, 2010
45
 * @version 1.0
46
 */
47
class CdmStoreConnector extends Job {
48
    private final Display display;
49
    private final ICdmSource cdmSource;
50
    private DbSchemaValidation dbSchemaValidation;
51
    private final Resource applicationContextBean;
52

    
53

    
54
    /**
55
     * @param datasource
56
     * @param dbSchemaValidation
57
     * @param applicationContextBean
58
     */
59
    public CdmStoreConnector(Display display,
60
            ICdmSource cdmSource,
61
            DbSchemaValidation dbSchemaValidation,
62
            Resource applicationContextBean) {
63
        super("Connecting to datasource: " + cdmSource);
64
        this.display = display;
65
        this.cdmSource = cdmSource;
66
        this.dbSchemaValidation = dbSchemaValidation;
67
        this.applicationContextBean = applicationContextBean;
68
    }
69

    
70

    
71

    
72
    @Override
73
    public IStatus run(final IProgressMonitor monitor) {
74

    
75
        monitor.beginTask(getConnectionMessage(), 10);
76

    
77
        // check if database is up and running
78
        checkDatabaseReachable(monitor);
79

    
80
        if (!monitor.isCanceled()) {
81
            // check if the datasource actually holds data
82
            checkIsNonEmptyCdmDatabase(monitor);
83
        }
84

    
85
        if (dbSchemaValidation != DbSchemaValidation.CREATE
86
                && !monitor.isCanceled()) {
87
            // if we do not create the datasource, we want to check if the
88
            // datasource is compatible with this editor
89
            checkDbSchemaVersionCompatibility(monitor);
90
        }
91

    
92
        // we are done with our low level checking and will free resources now
93
        cdmSource.closeOpenConnections();
94

    
95
        if (!monitor.isCanceled()) {
96
            CdmStore.close(monitor);
97
        }
98

    
99
        ICdmApplicationConfiguration applicationController = null;
100

    
101
        if (!monitor.isCanceled()) {
102
            CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
103
                    .CreateSubMonitor(monitor, 7);
104
            // This is where we instantiate the application controller
105
            int oldPriority = Thread.currentThread().getPriority();
106
            try {
107
                Thread.currentThread().setPriority(10);
108
                applicationController = getApplicationController(cdmSource,subprogressMonitor);
109
            } catch (Exception e) {
110
                if(! causeIsCancelationExceptionRecursive(e)){
111
                    return new Status(IStatus.ERROR, "Could not connect to CDM Store", "An error occurred while trying to connect to datasource: " + cdmSource.getName(), e);
112
                }
113
            } finally {
114
                monitor.done();
115
                Thread.currentThread().setPriority(oldPriority);
116
            }
117
        }
118

    
119

    
120

    
121
        if (!monitor.isCanceled()) {
122
            CdmStore.setInstance(applicationController, cdmSource);
123

    
124
            display.asyncExec(new Runnable() {
125
                /*
126
                 * (non-Javadoc)
127
                 *
128
                 * @see java.lang.Runnable#run()
129
                 */
130
                @Override
131
                public void run() {
132
                    authenticate();
133

    
134
                    startContext();
135
                }
136
            });
137

    
138
            MessagingUtils.info("Application context initialized.");
139
            return Status.OK_STATUS;
140
        } else {
141
            // Show datasource view if not shown yet
142
            display.asyncExec(new Runnable() {
143
                /*
144
                 * (non-Javadoc)
145
                 *
146
                 * @see java.lang.Runnable#run()
147
                 */
148
                @Override
149
                public void run() {
150
                    StoreUtil.showView(CdmDataSourceViewPart.ID);
151
                }
152
            });
153
            return Status.CANCEL_STATUS;
154
        }
155

    
156
    }
157

    
158
    public void start(final RemotingLoginDialog loginDialog) {
159
        // hide login dialog and start connection dialog
160
        loginDialog.setMessage(null);
161
        loginDialog.hide(true);
162

    
163

    
164
        ProgressMonitorDialog dialog = new ProgressMonitorDialog(StoreUtil.getShell());
165

    
166
        try {
167
            dialog.run(true, true, new IRunnableWithProgress() {
168
                @Override
169
                public void run(final IProgressMonitor monitor) {
170
                    try {
171
                        monitor.beginTask(getConnectionMessage(), 7);
172

    
173
                        // check if database is up and running
174
                        checkDatabaseReachable(monitor);
175

    
176
                        // check if the datasource actually holds data
177
                        checkIsNonEmptyCdmDatabase(monitor);
178

    
179
                        if (dbSchemaValidation != DbSchemaValidation.CREATE) {
180
                            // if we do not create the datasource, we want to check if the
181
                            // datasource is compatible with this editor
182
                            checkDbSchemaVersionCompatibility(monitor);
183
                        }
184

    
185
                        // we are done with our low level checking and will free resources now
186
                        cdmSource.closeOpenConnections();
187

    
188
                        display.syncExec(new Runnable() {
189
                            /*
190
                             * (non-Javadoc)
191
                             *
192
                             * @see java.lang.Runnable#run()
193
                             */
194
                            @Override
195
                            public void run() {
196
                                // close the current context
197
                                CdmStore.close(monitor, false);
198
                            }
199
                        });
200

    
201
                        ICdmApplicationConfiguration applicationController = null;
202

    
203
                        if (!monitor.isCanceled()) {
204
                            CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
205
                                    .CreateSubMonitor(monitor, 3);
206
                            // genrerate new application controller
207
                            applicationController = getApplicationController(cdmSource,subprogressMonitor);
208
                        }
209

    
210

    
211
                        if (!monitor.isCanceled()) {
212
                            CdmStore.setInstance(applicationController, cdmSource);
213
                            monitor.subTask("Authenticating user and starting editor context...");
214
                            display.syncExec(new Runnable() {
215
                                /*
216
                                 * (non-Javadoc)
217
                                 *
218
                                 * @see java.lang.Runnable#run()
219
                                 */
220
                                @Override
221
                                public void run() {
222

    
223
                                    try {
224
                                        // create new security context
225
                                        CdmStore.getLoginManager().doAuthenticate(loginDialog.getUsername(), loginDialog.getPassword());
226
                                        loginDialog.dispose();
227
                                        // start editor context
228
                                        CdmStore.getContextManager().notifyContextStartWithoutDialog(monitor);
229

    
230
                                    } catch(CdmAuthenticationException cae) {
231
                                        loginDialog.hide(false);
232
                                        loginDialog.setMessage(cae.getMessage());
233
                                    }
234

    
235
                                }
236
                            });
237
                        } else {
238
                            throw new RuntimeException("Login cancelled");
239
                        }
240
                    } finally {
241
                        monitor.done();
242
                    }
243
                }
244
            });
245
        } catch (InvocationTargetException e) {
246
            loginDialog.hide(false);
247
            loginDialog.setMessage(e.getMessage());
248
        } catch (InterruptedException e) {
249
            loginDialog.hide(false);
250
            loginDialog.setMessage(e.getMessage());
251
        }
252
    }
253

    
254

    
255
    private ICdmApplicationConfiguration getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
256
        if(cdmSource instanceof ICdmDataSource) {
257
            return  CdmApplicationController.NewInstance(applicationContextBean,
258
                    (ICdmDataSource)cdmSource,
259
                    dbSchemaValidation,
260
                    false,
261
                    subprogressMonitor);
262
        } else if(cdmSource instanceof ICdmRemoteSource) {
263
            return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
264
                    subprogressMonitor,
265
                    null);
266
        } else {
267
            throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
268
        }
269
    }
270

    
271
    private void authenticate() {
272
        LoginDialog saloginDialog = new LoginDialog(StoreUtil.getShell());
273
        saloginDialog.open();
274
    }
275

    
276
    private void startContext() {
277
        CdmStore.getContextManager().notifyContextStart();
278
    }
279

    
280
    /**
281
     * @return
282
     */
283
    private String getConnectionMessage() {
284
        return cdmSource.getConnectionMessage();
285
    }
286

    
287
    /**
288
     * @return
289
     * @throws SQLException
290
     */
291
    private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
292
        monitor.subTask("Checking if datasource is compatible with this editor.");
293
        String dbSchemaVersion;
294

    
295
        String message = null;
296
        try {
297
            dbSchemaVersion = cdmSource.getDbSchemaVersion();
298
            // we assume that empty dbSchemaVersion means an empty database and
299
            // skip version checking
300

    
301
            if(dbSchemaVersion != null) {
302
                int compareVersion = CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
303
                // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
304
                // be updated else the datasource needs to be updated
305
                if(compareVersion > 0) {
306
                    message = "Please update the Taxonomic Editor (Help->Check for Updates) or choose a compatible datasource";
307
                } else if (compareVersion < 0) {
308
                    message = "Please update the chosen datasource or choose a new data source to connect to in the Datasource View.";
309
                }
310
            }
311
            monitor.worked(1);
312
        } catch (CdmSourceException e) {
313
            //
314
        }
315

    
316
        if (message != null) {
317
            // Show an error message
318
            MessagingUtils
319
            .messageDialog(
320
                    "Datasource Compatibility Check failed",
321
                    this,
322
                    "The database schema for the chosen "
323
                            + "datasource '"
324
                            + cdmSource
325
                            + "' \n is not compatible for this version of the taxonomic editor. \n\n"
326
                            + message,
327
                            null);
328

    
329
            monitor.setCanceled(true);
330
        }
331

    
332
    }
333

    
334
    private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
335
        monitor.subTask("Checking if datasource is a non empty CDM database.");
336
        boolean isDbEmpty = false;
337
        try {
338
            isDbEmpty = cdmSource.isDbEmpty();
339
        } catch (CdmSourceException e) {
340
            isDbEmpty = true;
341
        }
342
        if(isDbEmpty) {
343
            dbSchemaValidation = DbSchemaValidation.CREATE;
344
        }
345
    }
346

    
347
    private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
348
        if(throwable == null){
349
            return false;
350
        }else if(throwable instanceof CancellationException){
351
            return true;
352
        }else{
353
            return causeIsCancelationExceptionRecursive(throwable.getCause());
354
        }
355
    }
356

    
357
    private void checkDatabaseReachable(IProgressMonitor monitor) {
358
        try {
359
            monitor.subTask("Checking if datasource is reachable.");
360
            cdmSource.checkConnection();
361
            monitor.worked(1);
362
        } catch (CdmSourceException e) {
363
            MessagingUtils.messageDialog("Could not connect to chosen datasource",
364
                    this, "Reason: " + e.getMessage(), e);
365
            monitor.setCanceled(true);
366
        }
367
    }
368

    
369

    
370
}
(3-3/13)