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