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