Project

General

Profile

Download (13.8 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.util.concurrent.CancellationException;
15

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

    
25
import eu.etaxonomy.cdm.api.application.CdmApplicationController;
26
import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteController;
27
import eu.etaxonomy.cdm.api.application.ICdmRepository;
28
import eu.etaxonomy.cdm.config.CdmSourceException;
29
import eu.etaxonomy.cdm.config.ICdmSource;
30
import eu.etaxonomy.cdm.database.DbSchemaValidation;
31
import eu.etaxonomy.cdm.database.ICdmDataSource;
32
import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
33
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
34
import eu.etaxonomy.cdm.model.name.Rank;
35
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
36
import eu.etaxonomy.taxeditor.event.EventUtility;
37
import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
38
import eu.etaxonomy.taxeditor.l10n.Messages;
39
import eu.etaxonomy.taxeditor.model.AbstractUtility;
40
import eu.etaxonomy.taxeditor.model.CdmProgressMonitorAdapter;
41
import eu.etaxonomy.taxeditor.model.MessagingUtils;
42
import eu.etaxonomy.taxeditor.remoting.source.ICdmRemoteSource;
43
import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
44
import eu.etaxonomy.taxeditor.ui.dialog.LoginDialog;
45
import eu.etaxonomy.taxeditor.ui.dialog.RemotingLoginDialog;
46

    
47
/**
48
 * @author n.hoffmann
49
 * @created Dec 8, 2010
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
    public CdmStoreConnector(Display display,
58
            ICdmSource cdmSource,
59
            DbSchemaValidation dbSchemaValidation,
60
            Resource applicationContextBean) {
61
        super(String.format(Messages.CdmStoreConnector_CREATING_DATAMODEL, cdmSource));
62
        this.display = display;
63
        this.cdmSource = cdmSource;
64
        this.dbSchemaValidation = dbSchemaValidation;
65
        this.applicationContextBean = applicationContextBean;
66
    }
67

    
68
    @Override
69
    public IStatus run(final IProgressMonitor monitor) {
70

    
71
        monitor.beginTask(getConnectionMessage(), 10);
72

    
73
        // check if database is up and running
74
        checkDatabaseReachable(monitor);
75

    
76
        if (!monitor.isCanceled()) {
77
            // check if the datasource actually holds data
78
            checkIsNonEmptyCdmDatabase(monitor);
79
        }
80

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

    
88
        // we are done with our low level checking and will free resources now
89
        cdmSource.closeOpenConnections();
90

    
91
        if (!monitor.isCanceled()) {
92
            CdmStore.close(monitor);
93
        }
94

    
95
        ICdmRepository applicationController = null;
96

    
97
        if (!monitor.isCanceled()) {
98
            CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
99
                    .CreateSubMonitor(monitor, 7);
100
            // This is where we instantiate the application controller
101
            int oldPriority = Thread.currentThread().getPriority();
102
            try {
103
                Thread.currentThread().setPriority(10);
104
                applicationController = getApplicationController(cdmSource,subprogressMonitor);
105
                MessagingUtils.informationDialog(Messages.CdmStoreConnector_SUCCESS, Messages.CdmStoreConnector_DATA_MODEL_CREATION_SUCCESSFUL);
106
                //FIXME E4 migrate or delete because data source view is not used anymore
107
//                CdmDataSourceViewPartE4 dataSourceView = (CdmDataSourceViewPartE4) WorkbenchUtility.getE4WrappedPart(AbstractUtility.getView("eu.etaxonomy.taxeditor.view.datasource", false));
108
//                if(dataSourceView!=null){
109
//                    dataSourceView.refresh();
110
//                }
111
                EventUtility.postEvent(WorkbenchEventConstants.REFRESH_DATASOURCE, true);
112
                return Status.OK_STATUS;
113
            } catch (Exception e) {
114
                if(! causeIsCancelationExceptionRecursive(e)){
115
                    MessagingUtils.errorDialog(Messages.CdmStoreConnector_COULD_NOT_CREATE_DATAMODEL, CdmStoreConnector.class,
116
                    		String.format(Messages.CdmStoreConnector_ERROR_DURING_DATAMODEL_CREATION, cdmSource.getName()), TaxeditorStorePlugin.PLUGIN_ID, e, true);
117
                    return Status.CANCEL_STATUS;
118
                }
119
            } finally {
120
                monitor.done();
121
                Thread.currentThread().setPriority(oldPriority);
122
            }
123
        }
124
        return Status.CANCEL_STATUS;
125
    }
126

    
127
    public void start(final RemotingLoginDialog loginDialog) {
128
        // hide login dialog and start connection dialog
129
        loginDialog.setMessage(null);
130
        loginDialog.hide(true);
131

    
132
        ProgressMonitorDialog dialog = new ProgressMonitorDialog(AbstractUtility.getShell());
133

    
134
        try {
135
            dialog.run(true, true, new IRunnableWithProgress() {
136
                @Override
137
                public void run(final IProgressMonitor monitor) {
138
                    try {
139
                        monitor.beginTask(getConnectionMessage(), 7);
140

    
141
                        // check if database is up and running
142
                        checkDatabaseReachable(monitor);
143

    
144
                        // check if the datasource actually holds data
145
                        checkIsNonEmptyCdmDatabase(monitor);
146

    
147
                        if (dbSchemaValidation != DbSchemaValidation.CREATE) {
148
                            // if we do not create the datasource, we want to check if the
149
                            // datasource is compatible with this editor
150
                            checkDbSchemaVersionCompatibility(monitor);
151
                        }
152

    
153
                        // we are done with our low level checking and will free resources now
154
                        cdmSource.closeOpenConnections();
155

    
156
                        display.syncExec(new Runnable() {
157
                            @Override
158
                            public void run() {
159
                                // close the current context
160
                                CdmStore.close(monitor, false);
161
                            }
162
                        });
163

    
164
                        ICdmRepository applicationController = null;
165

    
166
                        if (!monitor.isCanceled()) {
167
                            CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
168
                                    .CreateSubMonitor(monitor, 3);
169
                            // genrerate new application controller
170
                            applicationController = getApplicationController(cdmSource,subprogressMonitor);
171
                        }
172

    
173
                        if (!monitor.isCanceled()) {
174
                            CdmStore.setInstance(applicationController, cdmSource);
175
                            monitor.subTask(Messages.CdmStoreConnector_AUTHENTICATING_USER);
176
                            display.syncExec(()-> {
177
                                try {
178
                                    // create new security context
179
                                    CdmStore.getLoginManager().doAuthenticate(loginDialog.getUsername(), loginDialog.getPassword());
180
                                    //loginDialog.onComplete();
181
                                    CdmStore.getContextManager().notifyContextStart();
182
                                    loginDialog.onComplete();
183
                                    getInstance(Rank.class).resetTerms();
184
                                    getInstance(NomenclaturalStatusType.class).resetTerms();
185
                                    Rank.initDefaultTerms();
186
                                    NomenclaturalStatusType.initDefaultTerms();
187
                                } catch(CdmAuthenticationException cae) {
188
                                    loginDialog.hide(false);
189
                                    loginDialog.setMessage(Messages.RemotingLoginDialog_MISSING_PERMISSION);
190
                                }
191
                            });
192
                        } else {
193
                            throw new RuntimeException("Login cancelled");
194
                        }
195
                    } finally {
196
                        monitor.done();
197
                    }
198
                }
199
            });
200
        } catch (InvocationTargetException e) {
201
            loginDialog.hide(false);
202
            loginDialog.setMessage(e.getMessage());
203
        } catch (InterruptedException e) {
204
            loginDialog.hide(false);
205
            loginDialog.setMessage(e.getMessage());
206
        }
207
    }
208

    
209
    /**
210
     * Returns a new instance for the given class by using the default constructor.
211
     * The constructor must be declared but can be unaccessible (e.g. private)
212
     * @param termClass
213
     * @return
214
     */
215
    private  <T extends DefinedTermBase> T getInstance(Class<? extends DefinedTermBase> termClass) {
216
        try {
217
            Constructor<T> c = ((Class<T>)termClass).getDeclaredConstructor();
218
            c.setAccessible(true);
219
            T termInstance = c.newInstance();
220
            return termInstance;
221
        } catch (Exception e) {
222
            throw new RuntimeException(e);
223
        }
224
    }
225

    
226
    private ICdmRepository getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
227
        if(cdmSource instanceof ICdmDataSource) {
228
            return  CdmApplicationController.NewInstance(applicationContextBean,
229
                    (ICdmDataSource)cdmSource,
230
                    dbSchemaValidation,
231
                    false,
232
                    subprogressMonitor);
233
        } else if(cdmSource instanceof ICdmRemoteSource) {
234
            return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
235
                    subprogressMonitor,
236
                    null);
237
        } else {
238
            throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
239
        }
240
    }
241

    
242
    private void authenticate() {
243
        LoginDialog saloginDialog = new LoginDialog(StoreUtil.getShell());
244
        saloginDialog.open();
245
    }
246

    
247
    private void startContext() {
248
        CdmStore.getContextManager().notifyContextStart();
249
    }
250

    
251
    private String getConnectionMessage() {
252
        return cdmSource.getConnectionMessage();
253
    }
254

    
255
    private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
256
        monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_EDITOR_IS_COMPATIBLE);
257
        String dbSchemaVersion;
258

    
259
        String message = null;
260
        try {
261
            dbSchemaVersion = cdmSource.getDbSchemaVersion();
262
            // we assume that empty dbSchemaVersion means an empty database and
263
            // skip version checking
264

    
265
            if(dbSchemaVersion != null) {
266
                int compareVersion = CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
267
                // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
268
                // be updated else the datasource needs to be updated
269
                if(compareVersion > 0) {
270
                    message = Messages.CdmStoreConnector_UPDATE_EDITOR_OR_CHOOSE_COMPATIBLE_DATASOURCE;
271
                } else if (compareVersion < 0) {
272
                    message = Messages.CdmStoreConnector_UPDATE_DATASOUREC_OR_CHOOSE_NEW_DATASOURCE;
273
                }
274
            }
275
            monitor.worked(1);
276
        } catch (CdmSourceException e) {
277
            //
278
        }
279

    
280
        if (message != null) {
281
            // Show an error message
282
            MessagingUtils
283
            .messageDialog(
284
                    Messages.CdmStoreConnector_COMPATIBILITY_CHECK_FAILED,
285
                    this,
286
                    String.format(Messages.CdmStoreConnector_SCHEME_NOT_COMPATIBLE, cdmSource, message),
287
                            null);
288

    
289
            monitor.setCanceled(true);
290
        }
291
    }
292

    
293
    private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
294
        monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_NON_EMPTY);
295
        boolean isDbEmpty = false;
296
        try {
297
            isDbEmpty = cdmSource.isDbEmpty();
298
        } catch (CdmSourceException e) {
299
            isDbEmpty = true;
300
        }
301
        if(isDbEmpty) {
302
            dbSchemaValidation = DbSchemaValidation.CREATE;
303
        }
304
    }
305

    
306
    private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
307
        if(throwable == null){
308
            return false;
309
        }else if(throwable instanceof CancellationException){
310
            return true;
311
        }else{
312
            return causeIsCancelationExceptionRecursive(throwable.getCause());
313
        }
314
    }
315

    
316
    private void checkDatabaseReachable(IProgressMonitor monitor) {
317
        try {
318
            monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_REACHABLE);
319
            cdmSource.checkConnection();
320
            monitor.worked(1);
321
        } catch (CdmSourceException e) {
322
            MessagingUtils.messageDialog(Messages.CdmStoreConnector_COULD_NOT_CONNECT_TO_CHOSEN_DATASOURCE,
323
                    this, Messages.CdmStoreConnector_REASON + e.getMessage(), e);
324
            monitor.setCanceled(true);
325
        }
326
    }
327
}
(4-4/13)