- fixed saving problem due to cloning of FieldUnit
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / store / CdmStore.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.io.Serializable;
13 import java.lang.reflect.InvocationTargetException;
14 import java.lang.reflect.Method;
15 import java.lang.reflect.Type;
16 import java.util.EnumSet;
17
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.core.runtime.jobs.Job;
20 import org.eclipse.swt.widgets.Display;
21 import org.springframework.core.io.ClassPathResource;
22 import org.springframework.core.io.Resource;
23 import org.springframework.security.access.PermissionEvaluator;
24 import org.springframework.security.authentication.ProviderManager;
25 import org.springframework.security.core.context.SecurityContext;
26 import org.springframework.security.core.context.SecurityContextHolder;
27
28 import eu.etaxonomy.cdm.api.application.CdmApplicationController;
29 import eu.etaxonomy.cdm.api.application.ICdmApplicationConfiguration;
30 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
31 import eu.etaxonomy.cdm.api.service.IService;
32 import eu.etaxonomy.cdm.database.DbSchemaValidation;
33 import eu.etaxonomy.cdm.database.ICdmDataSource;
34 import eu.etaxonomy.cdm.ext.geo.IEditGeoService;
35 import eu.etaxonomy.cdm.model.common.CdmBase;
36 import eu.etaxonomy.cdm.model.common.Language;
37 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
38 import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;
39 import eu.etaxonomy.taxeditor.datasource.CdmDataSourceRepository;
40 import eu.etaxonomy.taxeditor.io.ExportManager;
41 import eu.etaxonomy.taxeditor.io.ImportManager;
42 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
43 import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
44 import eu.etaxonomy.taxeditor.view.datasource.CdmDataSourceViewPart;
45
46 /**
47 * This implementation of ICdmDataRepository depends on hibernate sessions to
48 * store the data correctly for the current session. No state is held in this
49 * class.
50 *
51 * Only methods that either get or manipulate data are exposed here. So this
52 * class acts as a facade for the methods in cdmlib-service.
53 *
54 * @author n.hoffmann
55 * @created 17.03.2009
56 * @version 1.0
57 */
58 public class CdmStore {
59
60 private static final Resource DEFAULT_APPLICATION_CONTEXT = new ClassPathResource(
61 "/eu/etaxonomy/cdm/editorApplicationContext.xml",
62 TaxeditorStorePlugin.class);
63 private static final DbSchemaValidation DEFAULT_DB_SCHEMA_VALIDATION = DbSchemaValidation.VALIDATE;
64
65 private static CdmStore instance;
66
67 private final ICdmApplicationConfiguration applicationConfiguration;
68
69 private static ContextManager contextManager = new ContextManager();
70
71 private static LoginManager loginManager = new LoginManager();
72
73 private static TermManager termManager = new TermManager();
74
75 private static SearchManager searchManager = new SearchManager();
76
77 private static EditorManager editorManager = new EditorManager();
78
79 private static CdmStoreConnector job;
80
81 private Language language;
82
83 private ICdmDataSource cdmDatasource;
84
85 private boolean isConnected;
86
87 /**
88 * <p>
89 * getDefault
90 * </p>
91 *
92 * @return a {@link eu.etaxonomy.taxeditor.store.CdmStore} object.
93 */
94 protected static CdmStore getDefault() {
95 if (instance != null && instance.isConnected) {
96 return instance;
97 } else if (instance == null || !instance.isConnected) {
98
99 StoreUtil
100 .warningDialog(
101 "Application is not connected to a datastore",
102 instance,
103 "The requested operation is only available when "
104 + "connected to a datasource. You may choose a datasource to connect to or create a new one in the datasource view.");
105
106 StoreUtil.showView(CdmDataSourceViewPart.ID);
107
108 }
109
110 throw new RuntimeException();
111 }
112
113 /**
114 * Initialize the with the last edited datasource
115 */
116 public static void connect() {
117
118 ICdmDataSource datasource = CdmDataSourceRepository
119 .getCurrentDataSource();
120
121 connect(datasource);
122 }
123
124 /**
125 * Initialize with a specific datasource
126 *
127 * @param datasource
128 * a {@link eu.etaxonomy.cdm.database.ICdmDataSource} object.
129 */
130 public static void connect(ICdmDataSource datasource) {
131 connect(datasource, DEFAULT_DB_SCHEMA_VALIDATION,
132 DEFAULT_APPLICATION_CONTEXT);
133 }
134
135 /**
136 * Initialize and provide
137 *
138 * @param datasource
139 * @param dbSchemaValidation
140 * @param applicationContextBean
141 */
142 private static void connect(final ICdmDataSource datasource,
143 final DbSchemaValidation dbSchemaValidation,
144 final Resource applicationContextBean) {
145 StoreUtil.info("Connecting to datasource: " + datasource);
146
147 job = new CdmStoreConnector(Display.getDefault(), datasource,
148 dbSchemaValidation, applicationContextBean);
149 job.setUser(true);
150 job.setPriority(Job.BUILD);
151 job.schedule();
152
153 }
154
155 public static boolean isConnecting() {
156 return job != null && job.getState() == Job.RUNNING;
157 }
158
159 /**
160 * Closes the current application context
161 *
162 * @param monitor
163 * a {@link org.eclipse.core.runtime.IProgressMonitor} object.
164 */
165 public static void close(final IProgressMonitor monitor) {
166 Display.getDefault().asyncExec(new Runnable() {
167 /*
168 * (non-Javadoc)
169 *
170 * @see java.lang.Runnable#run()
171 */
172 @Override
173 public void run() {
174 getContextManager().notifyContextAboutToStop(monitor);
175 if ((monitor == null || (!monitor.isCanceled()) && isActive())) {
176 getContextManager().notifyContextStop(monitor);
177 instance.close();
178 }
179 }
180 });
181 }
182
183 private void close() {
184 isConnected = false;
185 cdmDatasource = null;
186 }
187
188 static void setInstance(CdmApplicationController applicationController,
189 ICdmDataSource dataSource) {
190 instance = new CdmStore(applicationController, dataSource);
191 }
192
193 private CdmStore(CdmApplicationController applicationController,
194 ICdmDataSource dataSource) {
195 this.applicationConfiguration = applicationController;
196 this.cdmDatasource = dataSource;
197 isConnected = true;
198 }
199
200 /**
201 * All calls to the datastore require
202 *
203 * @return
204 */
205 private ICdmApplicationConfiguration getApplicationConfiguration() {
206 try {
207 return applicationConfiguration;
208 } catch (Exception e) {
209 StoreUtil.error(CdmStore.class, e);
210 }
211 return null;
212 }
213
214 /**
215 * <p>
216 * getCurrentApplicationController
217 * </p>
218 *
219 * @return a
220 * {@link eu.etaxonomy.cdm.api.application.CdmApplicationController}
221 * object.
222 */
223 public static ICdmApplicationConfiguration getCurrentApplicationConfiguration() {
224 if (getDefault() != null) {
225 return getDefault().getApplicationConfiguration();
226 }
227 return null;
228 }
229
230 /*
231 * CONVERSATIONS
232 */
233
234 /**
235 * Creates a new conversation, binds resources to the conversation and start
236 * a transaction for this conversation.
237 *
238 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
239 * object.
240 */
241 public static ConversationHolder createConversation() {
242 ConversationHolder conversation = getCurrentApplicationConfiguration()
243 .NewConversation();
244 try{
245 conversation.startTransaction();
246 }catch(Exception e){
247 StoreUtil.errorDialog("No database connection", CdmStore.class, "No database connection available", e);
248 }
249 return conversation;
250 }
251
252 /**
253 * Generic method that will scan the getters of {@link ICdmApplicationConfiguration} for the given service
254 * interface. If a matching getter is found the according service implementation is returned by
255 * invoking the getter otherwise the method returns <code>null</code>.
256 *
257 * @param <T>
258 * @param serviceClass
259 * @return the configured implementation of <code>serviceClass</code> or <code>null</code>
260 */
261 public static <T extends IService> T getService(Class<T> serviceClass) {
262 ICdmApplicationConfiguration configuration = getCurrentApplicationConfiguration();
263
264 Method[] methods = ICdmApplicationConfiguration.class.getDeclaredMethods();
265
266 T service = null;
267
268 for (Method method : methods) {
269 Type type = method.getGenericReturnType();
270
271 if (type.equals(serviceClass)) {
272 try {
273 service = (T) method.invoke(configuration, null);
274 break;
275 } catch (IllegalArgumentException e) {
276 StoreUtil.error(CdmStore.class, e);
277 } catch (IllegalAccessException e) {
278 StoreUtil.error(CdmStore.class, e);
279 } catch (InvocationTargetException e) {
280 StoreUtil.error(CdmStore.class, e);
281 }
282 }
283 }
284
285 return service;
286 }
287
288 /**
289 * <p>
290 * getAuthenticationManager
291 * </p>
292 *
293 * @return a
294 * {@link org.springframework.security.authentication.ProviderManager}
295 * object.
296 */
297 public static ProviderManager getAuthenticationManager() {
298 return getCurrentApplicationConfiguration().getAuthenticationManager();
299 }
300
301 /**
302 * <p>
303 * getAuthenticationManager
304 * </p>
305 *
306 * @return a
307 * {@link PermissionEvaluator} object.
308 */
309 public static PermissionEvaluator getPermissionEvaluator() {
310 return getCurrentApplicationConfiguration().getPermissionEvaluator();
311 }
312
313 /**
314 * <p>
315 * getGeoService
316 * </p>
317 *
318 * @return a {@link eu.etaxonomy.cdm.ext.geo.IEditGeoService} object.
319 */
320 public static IEditGeoService getGeoService() {
321 return (IEditGeoService) getCurrentApplicationConfiguration().getBean(
322 "editGeoService");
323 }
324
325 /*
326 * SECURITY RELATED CONVENIENCE METHODS
327 */
328
329 /**
330 * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.lang.Object, java.lang.Object)
331 *
332 * @param targetDomainObject
333 * @param permission
334 * @return
335 */
336 public static boolean currentAuthentiationHasPermission(CdmBase targetDomainObject, EnumSet<CRUD> permission){
337 //TODO use getCurrentApplicationConfiguration().currentAuthentiationHasPermission(CdmBase targetDomainObject, Operation permission) instead
338 SecurityContext context = SecurityContextHolder.getContext();
339 return getPermissionEvaluator().hasPermission(context.getAuthentication(), targetDomainObject, permission);
340 }
341
342 /**
343 * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.lang.Object, java.lang.Object)
344 *
345 * @param targetDomainObject
346 * @param permission
347 * @return
348 */
349 public static boolean currentAuthentiationHasPermission(Class<? extends CdmBase> targetType, EnumSet<CRUD> permission){
350 SecurityContext context = SecurityContextHolder.getContext();
351 return getPermissionEvaluator().hasPermission(context.getAuthentication(), null, targetType.getName(), permission);
352 }
353
354 /*
355 * LANGUAGE
356 */
357
358 /**
359 * <p>
360 * getDefaultLanguage
361 * </p>
362 *
363 * @return a {@link eu.etaxonomy.cdm.model.common.Language} object.
364 */
365 public static Language getDefaultLanguage() {
366 if (getDefault().getLanguage() == null) {
367 getDefault().setLanguage(PreferencesUtil.getGlobalLanguage());
368 }
369 return getDefault().getLanguage();
370 }
371
372 /**
373 * <p>
374 * setDefaultLanguage
375 * </p>
376 *
377 * @param language
378 * a {@link eu.etaxonomy.cdm.model.common.Language} object.
379 */
380 public static void setDefaultLanguage(Language language) {
381 getDefault().setLanguage(language);
382 }
383
384 /**
385 * @return the language
386 */
387 private Language getLanguage() {
388 return language;
389 }
390
391 /**
392 * @param language
393 * the language to set
394 */
395 private void setLanguage(Language language) {
396 this.language = language;
397 }
398
399 /*
400 * LOGIN
401 */
402
403 /**
404 * <p>
405 * Getter for the field <code>loginManager</code>.
406 * </p>
407 *
408 * @return a {@link eu.etaxonomy.taxeditor.store.LoginManager} object.
409 */
410 public static LoginManager getLoginManager() {
411 return loginManager;
412 }
413
414 /**
415 * <p>
416 * Getter for the field <code>contextManager</code>.
417 * </p>
418 *
419 * @return a {@link eu.etaxonomy.taxeditor.store.ContextManager} object.
420 */
421 public static ContextManager getContextManager() {
422 return contextManager;
423 }
424
425 public static TermManager getTermManager() {
426 return termManager;
427 }
428
429 public static SearchManager getSearchManager() {
430 return searchManager;
431 }
432
433 public static EditorManager getEditorManager() {
434 return editorManager;
435 }
436
437 /*
438 * IMPORT/EXPORT FACTORIES
439 */
440
441 /**
442 * <p>
443 * Getter for the field <code>importHandler</code>.
444 * </p>
445 *
446 * @return a {@link eu.etaxonomy.taxeditor.io.ImportManager} object.
447 */
448 public static ImportManager getImportManager() {
449 return ImportManager.NewInstance(getCurrentApplicationConfiguration());
450 }
451
452 /**
453 * <p>
454 * Getter for the field <code>exportHandler</code>.
455 * </p>
456 *
457 * @return a {@link eu.etaxonomy.taxeditor.io.ExportManager} object.
458 */
459 public static ExportManager getExportManager() {
460 return ExportManager.NewInstance(getCurrentApplicationConfiguration());
461 }
462
463 /**
464 * Whether this CdmStore is currently connected to a datasource
465 *
466 * @return a boolean.
467 */
468 public static boolean isActive() {
469 return instance != null && instance.isConnected;
470 }
471
472 /**
473 * <p>
474 * getDataSource
475 * </p>
476 *
477 * @return a {@link eu.etaxonomy.cdm.database.ICdmDataSource} object.
478 */
479 public static ICdmDataSource getDataSource() {
480 if (isActive()) {
481 return instance.getDatasource();
482 }
483 return null;
484 }
485
486 /**
487 * @return
488 */
489 private ICdmDataSource getDatasource() {
490 return cdmDatasource;
491 }
492
493 }