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