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