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