f70cded90edf0dac7d86cd13563e8beb880ddd2a
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / store / CdmStoreConnector.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
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.
8 */
9
10 package eu.etaxonomy.taxeditor.store;
11
12 import java.lang.reflect.InvocationTargetException;
13 import java.util.concurrent.CancellationException;
14
15 import org.eclipse.core.runtime.IProgressMonitor;
16 import org.eclipse.core.runtime.IStatus;
17 import org.eclipse.core.runtime.Status;
18 import org.eclipse.core.runtime.jobs.Job;
19 import org.eclipse.jface.dialogs.ProgressMonitorDialog;
20 import org.eclipse.jface.operation.IRunnableWithProgress;
21 import org.eclipse.swt.widgets.Display;
22 import org.springframework.core.io.Resource;
23
24 import eu.etaxonomy.cdm.api.application.CdmApplicationController;
25 import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteController;
26 import eu.etaxonomy.cdm.api.application.ICdmRepository;
27 import eu.etaxonomy.cdm.config.CdmSourceException;
28 import eu.etaxonomy.cdm.config.ICdmSource;
29 import eu.etaxonomy.cdm.database.DbSchemaValidation;
30 import eu.etaxonomy.cdm.database.ICdmDataSource;
31 import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
32 import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
33 import eu.etaxonomy.cdm.model.name.Rank;
34 import eu.etaxonomy.cdm.model.term.init.TermLoader;
35 import eu.etaxonomy.taxeditor.event.EventUtility;
36 import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
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.RemotingLoginDialog;
44
45 /**
46 * @author n.hoffmann
47 * @created Dec 8, 2010
48 */
49 class CdmStoreConnector extends Job {
50 private final Display display;
51 private final ICdmSource cdmSource;
52 private DbSchemaValidation dbSchemaValidation;
53 private final Resource applicationContextBean;
54
55 public CdmStoreConnector(Display display,
56 ICdmSource cdmSource,
57 DbSchemaValidation dbSchemaValidation,
58 Resource applicationContextBean) {
59 super(String.format(Messages.CdmStoreConnector_CREATING_DATAMODEL, cdmSource));
60 this.display = display;
61 this.cdmSource = cdmSource;
62 this.dbSchemaValidation = dbSchemaValidation;
63 this.applicationContextBean = applicationContextBean;
64 }
65
66 @Override
67 public IStatus run(final IProgressMonitor monitor) {
68
69 monitor.beginTask(getConnectionMessage(), 10);
70
71 // check if database is up and running
72 checkDatabaseReachable(monitor);
73
74 if (!monitor.isCanceled()) {
75 // check if the datasource actually holds data
76 checkIsNonEmptyCdmDatabase(monitor);
77 }
78
79 if (dbSchemaValidation != DbSchemaValidation.CREATE
80 && !monitor.isCanceled()) {
81 // if we do not create the datasource, we want to check if the
82 // datasource is compatible with this editor
83 checkDbSchemaVersionCompatibility(monitor);
84 }
85
86 // we are done with our low level checking and will free resources now
87 cdmSource.closeOpenConnections();
88
89 if (!monitor.isCanceled()) {
90 CdmStore.close(monitor);
91 }
92
93 ICdmRepository applicationController = null;
94
95 if (!monitor.isCanceled()) {
96 CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
97 .CreateSubMonitor(monitor, 7);
98 // This is where we instantiate the application controller
99 int oldPriority = Thread.currentThread().getPriority();
100 try {
101 Thread.currentThread().setPriority(10);
102 applicationController = getApplicationController(cdmSource,subprogressMonitor);
103 MessagingUtils.informationDialog(Messages.CdmStoreConnector_SUCCESS, Messages.CdmStoreConnector_DATA_MODEL_CREATION_SUCCESSFUL);
104 //FIXME E4 migrate or delete because data source view is not used anymore
105 // CdmDataSourceViewPartE4 dataSourceView = (CdmDataSourceViewPartE4) WorkbenchUtility.getE4WrappedPart(AbstractUtility.getView("eu.etaxonomy.taxeditor.view.datasource", false));
106 // if(dataSourceView!=null){
107 // dataSourceView.refresh();
108 // }
109 EventUtility.postEvent(WorkbenchEventConstants.REFRESH_DATASOURCE, true);
110 return Status.OK_STATUS;
111 } catch (Exception e) {
112 if(! causeIsCancelationExceptionRecursive(e)){
113 MessagingUtils.errorDialog(Messages.CdmStoreConnector_COULD_NOT_CREATE_DATAMODEL, CdmStoreConnector.class,
114 String.format(Messages.CdmStoreConnector_ERROR_DURING_DATAMODEL_CREATION, cdmSource.getName()), TaxeditorStorePlugin.PLUGIN_ID, e, true);
115 return Status.CANCEL_STATUS;
116 }
117 } finally {
118 monitor.done();
119 Thread.currentThread().setPriority(oldPriority);
120 }
121 }
122 return Status.CANCEL_STATUS;
123 }
124
125 public void start(final RemotingLoginDialog loginDialog) {
126 // hide login dialog and start connection dialog
127 loginDialog.setMessage(null);
128 loginDialog.hide(true);
129
130 ProgressMonitorDialog dialog = new ProgressMonitorDialog(AbstractUtility.getShell());
131
132 try {
133 dialog.run(true, true, new IRunnableWithProgress() {
134 @Override
135 public void run(final IProgressMonitor monitor) {
136 try {
137 monitor.beginTask(getConnectionMessage(), 7);
138
139 // check if database is up and running
140 checkDatabaseReachable(monitor);
141
142 // check if the datasource actually holds data
143 checkIsNonEmptyCdmDatabase(monitor);
144
145 if (dbSchemaValidation != DbSchemaValidation.CREATE) {
146 // if we do not create the datasource, we want to check if the
147 // datasource is compatible with this editor
148 checkDbSchemaVersionCompatibility(monitor);
149 }
150
151 // we are done with our low level checking and will free resources now
152 cdmSource.closeOpenConnections();
153
154 display.syncExec(new Runnable() {
155 @Override
156 public void run() {
157 // close the current context
158 CdmStore.close(monitor, false);
159 }
160 });
161
162 ICdmRepository applicationController = null;
163
164 if (!monitor.isCanceled()) {
165 CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
166 .CreateSubMonitor(monitor, 3);
167 // genrerate new application controller
168 applicationController = getApplicationController(cdmSource,subprogressMonitor);
169 }
170
171 if (!monitor.isCanceled()) {
172 CdmStore.setInstance(applicationController, cdmSource);
173 monitor.subTask(Messages.CdmStoreConnector_AUTHENTICATING_USER);
174 display.syncExec(()-> {
175 try {
176 // create new security context
177 CdmStore.getLoginManager().doAuthenticate(loginDialog.getUsername(), loginDialog.getPassword());
178 //loginDialog.onComplete();
179 CdmStore.getContextManager().notifyContextStart();
180 loginDialog.onComplete();
181 new TermLoader().unloadAllTerms();
182 Rank.initDefaultTerms();
183 NomenclaturalStatusType.initDefaultTerms();
184 } catch(CdmAuthenticationException cae) {
185 loginDialog.hide(false);
186 loginDialog.setMessage(LoginManager.INCORRECT_CREDENTIALS_MESSAGE);
187 }
188 });
189 } else {
190 throw new RuntimeException("Login cancelled");
191 }
192 } finally {
193 monitor.done();
194 }
195 }
196 });
197 } catch (InvocationTargetException e) {
198 loginDialog.hide(false);
199 loginDialog.setMessage(e.getMessage());
200 } catch (InterruptedException e) {
201 loginDialog.hide(false);
202 loginDialog.setMessage(e.getMessage());
203 }
204 }
205
206 private ICdmRepository getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
207 if(cdmSource instanceof ICdmDataSource) {
208 return CdmApplicationController.NewInstance(applicationContextBean,
209 (ICdmDataSource)cdmSource,
210 dbSchemaValidation,
211 false,
212 subprogressMonitor);
213 } else if(cdmSource instanceof ICdmRemoteSource) {
214 return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
215 subprogressMonitor,
216 null);
217 } else {
218 throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
219 }
220 }
221
222 private String getConnectionMessage() {
223 return cdmSource.getConnectionMessage();
224 }
225
226 private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
227 monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_EDITOR_IS_COMPATIBLE);
228 String dbSchemaVersion;
229
230 String message = null;
231 try {
232 dbSchemaVersion = cdmSource.getDbSchemaVersion();
233 // we assume that empty dbSchemaVersion means an empty database and
234 // skip version checking
235
236 if(dbSchemaVersion != null) {
237 int compareVersion = CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
238 // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
239 // be updated else the datasource needs to be updated
240 if(compareVersion > 0) {
241 message = Messages.CdmStoreConnector_UPDATE_EDITOR_OR_CHOOSE_COMPATIBLE_DATASOURCE;
242 } else if (compareVersion < 0) {
243 message = Messages.CdmStoreConnector_UPDATE_DATASOUREC_OR_CHOOSE_NEW_DATASOURCE;
244 }
245 }
246 monitor.worked(1);
247 } catch (CdmSourceException e) {
248 //
249 }
250
251 if (message != null) {
252 // Show an error message
253 MessagingUtils
254 .messageDialog(
255 Messages.CdmStoreConnector_COMPATIBILITY_CHECK_FAILED,
256 this,
257 String.format(Messages.CdmStoreConnector_SCHEME_NOT_COMPATIBLE, cdmSource, message),
258 null);
259
260 monitor.setCanceled(true);
261 }
262 }
263
264 private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
265 monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_NON_EMPTY);
266 boolean isDbEmpty = false;
267 try {
268 isDbEmpty = cdmSource.isDbEmpty();
269 } catch (CdmSourceException e) {
270 isDbEmpty = true;
271 }
272 if(isDbEmpty) {
273 dbSchemaValidation = DbSchemaValidation.CREATE;
274 }
275 }
276
277 private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
278 if(throwable == null){
279 return false;
280 }else if(throwable instanceof CancellationException){
281 return true;
282 }else{
283 return causeIsCancelationExceptionRecursive(throwable.getCause());
284 }
285 }
286
287 private void checkDatabaseReachable(IProgressMonitor monitor) {
288 try {
289 monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_REACHABLE);
290 cdmSource.checkConnection();
291 monitor.worked(1);
292 } catch (CdmSourceException e) {
293 MessagingUtils.messageDialog(Messages.CdmStoreConnector_COULD_NOT_CONNECT_TO_CHOSEN_DATASOURCE,
294 this, Messages.CdmStoreConnector_REASON + e.getMessage(), e);
295 monitor.setCanceled(true);
296 }
297 }
298 }