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