3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
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.
11 package eu
.etaxonomy
.taxeditor
.store
;
13 import java
.lang
.reflect
.Constructor
;
14 import java
.lang
.reflect
.InvocationTargetException
;
15 import java
.sql
.SQLException
;
16 import java
.util
.concurrent
.CancellationException
;
18 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
19 import org
.eclipse
.core
.runtime
.IStatus
;
20 import org
.eclipse
.core
.runtime
.Status
;
21 import org
.eclipse
.core
.runtime
.jobs
.Job
;
22 import org
.eclipse
.jface
.dialogs
.ProgressMonitorDialog
;
23 import org
.eclipse
.jface
.operation
.IRunnableWithProgress
;
24 import org
.eclipse
.swt
.widgets
.Display
;
25 import org
.springframework
.core
.io
.Resource
;
27 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationController
;
28 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationRemoteController
;
29 import eu
.etaxonomy
.cdm
.api
.application
.ICdmApplicationConfiguration
;
30 import eu
.etaxonomy
.cdm
.config
.CdmSourceException
;
31 import eu
.etaxonomy
.cdm
.config
.ICdmSource
;
32 import eu
.etaxonomy
.cdm
.database
.DbSchemaValidation
;
33 import eu
.etaxonomy
.cdm
.database
.ICdmDataSource
;
34 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
35 import eu
.etaxonomy
.cdm
.model
.metadata
.CdmMetaData
;
36 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
37 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
38 import eu
.etaxonomy
.taxeditor
.model
.CdmProgressMonitorAdapter
;
39 import eu
.etaxonomy
.taxeditor
.model
.MessagingUtils
;
40 import eu
.etaxonomy
.taxeditor
.remoting
.source
.ICdmRemoteSource
;
41 import eu
.etaxonomy
.taxeditor
.store
.internal
.TaxeditorStorePlugin
;
42 import eu
.etaxonomy
.taxeditor
.ui
.dialog
.LoginDialog
;
43 import eu
.etaxonomy
.taxeditor
.ui
.dialog
.RemotingLoginDialog
;
48 * @created Dec 8, 2010
51 class CdmStoreConnector
extends Job
{
52 private final Display display
;
53 private final ICdmSource cdmSource
;
54 private DbSchemaValidation dbSchemaValidation
;
55 private final Resource applicationContextBean
;
60 * @param dbSchemaValidation
61 * @param applicationContextBean
63 public CdmStoreConnector(Display display
,
65 DbSchemaValidation dbSchemaValidation
,
66 Resource applicationContextBean
) {
67 super("Connecting to datasource: " + cdmSource
);
68 this.display
= display
;
69 this.cdmSource
= cdmSource
;
70 this.dbSchemaValidation
= dbSchemaValidation
;
71 this.applicationContextBean
= applicationContextBean
;
77 public IStatus
run(final IProgressMonitor monitor
) {
79 monitor
.beginTask(getConnectionMessage(), 10);
81 // check if database is up and running
82 checkDatabaseReachable(monitor
);
84 if (!monitor
.isCanceled()) {
85 // check if the datasource actually holds data
86 checkIsNonEmptyCdmDatabase(monitor
);
89 if (dbSchemaValidation
!= DbSchemaValidation
.CREATE
90 && !monitor
.isCanceled()) {
91 // if we do not create the datasource, we want to check if the
92 // datasource is compatible with this editor
93 checkDbSchemaVersionCompatibility(monitor
);
96 // we are done with our low level checking and will free resources now
97 cdmSource
.closeOpenConnections();
99 if (!monitor
.isCanceled()) {
100 CdmStore
.close(monitor
);
103 ICdmApplicationConfiguration applicationController
= null;
105 if (!monitor
.isCanceled()) {
106 CdmProgressMonitorAdapter subprogressMonitor
= CdmProgressMonitorAdapter
107 .CreateSubMonitor(monitor
, 7);
108 // This is where we instantiate the application controller
109 int oldPriority
= Thread
.currentThread().getPriority();
111 Thread
.currentThread().setPriority(10);
112 applicationController
= getApplicationController(cdmSource
,subprogressMonitor
);
113 return Status
.OK_STATUS
;
114 } catch (Exception e
) {
115 if(! causeIsCancelationExceptionRecursive(e
)){
116 MessagingUtils
.errorDialog("Could not create data model", CdmStoreConnector
.class, "An error occurred while trying to create "
117 + "data model for data source: " + cdmSource
.getName()+"\n Please clear the data base and retry. ", TaxeditorStorePlugin
.PLUGIN_ID
, e
, true);
118 return Status
.CANCEL_STATUS
;
122 Thread
.currentThread().setPriority(oldPriority
);
126 return Status
.CANCEL_STATUS
;
130 public void start(final RemotingLoginDialog loginDialog
) {
131 // hide login dialog and start connection dialog
132 loginDialog
.setMessage(null);
133 loginDialog
.hide(true);
136 ProgressMonitorDialog dialog
= new ProgressMonitorDialog(StoreUtil
.getShell());
139 dialog
.run(true, true, new IRunnableWithProgress() {
141 public void run(final IProgressMonitor monitor
) {
143 monitor
.beginTask(getConnectionMessage(), 7);
145 // check if database is up and running
146 checkDatabaseReachable(monitor
);
148 // check if the datasource actually holds data
149 checkIsNonEmptyCdmDatabase(monitor
);
151 if (dbSchemaValidation
!= DbSchemaValidation
.CREATE
) {
152 // if we do not create the datasource, we want to check if the
153 // datasource is compatible with this editor
154 checkDbSchemaVersionCompatibility(monitor
);
157 // we are done with our low level checking and will free resources now
158 cdmSource
.closeOpenConnections();
160 display
.syncExec(new Runnable() {
164 * @see java.lang.Runnable#run()
168 // close the current context
169 CdmStore
.close(monitor
, false);
173 ICdmApplicationConfiguration applicationController
= null;
175 if (!monitor
.isCanceled()) {
176 CdmProgressMonitorAdapter subprogressMonitor
= CdmProgressMonitorAdapter
177 .CreateSubMonitor(monitor
, 3);
178 // genrerate new application controller
179 applicationController
= getApplicationController(cdmSource
,subprogressMonitor
);
183 if (!monitor
.isCanceled()) {
184 CdmStore
.setInstance(applicationController
, cdmSource
);
185 monitor
.subTask("Authenticating user");
186 display
.syncExec(new Runnable() {
190 * @see java.lang.Runnable#run()
196 // create new security context
197 CdmStore
.getLoginManager().doAuthenticate(loginDialog
.getUsername(), loginDialog
.getPassword());
198 loginDialog
.onComplete();
199 CdmStore
.getContextManager().notifyContextStart();
200 getInstance(Rank
.class).resetTerms();
201 getInstance(NomenclaturalStatusType
.class).resetTerms();
202 Rank
.initDefaultTerms();
203 NomenclaturalStatusType
.initDefaultTerms();
204 } catch(CdmAuthenticationException cae
) {
205 loginDialog
.hide(false);
206 loginDialog
.setMessage(cae
.getMessage());
212 throw new RuntimeException("Login cancelled");
219 } catch (InvocationTargetException e
) {
220 loginDialog
.hide(false);
221 loginDialog
.setMessage(e
.getMessage());
222 } catch (InterruptedException e
) {
223 loginDialog
.hide(false);
224 loginDialog
.setMessage(e
.getMessage());
229 * Returns a new instance for the given class by using the default constructor.
230 * The constructor must be declared but can be unaccessible (e.g. private)
234 private <T
extends DefinedTermBase
> T
getInstance(Class
<?
extends DefinedTermBase
> termClass
) {
236 Constructor
<T
> c
= ((Class
<T
>)termClass
).getDeclaredConstructor();
237 c
.setAccessible(true);
238 T termInstance
= c
.newInstance();
240 } catch (Exception e
) {
241 throw new RuntimeException(e
);
246 private ICdmApplicationConfiguration
getApplicationController(ICdmSource cdmSource
, CdmProgressMonitorAdapter subprogressMonitor
) {
247 if(cdmSource
instanceof ICdmDataSource
) {
248 return CdmApplicationController
.NewInstance(applicationContextBean
,
249 (ICdmDataSource
)cdmSource
,
253 } else if(cdmSource
instanceof ICdmRemoteSource
) {
254 return CdmApplicationRemoteController
.NewInstance((ICdmRemoteSource
)cdmSource
,
258 throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource
.getName());
262 private void authenticate() {
263 LoginDialog saloginDialog
= new LoginDialog(StoreUtil
.getShell());
264 saloginDialog
.open();
267 private void startContext() {
268 CdmStore
.getContextManager().notifyContextStart();
274 private String
getConnectionMessage() {
275 return cdmSource
.getConnectionMessage();
280 * @throws SQLException
282 private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor
) {
283 monitor
.subTask("Checking if datasource is compatible with this editor.");
284 String dbSchemaVersion
;
286 String message
= null;
288 dbSchemaVersion
= cdmSource
.getDbSchemaVersion();
289 // we assume that empty dbSchemaVersion means an empty database and
290 // skip version checking
292 if(dbSchemaVersion
!= null) {
293 int compareVersion
= CdmMetaData
.compareVersion(dbSchemaVersion
, CdmMetaData
.getDbSchemaVersion(), 3, null);
294 // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
295 // be updated else the datasource needs to be updated
296 if(compareVersion
> 0) {
297 message
= "Please update the Taxonomic Editor (Help->Check for Updates) or choose a compatible datasource";
298 } else if (compareVersion
< 0) {
299 message
= "Please update the chosen datasource or choose a new data source to connect to in the Datasource View.";
303 } catch (CdmSourceException e
) {
307 if (message
!= null) {
308 // Show an error message
311 "Datasource Compatibility Check failed",
313 "The database schema for the chosen "
316 + "' \n is not compatible for this version of the taxonomic editor. \n\n"
320 monitor
.setCanceled(true);
325 private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor
) {
326 monitor
.subTask("Checking if datasource is a non empty CDM database.");
327 boolean isDbEmpty
= false;
329 isDbEmpty
= cdmSource
.isDbEmpty();
330 } catch (CdmSourceException e
) {
334 dbSchemaValidation
= DbSchemaValidation
.CREATE
;
338 private boolean causeIsCancelationExceptionRecursive(Throwable throwable
){
339 if(throwable
== null){
341 }else if(throwable
instanceof CancellationException
){
344 return causeIsCancelationExceptionRecursive(throwable
.getCause());
348 private void checkDatabaseReachable(IProgressMonitor monitor
) {
350 monitor
.subTask("Checking if datasource is reachable.");
351 cdmSource
.checkConnection();
353 } catch (CdmSourceException e
) {
354 MessagingUtils
.messageDialog("Could not connect to chosen datasource",
355 this, "Reason: " + e
.getMessage(), e
);
356 monitor
.setCanceled(true);