2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.taxeditor
.store
;
12 import java
.lang
.reflect
.Constructor
;
13 import java
.lang
.reflect
.InvocationTargetException
;
14 import java
.sql
.SQLException
;
15 import java
.util
.concurrent
.CancellationException
;
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
;
26 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationController
;
27 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationRemoteController
;
28 import eu
.etaxonomy
.cdm
.api
.application
.ICdmRepository
;
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
.common
.DefinedTermBase
;
34 import eu
.etaxonomy
.cdm
.model
.metadata
.CdmMetaData
;
35 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
36 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
37 import eu
.etaxonomy
.taxeditor
.l10n
.Messages
;
38 import eu
.etaxonomy
.taxeditor
.model
.AbstractUtility
;
39 import eu
.etaxonomy
.taxeditor
.model
.CdmProgressMonitorAdapter
;
40 import eu
.etaxonomy
.taxeditor
.model
.MessagingUtils
;
41 import eu
.etaxonomy
.taxeditor
.remoting
.source
.ICdmRemoteSource
;
42 import eu
.etaxonomy
.taxeditor
.store
.internal
.TaxeditorStorePlugin
;
43 import eu
.etaxonomy
.taxeditor
.ui
.dialog
.LoginDialog
;
44 import eu
.etaxonomy
.taxeditor
.ui
.dialog
.RemotingLoginDialog
;
45 import eu
.etaxonomy
.taxeditor
.view
.datasource
.CdmDataSourceViewPart
;
50 * @created Dec 8, 2010
53 class CdmStoreConnector
extends Job
{
54 private final Display display
;
55 private final ICdmSource cdmSource
;
56 private DbSchemaValidation dbSchemaValidation
;
57 private final Resource applicationContextBean
;
62 * @param dbSchemaValidation
63 * @param applicationContextBean
65 public CdmStoreConnector(Display display
,
67 DbSchemaValidation dbSchemaValidation
,
68 Resource applicationContextBean
) {
69 super(String
.format(Messages
.CdmStoreConnector_CREATING_DATAMODEL
, cdmSource
));
70 this.display
= display
;
71 this.cdmSource
= cdmSource
;
72 this.dbSchemaValidation
= dbSchemaValidation
;
73 this.applicationContextBean
= applicationContextBean
;
79 public IStatus
run(final IProgressMonitor monitor
) {
81 monitor
.beginTask(getConnectionMessage(), 10);
83 // check if database is up and running
84 checkDatabaseReachable(monitor
);
86 if (!monitor
.isCanceled()) {
87 // check if the datasource actually holds data
88 checkIsNonEmptyCdmDatabase(monitor
);
91 if (dbSchemaValidation
!= DbSchemaValidation
.CREATE
92 && !monitor
.isCanceled()) {
93 // if we do not create the datasource, we want to check if the
94 // datasource is compatible with this editor
95 checkDbSchemaVersionCompatibility(monitor
);
98 // we are done with our low level checking and will free resources now
99 cdmSource
.closeOpenConnections();
101 if (!monitor
.isCanceled()) {
102 CdmStore
.close(monitor
);
105 ICdmRepository applicationController
= null;
107 if (!monitor
.isCanceled()) {
108 CdmProgressMonitorAdapter subprogressMonitor
= CdmProgressMonitorAdapter
109 .CreateSubMonitor(monitor
, 7);
110 // This is where we instantiate the application controller
111 int oldPriority
= Thread
.currentThread().getPriority();
113 Thread
.currentThread().setPriority(10);
114 applicationController
= getApplicationController(cdmSource
,subprogressMonitor
);
115 MessagingUtils
.informationDialog(Messages
.CdmStoreConnector_SUCCESS
, Messages
.CdmStoreConnector_DATA_MODEL_CREATION_SUCCESSFUL
);
116 CdmDataSourceViewPart dataSourceView
= (CdmDataSourceViewPart
) AbstractUtility
.getView("eu.etaxonomy.taxeditor.view.datasource", false);
117 if(dataSourceView
!=null){
118 dataSourceView
.refresh();
120 return Status
.OK_STATUS
;
121 } catch (Exception e
) {
122 if(! causeIsCancelationExceptionRecursive(e
)){
123 MessagingUtils
.errorDialog(Messages
.CdmStoreConnector_COULD_NOT_CREATE_DATAMODEL
, CdmStoreConnector
.class,
124 String
.format(Messages
.CdmStoreConnector_ERROR_DURING_DATAMODEL_CREATION
, cdmSource
.getName()), TaxeditorStorePlugin
.PLUGIN_ID
, e
, true);
125 return Status
.CANCEL_STATUS
;
129 Thread
.currentThread().setPriority(oldPriority
);
132 return Status
.CANCEL_STATUS
;
136 public void start(final RemotingLoginDialog loginDialog
) {
137 // hide login dialog and start connection dialog
138 loginDialog
.setMessage(null);
139 loginDialog
.hide(true);
142 ProgressMonitorDialog dialog
= new ProgressMonitorDialog(StoreUtil
.getShell());
145 dialog
.run(true, true, new IRunnableWithProgress() {
147 public void run(final IProgressMonitor monitor
) {
149 monitor
.beginTask(getConnectionMessage(), 7);
151 // check if database is up and running
152 checkDatabaseReachable(monitor
);
154 // check if the datasource actually holds data
155 checkIsNonEmptyCdmDatabase(monitor
);
157 if (dbSchemaValidation
!= DbSchemaValidation
.CREATE
) {
158 // if we do not create the datasource, we want to check if the
159 // datasource is compatible with this editor
160 checkDbSchemaVersionCompatibility(monitor
);
163 // we are done with our low level checking and will free resources now
164 cdmSource
.closeOpenConnections();
166 display
.syncExec(new Runnable() {
170 * @see java.lang.Runnable#run()
174 // close the current context
175 CdmStore
.close(monitor
, false);
179 ICdmRepository applicationController
= null;
181 if (!monitor
.isCanceled()) {
182 CdmProgressMonitorAdapter subprogressMonitor
= CdmProgressMonitorAdapter
183 .CreateSubMonitor(monitor
, 3);
184 // genrerate new application controller
185 applicationController
= getApplicationController(cdmSource
,subprogressMonitor
);
189 if (!monitor
.isCanceled()) {
190 CdmStore
.setInstance(applicationController
, cdmSource
);
191 monitor
.subTask(Messages
.CdmStoreConnector_AUTHENTICATING_USER
);
192 display
.syncExec(new Runnable() {
196 * @see java.lang.Runnable#run()
202 // create new security context
203 CdmStore
.getLoginManager().doAuthenticate(loginDialog
.getUsername(), loginDialog
.getPassword());
204 loginDialog
.onComplete();
205 CdmStore
.getContextManager().notifyContextStart();
206 getInstance(Rank
.class).resetTerms();
207 getInstance(NomenclaturalStatusType
.class).resetTerms();
208 Rank
.initDefaultTerms();
209 NomenclaturalStatusType
.initDefaultTerms();
210 } catch(CdmAuthenticationException cae
) {
211 loginDialog
.hide(false);
212 loginDialog
.setMessage(cae
.getMessage());
218 throw new RuntimeException("Login cancelled");
225 } catch (InvocationTargetException e
) {
226 loginDialog
.hide(false);
227 loginDialog
.setMessage(e
.getMessage());
228 } catch (InterruptedException e
) {
229 loginDialog
.hide(false);
230 loginDialog
.setMessage(e
.getMessage());
235 * Returns a new instance for the given class by using the default constructor.
236 * The constructor must be declared but can be unaccessible (e.g. private)
240 private <T
extends DefinedTermBase
> T
getInstance(Class
<?
extends DefinedTermBase
> termClass
) {
242 Constructor
<T
> c
= ((Class
<T
>)termClass
).getDeclaredConstructor();
243 c
.setAccessible(true);
244 T termInstance
= c
.newInstance();
246 } catch (Exception e
) {
247 throw new RuntimeException(e
);
252 private ICdmRepository
getApplicationController(ICdmSource cdmSource
, CdmProgressMonitorAdapter subprogressMonitor
) {
253 if(cdmSource
instanceof ICdmDataSource
) {
254 return CdmApplicationController
.NewInstance(applicationContextBean
,
255 (ICdmDataSource
)cdmSource
,
259 } else if(cdmSource
instanceof ICdmRemoteSource
) {
260 return CdmApplicationRemoteController
.NewInstance((ICdmRemoteSource
)cdmSource
,
264 throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource
.getName());
268 private void authenticate() {
269 LoginDialog saloginDialog
= new LoginDialog(StoreUtil
.getShell());
270 saloginDialog
.open();
273 private void startContext() {
274 CdmStore
.getContextManager().notifyContextStart();
280 private String
getConnectionMessage() {
281 return cdmSource
.getConnectionMessage();
286 * @throws SQLException
288 private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor
) {
289 monitor
.subTask(Messages
.CdmStoreConnector_CHECK_IF_EDITOR_IS_COMPATIBLE
);
290 String dbSchemaVersion
;
292 String message
= null;
294 dbSchemaVersion
= cdmSource
.getDbSchemaVersion();
295 // we assume that empty dbSchemaVersion means an empty database and
296 // skip version checking
298 if(dbSchemaVersion
!= null) {
299 int compareVersion
= CdmMetaData
.compareVersion(dbSchemaVersion
, CdmMetaData
.getDbSchemaVersion(), 3, null);
300 // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
301 // be updated else the datasource needs to be updated
302 if(compareVersion
> 0) {
303 message
= Messages
.CdmStoreConnector_UPDATE_EDITOR_OR_CHOOSE_COMPATIBLE_DATASOURCE
;
304 } else if (compareVersion
< 0) {
305 message
= Messages
.CdmStoreConnector_UPDATE_DATASOUREC_OR_CHOOSE_NEW_DATASOURCE
;
309 } catch (CdmSourceException e
) {
313 if (message
!= null) {
314 // Show an error message
317 Messages
.CdmStoreConnector_COMPATIBILITY_CHECK_FAILED
,
319 String
.format(Messages
.CdmStoreConnector_SCHEME_NOT_COMPATIBLE
, cdmSource
, message
),
322 monitor
.setCanceled(true);
327 private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor
) {
328 monitor
.subTask(Messages
.CdmStoreConnector_CHECK_IF_NON_EMPTY
);
329 boolean isDbEmpty
= false;
331 isDbEmpty
= cdmSource
.isDbEmpty();
332 } catch (CdmSourceException e
) {
336 dbSchemaValidation
= DbSchemaValidation
.CREATE
;
340 private boolean causeIsCancelationExceptionRecursive(Throwable throwable
){
341 if(throwable
== null){
343 }else if(throwable
instanceof CancellationException
){
346 return causeIsCancelationExceptionRecursive(throwable
.getCause());
350 private void checkDatabaseReachable(IProgressMonitor monitor
) {
352 monitor
.subTask(Messages
.CdmStoreConnector_CHECK_IF_REACHABLE
);
353 cdmSource
.checkConnection();
355 } catch (CdmSourceException e
) {
356 MessagingUtils
.messageDialog(Messages
.CdmStoreConnector_COULD_NOT_CONNECT_TO_CHOSEN_DATASOURCE
,
357 this, Messages
.CdmStoreConnector_REASON
+ e
.getMessage(), e
);
358 monitor
.setCanceled(true);