Merge branch 'release/5.18.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.local / src / main / java / eu / etaxonomy / taxeditor / local / server / CdmStoreConnectorLocal.java
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.local.server;
11
12 import java.lang.reflect.InvocationTargetException;
13 import java.util.concurrent.CancellationException;
14
15 import org.eclipse.core.runtime.IProgressMonitor;
16 import org.eclipse.core.runtime.IStatus;
17 import org.eclipse.core.runtime.Status;
18 import org.eclipse.core.runtime.jobs.Job;
19 import org.eclipse.jface.dialogs.ProgressMonitorDialog;
20 import org.eclipse.jface.operation.IRunnableWithProgress;
21 import org.eclipse.swt.widgets.Display;
22 import org.springframework.core.io.Resource;
23
24 import eu.etaxonomy.cdm.api.application.CdmApplicationController;
25 import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteController;
26 import eu.etaxonomy.cdm.api.application.ICdmRepository;
27 import eu.etaxonomy.cdm.config.CdmSourceException;
28 import eu.etaxonomy.cdm.config.ICdmSource;
29 import eu.etaxonomy.cdm.database.DbSchemaValidation;
30 import eu.etaxonomy.cdm.database.ICdmDataSource;
31 import eu.etaxonomy.cdm.model.common.Language;
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.init.TermLoader;
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.CdmAuthenticationException;
44 import eu.etaxonomy.taxeditor.store.CdmStore;
45 import eu.etaxonomy.taxeditor.store.LoginManager;
46 import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
47
48
49 /**
50 * @author n.hoffmann
51 * @created Dec 8, 2010
52 */
53 public class CdmStoreConnectorLocal extends Job {
54 private final Display display;
55 private final ICdmSource cdmSource;
56 private DbSchemaValidation dbSchemaValidation;
57 private final Resource applicationContextBean;
58
59 public CdmStoreConnectorLocal(Display display,
60 ICdmSource cdmSource,
61 DbSchemaValidation dbSchemaValidation,
62 Resource applicationContextBean) {
63 super(String.format(Messages.CdmStoreConnector_CREATING_DATAMODEL, cdmSource));
64 this.display = display;
65 this.cdmSource = cdmSource;
66 this.dbSchemaValidation = dbSchemaValidation;
67 this.applicationContextBean = applicationContextBean;
68 }
69
70 @Override
71 public IStatus run(final IProgressMonitor monitor) {
72
73 monitor.beginTask(getConnectionMessage(), 10);
74
75 // check if database is up and running
76 checkDatabaseReachable(monitor);
77
78 if (!monitor.isCanceled()) {
79 // check if the datasource actually holds data
80 checkIsNonEmptyCdmDatabase(monitor);
81 }
82
83 if (dbSchemaValidation != DbSchemaValidation.CREATE
84 && !monitor.isCanceled()) {
85 // if we do not create the datasource, we want to check if the
86 // datasource is compatible with this editor
87 checkDbSchemaVersionCompatibility(monitor);
88 }
89
90 // we are done with our low level checking and will free resources now
91 cdmSource.closeOpenConnections();
92
93 if (!monitor.isCanceled()) {
94 CdmStore.close(monitor);
95 }
96
97 ICdmRepository applicationController = null;
98
99 if (!monitor.isCanceled()) {
100 CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
101 .CreateSubMonitor(monitor, 7);
102 // This is where we instantiate the application controller
103 int oldPriority = Thread.currentThread().getPriority();
104 try {
105 Thread.currentThread().setPriority(10);
106 applicationController = getApplicationController(cdmSource,subprogressMonitor);
107 MessagingUtils.informationDialog(Messages.CdmStoreConnector_SUCCESS, Messages.CdmStoreConnector_DATA_MODEL_CREATION_SUCCESSFUL);
108 //FIXME E4 migrate or delete because data source view is not used anymore
109 // CdmDataSourceViewPartE4 dataSourceView = (CdmDataSourceViewPartE4) WorkbenchUtility.getE4WrappedPart(AbstractUtility.getView("eu.etaxonomy.taxeditor.view.datasource", false));
110 // if(dataSourceView!=null){
111 // dataSourceView.refresh();
112 // }
113 EventUtility.postEvent(WorkbenchEventConstants.REFRESH_DATASOURCE, true);
114 return Status.OK_STATUS;
115 } catch (Exception e) {
116 if(! causeIsCancelationExceptionRecursive(e)){
117 MessagingUtils.errorDialog(Messages.CdmStoreConnector_COULD_NOT_CREATE_DATAMODEL, CdmStoreConnectorLocal.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 return Status.CANCEL_STATUS;
127 }
128
129 public void start(final RemotingLoginDialogLocal loginDialog) {
130 // hide login dialog and start connection dialog
131 loginDialog.setMessage(null);
132 loginDialog.hide(true);
133
134 ProgressMonitorDialog dialog = new ProgressMonitorDialog(AbstractUtility.getShell());
135
136 try {
137 dialog.run(true, true, new IRunnableWithProgress() {
138 @Override
139 public void run(final IProgressMonitor monitor) {
140 try {
141 monitor.beginTask(getConnectionMessage(), 7);
142
143 // check if database is up and running
144 checkDatabaseReachable(monitor);
145
146 // check if the datasource actually holds data
147 checkIsNonEmptyCdmDatabase(monitor);
148
149 if (dbSchemaValidation != DbSchemaValidation.CREATE) {
150 // if we do not create the datasource, we want to check if the
151 // datasource is compatible with this editor
152 checkDbSchemaVersionCompatibility(monitor);
153 }
154
155 // we are done with our low level checking and will free resources now
156 cdmSource.closeOpenConnections();
157
158 display.syncExec(new Runnable() {
159 @Override
160 public void run() {
161 // close the current context
162 CdmStore.close(monitor, false);
163 }
164 });
165
166 ICdmRepository applicationController = null;
167
168 if (!monitor.isCanceled()) {
169 CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
170 .CreateSubMonitor(monitor, 3);
171 // genrerate new application controller
172 applicationController = getApplicationController(cdmSource,subprogressMonitor);
173 }
174
175 if (!monitor.isCanceled()) {
176 CdmStoreLocal.setInstance(applicationController, cdmSource);
177 CdmStoreLocal.getTermManager().reset();
178 monitor.subTask(Messages.CdmStoreConnector_AUTHENTICATING_USER);
179 display.syncExec(()-> {
180 try {
181 // create new security context
182 CdmStore.getLoginManager().doAuthenticate(loginDialog.getUsername(), loginDialog.getPassword());
183 //loginDialog.onComplete();
184 CdmStore.getContextManager().notifyContextStart();
185 loginDialog.onComplete();
186 //TODO AM: is this necessary to be done on display thread?
187 new TermLoader().unloadAllTerms();
188 Rank.initDefaultTerms();
189 NomenclaturalStatusType.initDefaultTerms();
190 Language.getDefaultLanguage();
191 } catch(CdmAuthenticationException cae) {
192 loginDialog.hide(false);
193 loginDialog.setMessage(LoginManager.INCORRECT_CREDENTIALS_MESSAGE);
194 }
195 });
196 } else {
197 throw new RuntimeException("Login cancelled");
198 }
199 } finally {
200 monitor.done();
201 }
202 }
203 });
204 } catch (InvocationTargetException e) {
205 loginDialog.hide(false);
206 loginDialog.setMessage(e.getMessage());
207 } catch (InterruptedException e) {
208 loginDialog.hide(false);
209 loginDialog.setMessage(e.getMessage());
210 }
211 }
212
213 private ICdmRepository getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
214 if(cdmSource instanceof ICdmDataSource) {
215 return CdmApplicationController.NewInstance(applicationContextBean,
216 (ICdmDataSource)cdmSource,
217 dbSchemaValidation,
218 false,
219 subprogressMonitor);
220 } else if(cdmSource instanceof ICdmRemoteSource) {
221 return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
222 subprogressMonitor,
223 null);
224 } else {
225 throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
226 }
227 }
228
229 private String getConnectionMessage() {
230 return cdmSource.getConnectionMessage();
231 }
232
233 private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
234 monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_EDITOR_IS_COMPATIBLE);
235 String dbSchemaVersion;
236
237 String message = null;
238 try {
239 dbSchemaVersion = cdmSource.getDbSchemaVersion();
240 // we assume that empty dbSchemaVersion means an empty database and
241 // skip version checking
242
243 if(dbSchemaVersion != null) {
244 int compareVersion = CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
245 // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
246 // be updated else the datasource needs to be updated
247 if(compareVersion > 0) {
248 message = Messages.CdmStoreConnector_UPDATE_EDITOR_OR_CHOOSE_COMPATIBLE_DATASOURCE;
249 } else if (compareVersion < 0) {
250 message = Messages.CdmStoreConnector_UPDATE_DATASOUREC_OR_CHOOSE_NEW_DATASOURCE;
251 }
252 }
253 monitor.worked(1);
254 } catch (CdmSourceException e) {
255 //
256 }
257
258 if (message != null) {
259 // Show an error message
260 MessagingUtils
261 .messageDialog(
262 Messages.CdmStoreConnector_COMPATIBILITY_CHECK_FAILED,
263 this,
264 String.format(Messages.CdmStoreConnector_SCHEME_NOT_COMPATIBLE, cdmSource, message),
265 null);
266
267 monitor.setCanceled(true);
268 }
269 }
270
271 private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
272 monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_NON_EMPTY);
273 boolean isDbEmpty = false;
274 try {
275 isDbEmpty = cdmSource.isDbEmpty();
276 } catch (CdmSourceException e) {
277 isDbEmpty = true;
278 }
279 if(isDbEmpty) {
280 dbSchemaValidation = DbSchemaValidation.CREATE;
281 }
282 }
283
284 private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
285 if(throwable == null){
286 return false;
287 }else if(throwable instanceof CancellationException){
288 return true;
289 }else{
290 return causeIsCancelationExceptionRecursive(throwable.getCause());
291 }
292 }
293
294 private void checkDatabaseReachable(IProgressMonitor monitor) {
295 try {
296 monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_REACHABLE);
297 cdmSource.checkConnection();
298 monitor.worked(1);
299 } catch (CdmSourceException e) {
300 MessagingUtils.messageDialog(Messages.CdmStoreConnector_COULD_NOT_CONNECT_TO_CHOSEN_DATASOURCE,
301 this, Messages.CdmStoreConnector_REASON + e.getMessage(), e);
302 monitor.setCanceled(true);
303 }
304 }
305 }