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