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