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