implementing GrantedAuthorityService for #2990 (implement missing parts of Groups...
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / application / CdmApplicationController.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10
11
12 package eu.etaxonomy.cdm.api.application;
13
14 import java.util.EnumSet;
15 import java.util.List;
16 import java.util.UUID;
17
18 import org.apache.log4j.Logger;
19 import org.hibernate.SessionFactory;
20 import org.springframework.beans.MutablePropertyValues;
21 import org.springframework.beans.factory.config.BeanDefinition;
22 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
23 import org.springframework.context.ApplicationListener;
24 import org.springframework.context.support.AbstractApplicationContext;
25 import org.springframework.core.io.ClassPathResource;
26 import org.springframework.core.io.Resource;
27 import org.springframework.security.access.PermissionEvaluator;
28 import org.springframework.security.authentication.ProviderManager;
29 import org.springframework.security.core.context.SecurityContext;
30 import org.springframework.security.core.context.SecurityContextHolder;
31 import org.springframework.transaction.PlatformTransactionManager;
32 import org.springframework.transaction.TransactionStatus;
33
34 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
35 import eu.etaxonomy.cdm.api.service.IAgentService;
36 import eu.etaxonomy.cdm.api.service.IClassificationService;
37 import eu.etaxonomy.cdm.api.service.ICollectionService;
38 import eu.etaxonomy.cdm.api.service.ICommonService;
39 import eu.etaxonomy.cdm.api.service.IDatabaseService;
40 import eu.etaxonomy.cdm.api.service.IDescriptionService;
41 import eu.etaxonomy.cdm.api.service.IFeatureNodeService;
42 import eu.etaxonomy.cdm.api.service.IFeatureTreeService;
43 import eu.etaxonomy.cdm.api.service.IGrantedAuthorityService;
44 import eu.etaxonomy.cdm.api.service.IGroupService;
45 import eu.etaxonomy.cdm.api.service.IIdentificationKeyService;
46 import eu.etaxonomy.cdm.api.service.ILocationService;
47 import eu.etaxonomy.cdm.api.service.IMediaService;
48 import eu.etaxonomy.cdm.api.service.INameService;
49 import eu.etaxonomy.cdm.api.service.IOccurrenceService;
50 import eu.etaxonomy.cdm.api.service.IPolytomousKeyNodeService;
51 import eu.etaxonomy.cdm.api.service.IPolytomousKeyService;
52 import eu.etaxonomy.cdm.api.service.IReferenceService;
53 import eu.etaxonomy.cdm.api.service.IService;
54 import eu.etaxonomy.cdm.api.service.ITaxonNodeService;
55 import eu.etaxonomy.cdm.api.service.ITaxonService;
56 import eu.etaxonomy.cdm.api.service.ITermService;
57 import eu.etaxonomy.cdm.api.service.IUserService;
58 import eu.etaxonomy.cdm.api.service.IVocabularyService;
59 import eu.etaxonomy.cdm.api.service.IWorkingSetService;
60 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
61 import eu.etaxonomy.cdm.common.monitor.NullProgressMonitor;
62 import eu.etaxonomy.cdm.common.monitor.SubProgressMonitor;
63 import eu.etaxonomy.cdm.database.CdmPersistentDataSource;
64 import eu.etaxonomy.cdm.database.DataSourceNotFoundException;
65 import eu.etaxonomy.cdm.database.DbSchemaValidation;
66 import eu.etaxonomy.cdm.database.ICdmDataSource;
67 import eu.etaxonomy.cdm.model.common.CdmBase;
68 import eu.etaxonomy.cdm.model.common.CdmMetaData;
69 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
70 import eu.etaxonomy.cdm.model.common.User;
71 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
72 import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;
73
74
75 /**
76 * @author a.mueller
77 *
78 */
79 public class CdmApplicationController implements ICdmApplicationConfiguration{
80 private static final Logger logger = Logger.getLogger(CdmApplicationController.class);
81
82 public static final String DEFAULT_APPLICATION_CONTEXT_RESOURCE = "/eu/etaxonomy/cdm/defaultApplicationContext.xml";
83
84 public AbstractApplicationContext applicationContext;
85 private ICdmApplicationConfiguration configuration;
86 private Resource applicationContextResource;
87
88 private IProgressMonitor progressMonitor;
89
90 final protected static DbSchemaValidation defaultDbSchemaValidation = DbSchemaValidation.VALIDATE;
91
92
93
94 /**
95 * Constructor, opens a spring ApplicationContext by using the default data source
96 * @throws DataSourceNotFoundException
97 */
98 public static CdmApplicationController NewInstance() throws DataSourceNotFoundException {
99 logger.info("Start CdmApplicationController with default data source");
100 CdmPersistentDataSource dataSource = getDefaultDatasource();
101 DbSchemaValidation dbSchemaValidation = defaultDbSchemaValidation;
102 return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, false);
103 }
104
105 /**
106 * Constructor, opens a spring ApplicationContext by using the default data source
107 * @param dbSchemaValidation validation type for database schema
108 * @throws DataSourceNotFoundException
109 */
110 public static CdmApplicationController NewInstance(DbSchemaValidation dbSchemaValidation) throws DataSourceNotFoundException {
111 logger.info("Start CdmApplicationController with default data source");
112 CdmPersistentDataSource dataSource = getDefaultDatasource();
113 return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, false);
114 }
115
116
117 /**
118 * Constructor, opens an spring ApplicationContext by using the according data source and the
119 * default database schema validation type
120 * @param dataSource
121 */
122 public static CdmApplicationController NewInstance(ICdmDataSource dataSource) {
123 return CdmApplicationController.NewInstance(null, dataSource, defaultDbSchemaValidation, false);
124 }
125
126 public static CdmApplicationController NewInstance(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation) {
127 return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, false);
128 }
129
130 public static CdmApplicationController NewInstance(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading) {
131 return CdmApplicationController.NewInstance(null, dataSource, dbSchemaValidation, omitTermLoading);
132 }
133
134 public static CdmApplicationController NewInstance(Resource applicationContextResource, ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading) {
135 return CdmApplicationController.NewInstance(applicationContextResource, dataSource, dbSchemaValidation, omitTermLoading, null);
136 }
137
138 public static CdmApplicationController NewInstance(Resource applicationContextResource, ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading, IProgressMonitor progressMonitor) {
139 return new CdmApplicationController(applicationContextResource, dataSource, dbSchemaValidation, omitTermLoading, progressMonitor, null);
140 }
141
142 //TODO discuss need for listeners before commit to trunk
143 // public static CdmApplicationController NewInstance(Resource applicationContextResource, ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading, IProgressMonitor progressMonitor, List<ApplicationListener> listeners) {
144 // return new CdmApplicationController(applicationContextResource, dataSource, dbSchemaValidation, omitTermLoading, progressMonitor,listeners);
145 // }
146
147
148 /**
149 * @return
150 */
151 protected static ClassPathResource getClasspathResource() {
152 return new ClassPathResource(DEFAULT_APPLICATION_CONTEXT_RESOURCE);
153 }
154
155 /**
156 * @return
157 * @throws DataSourceNotFoundException
158 */
159 protected static CdmPersistentDataSource getDefaultDatasource() throws DataSourceNotFoundException {
160 CdmPersistentDataSource dataSource = CdmPersistentDataSource.NewDefaultInstance();
161 return dataSource;
162 }
163
164
165 /**
166 * Constructor, opens an spring 2.5 ApplicationContext by using the according data source
167 * @param dataSource
168 * @param dbSchemaValidation
169 * @param omitTermLoading
170 */
171 protected CdmApplicationController(Resource applicationContextResource, ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading, IProgressMonitor progressMonitor, List<ApplicationListener> listeners){
172 logger.info("Start CdmApplicationController with datasource: " + dataSource.getName());
173
174 if (dbSchemaValidation == null){
175 dbSchemaValidation = defaultDbSchemaValidation;
176 }
177 this.applicationContextResource = applicationContextResource != null ? applicationContextResource : getClasspathResource();
178 this.progressMonitor = progressMonitor != null ? progressMonitor : new NullProgressMonitor();
179
180 setNewDataSource(dataSource, dbSchemaValidation, omitTermLoading, listeners);
181 }
182
183
184 /**
185 * Sets the application context to a new spring ApplicationContext by using the according data source and initializes the Controller.
186 * @param dataSource
187 */
188 private boolean setNewDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading, List<ApplicationListener> listeners){
189
190 if (dbSchemaValidation == null){
191 dbSchemaValidation = defaultDbSchemaValidation;
192 }
193 logger.info("Connecting to '" + dataSource.getName() + "'");
194
195 MonitoredGenericApplicationContext applicationContext = new MonitoredGenericApplicationContext();
196 int refreshTasks = 45;
197 int nTasks = 5 + refreshTasks;
198 // nTasks += applicationContext.countTasks();
199 progressMonitor.beginTask("Connecting to '" + dataSource.getName() + "'", nTasks);
200
201 // progressMonitor.worked(1);
202
203 BeanDefinition datasourceBean = dataSource.getDatasourceBean();
204 datasourceBean.setAttribute("isLazy", false);
205 progressMonitor.subTask("Registering datasource.");
206 applicationContext.registerBeanDefinition("dataSource", datasourceBean);
207 progressMonitor.worked(1);
208
209 BeanDefinition hibernatePropBean= dataSource.getHibernatePropertiesBean(dbSchemaValidation);
210 applicationContext.registerBeanDefinition("hibernateProperties", hibernatePropBean);
211
212 XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(applicationContext);
213 progressMonitor.subTask("Registering resources.");
214 xmlReader.loadBeanDefinitions(applicationContextResource);
215 progressMonitor.worked(1);
216
217 //omitTerms
218 if (omitTermLoading == true){
219 String initializerName = "persistentTermInitializer";
220 BeanDefinition beanDef = applicationContext.getBeanDefinition(initializerName);
221 MutablePropertyValues values = beanDef.getPropertyValues();
222 values.addPropertyValue("omit", omitTermLoading);
223 }
224
225 if (listeners != null){
226 for(ApplicationListener listener : listeners){
227 applicationContext.addApplicationListener(listener);
228 }
229 }
230
231 // String message = "Start application context. This might take a while ...";
232 //// progressMonitor.subTask(message);
233 // SubProgressMonitor subMonitor= new SubProgressMonitor(progressMonitor, 10);
234 // subMonitor.beginTask(message, 2);
235 // applicationContext.setProgressMonitor(subMonitor);
236
237 applicationContext.refresh(new SubProgressMonitor(progressMonitor, refreshTasks));
238 applicationContext.start();
239 // progressMonitor.worked(1);
240
241 progressMonitor.subTask("Cleaning up.");
242 setApplicationContext(applicationContext);
243 progressMonitor.worked(1);
244
245 //initialize user and metaData for new databases
246 int userCount = getUserService().count(User.class);
247 if (userCount == 0 ){
248 progressMonitor.subTask("Creating Admin User");
249 createAdminUser();
250 }
251 progressMonitor.worked(1);
252
253 //CDM Meta Data
254 int metaDataCount = getCommonService().getCdmMetaData().size();
255 if (metaDataCount == 0){
256 progressMonitor.subTask("Creating Meta Data");
257 createMetadata();
258 }
259 progressMonitor.worked(1);
260
261 progressMonitor.done();
262 return true;
263 }
264
265 protected void createAdminUser(){
266 User firstUser = User.NewInstance("admin", "00000");
267 getUserService().save(firstUser);
268 logger.info("Admin user created.");
269 }
270
271 protected void createMetadata(){
272 List<CdmMetaData> metaData = CdmMetaData.defaultMetaData();
273 getCommonService().saveAllMetaData(metaData);
274 logger.info("Metadata created.");
275 }
276
277
278 /**
279 * Tests if some DefinedTermsAreMissing.
280 * @return true, if at least one is missing, else false
281 */
282 public boolean testDefinedTermsAreMissing(){
283 UUID englishUuid = UUID.fromString("e9f8cdb7-6819-44e8-95d3-e2d0690c3523");
284 DefinedTermBase<?> english = this.getTermService().load(englishUuid);
285 if ( english == null || ! english.getUuid().equals(englishUuid)){
286 return true;
287 }else{
288 return false;
289 }
290 }
291
292
293 /**
294 * Changes the ApplicationContext to the new dataSource
295 * @param dataSource
296 */
297 public boolean changeDataSource(ICdmDataSource dataSource){
298 //logger.info("Change datasource to : " + dataSource);
299 return setNewDataSource(dataSource, DbSchemaValidation.VALIDATE, false, null);
300 }
301
302 /**
303 * Changes the ApplicationContext to the new dataSource
304 * @param dataSource
305 * @param dbSchemaValidation
306 */
307 public boolean changeDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation){
308 //logger.info("Change datasource to : " + dataSource);
309 return setNewDataSource(dataSource, dbSchemaValidation, false, null);
310 }
311
312 /**
313 * Changes the ApplicationContext to the new dataSource
314 * @param dataSource
315 * @param dbSchemaValidation
316 * @param omitTermLoading
317 */
318 public boolean changeDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading){
319 logger.info("Change datasource to : " + dataSource);
320 return setNewDataSource(dataSource, dbSchemaValidation, omitTermLoading, null);
321 }
322
323 /**
324 * Changes the ApplicationContext to the new dataSource
325 * @param dataSource
326 * @param dbSchemaValidation
327 * @param omitTermLoading
328 */
329 public boolean changeDataSource(ICdmDataSource dataSource, DbSchemaValidation dbSchemaValidation, boolean omitTermLoading, List<ApplicationListener> listeners){
330 logger.info("Change datasource to : " + dataSource);
331 return setNewDataSource(dataSource, dbSchemaValidation, omitTermLoading, listeners);
332 }
333
334 /**
335 * Sets a new application Context.
336 * @param ac
337 */
338 public void setApplicationContext(AbstractApplicationContext ac){
339 closeApplicationContext(); //closes old application context if necessary
340 applicationContext = ac;
341 applicationContext.registerShutdownHook();
342 init();
343 }
344
345 /* (non-Javadoc)
346 * @see java.lang.Object#finalize()
347 */
348 public void finalize(){
349 close();
350 }
351
352 /**
353 * closes the application
354 */
355 public void close(){
356 closeApplicationContext();
357 }
358
359 /**
360 * closes the application context
361 */
362 protected void closeApplicationContext(){
363 if (applicationContext != null){
364 logger.info("Close ApplicationContext");
365 applicationContext.close();
366 }
367 }
368
369 protected void init(){
370 logger.debug("Init " + this.getClass().getName() + " ... ");
371 if (logger.isDebugEnabled()){for (String beanName : applicationContext.getBeanDefinitionNames()){ logger.debug(beanName);}}
372 //TODO delete next row (was just for testing)
373 if (logger.isInfoEnabled()){
374 logger.info("Registered Beans: ");
375 String[] beanNames = applicationContext.getBeanDefinitionNames();
376 for (String beanName : beanNames){
377 logger.info(beanName);
378 }
379 }
380 configuration = (ICdmApplicationConfiguration)applicationContext.getBean("cdmApplicationDefaultConfiguration");
381 getDatabaseService().setApplicationController(this);
382 }
383
384
385
386 /* ****** Services *********/
387 public final INameService getNameService(){
388 return configuration.getNameService();
389 }
390
391 public final ITaxonService getTaxonService(){
392 return configuration.getTaxonService();
393 }
394
395 public final IClassificationService getClassificationService(){
396 return configuration.getClassificationService();
397 }
398
399 public final ITaxonNodeService getTaxonNodeService(){
400 return configuration.getTaxonNodeService();
401 }
402
403 public final IReferenceService getReferenceService(){
404 return configuration.getReferenceService();
405 }
406
407 public final IAgentService getAgentService(){
408 return configuration.getAgentService();
409 }
410
411 public final IDatabaseService getDatabaseService(){
412 return configuration.getDatabaseService();
413 }
414
415 public final ITermService getTermService(){
416 return configuration.getTermService();
417 }
418
419 public final IDescriptionService getDescriptionService(){
420 return configuration.getDescriptionService();
421 }
422
423 public final IOccurrenceService getOccurrenceService(){
424 return configuration.getOccurrenceService();
425 }
426
427 public final IMediaService getMediaService(){
428 return configuration.getMediaService();
429 }
430
431 public final ICommonService getCommonService(){
432 return configuration.getCommonService();
433 }
434
435 public final ILocationService getLocationService(){
436 return configuration.getLocationService();
437 }
438
439 public final IUserService getUserService(){
440 return configuration.getUserService();
441 }
442
443 public final IGrantedAuthorityService getGrantedAuthorityService(){
444 return configuration.getGrantedAuthorityService();
445 }
446
447 public IGroupService getGroupService() {
448 return configuration.getGroupService();
449 }
450
451 public final ICollectionService getCollectionService(){
452 return configuration.getCollectionService();
453 }
454
455 public final IFeatureTreeService getFeatureTreeService(){
456 return configuration.getFeatureTreeService();
457 }
458
459 public final IFeatureNodeService getFeatureNodeService(){
460 return configuration.getFeatureNodeService();
461 }
462
463 public final IVocabularyService getVocabularyService(){
464 return configuration.getVocabularyService();
465 }
466
467 public final IIdentificationKeyService getIdentificationKeyService(){
468 return configuration.getIdentificationKeyService();
469 }
470
471 public final IPolytomousKeyService getPolytomousKeyService(){
472 return configuration.getPolytomousKeyService();
473 }
474
475 public final IPolytomousKeyNodeService getPolytomousKeyNodeService(){
476 return configuration.getPolytomousKeyNodeService();
477 }
478
479 public final IService<CdmBase> getMainService(){
480 return configuration.getMainService();
481 }
482
483 public final IWorkingSetService getWorkingSetService(){
484 return configuration.getWorkingSetService();
485 }
486
487 public final ConversationHolder NewConversation(){
488 //return (ConversationHolder)applicationContext.getBean("conversationHolder");
489 return configuration.NewConversation();
490 }
491
492
493 /* **** Security ***** */
494
495 /* (non-Javadoc)
496 * @see eu.etaxonomy.cdm.api.application.ICdmApplicationConfiguration#getAuthenticationManager()
497 */
498 public final ProviderManager getAuthenticationManager(){
499 return configuration.getAuthenticationManager();
500 }
501
502
503 public PermissionEvaluator getPermissionEvaluator() {
504 return configuration.getPermissionEvaluator();
505 }
506
507 /**
508 * @see org.springframework.security.access.PermissionEvaluator#hasPermission(org.springframework.security.core.Authentication, java.lang.Object, java.lang.Object)
509 *
510 * @param targetDomainObject
511 * @param permission
512 * @return
513 */
514 public boolean currentAuthentiationHasPermissions(CdmBase targetDomainObject, EnumSet<CRUD> permission){
515 SecurityContext context = SecurityContextHolder.getContext();
516 return getPermissionEvaluator().hasPermission(context.getAuthentication(), targetDomainObject, permission);
517 }
518
519
520 @Override
521 public final PlatformTransactionManager getTransactionManager() {
522 return configuration.getTransactionManager();
523 }
524
525 public final Object getBean(String name){
526 return this.applicationContext.getBean(name);
527 }
528
529 /*
530 * OLD TRANSACTION STUFF
531 */
532
533 /* **** flush ***********/
534 public void flush() {
535 SessionFactory sf = (SessionFactory)applicationContext.getBean("sessionFactory");
536 sf.getCurrentSession().flush();
537 }
538
539 public SessionFactory getSessionFactory(){
540 return (SessionFactory)applicationContext.getBean("sessionFactory");
541 }
542
543 public TransactionStatus startTransaction() {
544 return startTransaction(false);
545 }
546
547 public TransactionStatus startTransaction(Boolean readOnly) {
548 return configuration.startTransaction(readOnly);
549 }
550
551 public void commitTransaction(TransactionStatus txStatus){
552 PlatformTransactionManager txManager = configuration.getTransactionManager();
553 txManager.commit(txStatus);
554 return;
555 }
556
557 }