4a9d7e1d1be5d0f3ee3b7c5eb234aae8ed19358e
[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.cdm.model.name.Rank;
35 import eu.etaxonomy.taxeditor.model.CdmProgressMonitorAdapter;
36 import eu.etaxonomy.taxeditor.model.MessagingUtils;
37 import eu.etaxonomy.taxeditor.remoting.source.ICdmRemoteSource;
38 import eu.etaxonomy.taxeditor.ui.dialog.LoginDialog;
39 import eu.etaxonomy.taxeditor.ui.dialog.RemotingLoginDialog;
40 import eu.etaxonomy.taxeditor.view.datasource.CdmDataSourceViewPart;
41
42
43 /**
44 * @author n.hoffmann
45 * @created Dec 8, 2010
46 * @version 1.0
47 */
48 class CdmStoreConnector extends Job {
49 private final Display display;
50 private final ICdmSource cdmSource;
51 private DbSchemaValidation dbSchemaValidation;
52 private final Resource applicationContextBean;
53
54
55 /**
56 * @param datasource
57 * @param dbSchemaValidation
58 * @param applicationContextBean
59 */
60 public CdmStoreConnector(Display display,
61 ICdmSource cdmSource,
62 DbSchemaValidation dbSchemaValidation,
63 Resource applicationContextBean) {
64 super("Connecting to datasource: " + cdmSource);
65 this.display = display;
66 this.cdmSource = cdmSource;
67 this.dbSchemaValidation = dbSchemaValidation;
68 this.applicationContextBean = applicationContextBean;
69 }
70
71
72
73 @Override
74 public IStatus run(final IProgressMonitor monitor) {
75
76 monitor.beginTask(getConnectionMessage(), 10);
77
78 // check if database is up and running
79 checkDatabaseReachable(monitor);
80
81 if (!monitor.isCanceled()) {
82 // check if the datasource actually holds data
83 checkIsNonEmptyCdmDatabase(monitor);
84 }
85
86 if (dbSchemaValidation != DbSchemaValidation.CREATE
87 && !monitor.isCanceled()) {
88 // if we do not create the datasource, we want to check if the
89 // datasource is compatible with this editor
90 checkDbSchemaVersionCompatibility(monitor);
91 }
92
93 // we are done with our low level checking and will free resources now
94 cdmSource.closeOpenConnections();
95
96 if (!monitor.isCanceled()) {
97 CdmStore.close(monitor);
98 }
99
100 ICdmApplicationConfiguration applicationController = null;
101
102 if (!monitor.isCanceled()) {
103 CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
104 .CreateSubMonitor(monitor, 7);
105 // This is where we instantiate the application controller
106 int oldPriority = Thread.currentThread().getPriority();
107 try {
108 Thread.currentThread().setPriority(10);
109 applicationController = getApplicationController(cdmSource,subprogressMonitor);
110 } catch (Exception e) {
111 if(! causeIsCancelationExceptionRecursive(e)){
112 return new Status(IStatus.ERROR, "Could not connect to CDM Store", "An error occurred while trying to connect to datasource: " + cdmSource.getName(), e);
113 }
114 } finally {
115 monitor.done();
116 Thread.currentThread().setPriority(oldPriority);
117 }
118 }
119
120
121
122 if (!monitor.isCanceled()) {
123 CdmStore.setInstance(applicationController, cdmSource);
124
125 display.asyncExec(new Runnable() {
126 /*
127 * (non-Javadoc)
128 *
129 * @see java.lang.Runnable#run()
130 */
131 @Override
132 public void run() {
133 authenticate();
134
135 startContext();
136 }
137 });
138
139 MessagingUtils.info("Application context initialized.");
140 return Status.OK_STATUS;
141 } else {
142 // Show datasource view if not shown yet
143 display.asyncExec(new Runnable() {
144 /*
145 * (non-Javadoc)
146 *
147 * @see java.lang.Runnable#run()
148 */
149 @Override
150 public void run() {
151 StoreUtil.showView(CdmDataSourceViewPart.ID);
152 }
153 });
154 return Status.CANCEL_STATUS;
155 }
156
157 }
158
159 public void start(final RemotingLoginDialog loginDialog) {
160 // hide login dialog and start connection dialog
161 loginDialog.setMessage(null);
162 loginDialog.hide(true);
163
164
165 ProgressMonitorDialog dialog = new ProgressMonitorDialog(StoreUtil.getShell());
166
167 try {
168 dialog.run(true, true, new IRunnableWithProgress() {
169 @Override
170 public void run(final IProgressMonitor monitor) {
171 try {
172 monitor.beginTask(getConnectionMessage(), 7);
173
174 // check if database is up and running
175 checkDatabaseReachable(monitor);
176
177 // check if the datasource actually holds data
178 checkIsNonEmptyCdmDatabase(monitor);
179
180 if (dbSchemaValidation != DbSchemaValidation.CREATE) {
181 // if we do not create the datasource, we want to check if the
182 // datasource is compatible with this editor
183 checkDbSchemaVersionCompatibility(monitor);
184 }
185
186 // we are done with our low level checking and will free resources now
187 cdmSource.closeOpenConnections();
188
189 display.syncExec(new Runnable() {
190 /*
191 * (non-Javadoc)
192 *
193 * @see java.lang.Runnable#run()
194 */
195 @Override
196 public void run() {
197 // close the current context
198 CdmStore.close(monitor, false);
199 }
200 });
201
202 ICdmApplicationConfiguration applicationController = null;
203
204 if (!monitor.isCanceled()) {
205 CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
206 .CreateSubMonitor(monitor, 3);
207 // genrerate new application controller
208 applicationController = getApplicationController(cdmSource,subprogressMonitor);
209 }
210
211
212 if (!monitor.isCanceled()) {
213 CdmStore.setInstance(applicationController, cdmSource);
214 monitor.subTask("Authenticating user");
215 display.syncExec(new Runnable() {
216 /*
217 * (non-Javadoc)
218 *
219 * @see java.lang.Runnable#run()
220 */
221 @Override
222 public void run() {
223
224 try {
225 // create new security context
226 CdmStore.getLoginManager().doAuthenticate(loginDialog.getUsername(), loginDialog.getPassword());
227 loginDialog.onComplete();
228 CdmStore.getContextManager().notifyContextStart();
229 Rank.initDefaultTerms();
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 }