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