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