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