Project

General

Profile

Download (14.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.Constructor;
14
import java.lang.reflect.InvocationTargetException;
15
import java.sql.SQLException;
16
import java.util.concurrent.CancellationException;
17

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

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

    
45

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

    
57

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

    
74

    
75

    
76
    @Override
77
    public IStatus run(final IProgressMonitor monitor) {
78

    
79
        monitor.beginTask(getConnectionMessage(), 10);
80

    
81
        // check if database is up and running
82
        checkDatabaseReachable(monitor);
83

    
84
        if (!monitor.isCanceled()) {
85
            // check if the datasource actually holds data
86
            checkIsNonEmptyCdmDatabase(monitor);
87
        }
88

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

    
96
        // we are done with our low level checking and will free resources now
97
        cdmSource.closeOpenConnections();
98

    
99
        if (!monitor.isCanceled()) {
100
            CdmStore.close(monitor);
101
        }
102

    
103
        ICdmApplicationConfiguration applicationController = null;
104

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

    
123

    
124

    
125
        if (!monitor.isCanceled()) {
126
            CdmStore.setInstance(applicationController, cdmSource);
127

    
128
            display.asyncExec(new Runnable() {
129
                /*
130
                 * (non-Javadoc)
131
                 *
132
                 * @see java.lang.Runnable#run()
133
                 */
134
                @Override
135
                public void run() {
136
                    authenticate();
137

    
138
                    startContext();
139
                }
140
            });
141

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

    
160
    }
161

    
162
    public void start(final RemotingLoginDialog loginDialog) {
163
        // hide login dialog and start connection dialog
164
        loginDialog.setMessage(null);
165
        loginDialog.hide(true);
166

    
167

    
168
        ProgressMonitorDialog dialog = new ProgressMonitorDialog(StoreUtil.getShell());
169

    
170
        try {
171
            dialog.run(true, true, new IRunnableWithProgress() {
172
                @Override
173
                public void run(final IProgressMonitor monitor) {
174
                    try {
175
                        monitor.beginTask(getConnectionMessage(), 7);
176

    
177
                        // check if database is up and running
178
                        checkDatabaseReachable(monitor);
179

    
180
                        // check if the datasource actually holds data
181
                        checkIsNonEmptyCdmDatabase(monitor);
182

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

    
189
                        // we are done with our low level checking and will free resources now
190
                        cdmSource.closeOpenConnections();
191

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

    
205
                        ICdmApplicationConfiguration applicationController = null;
206

    
207
                        if (!monitor.isCanceled()) {
208
                            CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
209
                                    .CreateSubMonitor(monitor, 3);
210
                            // genrerate new application controller
211
                            applicationController = getApplicationController(cdmSource,subprogressMonitor);
212
                        }
213

    
214

    
215
                        if (!monitor.isCanceled()) {
216
                            CdmStore.setInstance(applicationController, cdmSource);
217
                            monitor.subTask("Authenticating user");
218
                            display.syncExec(new Runnable() {
219
                                /*
220
                                 * (non-Javadoc)
221
                                 *
222
                                 * @see java.lang.Runnable#run()
223
                                 */
224
                                @Override
225
                                public void run() {
226

    
227
                                    try {
228
                                        // create new security context
229
                                        CdmStore.getLoginManager().doAuthenticate(loginDialog.getUsername(), loginDialog.getPassword());
230
                                        loginDialog.onComplete();
231
                                        CdmStore.getContextManager().notifyContextStart();
232
                                        getInstance(Rank.class).resetTerms();
233
                                        getInstance(NomenclaturalStatusType.class).resetTerms();
234
                                        Rank.initDefaultTerms();
235
                                        NomenclaturalStatusType.initDefaultTerms();
236
                                    } catch(CdmAuthenticationException cae) {
237
                                        loginDialog.hide(false);
238
                                        loginDialog.setMessage(cae.getMessage());
239
                                    }
240

    
241
                                }
242
                            });
243
                        } else {
244
                            throw new RuntimeException("Login cancelled");
245
                        }
246
                    } finally {
247
                        monitor.done();
248
                    }
249
                }
250
            });
251
        } catch (InvocationTargetException e) {
252
            loginDialog.hide(false);
253
            loginDialog.setMessage(e.getMessage());
254
        } catch (InterruptedException e) {
255
            loginDialog.hide(false);
256
            loginDialog.setMessage(e.getMessage());
257
        }
258
    }
259

    
260
    /**
261
     * Returns a new instance for the given class by using the default constructor.
262
     * The constructor must be declared but can be unaccessible (e.g. private)
263
     * @param termClass
264
     * @return
265
     */
266
    private  <T extends DefinedTermBase> T getInstance(Class<? extends DefinedTermBase> termClass) {
267
        try {
268
            Constructor<T> c = ((Class<T>)termClass).getDeclaredConstructor();
269
            c.setAccessible(true);
270
            T termInstance = c.newInstance();
271
            return termInstance;
272
        } catch (Exception e) {
273
            throw new RuntimeException(e);
274
        }
275
    }
276

    
277

    
278
    private ICdmApplicationConfiguration getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
279
        if(cdmSource instanceof ICdmDataSource) {
280
            return  CdmApplicationController.NewInstance(applicationContextBean,
281
                    (ICdmDataSource)cdmSource,
282
                    dbSchemaValidation,
283
                    false,
284
                    subprogressMonitor);
285
        } else if(cdmSource instanceof ICdmRemoteSource) {
286
            return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
287
                    subprogressMonitor,
288
                    null);
289
        } else {
290
            throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
291
        }
292
    }
293

    
294
    private void authenticate() {
295
        LoginDialog saloginDialog = new LoginDialog(StoreUtil.getShell());
296
        saloginDialog.open();
297
    }
298

    
299
    private void startContext() {
300
        CdmStore.getContextManager().notifyContextStart();
301
    }
302

    
303
    /**
304
     * @return
305
     */
306
    private String getConnectionMessage() {
307
        return cdmSource.getConnectionMessage();
308
    }
309

    
310
    /**
311
     * @return
312
     * @throws SQLException
313
     */
314
    private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
315
        monitor.subTask("Checking if datasource is compatible with this editor.");
316
        String dbSchemaVersion;
317

    
318
        String message = null;
319
        try {
320
            dbSchemaVersion = cdmSource.getDbSchemaVersion();
321
            // we assume that empty dbSchemaVersion means an empty database and
322
            // skip version checking
323

    
324
            if(dbSchemaVersion != null) {
325
                int compareVersion = CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
326
                // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
327
                // be updated else the datasource needs to be updated
328
                if(compareVersion > 0) {
329
                    message = "Please update the Taxonomic Editor (Help->Check for Updates) or choose a compatible datasource";
330
                } else if (compareVersion < 0) {
331
                    message = "Please update the chosen datasource or choose a new data source to connect to in the Datasource View.";
332
                }
333
            }
334
            monitor.worked(1);
335
        } catch (CdmSourceException e) {
336
            //
337
        }
338

    
339
        if (message != null) {
340
            // Show an error message
341
            MessagingUtils
342
            .messageDialog(
343
                    "Datasource Compatibility Check failed",
344
                    this,
345
                    "The database schema for the chosen "
346
                            + "datasource '"
347
                            + cdmSource
348
                            + "' \n is not compatible for this version of the taxonomic editor. \n\n"
349
                            + message,
350
                            null);
351

    
352
            monitor.setCanceled(true);
353
        }
354

    
355
    }
356

    
357
    private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
358
        monitor.subTask("Checking if datasource is a non empty CDM database.");
359
        boolean isDbEmpty = false;
360
        try {
361
            isDbEmpty = cdmSource.isDbEmpty();
362
        } catch (CdmSourceException e) {
363
            isDbEmpty = true;
364
        }
365
        if(isDbEmpty) {
366
            dbSchemaValidation = DbSchemaValidation.CREATE;
367
        }
368
    }
369

    
370
    private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
371
        if(throwable == null){
372
            return false;
373
        }else if(throwable instanceof CancellationException){
374
            return true;
375
        }else{
376
            return causeIsCancelationExceptionRecursive(throwable.getCause());
377
        }
378
    }
379

    
380
    private void checkDatabaseReachable(IProgressMonitor monitor) {
381
        try {
382
            monitor.subTask("Checking if datasource is reachable.");
383
            cdmSource.checkConnection();
384
            monitor.worked(1);
385
        } catch (CdmSourceException e) {
386
            MessagingUtils.messageDialog("Could not connect to chosen datasource",
387
                    this, "Reason: " + e.getMessage(), e);
388
            monitor.setCanceled(true);
389
        }
390
    }
391

    
392

    
393
}
(3-3/13)