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