Project

General

Profile

Download (13.8 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.Messages;
39
import eu.etaxonomy.taxeditor.model.CdmProgressMonitorAdapter;
40
import eu.etaxonomy.taxeditor.model.MessagingUtils;
41
import eu.etaxonomy.taxeditor.remoting.source.ICdmRemoteSource;
42
import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
43
import eu.etaxonomy.taxeditor.ui.dialog.LoginDialog;
44
import eu.etaxonomy.taxeditor.ui.dialog.RemotingLoginDialog;
45

    
46

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

    
58

    
59
    /**
60
     * @param datasource
61
     * @param dbSchemaValidation
62
     * @param applicationContextBean
63
     */
64
    public CdmStoreConnector(Display display,
65
            ICdmSource cdmSource,
66
            DbSchemaValidation dbSchemaValidation,
67
            Resource applicationContextBean) {
68
        super(String.format(Messages.CdmStoreConnector_CREATING_DATAMODEL, cdmSource));
69
        this.display = display;
70
        this.cdmSource = cdmSource;
71
        this.dbSchemaValidation = dbSchemaValidation;
72
        this.applicationContextBean = applicationContextBean;
73
    }
74

    
75

    
76

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

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

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

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

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

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

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

    
104
        ICdmApplicationConfiguration applicationController = null;
105

    
106
        if (!monitor.isCanceled()) {
107
            CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
108
                    .CreateSubMonitor(monitor, 7);
109
            // This is where we instantiate the application controller
110
            int oldPriority = Thread.currentThread().getPriority();
111
            try {
112
                Thread.currentThread().setPriority(10);
113
                applicationController = getApplicationController(cdmSource,subprogressMonitor);
114
                return Status.OK_STATUS;
115
            } catch (Exception e) {
116
                if(! causeIsCancelationExceptionRecursive(e)){
117
                    MessagingUtils.errorDialog(Messages.CdmStoreConnector_COULD_NOT_CREATE_DATAMODEL, CdmStoreConnector.class, 
118
                    		String.format(Messages.CdmStoreConnector_ERROR_DURING_DATAMODEL_CREATION, cdmSource.getName()), TaxeditorStorePlugin.PLUGIN_ID, e, true);
119
                    return Status.CANCEL_STATUS;
120
                }
121
            } finally {
122
                monitor.done();
123
                Thread.currentThread().setPriority(oldPriority);
124
            }
125
        }
126

    
127
            return Status.CANCEL_STATUS;
128

    
129
    }
130

    
131
    public void start(final RemotingLoginDialog loginDialog) {
132
        // hide login dialog and start connection dialog
133
        loginDialog.setMessage(null);
134
        loginDialog.hide(true);
135

    
136

    
137
        ProgressMonitorDialog dialog = new ProgressMonitorDialog(StoreUtil.getShell());
138

    
139
        try {
140
            dialog.run(true, true, new IRunnableWithProgress() {
141
                @Override
142
                public void run(final IProgressMonitor monitor) {
143
                    try {
144
                        monitor.beginTask(getConnectionMessage(), 7);
145

    
146
                        // check if database is up and running
147
                        checkDatabaseReachable(monitor);
148

    
149
                        // check if the datasource actually holds data
150
                        checkIsNonEmptyCdmDatabase(monitor);
151

    
152
                        if (dbSchemaValidation != DbSchemaValidation.CREATE) {
153
                            // if we do not create the datasource, we want to check if the
154
                            // datasource is compatible with this editor
155
                            checkDbSchemaVersionCompatibility(monitor);
156
                        }
157

    
158
                        // we are done with our low level checking and will free resources now
159
                        cdmSource.closeOpenConnections();
160

    
161
                        display.syncExec(new Runnable() {
162
                            /*
163
                             * (non-Javadoc)
164
                             *
165
                             * @see java.lang.Runnable#run()
166
                             */
167
                            @Override
168
                            public void run() {
169
                                // close the current context
170
                                CdmStore.close(monitor, false);
171
                            }
172
                        });
173

    
174
                        ICdmApplicationConfiguration applicationController = null;
175

    
176
                        if (!monitor.isCanceled()) {
177
                            CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
178
                                    .CreateSubMonitor(monitor, 3);
179
                            // genrerate new application controller
180
                            applicationController = getApplicationController(cdmSource,subprogressMonitor);
181
                        }
182

    
183

    
184
                        if (!monitor.isCanceled()) {
185
                            CdmStore.setInstance(applicationController, cdmSource);
186
                            monitor.subTask(Messages.CdmStoreConnector_AUTHENTICATING_USER);
187
                            display.syncExec(new Runnable() {
188
                                /*
189
                                 * (non-Javadoc)
190
                                 *
191
                                 * @see java.lang.Runnable#run()
192
                                 */
193
                                @Override
194
                                public void run() {
195

    
196
                                    try {
197
                                        // create new security context
198
                                        CdmStore.getLoginManager().doAuthenticate(loginDialog.getUsername(), loginDialog.getPassword());
199
                                        loginDialog.onComplete();
200
                                        CdmStore.getContextManager().notifyContextStart();
201
                                        getInstance(Rank.class).resetTerms();
202
                                        getInstance(NomenclaturalStatusType.class).resetTerms();
203
                                        Rank.initDefaultTerms();
204
                                        NomenclaturalStatusType.initDefaultTerms();
205
                                    } catch(CdmAuthenticationException cae) {
206
                                        loginDialog.hide(false);
207
                                        loginDialog.setMessage(cae.getMessage());
208
                                    }
209

    
210
                                }
211
                            });
212
                        } else {
213
                            throw new RuntimeException("Login cancelled");
214
                        }
215
                    } finally {
216
                        monitor.done();
217
                    }
218
                }
219
            });
220
        } catch (InvocationTargetException e) {
221
            loginDialog.hide(false);
222
            loginDialog.setMessage(e.getMessage());
223
        } catch (InterruptedException e) {
224
            loginDialog.hide(false);
225
            loginDialog.setMessage(e.getMessage());
226
        }
227
    }
228

    
229
    /**
230
     * Returns a new instance for the given class by using the default constructor.
231
     * The constructor must be declared but can be unaccessible (e.g. private)
232
     * @param termClass
233
     * @return
234
     */
235
    private  <T extends DefinedTermBase> T getInstance(Class<? extends DefinedTermBase> termClass) {
236
        try {
237
            Constructor<T> c = ((Class<T>)termClass).getDeclaredConstructor();
238
            c.setAccessible(true);
239
            T termInstance = c.newInstance();
240
            return termInstance;
241
        } catch (Exception e) {
242
            throw new RuntimeException(e);
243
        }
244
    }
245

    
246

    
247
    private ICdmApplicationConfiguration getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
248
        if(cdmSource instanceof ICdmDataSource) {
249
            return  CdmApplicationController.NewInstance(applicationContextBean,
250
                    (ICdmDataSource)cdmSource,
251
                    dbSchemaValidation,
252
                    false,
253
                    subprogressMonitor);
254
        } else if(cdmSource instanceof ICdmRemoteSource) {
255
            return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
256
                    subprogressMonitor,
257
                    null);
258
        } else {
259
            throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
260
        }
261
    }
262

    
263
    private void authenticate() {
264
        LoginDialog saloginDialog = new LoginDialog(StoreUtil.getShell());
265
        saloginDialog.open();
266
    }
267

    
268
    private void startContext() {
269
        CdmStore.getContextManager().notifyContextStart();
270
    }
271

    
272
    /**
273
     * @return
274
     */
275
    private String getConnectionMessage() {
276
        return cdmSource.getConnectionMessage();
277
    }
278

    
279
    /**
280
     * @return
281
     * @throws SQLException
282
     */
283
    private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
284
        monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_EDITOR_IS_COMPATIBLE);
285
        String dbSchemaVersion;
286

    
287
        String message = null;
288
        try {
289
            dbSchemaVersion = cdmSource.getDbSchemaVersion();
290
            // we assume that empty dbSchemaVersion means an empty database and
291
            // skip version checking
292

    
293
            if(dbSchemaVersion != null) {
294
                int compareVersion = CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
295
                // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
296
                // be updated else the datasource needs to be updated
297
                if(compareVersion > 0) {
298
                    message = Messages.CdmStoreConnector_UPDATE_EDITOR_OR_CHOOSE_COMPATIBLE_DATASOURCE;
299
                } else if (compareVersion < 0) {
300
                    message = Messages.CdmStoreConnector_UPDATE_DATASOUREC_OR_CHOOSE_NEW_DATASOURCE;
301
                }
302
            }
303
            monitor.worked(1);
304
        } catch (CdmSourceException e) {
305
            //
306
        }
307

    
308
        if (message != null) {
309
            // Show an error message
310
            MessagingUtils
311
            .messageDialog(
312
                    Messages.CdmStoreConnector_COMPATIBILITY_CHECK_FAILED,
313
                    this,
314
                    String.format(Messages.CdmStoreConnector_SCHEME_NOT_COMPATIBLE, cdmSource, message),
315
                            null);
316

    
317
            monitor.setCanceled(true);
318
        }
319

    
320
    }
321

    
322
    private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
323
        monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_NON_EMPTY);
324
        boolean isDbEmpty = false;
325
        try {
326
            isDbEmpty = cdmSource.isDbEmpty();
327
        } catch (CdmSourceException e) {
328
            isDbEmpty = true;
329
        }
330
        if(isDbEmpty) {
331
            dbSchemaValidation = DbSchemaValidation.CREATE;
332
        }
333
    }
334

    
335
    private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
336
        if(throwable == null){
337
            return false;
338
        }else if(throwable instanceof CancellationException){
339
            return true;
340
        }else{
341
            return causeIsCancelationExceptionRecursive(throwable.getCause());
342
        }
343
    }
344

    
345
    private void checkDatabaseReachable(IProgressMonitor monitor) {
346
        try {
347
            monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_REACHABLE);
348
            cdmSource.checkConnection();
349
            monitor.worked(1);
350
        } catch (CdmSourceException e) {
351
            MessagingUtils.messageDialog(Messages.CdmStoreConnector_COULD_NOT_CONNECT_TO_CHOSEN_DATASOURCE,
352
                    this, Messages.CdmStoreConnector_REASON + e.getMessage(), e);
353
            monitor.setCanceled(true);
354
        }
355
    }
356

    
357

    
358
}
(3-3/13)