Merge branch 'develop' into remoting-4.0
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / store / CdmStoreConnector.java
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.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.ICdmApplicationConfiguration;
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.metadata.CdmMetaData;
34 import eu.etaxonomy.taxeditor.model.CdmProgressMonitorAdapter;
35 import eu.etaxonomy.taxeditor.model.MessagingUtils;
36 import eu.etaxonomy.taxeditor.remoting.source.ICdmRemoteSource;
37 import eu.etaxonomy.taxeditor.ui.dialog.LoginDialog;
38 import eu.etaxonomy.taxeditor.ui.dialog.RemotingLoginDialog;
39 import eu.etaxonomy.taxeditor.view.datasource.CdmDataSourceViewPart;
40
41
42 /**
43 * @author n.hoffmann
44 * @created Dec 8, 2010
45 * @version 1.0
46 */
47 class CdmStoreConnector extends Job {
48 private final Display display;
49 private final ICdmSource cdmSource;
50 private DbSchemaValidation dbSchemaValidation;
51 private final Resource applicationContextBean;
52
53
54 /**
55 * @param datasource
56 * @param dbSchemaValidation
57 * @param applicationContextBean
58 */
59 public CdmStoreConnector(Display display,
60 ICdmSource cdmSource,
61 DbSchemaValidation dbSchemaValidation,
62 Resource applicationContextBean) {
63 super("Connecting to datasource: " + cdmSource);
64 this.display = display;
65 this.cdmSource = cdmSource;
66 this.dbSchemaValidation = dbSchemaValidation;
67 this.applicationContextBean = applicationContextBean;
68 }
69
70
71
72 @Override
73 public IStatus run(final IProgressMonitor monitor) {
74
75 monitor.beginTask(getConnectionMessage(), 10);
76
77 // check if database is up and running
78 checkDatabaseReachable(monitor);
79
80 if (!monitor.isCanceled()) {
81 // check if the datasource actually holds data
82 checkIsNonEmptyCdmDatabase(monitor);
83 }
84
85 if (dbSchemaValidation != DbSchemaValidation.CREATE
86 && !monitor.isCanceled()) {
87 // if we do not create the datasource, we want to check if the
88 // datasource is compatible with this editor
89 checkDbSchemaVersionCompatibility(monitor);
90 }
91
92 // we are done with our low level checking and will free resources now
93 cdmSource.closeOpenConnections();
94
95 if (!monitor.isCanceled()) {
96 CdmStore.close(monitor);
97 }
98
99 ICdmApplicationConfiguration applicationController = null;
100
101 if (!monitor.isCanceled()) {
102 CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
103 .CreateSubMonitor(monitor, 7);
104 // This is where we instantiate the application controller
105 int oldPriority = Thread.currentThread().getPriority();
106 try {
107 Thread.currentThread().setPriority(10);
108 applicationController = getApplicationController(cdmSource,subprogressMonitor);
109 } catch (Exception e) {
110 if(! causeIsCancelationExceptionRecursive(e)){
111 return new Status(IStatus.ERROR, "Could not connect to CDM Store", "An error occurred while trying to connect to datasource: " + cdmSource.getName(), e);
112 }
113 } finally {
114 monitor.done();
115 Thread.currentThread().setPriority(oldPriority);
116 }
117 }
118
119
120
121 if (!monitor.isCanceled()) {
122 CdmStore.setInstance(applicationController, cdmSource);
123
124 display.asyncExec(new Runnable() {
125 /*
126 * (non-Javadoc)
127 *
128 * @see java.lang.Runnable#run()
129 */
130 @Override
131 public void run() {
132 authenticate();
133
134 startContext();
135 }
136 });
137
138 MessagingUtils.info("Application context initialized.");
139 return Status.OK_STATUS;
140 } else {
141 // Show datasource view if not shown yet
142 display.asyncExec(new Runnable() {
143 /*
144 * (non-Javadoc)
145 *
146 * @see java.lang.Runnable#run()
147 */
148 @Override
149 public void run() {
150 StoreUtil.showView(CdmDataSourceViewPart.ID);
151 }
152 });
153 return Status.CANCEL_STATUS;
154 }
155
156 }
157
158 public void start(final RemotingLoginDialog loginDialog) {
159 // hide login dialog and start connection dialog
160 loginDialog.setMessage(null);
161 loginDialog.hide(true);
162
163
164 ProgressMonitorDialog dialog = new ProgressMonitorDialog(StoreUtil.getShell());
165
166 try {
167 dialog.run(true, true, new IRunnableWithProgress() {
168 @Override
169 public void run(final IProgressMonitor monitor) {
170 try {
171 monitor.beginTask(getConnectionMessage(), 7);
172
173 // check if database is up and running
174 checkDatabaseReachable(monitor);
175
176 // check if the datasource actually holds data
177 checkIsNonEmptyCdmDatabase(monitor);
178
179 if (dbSchemaValidation != DbSchemaValidation.CREATE) {
180 // if we do not create the datasource, we want to check if the
181 // datasource is compatible with this editor
182 checkDbSchemaVersionCompatibility(monitor);
183 }
184
185 // we are done with our low level checking and will free resources now
186 cdmSource.closeOpenConnections();
187
188 display.syncExec(new Runnable() {
189 /*
190 * (non-Javadoc)
191 *
192 * @see java.lang.Runnable#run()
193 */
194 @Override
195 public void run() {
196 // close the current context
197 CdmStore.close(monitor, false);
198 }
199 });
200
201 ICdmApplicationConfiguration applicationController = null;
202
203 if (!monitor.isCanceled()) {
204 CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
205 .CreateSubMonitor(monitor, 3);
206 // genrerate new application controller
207 applicationController = getApplicationController(cdmSource,subprogressMonitor);
208 }
209
210
211 if (!monitor.isCanceled()) {
212 CdmStore.setInstance(applicationController, cdmSource);
213 monitor.subTask("Authenticating user and starting editor context...");
214 display.syncExec(new Runnable() {
215 /*
216 * (non-Javadoc)
217 *
218 * @see java.lang.Runnable#run()
219 */
220 @Override
221 public void run() {
222
223 try {
224 // create new security context
225 CdmStore.getLoginManager().doAuthenticate(loginDialog.getUsername(), loginDialog.getPassword());
226 loginDialog.onComplete();
227 // start editor context
228 CdmStore.getContextManager().notifyContextStartWithoutDialog(monitor);
229
230 } catch(CdmAuthenticationException cae) {
231 loginDialog.hide(false);
232 loginDialog.setMessage(cae.getMessage());
233 }
234
235 }
236 });
237 } else {
238 throw new RuntimeException("Login cancelled");
239 }
240 } finally {
241 monitor.done();
242 }
243 }
244 });
245 } catch (InvocationTargetException e) {
246 loginDialog.hide(false);
247 loginDialog.setMessage(e.getMessage());
248 } catch (InterruptedException e) {
249 loginDialog.hide(false);
250 loginDialog.setMessage(e.getMessage());
251 }
252 }
253
254
255 private ICdmApplicationConfiguration getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
256 if(cdmSource instanceof ICdmDataSource) {
257 return CdmApplicationController.NewInstance(applicationContextBean,
258 (ICdmDataSource)cdmSource,
259 dbSchemaValidation,
260 false,
261 subprogressMonitor);
262 } else if(cdmSource instanceof ICdmRemoteSource) {
263 return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
264 subprogressMonitor,
265 null);
266 } else {
267 throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
268 }
269 }
270
271 private void authenticate() {
272 LoginDialog saloginDialog = new LoginDialog(StoreUtil.getShell());
273 saloginDialog.open();
274 }
275
276 private void startContext() {
277 CdmStore.getContextManager().notifyContextStart();
278 }
279
280 /**
281 * @return
282 */
283 private String getConnectionMessage() {
284 return cdmSource.getConnectionMessage();
285 }
286
287 /**
288 * @return
289 * @throws SQLException
290 */
291 private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
292 monitor.subTask("Checking if datasource is compatible with this editor.");
293 String dbSchemaVersion;
294
295 String message = null;
296 try {
297 dbSchemaVersion = cdmSource.getDbSchemaVersion();
298 // we assume that empty dbSchemaVersion means an empty database and
299 // skip version checking
300
301 if(dbSchemaVersion != null) {
302 int compareVersion = CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
303 // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
304 // be updated else the datasource needs to be updated
305 if(compareVersion > 0) {
306 message = "Please update the Taxonomic Editor (Help->Check for Updates) or choose a compatible datasource";
307 } else if (compareVersion < 0) {
308 message = "Please update the chosen datasource or choose a new data source to connect to in the Datasource View.";
309 }
310 }
311 monitor.worked(1);
312 } catch (CdmSourceException e) {
313 //
314 }
315
316 if (message != null) {
317 // Show an error message
318 MessagingUtils
319 .messageDialog(
320 "Datasource Compatibility Check failed",
321 this,
322 "The database schema for the chosen "
323 + "datasource '"
324 + cdmSource
325 + "' \n is not compatible for this version of the taxonomic editor. \n\n"
326 + message,
327 null);
328
329 monitor.setCanceled(true);
330 }
331
332 }
333
334 private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
335 monitor.subTask("Checking if datasource is a non empty CDM database.");
336 boolean isDbEmpty = false;
337 try {
338 isDbEmpty = cdmSource.isDbEmpty();
339 } catch (CdmSourceException e) {
340 isDbEmpty = true;
341 }
342 if(isDbEmpty) {
343 dbSchemaValidation = DbSchemaValidation.CREATE;
344 }
345 }
346
347 private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
348 if(throwable == null){
349 return false;
350 }else if(throwable instanceof CancellationException){
351 return true;
352 }else{
353 return causeIsCancelationExceptionRecursive(throwable.getCause());
354 }
355 }
356
357 private void checkDatabaseReachable(IProgressMonitor monitor) {
358 try {
359 monitor.subTask("Checking if datasource is reachable.");
360 cdmSource.checkConnection();
361 monitor.worked(1);
362 } catch (CdmSourceException e) {
363 MessagingUtils.messageDialog("Could not connect to chosen datasource",
364 this, "Reason: " + e.getMessage(), e);
365 monitor.setCanceled(true);
366 }
367 }
368
369
370 }