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