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