Merge branch 'develop' into remoting-4.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.ICommonService;
32 import eu.etaxonomy.cdm.api.service.IService;
33 import eu.etaxonomy.cdm.config.ICdmSource;
34 import eu.etaxonomy.cdm.database.DbSchemaValidation;
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 remotingLoginDialog) {
177 RemotingLoginDialog loginDialog = remotingLoginDialog;
178 if(isActive()) {
179 // before we connect we clear the entity caches and the sessions
180 CdmRemoteCacheManager.removeEntityCaches();
181 if(getCurrentSessionManager() != null) {
182 getCurrentSessionManager().disposeAll();
183 }
184 }
185 MessagingUtils.info("Connecting to datasource: " + cdmSource);
186
187 job = new CdmStoreConnector(Display.getDefault(),
188 cdmSource,
189 dbSchemaValidation,
190 applicationContextBean);
191 job.start(loginDialog);
192
193 }
194
195 public static boolean isConnecting() {
196 return job != null && job.getState() == Job.RUNNING;
197 }
198
199 /**
200 * Closes the current application context
201 *
202 * @param monitor
203 * a {@link org.eclipse.core.runtime.IProgressMonitor} object.
204 */
205 public static void close(final IProgressMonitor monitor) {
206 Display.getDefault().asyncExec(new Runnable() {
207 /*
208 * (non-Javadoc)
209 *
210 * @see java.lang.Runnable#run()
211 */
212 @Override
213 public void run() {
214 getContextManager().notifyContextAboutToStop(monitor);
215 if ((monitor == null || (!monitor.isCanceled()) && isActive())) {
216 getContextManager().notifyContextStop(monitor);
217 instance.close();
218 }
219 }
220 });
221 }
222
223 public static void close(IProgressMonitor monitor, boolean async) {
224 if(async) {
225 close(monitor);
226 } else {
227 getContextManager().notifyContextAboutToStop(monitor);
228 if ((monitor == null || (!monitor.isCanceled()) && isActive())) {
229 getContextManager().notifyContextStop(monitor);
230 instance.close();
231 }
232 }
233
234 }
235 private void close() {
236 isConnected = false;
237 cdmSource = null;
238 CdmApplicationState.dispose();
239 }
240
241 static void setInstance(ICdmApplicationConfiguration applicationController,
242 ICdmSource cdmSource) {
243 instance = new CdmStore(applicationController, cdmSource);
244 if(getCurrentSessionManager().isRemoting()) {
245 CdmApplicationState.setCdmServiceCacher(new CdmServiceCacher());
246 }
247 }
248
249 private CdmStore(ICdmApplicationConfiguration applicationController,
250 ICdmSource cdmSource) {
251 CdmApplicationState.setCurrentAppConfig(applicationController);
252 CdmApplicationState.setCurrentDataChangeService(new CdmUIDataChangeService());
253 this.cdmSource = cdmSource;
254 isConnected = true;
255 }
256
257 /**
258 * All calls to the datastore require
259 *
260 * @return
261 */
262 private ICdmApplicationConfiguration getApplicationConfiguration() {
263 try {
264 return CdmApplicationState.getCurrentAppConfig();
265 } catch (Exception e) {
266 MessagingUtils.error(CdmStore.class, e);
267 }
268 return null;
269 }
270
271 /**
272 * <p>
273 * getCurrentApplicationController
274 * </p>
275 *
276 * @return a
277 * {@link eu.etaxonomy.cdm.remote.api.application.CdmApplicationController}
278 * object.
279 */
280 public static ICdmApplicationConfiguration getCurrentApplicationConfiguration() {
281 if (getDefault() != null) {
282 return getDefault().getApplicationConfiguration();
283 }
284 return null;
285 }
286
287 /*
288 * CONVERSATIONS
289 */
290
291 /**
292 * Creates a new conversation, binds resources to the conversation and start
293 * a transaction for this conversation.
294 *
295 * @return a {@link eu.etaxonomy.cdm.api.conversation.ConversationHolder}
296 * object.
297 */
298 public static ConversationHolder createConversation() {
299 ConversationHolder conversation = getCurrentApplicationConfiguration()
300 .NewConversation();
301 try {
302 conversation.startTransaction();
303 }catch(Exception e){
304 MessagingUtils.messageDialog("No database connection", CdmStore.class, "No database connection available", e);
305 }
306 return conversation;
307 }
308
309 //FIXME:Remoting should be removed after moving completely to remoting
310 private MockCdmEntitySessionManager mockCdmEntitySessionManager;
311
312 private ICdmEntitySessionManager getSessionManager() {
313 //FIXME:Remoting we should only have CdmApplicationRemoteConfiguration after move to remoting
314 // bad hack which should be finally removed
315 if(getCurrentApplicationConfiguration() instanceof CdmApplicationRemoteController) {
316 return ((CdmApplicationRemoteController)getCurrentApplicationConfiguration()).getCdmEntitySessionManager();
317 } else {
318 if(mockCdmEntitySessionManager == null) {
319 mockCdmEntitySessionManager = new MockCdmEntitySessionManager();
320 }
321 return mockCdmEntitySessionManager;
322 }
323 }
324
325 public static ICdmEntitySessionManager getCurrentSessionManager() {
326 if (getDefault() != null) {
327 return getDefault().getSessionManager();
328 }
329 return null;
330
331 }
332
333 /**
334 * Generic method that will scan the getters of {@link ICdmApplicationConfiguration} for the given service
335 * interface. If a matching getter is found the according service implementation is returned by
336 * invoking the getter otherwise the method returns <code>null</code>.
337 *
338 * @param <T>
339 * @param serviceClass
340 * @return the configured implementation of <code>serviceClass</code> or <code>null</code>
341 */
342 public static <T extends IService> T getService(Class<T> serviceClass) {
343 T service = null;
344 try {
345 service = CdmApplicationState.getService(serviceClass);
346 } catch (CdmApplicationException cae) {
347 MessagingUtils.error(CdmStore.class, cae);
348 }
349
350 return service;
351 }
352
353 /**
354 * @see #getService(Class)
355 * As ICommonService is not extending IService we need a specific request here
356 */
357 public static ICommonService getCommonService() {
358 return CdmApplicationState.getCommonService();
359
360 }
361
362 /**
363 * <p>
364 * getAuthenticationManager
365 * </p>
366 *
367 * @return a
368 * {@link org.springframework.security.authentication.ProviderManager}
369 * object.
370 */
371 public static AuthenticationManager getAuthenticationManager() {
372 return getCurrentApplicationConfiguration().getAuthenticationManager();
373 }
374
375 /**
376 * <p>
377 * getAuthenticationManager
378 * </p>
379 *
380 * @return a
381 * {@link ICdmPermissionEvaluator} object.
382 */
383 public static ICdmPermissionEvaluator getPermissionEvaluator() {
384 return getCurrentApplicationConfiguration().getPermissionEvaluator();
385 }
386
387
388 /*
389 * SECURITY RELATED CONVENIENCE METHODS
390 */
391
392 /**
393 * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.lang.Object, java.lang.Object)
394 *
395 * @param targetDomainObject
396 * @param permission
397 * @return
398 */
399 public static boolean currentAuthentiationHasPermission(CdmBase targetDomainObject, EnumSet<CRUD> permission){
400 //TODO use getCurrentApplicationConfiguration().currentAuthentiationHasPermission(CdmBase targetDomainObject, Operation permission) instead
401 SecurityContext context = SecurityContextHolder.getContext();
402 PermissionEvaluator pe = getPermissionEvaluator();
403 boolean hasPermission = false;
404 try {
405 hasPermission = getPermissionEvaluator().hasPermission(context.getAuthentication(), targetDomainObject,
406 permission);
407 } catch (org.springframework.security.access.AccessDeniedException e) {
408 /* IGNORE */
409 }
410 return hasPermission;
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(Class<? extends CdmBase> targetType, EnumSet<CRUD> permission){
421 boolean hasPermission = false;
422 try {
423 hasPermission = getPermissionEvaluator().hasPermission(getCurrentAuthentiation(), null, targetType.getName(), permission);
424 } catch (org.springframework.security.access.AccessDeniedException e) {
425 /* IGNORE */
426 }
427 return hasPermission;
428 }
429
430 public static boolean currentAuthentiationHasOneOfRoles(Role ... roles){
431 boolean hasPermission = false;
432 try {
433 hasPermission = getPermissionEvaluator().hasOneOfRoles(getCurrentAuthentiation(), roles);
434 } catch (org.springframework.security.access.AccessDeniedException e) {
435 /* IGNORE */
436 }
437 return hasPermission;
438 }
439
440 public static Authentication getCurrentAuthentiation() {
441 SecurityContext context = SecurityContextHolder.getContext();
442 return context.getAuthentication();
443 }
444
445 /*
446 * LANGUAGE
447 */
448
449 /**
450 * Provides access to the global default language set in the application preferences.
451 *
452 * @return a {@link eu.etaxonomy.cdm.model.common.Language} object.
453 */
454 public static Language getDefaultLanguage() {
455 if (getDefault().getLanguage() == null) {
456 getDefault().setLanguage(PreferencesUtil.getGlobalLanguage());
457 }
458 return getDefault().getLanguage();
459 }
460
461 /**
462 * <p>
463 * setDefaultLanguage
464 * </p>
465 *
466 * @param language
467 * a {@link eu.etaxonomy.cdm.model.common.Language} object.
468 */
469 public static void setDefaultLanguage(Language language) {
470 getDefault().setLanguage(language);
471 }
472
473 /**
474 * @return the language
475 */
476 private Language getLanguage() {
477 return language;
478 }
479
480 /**
481 * @param language
482 * the language to set
483 */
484 private void setLanguage(Language language) {
485 this.language = language;
486 }
487
488 /*
489 * LOGIN
490 */
491
492 /**
493 * <p>
494 * Getter for the field <code>loginManager</code>.
495 * </p>
496 *
497 * @return a {@link eu.etaxonomy.taxeditor.store.LoginManager} object.
498 */
499 public static LoginManager getLoginManager() {
500 return loginManager;
501 }
502
503 /**
504 * <p>
505 * Getter for the field <code>contextManager</code>.
506 * </p>
507 *
508 * @return a {@link eu.etaxonomy.taxeditor.store.ContextManager} object.
509 */
510 public static ContextManager getContextManager() {
511 return contextManager;
512 }
513
514 public static TermManager getTermManager() {
515 return termManager;
516 }
517
518 public static SearchManager getSearchManager() {
519 return searchManager;
520 }
521
522 public static EditorManager getEditorManager() {
523 return editorManager;
524 }
525
526 /*
527 * IMPORT/EXPORT FACTORIES
528 */
529
530 /**
531 * <p>
532 * Getter for the field <code>importHandler</code>.
533 * </p>
534 *
535 * @return a {@link eu.etaxonomy.taxeditor.io.ImportManager} object.
536 */
537 public static ImportManager getImportManager() {
538 return ImportManager.NewInstance(getCurrentApplicationConfiguration());
539 }
540
541 /**
542 * <p>
543 * Getter for the field <code>exportHandler</code>.
544 * </p>
545 *
546 * @return a {@link eu.etaxonomy.taxeditor.io.ExportManager} object.
547 */
548 public static ExportManager getExportManager() {
549 return ExportManager.NewInstance(getCurrentApplicationConfiguration());
550 }
551
552 /**
553 * Whether this CdmStore is currently connected to a datasource
554 *
555 * @return a boolean.
556 */
557 public static boolean isActive() {
558 return instance != null && instance.isConnected;
559 }
560
561 public static ICdmSource getActiveCdmSource() {
562 if (isActive()) {
563 return instance.getCdmSource();
564 }
565 return null;
566 }
567
568 /**
569 * <p>
570 * getDataSource
571 * </p>
572 *
573 * @return a {@link eu.etaxonomy.cdm.database.ICdmDataSource} object.
574 * @deprecated currently retained for backward compatibility - use {@link getActiveCdmSource()} instead
575 */
576 // public static ICdmDataSource getDataSource() {
577 // if (isActive()) {
578 // return (ICdmDataSource)instance.getCdmSource();
579 // }
580 // return null;
581 // }
582
583 /**
584 * @return
585 */
586 private ICdmSource getCdmSource() {
587 return cdmSource;
588 }
589
590 }