Moved all logging and dialog functionality to the new class MessagingUtils.
[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.sql.SQLException;
14 import java.util.concurrent.CancellationException;
15
16 import org.eclipse.core.runtime.IProgressMonitor;
17 import org.eclipse.core.runtime.IStatus;
18 import org.eclipse.core.runtime.Status;
19 import org.eclipse.core.runtime.jobs.Job;
20 import org.eclipse.swt.widgets.Display;
21 import org.hibernate.collection.internal.AbstractPersistentCollection;
22 import org.hibernate.proxy.AbstractLazyInitializer;
23 import org.springframework.core.io.Resource;
24
25 import eu.etaxonomy.cdm.api.application.CdmApplicationController;
26 import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteController;
27 import eu.etaxonomy.cdm.api.application.ICdmApplicationConfiguration;
28 import eu.etaxonomy.cdm.config.ICdmSource;
29 import eu.etaxonomy.cdm.remote.ICdmRemoteSource;
30 import eu.etaxonomy.cdm.config.CdmSourceException;
31 import eu.etaxonomy.cdm.database.DatabaseTypeEnum;
32 import eu.etaxonomy.cdm.database.DbSchemaValidation;
33 import eu.etaxonomy.cdm.database.ICdmDataSource;
34 import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
35 import eu.etaxonomy.cdm.model.metadata.CdmMetaData.MetaDataPropertyName;
36 import eu.etaxonomy.taxeditor.model.CdmProgressMonitorAdapter;
37 import eu.etaxonomy.taxeditor.model.MessagingUtils;
38 import eu.etaxonomy.taxeditor.ui.dialog.LoginDialog;
39 import eu.etaxonomy.taxeditor.view.datasource.CdmDataSourceViewPart;
40
41 /**
42 * @author n.hoffmann
43 * @created Dec 8, 2010
44 * @version 1.0
45 */
46 class CdmStoreConnector extends Job {
47 private final Display display;
48 private final ICdmSource cdmSource;
49 private DbSchemaValidation dbSchemaValidation;
50 private final Resource applicationContextBean;
51
52 /**
53 * @param datasource
54 * @param dbSchemaValidation
55 * @param applicationContextBean
56 */
57 public CdmStoreConnector(Display display, ICdmSource cdmSource,
58 DbSchemaValidation dbSchemaValidation,
59 Resource applicationContextBean) {
60 super("Connecting to datasource: " + cdmSource);
61 this.display = display;
62 this.cdmSource = cdmSource;
63 this.dbSchemaValidation = dbSchemaValidation;
64 this.applicationContextBean = applicationContextBean;
65 }
66
67 @Override
68 public IStatus run(final IProgressMonitor monitor) {
69
70 monitor.beginTask(getConnectionMessage(), 10);
71
72 // check if database is up and running
73 checkDatabaseReachable(monitor);
74
75 if (!monitor.isCanceled()) {
76 // check if the datasource actually holds data
77 checkIsNonEmptyCdmDatabase(monitor);
78 }
79
80 if (dbSchemaValidation != DbSchemaValidation.CREATE
81 && !monitor.isCanceled()) {
82 // if we do not create the datasource, we want to check if the
83 // datasource is compatible with this editor
84 checkDbSchemaVersionCompatibility(monitor);
85 }
86
87 // we are done with our low level checking and will free resources now
88 cdmSource.closeOpenConnections();
89
90 if (!monitor.isCanceled()) {
91 CdmStore.close(monitor);
92 }
93
94 ICdmApplicationConfiguration applicationController = null;
95
96 if (!monitor.isCanceled()) {
97 CdmProgressMonitorAdapter subprogressMonitor = CdmProgressMonitorAdapter
98 .CreateSubMonitor(monitor, 7);
99 // This is where we instantiate the application controller
100 try {
101
102 applicationController = getApplicationController(cdmSource,subprogressMonitor);
103
104 } catch (Exception e) {
105 if(! causeIsCancelationExceptionRecursive(e)){
106 return new Status(IStatus.ERROR, "Could not connect to CDM Store", "An error occurred while trying to connect to datasource: " + cdmSource.getName(), e);
107 }
108 } finally {
109 monitor.done();
110 }
111 }
112
113
114
115 if (!monitor.isCanceled()) {
116 CdmStore.setInstance(applicationController, cdmSource);
117
118 display.asyncExec(new Runnable() {
119 /*
120 * (non-Javadoc)
121 *
122 * @see java.lang.Runnable#run()
123 */
124 @Override
125 public void run() {
126 authenticate();
127
128 startContext();
129 }
130 });
131
132 MessagingUtils.info("Application context initialized.");
133 return Status.OK_STATUS;
134 } else {
135 // Show datasource view if not shown yet
136 display.asyncExec(new Runnable() {
137 /*
138 * (non-Javadoc)
139 *
140 * @see java.lang.Runnable#run()
141 */
142 @Override
143 public void run() {
144 StoreUtil.showView(CdmDataSourceViewPart.ID);
145 }
146 });
147 return Status.CANCEL_STATUS;
148 }
149
150 }
151
152 private ICdmApplicationConfiguration getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
153 if(cdmSource instanceof ICdmDataSource) {
154 return CdmApplicationController.NewInstance(applicationContextBean,
155 (ICdmDataSource)cdmSource,
156 dbSchemaValidation,
157 false,
158 subprogressMonitor);
159 } else if(cdmSource instanceof ICdmRemoteSource) {
160 return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
161 false,
162 subprogressMonitor,
163 null);
164 } else {
165 throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
166 }
167 }
168 private void authenticate() {
169 LoginDialog loginDialog = new LoginDialog(StoreUtil.getShell());
170 loginDialog.open();
171 }
172
173 private void startContext() {
174 CdmStore.getContextManager().notifyContextStart();
175 }
176
177 /**
178 * @return
179 */
180 private String getConnectionMessage() {
181 return cdmSource.getConnectionMessage();
182 }
183
184 /**
185 * @return
186 * @throws SQLException
187 */
188 private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
189 monitor.subTask("Checking if datasource is compatible with this editor.");
190 String dbSchemaVersion;
191 boolean result = false;
192 try {
193 dbSchemaVersion = cdmSource.getDbSchemaVersion();
194 // we assume that empty dbSchemaVersion means an empty database and
195 // skip version checking
196 result = dbSchemaVersion == null ? true : CdmMetaData
197 .isDbSchemaVersionCompatible(dbSchemaVersion);
198 monitor.worked(1);
199 } catch (CdmSourceException e) {
200 //
201 }
202
203 if (!result) {
204 // Show an error message
205 MessagingUtils
206 .messageDialog(
207 "DatabaseCompatibilityCheck failed",
208 this,
209 "The database schema for the chosen "
210 + "datasource '"
211 + cdmSource
212 + "' \n is not valid for this version of the taxonomic editor. \n"
213 + "Please update the chosen datasource or choose a new data source to connect to in the Datasource View.",
214 null);
215
216 monitor.setCanceled(true);
217 }
218
219 }
220
221 private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
222 monitor.subTask("Checking if datasource is a non empty CDM database.");
223 boolean isDbEmpty = false;
224 try {
225 isDbEmpty = cdmSource.isDbEmpty();
226 } catch (CdmSourceException e) {
227 isDbEmpty = true;
228 }
229 if(isDbEmpty) {
230 dbSchemaValidation = DbSchemaValidation.CREATE;
231 }
232 }
233
234 private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
235 if(throwable == null){
236 return false;
237 }else if(throwable instanceof CancellationException){
238 return true;
239 }else{
240 return causeIsCancelationExceptionRecursive(throwable.getCause());
241 }
242 }
243
244 private void checkDatabaseReachable(IProgressMonitor monitor) {
245 try {
246 monitor.subTask("Checking if datasource is reachable.");
247 cdmSource.checkConnection();
248 monitor.worked(1);
249 } catch (CdmSourceException e) {
250 MessagingUtils.messageDialog("Could not connect to chosen datasource",
251 this, "Reason: " + e.getMessage(), e);
252 monitor.setCanceled(true);
253 }
254 }
255 }