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");
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 CdmStore.getContextManager().notifyContextStart();
228 } catch(CdmAuthenticationException cae) {
229 loginDialog.hide(false);
230 loginDialog.setMessage(cae.getMessage());
231 }
232
233 }
234 });
235 } else {
236 throw new RuntimeException("Login cancelled");
237 }
238 } finally {
239 monitor.done();
240 }
241 }
242 });
243 } catch (InvocationTargetException e) {
244 loginDialog.hide(false);
245 loginDialog.setMessage(e.getMessage());
246 } catch (InterruptedException e) {
247 loginDialog.hide(false);
248 loginDialog.setMessage(e.getMessage());
249 }
250 }
251
252
253 private ICdmApplicationConfiguration getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
254 if(cdmSource instanceof ICdmDataSource) {
255 return CdmApplicationController.NewInstance(applicationContextBean,
256 (ICdmDataSource)cdmSource,
257 dbSchemaValidation,
258 false,
259 subprogressMonitor);
260 } else if(cdmSource instanceof ICdmRemoteSource) {
261 return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
262 subprogressMonitor,
263 null);
264 } else {
265 throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
266 }
267 }
268
269 private void authenticate() {
270 LoginDialog saloginDialog = new LoginDialog(StoreUtil.getShell());
271 saloginDialog.open();
272 }
273
274 private void startContext() {
275 CdmStore.getContextManager().notifyContextStart();
276 }
277
278 /**
279 * @return
280 */
281 private String getConnectionMessage() {
282 return cdmSource.getConnectionMessage();
283 }
284
285 /**
286 * @return
287 * @throws SQLException
288 */
289 private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
290 monitor.subTask("Checking if datasource is compatible with this editor.");
291 String dbSchemaVersion;
292
293 String message = null;
294 try {
295 dbSchemaVersion = cdmSource.getDbSchemaVersion();
296 // we assume that empty dbSchemaVersion means an empty database and
297 // skip version checking
298
299 if(dbSchemaVersion != null) {
300 int compareVersion = CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
301 // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
302 // be updated else the datasource needs to be updated
303 if(compareVersion > 0) {
304 message = "Please update the Taxonomic Editor (Help->Check for Updates) or choose a compatible datasource";
305 } else if (compareVersion < 0) {
306 message = "Please update the chosen datasource or choose a new data source to connect to in the Datasource View.";
307 }
308 }
309 monitor.worked(1);
310 } catch (CdmSourceException e) {
311 //
312 }
313
314 if (message != null) {
315 // Show an error message
316 MessagingUtils
317 .messageDialog(
318 "Datasource Compatibility Check failed",
319 this,
320 "The database schema for the chosen "
321 + "datasource '"
322 + cdmSource
323 + "' \n is not compatible for this version of the taxonomic editor. \n\n"
324 + message,
325 null);
326
327 monitor.setCanceled(true);
328 }
329
330 }
331
332 private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
333 monitor.subTask("Checking if datasource is a non empty CDM database.");
334 boolean isDbEmpty = false;
335 try {
336 isDbEmpty = cdmSource.isDbEmpty();
337 } catch (CdmSourceException e) {
338 isDbEmpty = true;
339 }
340 if(isDbEmpty) {
341 dbSchemaValidation = DbSchemaValidation.CREATE;
342 }
343 }
344
345 private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
346 if(throwable == null){
347 return false;
348 }else if(throwable instanceof CancellationException){
349 return true;
350 }else{
351 return causeIsCancelationExceptionRecursive(throwable.getCause());
352 }
353 }
354
355 private void checkDatabaseReachable(IProgressMonitor monitor) {
356 try {
357 monitor.subTask("Checking if datasource is reachable.");
358 cdmSource.checkConnection();
359 monitor.worked(1);
360 } catch (CdmSourceException e) {
361 MessagingUtils.messageDialog("Could not connect to chosen datasource",
362 this, "Reason: " + e.getMessage(), e);
363 monitor.setCanceled(true);
364 }
365 }
366
367
368 }