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