ref #7993: change message size of message part
[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.Constructor;
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.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.event.EventUtility;
38 import eu.etaxonomy.taxeditor.event.WorkbenchEventConstants;
39 import eu.etaxonomy.taxeditor.l10n.Messages;
40 import eu.etaxonomy.taxeditor.model.CdmProgressMonitorAdapter;
41 import eu.etaxonomy.taxeditor.model.MessagingUtils;
42 import eu.etaxonomy.taxeditor.remoting.source.ICdmRemoteSource;
43 import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
44 import eu.etaxonomy.taxeditor.ui.dialog.LoginDialog;
45 import eu.etaxonomy.taxeditor.ui.dialog.RemotingLoginDialog;
46
47
48 /**
49 * @author n.hoffmann
50 * @created Dec 8, 2010
51 * @version 1.0
52 */
53 class CdmStoreConnector extends Job {
54 private final Display display;
55 private final ICdmSource cdmSource;
56 private DbSchemaValidation dbSchemaValidation;
57 private final Resource applicationContextBean;
58
59
60 /**
61 * @param datasource
62 * @param dbSchemaValidation
63 * @param applicationContextBean
64 */
65 public CdmStoreConnector(Display display,
66 ICdmSource cdmSource,
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;
74 }
75
76
77
78 @Override
79 public IStatus run(final IProgressMonitor monitor) {
80
81 monitor.beginTask(getConnectionMessage(), 10);
82
83 // check if database is up and running
84 checkDatabaseReachable(monitor);
85
86 if (!monitor.isCanceled()) {
87 // check if the datasource actually holds data
88 checkIsNonEmptyCdmDatabase(monitor);
89 }
90
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);
96 }
97
98 // we are done with our low level checking and will free resources now
99 cdmSource.closeOpenConnections();
100
101 if (!monitor.isCanceled()) {
102 CdmStore.close(monitor);
103 }
104
105 ICdmRepository applicationController = null;
106
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();
112 try {
113 Thread.currentThread().setPriority(10);
114 applicationController = getApplicationController(cdmSource,subprogressMonitor);
115 MessagingUtils.informationDialog(Messages.CdmStoreConnector_SUCCESS, Messages.CdmStoreConnector_DATA_MODEL_CREATION_SUCCESSFUL);
116 //FIXME E4 migrate or delete because data source view is not used anymore
117 // CdmDataSourceViewPartE4 dataSourceView = (CdmDataSourceViewPartE4) WorkbenchUtility.getE4WrappedPart(AbstractUtility.getView("eu.etaxonomy.taxeditor.view.datasource", false));
118 // if(dataSourceView!=null){
119 // dataSourceView.refresh();
120 // }
121 EventUtility.postEvent(WorkbenchEventConstants.REFRESH_DATASOURCE, true);
122 return Status.OK_STATUS;
123 } catch (Exception e) {
124 if(! causeIsCancelationExceptionRecursive(e)){
125 MessagingUtils.errorDialog(Messages.CdmStoreConnector_COULD_NOT_CREATE_DATAMODEL, CdmStoreConnector.class,
126 String.format(Messages.CdmStoreConnector_ERROR_DURING_DATAMODEL_CREATION, cdmSource.getName()), TaxeditorStorePlugin.PLUGIN_ID, e, true);
127 return Status.CANCEL_STATUS;
128 }
129 } finally {
130 monitor.done();
131 Thread.currentThread().setPriority(oldPriority);
132 }
133 }
134 return Status.CANCEL_STATUS;
135
136 }
137
138 public void start(final RemotingLoginDialog loginDialog) {
139 // hide login dialog and start connection dialog
140 loginDialog.setMessage(null);
141 loginDialog.hide(true);
142
143
144 ProgressMonitorDialog dialog = new ProgressMonitorDialog(StoreUtil.getShell());
145
146 try {
147 dialog.run(true, true, new IRunnableWithProgress() {
148 @Override
149 public void run(final IProgressMonitor monitor) {
150 try {
151 monitor.beginTask(getConnectionMessage(), 7);
152
153 // check if database is up and running
154 checkDatabaseReachable(monitor);
155
156 // check if the datasource actually holds data
157 checkIsNonEmptyCdmDatabase(monitor);
158
159 if (dbSchemaValidation != DbSchemaValidation.CREATE) {
160 // if we do not create the datasource, we want to check if the
161 // datasource is compatible with this editor
162 checkDbSchemaVersionCompatibility(monitor);
163 }
164
165 // we are done with our low level checking and will free resources now
166 cdmSource.closeOpenConnections();
167
168 display.syncExec(new Runnable() {
169 /*
170 * (non-Javadoc)
171 *
172 * @see java.lang.Runnable#run()
173 */
174 @Override
175 public void run() {
176 // close the current context
177 CdmStore.close(monitor, false);
178 }
179 });
180
181 ICdmRepository applicationController = null;
182
183 if (!monitor.isCanceled()) {
184 CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
185 .CreateSubMonitor(monitor, 3);
186 // genrerate new application controller
187 applicationController = getApplicationController(cdmSource,subprogressMonitor);
188 }
189
190
191 if (!monitor.isCanceled()) {
192 CdmStore.setInstance(applicationController, cdmSource);
193 monitor.subTask(Messages.CdmStoreConnector_AUTHENTICATING_USER);
194 display.syncExec(new Runnable() {
195 /*
196 * (non-Javadoc)
197 *
198 * @see java.lang.Runnable#run()
199 */
200 @Override
201 public void run() {
202
203 try {
204 // create new security context
205 CdmStore.getLoginManager().doAuthenticate(loginDialog.getUsername(), loginDialog.getPassword());
206 //loginDialog.onComplete();
207 CdmStore.getContextManager().notifyContextStart();
208 loginDialog.onComplete();
209 getInstance(Rank.class).resetTerms();
210 getInstance(NomenclaturalStatusType.class).resetTerms();
211 Rank.initDefaultTerms();
212 NomenclaturalStatusType.initDefaultTerms();
213 } catch(CdmAuthenticationException cae) {
214 loginDialog.hide(false);
215 loginDialog.setMessage("Your credentials are valid \nbut you are not permitted to use \nthe TaxEditor with the selected data source");
216
217 }
218
219 }
220 });
221 } else {
222 throw new RuntimeException("Login cancelled");
223 }
224 } finally {
225 monitor.done();
226 }
227 }
228 });
229 } catch (InvocationTargetException e) {
230 loginDialog.hide(false);
231 loginDialog.setMessage(e.getMessage());
232 } catch (InterruptedException e) {
233 loginDialog.hide(false);
234 loginDialog.setMessage(e.getMessage());
235 }
236 }
237
238 /**
239 * Returns a new instance for the given class by using the default constructor.
240 * The constructor must be declared but can be unaccessible (e.g. private)
241 * @param termClass
242 * @return
243 */
244 private <T extends DefinedTermBase> T getInstance(Class<? extends DefinedTermBase> termClass) {
245 try {
246 Constructor<T> c = ((Class<T>)termClass).getDeclaredConstructor();
247 c.setAccessible(true);
248 T termInstance = c.newInstance();
249 return termInstance;
250 } catch (Exception e) {
251 throw new RuntimeException(e);
252 }
253 }
254
255
256 private ICdmRepository getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
257 if(cdmSource instanceof ICdmDataSource) {
258 return CdmApplicationController.NewInstance(applicationContextBean,
259 (ICdmDataSource)cdmSource,
260 dbSchemaValidation,
261 false,
262 subprogressMonitor);
263 } else if(cdmSource instanceof ICdmRemoteSource) {
264 return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
265 subprogressMonitor,
266 null);
267 } else {
268 throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
269 }
270 }
271
272 private void authenticate() {
273 LoginDialog saloginDialog = new LoginDialog(StoreUtil.getShell());
274 saloginDialog.open();
275 }
276
277 private void startContext() {
278 CdmStore.getContextManager().notifyContextStart();
279 }
280
281 /**
282 * @return
283 */
284 private String getConnectionMessage() {
285 return cdmSource.getConnectionMessage();
286 }
287
288 /**
289 * @return
290 * @throws SQLException
291 */
292 private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
293 monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_EDITOR_IS_COMPATIBLE);
294 String dbSchemaVersion;
295
296 String message = null;
297 try {
298 dbSchemaVersion = cdmSource.getDbSchemaVersion();
299 // we assume that empty dbSchemaVersion means an empty database and
300 // skip version checking
301
302 if(dbSchemaVersion != null) {
303 int compareVersion = CdmMetaData.compareVersion(dbSchemaVersion, CdmMetaData.getDbSchemaVersion(), 3, null);
304 // if the datasource version is greater than the taxeditor compatible version then the taxeditor needs to
305 // be updated else the datasource needs to be updated
306 if(compareVersion > 0) {
307 message = Messages.CdmStoreConnector_UPDATE_EDITOR_OR_CHOOSE_COMPATIBLE_DATASOURCE;
308 } else if (compareVersion < 0) {
309 message = Messages.CdmStoreConnector_UPDATE_DATASOUREC_OR_CHOOSE_NEW_DATASOURCE;
310 }
311 }
312 monitor.worked(1);
313 } catch (CdmSourceException e) {
314 //
315 }
316
317 if (message != null) {
318 // Show an error message
319 MessagingUtils
320 .messageDialog(
321 Messages.CdmStoreConnector_COMPATIBILITY_CHECK_FAILED,
322 this,
323 String.format(Messages.CdmStoreConnector_SCHEME_NOT_COMPATIBLE, cdmSource, message),
324 null);
325
326 monitor.setCanceled(true);
327 }
328
329 }
330
331 private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
332 monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_NON_EMPTY);
333 boolean isDbEmpty = false;
334 try {
335 isDbEmpty = cdmSource.isDbEmpty();
336 } catch (CdmSourceException e) {
337 isDbEmpty = true;
338 }
339 if(isDbEmpty) {
340 dbSchemaValidation = DbSchemaValidation.CREATE;
341 }
342 }
343
344 private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
345 if(throwable == null){
346 return false;
347 }else if(throwable instanceof CancellationException){
348 return true;
349 }else{
350 return causeIsCancelationExceptionRecursive(throwable.getCause());
351 }
352 }
353
354 private void checkDatabaseReachable(IProgressMonitor monitor) {
355 try {
356 monitor.subTask(Messages.CdmStoreConnector_CHECK_IF_REACHABLE);
357 cdmSource.checkConnection();
358 monitor.worked(1);
359 } catch (CdmSourceException e) {
360 MessagingUtils.messageDialog(Messages.CdmStoreConnector_COULD_NOT_CONNECT_TO_CHOSEN_DATASOURCE,
361 this, Messages.CdmStoreConnector_REASON + e.getMessage(), e);
362 monitor.setCanceled(true);
363 }
364 }
365
366
367 }