Project

General

Profile

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

    
10
package eu.etaxonomy.taxeditor.store;
11

    
12
import java.lang.reflect.Constructor;
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.ICdmRepository;
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.common.DefinedTermBase;
34
import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
35
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
36
import eu.etaxonomy.cdm.model.name.Rank;
37
import eu.etaxonomy.taxeditor.l10n.Messages;
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.store.internal.TaxeditorStorePlugin;
42
import eu.etaxonomy.taxeditor.ui.dialog.LoginDialog;
43
import eu.etaxonomy.taxeditor.ui.dialog.RemotingLoginDialog;
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(String.format(Messages.CdmStoreConnector_CREATING_DATAMODEL, 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
        ICdmRepository 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
                MessagingUtils.informationDialog(Messages.CdmStoreConnector_SUCCESS, Messages.CdmStoreConnector_DATA_MODEL_CREATION_SUCCESSFUL);
114
                //FIXME E4 migrate or delete because data source view is not used anymore
115
//                CdmDataSourceViewPartE4 dataSourceView = (CdmDataSourceViewPartE4) WorkbenchUtility.getE4WrappedPart(AbstractUtility.getView("eu.etaxonomy.taxeditor.view.datasource", false));
116
//                if(dataSourceView!=null){
117
//                    dataSourceView.refresh();
118
//                }
119
                return Status.OK_STATUS;
120
            } catch (Exception e) {
121
                if(! causeIsCancelationExceptionRecursive(e)){
122
                    MessagingUtils.errorDialog(Messages.CdmStoreConnector_COULD_NOT_CREATE_DATAMODEL, CdmStoreConnector.class,
123
                    		String.format(Messages.CdmStoreConnector_ERROR_DURING_DATAMODEL_CREATION, cdmSource.getName()), TaxeditorStorePlugin.PLUGIN_ID, e, true);
124
                    return Status.CANCEL_STATUS;
125
                }
126
            } finally {
127
                monitor.done();
128
                Thread.currentThread().setPriority(oldPriority);
129
            }
130
        }
131
        return Status.CANCEL_STATUS;
132

    
133
    }
134

    
135
    public void start(final RemotingLoginDialog loginDialog) {
136
        // hide login dialog and start connection dialog
137
        loginDialog.setMessage(null);
138
        loginDialog.hide(true);
139

    
140

    
141
        ProgressMonitorDialog dialog = new ProgressMonitorDialog(StoreUtil.getShell());
142

    
143
        try {
144
            dialog.run(true, true, new IRunnableWithProgress() {
145
                @Override
146
                public void run(final IProgressMonitor monitor) {
147
                    try {
148
                        monitor.beginTask(getConnectionMessage(), 7);
149

    
150
                        // check if database is up and running
151
                        checkDatabaseReachable(monitor);
152

    
153
                        // check if the datasource actually holds data
154
                        checkIsNonEmptyCdmDatabase(monitor);
155

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

    
162
                        // we are done with our low level checking and will free resources now
163
                        cdmSource.closeOpenConnections();
164

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

    
178
                        ICdmRepository applicationController = null;
179

    
180
                        if (!monitor.isCanceled()) {
181
                            CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
182
                                    .CreateSubMonitor(monitor, 3);
183
                            // genrerate new application controller
184
                            applicationController = getApplicationController(cdmSource,subprogressMonitor);
185
                        }
186

    
187

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

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

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

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

    
250

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

    
267
    private void authenticate() {
268
        LoginDialog saloginDialog = new LoginDialog(StoreUtil.getShell());
269
        saloginDialog.open();
270
    }
271

    
272
    private void startContext() {
273
        CdmStore.getContextManager().notifyContextStart();
274
    }
275

    
276
    /**
277
     * @return
278
     */
279
    private String getConnectionMessage() {
280
        return cdmSource.getConnectionMessage();
281
    }
282

    
283
    /**
284
     * @return
285
     * @throws SQLException
286
     */
287
    private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
288
        monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_EDITOR_IS_COMPATIBLE);
289
        String dbSchemaVersion;
290

    
291
        String message = null;
292
        try {
293
            dbSchemaVersion = cdmSource.getDbSchemaVersion();
294
            // we assume that empty dbSchemaVersion means an empty database and
295
            // skip version checking
296

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

    
312
        if (message != null) {
313
            // Show an error message
314
            MessagingUtils
315
            .messageDialog(
316
                    Messages.CdmStoreConnector_COMPATIBILITY_CHECK_FAILED,
317
                    this,
318
                    String.format(Messages.CdmStoreConnector_SCHEME_NOT_COMPATIBLE, cdmSource, message),
319
                            null);
320

    
321
            monitor.setCanceled(true);
322
        }
323

    
324
    }
325

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

    
339
    private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
340
        if(throwable == null){
341
            return false;
342
        }else if(throwable instanceof CancellationException){
343
            return true;
344
        }else{
345
            return causeIsCancelationExceptionRecursive(throwable.getCause());
346
        }
347
    }
348

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

    
361

    
362
}
(3-3/13)