2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.taxeditor
.store
;
12 import java
.util
.EnumSet
;
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
;
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
.ICdmRepository
;
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
.TaxonName
;
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
;
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
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.
83 public class CdmStore
{
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
;
90 private static CdmStore instance
;
92 //private final ICdmRepository applicationConfiguration;
94 private static ContextManager contextManager
= new ContextManager();
96 private static LoginManager loginManager
= new LoginManager();
98 private static TermManager termManager
= new TermManager();
100 private static SearchManager searchManager
= new SearchManager();
102 private static EditorManager editorManager
= new EditorManager();
104 private static UseObjectStore useObjectInitializer
= new UseObjectStore();
106 private static ProgressMonitorClientManager progressMonitorClientManager
= new ProgressMonitorClientManager();
108 private static CdmStoreConnector job
;
110 private static CDMServer managedServer
;
112 private Language language
;
114 private ICdmSource cdmSource
;
116 private boolean isConnected
;
125 * @return a {@link eu.etaxonomy.taxeditor.store.CdmStore} object.
127 protected static CdmStore
getDefault(boolean connecting
){
128 if (instance
!= null && instance
.isConnected
) {
130 } else{// if (instance == null || !instance.isConnected) {
132 MessagingUtils
.dataSourceNotAvailableWarningDialog(instance
);
134 MessagingUtils
.noDataSourceWarningDialog(instance
);
146 * @return a {@link eu.etaxonomy.taxeditor.store.CdmStore} object.
148 protected static CdmStore
getDefault(){
149 return getDefault(false);
153 * Initialize the with the last edited datasource
155 public static void connect() {
157 ICdmSource cdmSource
;
160 cdmSource
= CdmDataSourceRepository
.getCurrentCdmSource();
162 } catch (Exception e
) {
163 MessagingUtils
.messageDialog("Connection to CDM Source Failed", CdmStore
.class, "Could not connect to target CDM Source", e
);
170 * Initialize with a specific datasource
173 * a {@link eu.etaxonomy.cdm.database.ICdmDataSource} object.
175 public static void connect(ICdmSource cdmSource
) {
176 connect(cdmSource
, DEFAULT_DB_SCHEMA_VALIDATION
,
177 DEFAULT_APPLICATION_CONTEXT
);
180 public static void connect(ICdmSource cdmSource
, RemotingLoginDialog loginDialog
) {
182 DEFAULT_DB_SCHEMA_VALIDATION
,
183 DEFAULT_APPLICATION_CONTEXT
,
188 * Initialize and provide
191 * @param dbSchemaValidation
192 * @param applicationContextBean
194 private static void connect(final ICdmSource cdmSource
,
195 final DbSchemaValidation dbSchemaValidation
,
196 final Resource applicationContextBean
) {
198 MessagingUtils
.info("Connecting to datasource: " + cdmSource
);
200 job
= new CdmStoreConnector(Display
.getDefault(), cdmSource
,
201 dbSchemaValidation
, applicationContextBean
);
203 job
.setPriority(Job
.BUILD
);
208 private static void connect(final ICdmSource cdmSource
,
209 final DbSchemaValidation dbSchemaValidation
,
210 final Resource applicationContextBean
,
211 RemotingLoginDialog remotingLoginDialog
) {
212 RemotingLoginDialog loginDialog
= remotingLoginDialog
;
214 // before we connect we clear the entity caches and the sessions
215 CdmRemoteCacheManager
.removeEntityCaches();
216 if(getCurrentSessionManager(true) != null) {
217 getCurrentSessionManager(true).disposeAll();
220 MessagingUtils
.info("Connecting to datasource: " + cdmSource
);
222 job
= new CdmStoreConnector(Display
.getDefault(),
225 applicationContextBean
);
226 job
.start(loginDialog
);
230 public static boolean isConnecting() {
231 return job
!= null && job
.getState() == Job
.RUNNING
;
235 * Closes the current application context
238 * a {@link org.eclipse.core.runtime.IProgressMonitor} object.
240 public static void close(final IProgressMonitor monitor
) {
241 Display
.getDefault().asyncExec(new Runnable() {
245 * @see java.lang.Runnable#run()
249 getContextManager().notifyContextAboutToStop(monitor
);
250 if ((monitor
== null || (!monitor
.isCanceled()) && isActive())) {
251 getContextManager().notifyContextStop(monitor
);
258 public static void close(IProgressMonitor monitor
, boolean async
) {
262 getContextManager().notifyContextAboutToStop(monitor
);
263 if ((monitor
== null || (!monitor
.isCanceled()) && isActive())) {
264 getContextManager().notifyContextStop(monitor
);
270 private void close() {
273 CdmApplicationState
.dispose();
276 static void setInstance(ICdmRepository applicationController
,
277 ICdmSource cdmSource
) {
278 instance
= new CdmStore(applicationController
, cdmSource
);
279 CdmApplicationState
.setCdmServiceCacher(new CdmServiceCacher());
283 private CdmStore(ICdmRepository repository
,
284 ICdmSource cdmSource
) {
285 CdmApplicationState
.setCurrentAppConfig(repository
);
286 CdmApplicationState
.setCurrentDataChangeService(new CdmUIDataChangeService());
287 this.cdmSource
= cdmSource
;
292 * All calls to the datastore require
296 private ICdmRepository
getApplicationConfiguration() {
298 return CdmApplicationState
.getCurrentAppConfig();
299 } catch (Exception e
) {
300 MessagingUtils
.error(CdmStore
.class, e
);
307 * getCurrentApplicationController
311 * {@link eu.etaxonomy.cdm.remote.api.application.CdmApplicationController}
314 public static ICdmRepository
getCurrentApplicationConfiguration() {
315 if (getDefault() != null) {
316 return getDefault().getApplicationConfiguration();
326 * Creates a new conversation, binds resources to the conversation and start
327 * a transaction for this conversation.
329 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
332 public static ConversationHolder
createConversation() {
333 ConversationHolder conversation
= getCurrentApplicationConfiguration()
336 conversation
.startTransaction();
338 MessagingUtils
.messageDialog("No database connection", CdmStore
.class, "No database connection available", e
);
343 //FIXME:Remoting should be removed after moving completely to remoting
344 private MockCdmEntitySessionManager mockCdmEntitySessionManager
;
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();
352 if(mockCdmEntitySessionManager
== null) {
353 mockCdmEntitySessionManager
= new MockCdmEntitySessionManager();
355 return mockCdmEntitySessionManager
;
358 public static ICdmEntitySessionManager
getCurrentSessionManager() {
359 return getCurrentSessionManager(false);
363 public static ICdmEntitySessionManager
getCurrentSessionManager(boolean connecting
) {
364 if (getDefault(connecting
) != null) {
365 return getDefault(connecting
).getSessionManager();
372 * Generic method that will scan the getters of {@link ICdmRepository} 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>.
377 * @param serviceClass
378 * @return the configured implementation of <code>serviceClass</code> or <code>null</code>
380 public static <T
extends IService
> T
getService(Class
<T
> serviceClass
) {
383 service
= CdmApplicationState
.getService(serviceClass
);
384 } catch (CdmApplicationException cae
) {
385 MessagingUtils
.error(CdmStore
.class, cae
);
392 * @see #getService(Class)
393 * As ICommonService is not extending IService we need a specific request here
395 public static ICommonService
getCommonService() {
396 return CdmApplicationState
.getCommonService();
402 * getAuthenticationManager
406 * {@link org.springframework.security.authentication.ProviderManager}
409 public static AuthenticationManager
getAuthenticationManager() {
410 return getCurrentApplicationConfiguration().getAuthenticationManager();
415 * getAuthenticationManager
419 * {@link ICdmPermissionEvaluator} object.
421 public static ICdmPermissionEvaluator
getPermissionEvaluator() {
422 return getCurrentApplicationConfiguration().getPermissionEvaluator();
427 * SECURITY RELATED CONVENIENCE METHODS
431 * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.lang.Object, java.lang.Object)
433 * @param targetDomainObject
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;
443 hasPermission
= getPermissionEvaluator().hasPermission(context
.getAuthentication(), targetDomainObject
,
445 } catch (org
.springframework
.security
.access
.AccessDeniedException e
) {
448 return hasPermission
;
452 * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.lang.Object, java.lang.Object)
454 * @param targetDomainObject
458 public static boolean currentAuthentiationHasPermission(Class
<?
extends CdmBase
> targetType
, EnumSet
<CRUD
> permission
){
459 boolean hasPermission
= false;
461 hasPermission
= getPermissionEvaluator().hasPermission(getCurrentAuthentiation(), null, targetType
.getName(), permission
);
462 } catch (org
.springframework
.security
.access
.AccessDeniedException e
) {
465 return hasPermission
;
468 public static boolean currentAuthentiationHasOneOfRoles(Role
... roles
){
469 boolean hasPermission
= false;
471 hasPermission
= getPermissionEvaluator().hasOneOfRoles(getCurrentAuthentiation(), roles
);
472 } catch (org
.springframework
.security
.access
.AccessDeniedException e
) {
475 return hasPermission
;
478 public static Authentication
getCurrentAuthentiation() {
479 SecurityContext context
= SecurityContextHolder
.getContext();
480 return context
.getAuthentication();
488 * Provides access to the global default language set in the application preferences.
490 * @return a {@link eu.etaxonomy.cdm.model.common.Language} object.
492 public static Language
getDefaultLanguage() {
493 if (getDefault().getLanguage() == null) {
494 getDefault().setLanguage(PreferencesUtil
.getGlobalLanguage());
496 return getDefault().getLanguage();
505 * a {@link eu.etaxonomy.cdm.model.common.Language} object.
507 public static void setDefaultLanguage(Language language
) {
508 getDefault().setLanguage(language
);
512 * @return the language
514 private Language
getLanguage() {
520 * the language to set
522 private void setLanguage(Language language
) {
523 this.language
= language
;
532 * Getter for the field <code>loginManager</code>.
535 * @return a {@link eu.etaxonomy.taxeditor.store.LoginManager} object.
537 public static LoginManager
getLoginManager() {
543 * Getter for the field <code>contextManager</code>.
546 * @return a {@link eu.etaxonomy.taxeditor.store.ContextManager} object.
548 public static ContextManager
getContextManager() {
549 return contextManager
;
552 public static TermManager
getTermManager() {
556 public static SearchManager
getSearchManager() {
557 return searchManager
;
560 public static EditorManager
getEditorManager() {
561 return editorManager
;
564 public static ProgressMonitorClientManager
getProgressMonitorClientManager() {
565 return progressMonitorClientManager
;
569 * IMPORT/EXPORT FACTORIES
574 * Getter for the field <code>importHandler</code>.
577 * @return a {@link eu.etaxonomy.taxeditor.io.ImportManager} object.
579 public static ImportManager
getImportManager() {
580 return ImportManager
.NewInstance(getCurrentApplicationConfiguration());
585 * Getter for the field <code>exportHandler</code>.
588 * @return a {@link eu.etaxonomy.taxeditor.io.ExportManager} object.
590 public static ExportManager
getExportManager() {
591 return ExportManager
.NewInstance(getCurrentApplicationConfiguration());
595 * Whether this CdmStore is currently connected to a datasource
599 public static boolean isActive() {
600 return instance
!= null && instance
.isConnected
;
603 public static ICdmSource
getActiveCdmSource() {
605 return instance
.getCdmSource();
615 * @return a {@link eu.etaxonomy.cdm.database.ICdmDataSource} object.
616 * @deprecated currently retained for backward compatibility - use {@link getActiveCdmSource()} instead
618 // public static ICdmDataSource getDataSource() {
620 // return (ICdmDataSource)instance.getCdmSource();
628 private ICdmSource
getCdmSource() {
633 public static <T
extends CdmBase
> IService
<T
> getService(T cdmBase
){
634 IService
<T
> service
= null;
636 //get corresponding service
637 if(cdmBase
.isInstanceOf(Reference
.class)){
638 service
= (IService
<T
>) getService(IReferenceService
.class);
640 else if (cdmBase
.isInstanceOf(AgentBase
.class)){
641 service
= (IService
<T
>) getService(IAgentService
.class);
643 else if (cdmBase
instanceof TaxonName
) {
644 service
= (IService
<T
>) getService(INameService
.class);
646 else if (cdmBase
instanceof SpecimenOrObservationBase
) {
647 service
= (IService
<T
>) getService(IOccurrenceService
.class);
649 else if (cdmBase
instanceof Collection
) {
650 service
= (IService
<T
>) getService(ICollectionService
.class);
652 else if (cdmBase
instanceof User
) {
653 service
= (IService
<T
>) getService(IUserService
.class);
655 else if (cdmBase
instanceof Primer
) {
656 service
= (IService
<T
>) getService(IPrimerService
.class);
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);
667 public static void setManagedServer(CDMServer server
) {
668 managedServer
= server
;
671 public static CDMServer
getManagedServer() {
672 return managedServer
;