52ce1b559fc3e856c83ce17f5d9f7cb61c4b61c8
[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.ui.dialog.LoginDialog;
38 import eu.etaxonomy.taxeditor.view.datasource.CdmDataSourceViewPart;
39
40 /**
41 * @author n.hoffmann
42 * @created Dec 8, 2010
43 * @version 1.0
44 */
45 class CdmStoreConnector extends Job {
46 private final Display display;
47 private final ICdmSource cdmSource;
48 private DbSchemaValidation dbSchemaValidation;
49 private final Resource applicationContextBean;
50
51 /**
52 * @param datasource
53 * @param dbSchemaValidation
54 * @param applicationContextBean
55 */
56 public CdmStoreConnector(Display display, ICdmSource cdmSource,
57 DbSchemaValidation dbSchemaValidation,
58 Resource applicationContextBean) {
59 super("Connecting to datasource: " + 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 ICdmApplicationConfiguration 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 try {
100
101 applicationController = getApplicationController(cdmSource,subprogressMonitor);
102
103 } catch (Exception e) {
104 if(! causeIsCancelationExceptionRecursive(e)){
105 return new Status(IStatus.ERROR, "Could not connect to CDM Store", "An error occurred while trying to connect to datasource: " + cdmSource.getName(), e);
106 }
107 } finally {
108 monitor.done();
109 }
110 }
111
112
113
114 if (!monitor.isCanceled()) {
115 CdmStore.setInstance(applicationController, cdmSource);
116
117 display.asyncExec(new Runnable() {
118 /*
119 * (non-Javadoc)
120 *
121 * @see java.lang.Runnable#run()
122 */
123 @Override
124 public void run() {
125 authenticate();
126
127 startContext();
128 }
129 });
130
131 StoreUtil.info("Application context initialized.");
132 return Status.OK_STATUS;
133 } else {
134 // Show datasource view if not shown yet
135 display.asyncExec(new Runnable() {
136 /*
137 * (non-Javadoc)
138 *
139 * @see java.lang.Runnable#run()
140 */
141 @Override
142 public void run() {
143 StoreUtil.showView(CdmDataSourceViewPart.ID);
144 }
145 });
146 return Status.CANCEL_STATUS;
147 }
148
149 }
150
151 private ICdmApplicationConfiguration getApplicationController(ICdmSource cdmSource, CdmProgressMonitorAdapter subprogressMonitor) {
152 if(cdmSource instanceof ICdmDataSource) {
153 return CdmApplicationController.NewInstance(applicationContextBean,
154 (ICdmDataSource)cdmSource,
155 dbSchemaValidation,
156 false,
157 subprogressMonitor);
158 } else if(cdmSource instanceof ICdmRemoteSource) {
159 return CdmApplicationRemoteController.NewInstance((ICdmRemoteSource)cdmSource,
160 false,
161 subprogressMonitor,
162 null);
163 } else {
164 throw new UnsupportedOperationException("Cannot create application controller for " + cdmSource.getName());
165 }
166 }
167 private void authenticate() {
168 LoginDialog loginDialog = new LoginDialog(StoreUtil.getShell());
169 loginDialog.open();
170 }
171
172 private void startContext() {
173 CdmStore.getContextManager().notifyContextStart();
174 }
175
176 /**
177 * @return
178 */
179 private String getConnectionMessage() {
180 return cdmSource.getConnectionMessage();
181 }
182
183 /**
184 * @return
185 * @throws SQLException
186 */
187 private void checkDbSchemaVersionCompatibility(IProgressMonitor monitor) {
188 monitor.subTask("Checking if datasource is compatible with this editor.");
189 String dbSchemaVersion;
190 boolean result = false;
191 try {
192 dbSchemaVersion = cdmSource.getDbSchemaVersion();
193 // we assume that empty dbSchemaVersion means an empty database and
194 // skip version checking
195 result = dbSchemaVersion == null ? true : CdmMetaData
196 .isDbSchemaVersionCompatible(dbSchemaVersion);
197 monitor.worked(1);
198 } catch (CdmSourceException e) {
199 //
200 }
201
202 if (!result) {
203 // Show an error message
204 StoreUtil
205 .errorDialog(
206 "DatabaseCompatibilityCheck failed",
207 this,
208 "The database schema for the chosen "
209 + "datasource '"
210 + cdmSource
211 + "' \n is not valid for this version of the taxonomic editor. \n"
212 + "Please update the chosen datasource or choose a new data source to connect to in the Datasource View.",
213 null);
214
215 monitor.setCanceled(true);
216 }
217
218 }
219
220 private void checkIsNonEmptyCdmDatabase(IProgressMonitor monitor) {
221 monitor.subTask("Checking if datasource is a non empty CDM database.");
222 boolean isDbEmpty = false;
223 try {
224 isDbEmpty = cdmSource.isDbEmpty();
225 } catch (CdmSourceException e) {
226 isDbEmpty = true;
227 }
228 if(isDbEmpty) {
229 dbSchemaValidation = DbSchemaValidation.CREATE;
230 }
231 }
232
233 private boolean causeIsCancelationExceptionRecursive(Throwable throwable){
234 if(throwable == null){
235 return false;
236 }else if(throwable instanceof CancellationException){
237 return true;
238 }else{
239 return causeIsCancelationExceptionRecursive(throwable.getCause());
240 }
241 }
242
243 private void checkDatabaseReachable(IProgressMonitor monitor) {
244 try {
245 monitor.subTask("Checking if datasource is reachable.");
246 cdmSource.checkConnection();
247 monitor.worked(1);
248 } catch (CdmSourceException e) {
249 StoreUtil.errorDialog("Could not connect to chosen datasource",
250 this, "Reason: " + e.getMessage(), e);
251 monitor.setCanceled(true);
252 }
253 }
254 }