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