fix #6209: adapt the message if a datasource is not available
[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() {
128 if (instance != null && instance.isConnected) {
129 return instance;
130 } else{// if (instance == null || !instance.isConnected) {
131
132 MessagingUtils.dataSourceNotAvailableWarningDialog(instance);
133
134
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 CdmApplicationState.setCdmServiceCacher(new CdmServiceCacher());
267
268 }
269
270 private CdmStore(ICdmApplicationConfiguration applicationController,
271 ICdmSource cdmSource) {
272 CdmApplicationState.setCurrentAppConfig(applicationController);
273 CdmApplicationState.setCurrentDataChangeService(new CdmUIDataChangeService());
274 this.cdmSource = cdmSource;
275 isConnected = true;
276 }
277
278 /**
279 * All calls to the datastore require
280 *
281 * @return
282 */
283 private ICdmApplicationConfiguration getApplicationConfiguration() {
284 try {
285 return CdmApplicationState.getCurrentAppConfig();
286 } catch (Exception e) {
287 MessagingUtils.error(CdmStore.class, e);
288 }
289 return null;
290 }
291
292 /**
293 * <p>
294 * getCurrentApplicationController
295 * </p>
296 *
297 * @return a
298 * {@link eu.etaxonomy.cdm.remote.api.application.CdmApplicationController}
299 * object.
300 */
301 public static ICdmApplicationConfiguration getCurrentApplicationConfiguration() {
302 if (getDefault() != null) {
303 return getDefault().getApplicationConfiguration();
304 }
305 return null;
306 }
307
308 /*
309 * CONVERSATIONS
310 */
311
312 /**
313 * Creates a new conversation, binds resources to the conversation and start
314 * a transaction for this conversation.
315 *
316 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
317 * object.
318 */
319 public static ConversationHolder createConversation() {
320 ConversationHolder conversation = getCurrentApplicationConfiguration()
321 .NewConversation();
322 try {
323 conversation.startTransaction();
324 }catch(Exception e){
325 MessagingUtils.messageDialog("No database connection", CdmStore.class, "No database connection available", e);
326 }
327 return conversation;
328 }
329
330 //FIXME:Remoting should be removed after moving completely to remoting
331 private MockCdmEntitySessionManager mockCdmEntitySessionManager;
332
333 private ICdmEntitySessionManager getSessionManager() {
334 //FIXME:Remoting we should only have CdmApplicationRemoteConfiguration after move to remoting
335 // bad hack which should be finally removed
336 if(getCurrentApplicationConfiguration() instanceof CdmApplicationRemoteController) {
337 return ((CdmApplicationRemoteController)getCurrentApplicationConfiguration()).getCdmEntitySessionManager();
338 } else {
339 if(mockCdmEntitySessionManager == null) {
340 mockCdmEntitySessionManager = new MockCdmEntitySessionManager();
341 }
342 return mockCdmEntitySessionManager;
343 }
344 }
345
346 public static ICdmEntitySessionManager getCurrentSessionManager() {
347 if (getDefault() != null) {
348 return getDefault().getSessionManager();
349 }
350 return null;
351
352 }
353
354 /**
355 * Generic method that will scan the getters of {@link ICdmApplicationConfiguration} for the given service
356 * interface. If a matching getter is found the according service implementation is returned by
357 * invoking the getter otherwise the method returns <code>null</code>.
358 *
359 * @param <T>
360 * @param serviceClass
361 * @return the configured implementation of <code>serviceClass</code> or <code>null</code>
362 */
363 public static <T extends IService> T getService(Class<T> serviceClass) {
364 T service = null;
365 try {
366 service = CdmApplicationState.getService(serviceClass);
367 } catch (CdmApplicationException cae) {
368 MessagingUtils.error(CdmStore.class, cae);
369 }
370
371 return service;
372 }
373
374 /**
375 * @see #getService(Class)
376 * As ICommonService is not extending IService we need a specific request here
377 */
378 public static ICommonService getCommonService() {
379 return CdmApplicationState.getCommonService();
380
381 }
382
383 /**
384 * <p>
385 * getAuthenticationManager
386 * </p>
387 *
388 * @return a
389 * {@link org.springframework.security.authentication.ProviderManager}
390 * object.
391 */
392 public static AuthenticationManager getAuthenticationManager() {
393 return getCurrentApplicationConfiguration().getAuthenticationManager();
394 }
395
396 /**
397 * <p>
398 * getAuthenticationManager
399 * </p>
400 *
401 * @return a
402 * {@link ICdmPermissionEvaluator} object.
403 */
404 public static ICdmPermissionEvaluator getPermissionEvaluator() {
405 return getCurrentApplicationConfiguration().getPermissionEvaluator();
406 }
407
408
409 /*
410 * SECURITY RELATED CONVENIENCE METHODS
411 */
412
413 /**
414 * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.lang.Object, java.lang.Object)
415 *
416 * @param targetDomainObject
417 * @param permission
418 * @return
419 */
420 public static boolean currentAuthentiationHasPermission(CdmBase targetDomainObject, EnumSet<CRUD> permission){
421 //TODO use getCurrentApplicationConfiguration().currentAuthentiationHasPermission(CdmBase targetDomainObject, Operation permission) instead
422 SecurityContext context = SecurityContextHolder.getContext();
423 PermissionEvaluator pe = getPermissionEvaluator();
424 boolean hasPermission = false;
425 try {
426 hasPermission = getPermissionEvaluator().hasPermission(context.getAuthentication(), targetDomainObject,
427 permission);
428 } catch (org.springframework.security.access.AccessDeniedException e) {
429 /* IGNORE */
430 }
431 return hasPermission;
432 }
433
434 /**
435 * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.lang.Object, java.lang.Object)
436 *
437 * @param targetDomainObject
438 * @param permission
439 * @return
440 */
441 public static boolean currentAuthentiationHasPermission(Class<? extends CdmBase> targetType, EnumSet<CRUD> permission){
442 boolean hasPermission = false;
443 try {
444 hasPermission = getPermissionEvaluator().hasPermission(getCurrentAuthentiation(), null, targetType.getName(), permission);
445 } catch (org.springframework.security.access.AccessDeniedException e) {
446 /* IGNORE */
447 }
448 return hasPermission;
449 }
450
451 public static boolean currentAuthentiationHasOneOfRoles(Role ... roles){
452 boolean hasPermission = false;
453 try {
454 hasPermission = getPermissionEvaluator().hasOneOfRoles(getCurrentAuthentiation(), roles);
455 } catch (org.springframework.security.access.AccessDeniedException e) {
456 /* IGNORE */
457 }
458 return hasPermission;
459 }
460
461 public static Authentication getCurrentAuthentiation() {
462 SecurityContext context = SecurityContextHolder.getContext();
463 return context.getAuthentication();
464 }
465
466 /*
467 * LANGUAGE
468 */
469
470 /**
471 * Provides access to the global default language set in the application preferences.
472 *
473 * @return a {@link eu.etaxonomy.cdm.model.common.Language} object.
474 */
475 public static Language getDefaultLanguage() {
476 if (getDefault().getLanguage() == null) {
477 getDefault().setLanguage(PreferencesUtil.getGlobalLanguage());
478 }
479 return getDefault().getLanguage();
480 }
481
482 /**
483 * <p>
484 * setDefaultLanguage
485 * </p>
486 *
487 * @param language
488 * a {@link eu.etaxonomy.cdm.model.common.Language} object.
489 */
490 public static void setDefaultLanguage(Language language) {
491 getDefault().setLanguage(language);
492 }
493
494 /**
495 * @return the language
496 */
497 private Language getLanguage() {
498 return language;
499 }
500
501 /**
502 * @param language
503 * the language to set
504 */
505 private void setLanguage(Language language) {
506 this.language = language;
507 }
508
509 /*
510 * LOGIN
511 */
512
513 /**
514 * <p>
515 * Getter for the field <code>loginManager</code>.
516 * </p>
517 *
518 * @return a {@link eu.etaxonomy.taxeditor.store.LoginManager} object.
519 */
520 public static LoginManager getLoginManager() {
521 return loginManager;
522 }
523
524 /**
525 * <p>
526 * Getter for the field <code>contextManager</code>.
527 * </p>
528 *
529 * @return a {@link eu.etaxonomy.taxeditor.store.ContextManager} object.
530 */
531 public static ContextManager getContextManager() {
532 return contextManager;
533 }
534
535 public static TermManager getTermManager() {
536 return termManager;
537 }
538
539 public static SearchManager getSearchManager() {
540 return searchManager;
541 }
542
543 public static EditorManager getEditorManager() {
544 return editorManager;
545 }
546
547 public static ProgressMonitorClientManager getProgressMonitorClientManager() {
548 return progressMonitorClientManager;
549 }
550
551 /*
552 * IMPORT/EXPORT FACTORIES
553 */
554
555 /**
556 * <p>
557 * Getter for the field <code>importHandler</code>.
558 * </p>
559 *
560 * @return a {@link eu.etaxonomy.taxeditor.io.ImportManager} object.
561 */
562 public static ImportManager getImportManager() {
563 return ImportManager.NewInstance(getCurrentApplicationConfiguration());
564 }
565
566 /**
567 * <p>
568 * Getter for the field <code>exportHandler</code>.
569 * </p>
570 *
571 * @return a {@link eu.etaxonomy.taxeditor.io.ExportManager} object.
572 */
573 public static ExportManager getExportManager() {
574 return ExportManager.NewInstance(getCurrentApplicationConfiguration());
575 }
576
577 /**
578 * Whether this CdmStore is currently connected to a datasource
579 *
580 * @return a boolean.
581 */
582 public static boolean isActive() {
583 return instance != null && instance.isConnected;
584 }
585
586 public static ICdmSource getActiveCdmSource() {
587 if (isActive()) {
588 return instance.getCdmSource();
589 }
590 return null;
591 }
592
593 /**
594 * <p>
595 * getDataSource
596 * </p>
597 *
598 * @return a {@link eu.etaxonomy.cdm.database.ICdmDataSource} object.
599 * @deprecated currently retained for backward compatibility - use {@link getActiveCdmSource()} instead
600 */
601 // public static ICdmDataSource getDataSource() {
602 // if (isActive()) {
603 // return (ICdmDataSource)instance.getCdmSource();
604 // }
605 // return null;
606 // }
607
608 /**
609 * @return
610 */
611 private ICdmSource getCdmSource() {
612 return cdmSource;
613 }
614
615
616 public static <T extends CdmBase> IService<T> getService(T cdmBase){
617 IService<T> service = null;
618 if(cdmBase!=null){
619 //get corresponding service
620 if(cdmBase.isInstanceOf(Reference.class)){
621 service = (IService<T>) getService(IReferenceService.class);
622 }
623 else if (cdmBase.isInstanceOf(AgentBase.class)){
624 service = (IService<T>) getService(IAgentService.class);
625 }
626 else if (cdmBase instanceof NonViralName) {
627 service = (IService<T>) getService(INameService.class);
628 }
629 else if (cdmBase instanceof SpecimenOrObservationBase) {
630 service = (IService<T>) getService(IOccurrenceService.class);
631 }
632 else if (cdmBase instanceof Collection) {
633 service = (IService<T>) getService(ICollectionService.class);
634 }
635 else if (cdmBase instanceof User) {
636 service = (IService<T>) getService(IUserService.class);
637 }
638 else if (cdmBase instanceof Primer) {
639 service = (IService<T>) getService(IPrimerService.class);
640 }
641 else if (cdmBase instanceof Amplification) {
642 service = (IService<T>) getService(IAmplificationService.class);
643 } else if (cdmBase instanceof PolytomousKey) {
644 service = (IService<T>) getService(IPolytomousKeyService.class);
645 }
646 }
647 return service;
648 }
649
650 public static void setManagedServer(CDMServer server) {
651 managedServer = server;
652 }
653
654 public static CDMServer getManagedServer() {
655 return managedServer;
656 }
657
658 }