Revision 97ee0157
Added by Andreas Müller over 8 years ago
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/CacheStrategyGenerator.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.cdm.persistence.hibernate; |
|
11 |
|
|
12 |
import java.util.Map; |
|
13 |
|
|
14 |
import org.apache.log4j.Logger; |
|
15 |
import org.hibernate.HibernateException; |
|
16 |
import org.hibernate.event.spi.MergeEvent; |
|
17 |
import org.hibernate.event.spi.MergeEventListener; |
|
18 |
import org.hibernate.event.spi.SaveOrUpdateEvent; |
|
19 |
import org.hibernate.event.spi.SaveOrUpdateEventListener; |
|
20 |
|
|
21 |
import eu.etaxonomy.cdm.model.agent.Team; |
|
22 |
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase; |
|
23 |
import eu.etaxonomy.cdm.model.common.CdmBase; |
|
24 |
import eu.etaxonomy.cdm.model.common.IdentifiableEntity; |
|
25 |
import eu.etaxonomy.cdm.model.molecular.Amplification; |
|
26 |
import eu.etaxonomy.cdm.model.name.NonViralName; |
|
27 |
import eu.etaxonomy.cdm.model.reference.Reference; |
|
28 |
|
|
29 |
/** |
|
30 |
* @author a.mueller |
|
31 |
* @created 04.03.2009 |
|
32 |
*/ |
|
33 |
public class CacheStrategyGenerator implements SaveOrUpdateEventListener, MergeEventListener { |
|
34 |
private static final long serialVersionUID = -5511287200489449838L; |
|
35 |
@SuppressWarnings("unused") |
|
36 |
private static final Logger logger = Logger.getLogger(CacheStrategyGenerator.class); |
|
37 |
|
|
38 |
@Override |
|
39 |
public void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException { |
|
40 |
Object entity = event.getObject(); |
|
41 |
saveOrUpdateOrMerge(entity); |
|
42 |
} |
|
43 |
|
|
44 |
/* (non-Javadoc) |
|
45 |
* @see org.hibernate.event.spi.MergeEventListener#onMerge(org.hibernate.event.spi.MergeEvent) |
|
46 |
*/ |
|
47 |
@Override |
|
48 |
public void onMerge(MergeEvent event) throws HibernateException { |
|
49 |
Object entity = event.getOriginal(); |
|
50 |
saveOrUpdateOrMerge(entity); |
|
51 |
} |
|
52 |
|
|
53 |
/* (non-Javadoc) |
|
54 |
* @see org.hibernate.event.spi.MergeEventListener#onMerge(org.hibernate.event.spi.MergeEvent, java.util.Map) |
|
55 |
*/ |
|
56 |
@Override |
|
57 |
public void onMerge(MergeEvent event, Map copiedAlready) throws HibernateException { |
|
58 |
|
|
59 |
} |
|
60 |
|
|
61 |
private void saveOrUpdateOrMerge(Object entity) { |
|
62 |
if (entity != null){ |
|
63 |
Class<?> entityClazz = entity.getClass(); |
|
64 |
|
|
65 |
//non-viral-name caches |
|
66 |
if(NonViralName.class.isAssignableFrom(entityClazz)) { |
|
67 |
NonViralName<?> nonViralName = (NonViralName<?>)entity; |
|
68 |
nonViralName.getAuthorshipCache(); |
|
69 |
nonViralName.getNameCache(); |
|
70 |
nonViralName.getTitleCache(); |
|
71 |
nonViralName.getFullTitleCache(); |
|
72 |
//team-or-person caches |
|
73 |
}else if(TeamOrPersonBase.class.isAssignableFrom(entityClazz)){ |
|
74 |
TeamOrPersonBase<?> teamOrPerson = (TeamOrPersonBase<?>)entity; |
|
75 |
String nomTitle = teamOrPerson.getNomenclaturalTitle(); |
|
76 |
if (teamOrPerson instanceof Team){ |
|
77 |
Team team =CdmBase.deproxy(teamOrPerson, Team.class); |
|
78 |
team.setNomenclaturalTitle(nomTitle, team.isProtectedNomenclaturalTitleCache()); //nomTitle is not necessarily cached when it is created |
|
79 |
}else{ |
|
80 |
teamOrPerson.setNomenclaturalTitle(nomTitle); |
|
81 |
} |
|
82 |
String titleCache = teamOrPerson.getTitleCache(); |
|
83 |
if (! teamOrPerson.isProtectedTitleCache()){ |
|
84 |
teamOrPerson.setTitleCache(titleCache, false); |
|
85 |
} |
|
86 |
|
|
87 |
//reference caches |
|
88 |
}else if(Reference.class.isAssignableFrom(entityClazz)){ |
|
89 |
Reference<?> ref = (Reference<?>)entity; |
|
90 |
ref.getAbbrevTitleCache(); |
|
91 |
ref.getTitleCache(); |
|
92 |
//title cache |
|
93 |
}else if(IdentifiableEntity.class.isAssignableFrom(entityClazz)) { |
|
94 |
IdentifiableEntity<?> identifiableEntity = (IdentifiableEntity)entity; |
|
95 |
identifiableEntity.getTitleCache(); |
|
96 |
}else if(Amplification.class.isAssignableFrom(entityClazz)) { |
|
97 |
Amplification amplification = (Amplification)entity; |
|
98 |
amplification.updateCache(); |
|
99 |
} |
|
100 |
|
|
101 |
} |
|
102 |
} |
|
103 |
} |
|
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.cdm.persistence.hibernate; |
|
11 |
|
|
12 |
import java.util.Map; |
|
13 |
|
|
14 |
import org.apache.log4j.Logger; |
|
15 |
import org.hibernate.HibernateException; |
|
16 |
import org.hibernate.event.spi.MergeEvent; |
|
17 |
import org.hibernate.event.spi.MergeEventListener; |
|
18 |
import org.hibernate.event.spi.SaveOrUpdateEvent; |
|
19 |
import org.hibernate.event.spi.SaveOrUpdateEventListener; |
|
20 |
|
|
21 |
/** |
|
22 |
* @author a.mueller |
|
23 |
* @created 04.03.2009 |
|
24 |
*/ |
|
25 |
public class CacheStrategyGenerator implements SaveOrUpdateEventListener, MergeEventListener { |
|
26 |
private static final long serialVersionUID = -5511287200489449838L; |
|
27 |
@SuppressWarnings("unused") |
|
28 |
private static final Logger logger = Logger.getLogger(CacheStrategyGenerator.class); |
|
29 |
|
|
30 |
@Override |
|
31 |
public void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException { |
|
32 |
Object entity = event.getObject(); |
|
33 |
saveOrUpdateOrMerge(entity); |
|
34 |
} |
|
35 |
|
|
36 |
@Override |
|
37 |
public void onMerge(MergeEvent event) throws HibernateException { |
|
38 |
Object entity = event.getOriginal(); |
|
39 |
saveOrUpdateOrMerge(entity); |
|
40 |
} |
|
41 |
|
|
42 |
@Override |
|
43 |
public void onMerge(MergeEvent event, Map copiedAlready) throws HibernateException { |
|
44 |
|
|
45 |
} |
|
46 |
|
|
47 |
private void saveOrUpdateOrMerge(Object entity) { |
|
48 |
CdmPreDataChangeObservableListener.generateCaches(entity); |
|
49 |
//moved to CdmPreDataChangeObservableListener |
|
50 |
// if (entity != null){ |
|
51 |
// Class<?> entityClazz = entity.getClass(); |
|
52 |
// |
|
53 |
// //non-viral-name caches |
|
54 |
// if(NonViralName.class.isAssignableFrom(entityClazz)) { |
|
55 |
// NonViralName<?> nonViralName = (NonViralName<?>)entity; |
|
56 |
// nonViralName.getAuthorshipCache(); |
|
57 |
// nonViralName.getNameCache(); |
|
58 |
// nonViralName.getTitleCache(); |
|
59 |
// nonViralName.getFullTitleCache(); |
|
60 |
// //team-or-person caches |
|
61 |
// }else if(TeamOrPersonBase.class.isAssignableFrom(entityClazz)){ |
|
62 |
// TeamOrPersonBase<?> teamOrPerson = (TeamOrPersonBase<?>)entity; |
|
63 |
// String nomTitle = teamOrPerson.getNomenclaturalTitle(); |
|
64 |
// if (teamOrPerson instanceof Team){ |
|
65 |
// Team team =CdmBase.deproxy(teamOrPerson, Team.class); |
|
66 |
// team.setNomenclaturalTitle(nomTitle, team.isProtectedNomenclaturalTitleCache()); //nomTitle is not necessarily cached when it is created |
|
67 |
// }else{ |
|
68 |
// teamOrPerson.setNomenclaturalTitle(nomTitle); |
|
69 |
// } |
|
70 |
// String titleCache = teamOrPerson.getTitleCache(); |
|
71 |
// if (! teamOrPerson.isProtectedTitleCache()){ |
|
72 |
// teamOrPerson.setTitleCache(titleCache, false); |
|
73 |
// } |
|
74 |
// |
|
75 |
// //reference caches |
|
76 |
// }else if(Reference.class.isAssignableFrom(entityClazz)){ |
|
77 |
// Reference<?> ref = (Reference<?>)entity; |
|
78 |
// ref.getAbbrevTitleCache(); |
|
79 |
// ref.getTitleCache(); |
|
80 |
// //title cache |
|
81 |
// }else if(IdentifiableEntity.class.isAssignableFrom(entityClazz)) { |
|
82 |
// IdentifiableEntity<?> identifiableEntity = (IdentifiableEntity)entity; |
|
83 |
// identifiableEntity.getTitleCache(); |
|
84 |
// }else if(Amplification.class.isAssignableFrom(entityClazz)) { |
|
85 |
// Amplification amplification = (Amplification)entity; |
|
86 |
// amplification.updateCache(); |
|
87 |
// } |
|
88 |
// |
|
89 |
// } |
|
90 |
} |
|
91 |
} |
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/CdmListenerIntegrator.java | ||
---|---|---|
1 |
/** |
|
2 |
* |
|
3 |
*/ |
|
4 |
package eu.etaxonomy.cdm.persistence.hibernate; |
|
5 |
|
|
6 |
import org.apache.log4j.Logger; |
|
7 |
import org.hibernate.cfg.Configuration; |
|
8 |
import org.hibernate.engine.spi.SessionFactoryImplementor; |
|
9 |
import org.hibernate.event.service.spi.EventListenerRegistry; |
|
10 |
import org.hibernate.event.spi.EventType; |
|
11 |
import org.hibernate.integrator.spi.Integrator; |
|
12 |
import org.hibernate.metamodel.source.MetadataImplementor; |
|
13 |
import org.hibernate.service.spi.SessionFactoryServiceRegistry; |
|
14 |
|
|
15 |
/** |
|
16 |
* @author a.mueller |
|
17 |
* @created 30.03.2013 |
|
18 |
* |
|
19 |
*/ |
|
20 |
public class CdmListenerIntegrator implements Integrator { |
|
21 |
private static final Logger logger = Logger.getLogger(CdmListenerIntegrator.class); |
|
22 |
|
|
23 |
|
|
24 |
/* |
|
25 |
* (non-Javadoc) |
|
26 |
* |
|
27 |
* @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.cfg.Configuration, |
|
28 |
* org.hibernate.engine.spi.SessionFactoryImplementor, |
|
29 |
* org.hibernate.service.spi.SessionFactoryServiceRegistry) |
|
30 |
*/ |
|
31 |
@Override |
|
32 |
public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry){ |
|
33 |
if (logger.isInfoEnabled()) { |
|
34 |
logger.info("Registering event listeners"); |
|
35 |
} |
|
36 |
|
|
37 |
final EventListenerRegistry eventRegistry = serviceRegistry.getService(EventListenerRegistry.class); |
|
38 |
|
|
39 |
//duplication strategy |
|
40 |
eventRegistry.addDuplicationStrategy(CdmListenerDuplicationStrategy.NewInstance); |
|
41 |
|
|
42 |
// ValidationExecutor validationExecutor = new ValidationExecutor(); |
|
43 |
// Level2ValidationEventListener l2Listener = new Level2ValidationEventListener(); |
|
44 |
// l2Listener.setValidationExecutor(validationExecutor); |
|
45 |
// Level3ValidationEventListener l3Listener = new Level3ValidationEventListener(); |
|
46 |
// l3Listener.setValidationExecutor(validationExecutor); |
|
47 |
|
|
48 |
// prepend to register before or append to register after |
|
49 |
// this example will register a persist event listener |
|
50 |
//eventRegistry.prependListeners(EventType.SAVE, new CacheStrategyGenerator(), new SaveEntityListener()); |
|
51 |
eventRegistry.prependListeners(EventType.UPDATE, new CacheStrategyGenerator(), new UpdateEntityListener()); |
|
52 |
|
|
53 |
eventRegistry.prependListeners(EventType.SAVE_UPDATE, new CacheStrategyGenerator(), new SaveOrUpdateorMergeEntityListener()); |
|
54 |
eventRegistry.prependListeners(EventType.MERGE, new CacheStrategyGenerator(), new SaveOrUpdateorMergeEntityListener()); |
|
55 |
|
|
56 |
// eventRegistry.prependListeners(EventType.SAVE_UPDATE, new CacheStrategyGenerator(), new SaveOrUpdateEntityListener()); |
|
57 |
//TODO Cherian move to SaveOrUpdateorMergeEntityListener |
|
58 |
eventRegistry.appendListeners(EventType.MERGE, new PostMergeEntityListener()); |
|
59 |
|
|
60 |
eventRegistry.appendListeners(EventType.DELETE, new CdmDeleteListener()); |
|
61 |
eventRegistry.appendListeners(EventType.POST_LOAD, new CdmPostDataChangeObservableListener()); |
|
62 |
//with validation |
|
63 |
// eventRegistry.appendListeners(EventType.POST_INSERT, new CdmPostDataChangeObservableListener(), l2Listener, l3Listener); |
|
64 |
// eventRegistry.appendListeners(EventType.POST_UPDATE, new CdmPostDataChangeObservableListener(), l2Listener, l3Listener); |
|
65 |
// eventRegistry.appendListeners(EventType.POST_DELETE, new CdmPostDataChangeObservableListener(), l3Listener); |
|
66 |
//without validation |
|
67 |
eventRegistry.appendListeners(EventType.POST_INSERT, new CdmPostDataChangeObservableListener()); |
|
68 |
eventRegistry.appendListeners(EventType.POST_UPDATE, new CdmPostDataChangeObservableListener()); |
|
69 |
eventRegistry.appendListeners(EventType.POST_DELETE, new CdmPostDataChangeObservableListener()); |
|
70 |
|
|
71 |
eventRegistry.appendListeners(EventType.PRE_INSERT, new CdmPreDataChangeObservableListener()); |
|
72 |
eventRegistry.appendListeners(EventType.PRE_UPDATE, new CdmPreDataChangeObservableListener()); |
|
73 |
} |
|
74 |
|
|
75 |
|
|
76 |
/* |
|
77 |
* (non-Javadoc) |
|
78 |
* |
|
79 |
* @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.metamodel.source. |
|
80 |
* MetadataImplementor, org.hibernate.engine.spi.SessionFactoryImplementor, |
|
81 |
* org.hibernate.service.spi.SessionFactoryServiceRegistry) |
|
82 |
*/ |
|
83 |
@Override |
|
84 |
public void integrate(MetadataImplementor metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry){ |
|
85 |
//nothing to do for now |
|
86 |
logger.warn("Metadata integrate not yet implemented"); |
|
87 |
} |
|
88 |
|
|
89 |
|
|
90 |
/* |
|
91 |
* (non-Javadoc) |
|
92 |
* |
|
93 |
* @see org.hibernate.integrator.spi.Integrator#disintegrate(org.hibernate.engine.spi. |
|
94 |
* SessionFactoryImplementor, org.hibernate.service.spi.SessionFactoryServiceRegistry) |
|
95 |
*/ |
|
96 |
@Override |
|
97 |
public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) |
|
98 |
{ |
|
99 |
//nothing to do for now |
|
100 |
logger.warn("Disintegrate not yet implemented"); |
|
101 |
} |
|
102 |
|
|
103 |
} |
|
1 |
/** |
|
2 |
* |
|
3 |
*/ |
|
4 |
package eu.etaxonomy.cdm.persistence.hibernate; |
|
5 |
|
|
6 |
import org.apache.log4j.Logger; |
|
7 |
import org.hibernate.cfg.Configuration; |
|
8 |
import org.hibernate.engine.spi.SessionFactoryImplementor; |
|
9 |
import org.hibernate.event.service.spi.EventListenerRegistry; |
|
10 |
import org.hibernate.event.spi.EventType; |
|
11 |
import org.hibernate.integrator.spi.Integrator; |
|
12 |
import org.hibernate.metamodel.source.MetadataImplementor; |
|
13 |
import org.hibernate.service.spi.SessionFactoryServiceRegistry; |
|
14 |
|
|
15 |
/** |
|
16 |
* @author a.mueller |
|
17 |
* @created 30.03.2013 |
|
18 |
* |
|
19 |
*/ |
|
20 |
public class CdmListenerIntegrator implements Integrator { |
|
21 |
private static final Logger logger = Logger.getLogger(CdmListenerIntegrator.class); |
|
22 |
|
|
23 |
|
|
24 |
/* |
|
25 |
* (non-Javadoc) |
|
26 |
* |
|
27 |
* @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.cfg.Configuration, |
|
28 |
* org.hibernate.engine.spi.SessionFactoryImplementor, |
|
29 |
* org.hibernate.service.spi.SessionFactoryServiceRegistry) |
|
30 |
*/ |
|
31 |
@Override |
|
32 |
public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry){ |
|
33 |
if (logger.isInfoEnabled()) { |
|
34 |
logger.info("Registering event listeners"); |
|
35 |
} |
|
36 |
|
|
37 |
final EventListenerRegistry eventRegistry = serviceRegistry.getService(EventListenerRegistry.class); |
|
38 |
|
|
39 |
//duplication strategy |
|
40 |
eventRegistry.addDuplicationStrategy(CdmListenerDuplicationStrategy.NewInstance); |
|
41 |
|
|
42 |
// ValidationExecutor validationExecutor = new ValidationExecutor(); |
|
43 |
// Level2ValidationEventListener l2Listener = new Level2ValidationEventListener(); |
|
44 |
// l2Listener.setValidationExecutor(validationExecutor); |
|
45 |
// Level3ValidationEventListener l3Listener = new Level3ValidationEventListener(); |
|
46 |
// l3Listener.setValidationExecutor(validationExecutor); |
|
47 |
|
|
48 |
// prepend to register before or append to register after |
|
49 |
// this example will register a persist event listener |
|
50 |
eventRegistry.prependListeners(EventType.SAVE, new CacheStrategyGenerator(), new SaveEntityListener()); |
|
51 |
eventRegistry.prependListeners(EventType.UPDATE, new CacheStrategyGenerator(), new UpdateEntityListener()); |
|
52 |
|
|
53 |
eventRegistry.prependListeners(EventType.SAVE_UPDATE, new CacheStrategyGenerator(), new SaveOrUpdateorMergeEntityListener()); |
|
54 |
eventRegistry.prependListeners(EventType.MERGE, new CacheStrategyGenerator(), new SaveOrUpdateorMergeEntityListener()); |
|
55 |
|
|
56 |
// eventRegistry.prependListeners(EventType.SAVE_UPDATE, new CacheStrategyGenerator(), new SaveOrUpdateEntityListener()); |
|
57 |
//TODO Cherian move to SaveOrUpdateorMergeEntityListener |
|
58 |
eventRegistry.appendListeners(EventType.MERGE, new PostMergeEntityListener()); |
|
59 |
|
|
60 |
eventRegistry.appendListeners(EventType.DELETE, new CdmDeleteListener()); |
|
61 |
eventRegistry.appendListeners(EventType.POST_LOAD, new CdmPostDataChangeObservableListener()); |
|
62 |
//with validation |
|
63 |
// eventRegistry.appendListeners(EventType.POST_INSERT, new CdmPostDataChangeObservableListener(), l2Listener, l3Listener); |
|
64 |
// eventRegistry.appendListeners(EventType.POST_UPDATE, new CdmPostDataChangeObservableListener(), l2Listener, l3Listener); |
|
65 |
// eventRegistry.appendListeners(EventType.POST_DELETE, new CdmPostDataChangeObservableListener(), l3Listener); |
|
66 |
//without validation |
|
67 |
eventRegistry.appendListeners(EventType.POST_INSERT, new CdmPostDataChangeObservableListener()); |
|
68 |
eventRegistry.appendListeners(EventType.POST_UPDATE, new CdmPostDataChangeObservableListener()); |
|
69 |
eventRegistry.appendListeners(EventType.POST_DELETE, new CdmPostDataChangeObservableListener()); |
|
70 |
|
|
71 |
eventRegistry.appendListeners(EventType.PRE_INSERT, new CdmPreDataChangeObservableListener()); |
|
72 |
eventRegistry.appendListeners(EventType.PRE_UPDATE, new CdmPreDataChangeObservableListener()); |
|
73 |
} |
|
74 |
|
|
75 |
|
|
76 |
/* |
|
77 |
* (non-Javadoc) |
|
78 |
* |
|
79 |
* @see org.hibernate.integrator.spi.Integrator#integrate(org.hibernate.metamodel.source. |
|
80 |
* MetadataImplementor, org.hibernate.engine.spi.SessionFactoryImplementor, |
|
81 |
* org.hibernate.service.spi.SessionFactoryServiceRegistry) |
|
82 |
*/ |
|
83 |
@Override |
|
84 |
public void integrate(MetadataImplementor metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry){ |
|
85 |
//nothing to do for now |
|
86 |
logger.warn("Metadata integrate not yet implemented"); |
|
87 |
} |
|
88 |
|
|
89 |
|
|
90 |
/* |
|
91 |
* (non-Javadoc) |
|
92 |
* |
|
93 |
* @see org.hibernate.integrator.spi.Integrator#disintegrate(org.hibernate.engine.spi. |
|
94 |
* SessionFactoryImplementor, org.hibernate.service.spi.SessionFactoryServiceRegistry) |
|
95 |
*/ |
|
96 |
@Override |
|
97 |
public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) |
|
98 |
{ |
|
99 |
//nothing to do for now |
|
100 |
logger.warn("Disintegrate not yet implemented"); |
|
101 |
} |
|
102 |
|
|
103 |
} |
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/CdmPreDataChangeObservableListener.java | ||
---|---|---|
9 | 9 |
*/ |
10 | 10 |
package eu.etaxonomy.cdm.persistence.hibernate; |
11 | 11 |
|
12 |
import java.util.List; |
|
13 |
|
|
12 | 14 |
import org.hibernate.event.spi.PreInsertEvent; |
13 | 15 |
import org.hibernate.event.spi.PreInsertEventListener; |
14 | 16 |
import org.hibernate.event.spi.PreUpdateEvent; |
... | ... | |
17 | 19 |
import org.springframework.security.core.Authentication; |
18 | 20 |
import org.springframework.security.core.context.SecurityContextHolder; |
19 | 21 |
|
22 |
import eu.etaxonomy.cdm.model.agent.Team; |
|
23 |
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase; |
|
24 |
import eu.etaxonomy.cdm.model.common.CdmBase; |
|
20 | 25 |
import eu.etaxonomy.cdm.model.common.ICdmBase; |
26 |
import eu.etaxonomy.cdm.model.common.ITreeNode; |
|
27 |
import eu.etaxonomy.cdm.model.common.IdentifiableEntity; |
|
21 | 28 |
import eu.etaxonomy.cdm.model.common.User; |
22 | 29 |
import eu.etaxonomy.cdm.model.common.VersionableEntity; |
30 |
import eu.etaxonomy.cdm.model.molecular.Amplification; |
|
31 |
import eu.etaxonomy.cdm.model.name.NonViralName; |
|
32 |
import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent; |
|
33 |
import eu.etaxonomy.cdm.model.reference.Reference; |
|
23 | 34 |
|
24 | 35 |
/** |
25 | 36 |
* @author cmathew |
... | ... | |
27 | 38 |
* |
28 | 39 |
*/ |
29 | 40 |
public class CdmPreDataChangeObservableListener implements PreInsertEventListener, PreUpdateEventListener { |
41 |
private static final long serialVersionUID = -7581071903134036209L; |
|
42 |
|
|
43 |
static String sep = ITreeNode.separator; |
|
44 |
static String pref = ITreeNode.treePrefix; |
|
30 | 45 |
|
31 |
/* (non-Javadoc) |
|
32 |
* @see org.hibernate.event.spi.PreUpdateEventListener#onPreUpdate(org.hibernate.event.spi.PreUpdateEvent) |
|
33 |
*/ |
|
34 | 46 |
@Override |
35 | 47 |
public boolean onPreUpdate(PreUpdateEvent event) { |
36 | 48 |
try { |
... | ... | |
44 | 56 |
versionableEntity.setUpdatedBy(user); |
45 | 57 |
} |
46 | 58 |
} |
59 |
insertUpdateMerge(event.getEntity()); |
|
47 | 60 |
} finally { |
48 | 61 |
return false; |
49 | 62 |
} |
50 | 63 |
} |
51 | 64 |
|
52 |
/* (non-Javadoc) |
|
53 |
* @see org.hibernate.event.spi.PreInsertEventListener#onPreInsert(org.hibernate.event.spi.PreInsertEvent) |
|
54 |
*/ |
|
55 | 65 |
@Override |
56 | 66 |
public boolean onPreInsert(PreInsertEvent event) { |
57 | 67 |
try { |
... | ... | |
71 | 81 |
} |
72 | 82 |
} |
73 | 83 |
} |
84 |
insertUpdateMerge(entity); |
|
74 | 85 |
} finally { |
75 | 86 |
return false; |
76 | 87 |
} |
77 | 88 |
|
78 | 89 |
} |
79 | 90 |
|
91 |
//from former SaveOrUpdateOrMergeEntityListener |
|
92 |
public static void insertUpdateMerge(Object entity){ |
|
93 |
if(entity != null && CdmBase.class.isAssignableFrom(entity.getClass())){ |
|
94 |
generateTreeIndex(entity); |
|
95 |
cacheDeterminationNames(entity); |
|
96 |
generateCaches(entity); |
|
97 |
} |
|
98 |
} |
|
99 |
|
|
100 |
private static void cacheDeterminationNames(Object entity) { |
|
101 |
if (entity instanceof DeterminationEvent) { |
|
102 |
DeterminationEvent detEv = (DeterminationEvent)entity; |
|
103 |
if (detEv.getTaxon() != null && detEv.getTaxonName() == null && detEv.getTaxon().getName() != null){ |
|
104 |
detEv.setTaxonName(detEv.getTaxon().getName()); |
|
105 |
} |
|
106 |
} |
|
107 |
} |
|
108 |
|
|
109 |
private static void generateTreeIndex(Object entity) { |
|
110 |
if (entity instanceof ITreeNode) { |
|
111 |
ITreeNode<?> node = (ITreeNode<?>)entity; |
|
112 |
reindex(node); |
|
113 |
|
|
114 |
} |
|
115 |
} |
|
116 |
|
|
117 |
public static void generateCaches(Object entity){ |
|
118 |
if (entity != null){ |
|
119 |
Class<?> entityClazz = entity.getClass(); |
|
120 |
|
|
121 |
//non-viral-name caches |
|
122 |
if(NonViralName.class.isAssignableFrom(entityClazz)) { |
|
123 |
NonViralName<?> nonViralName = (NonViralName<?>)entity; |
|
124 |
nonViralName.getAuthorshipCache(); |
|
125 |
nonViralName.getNameCache(); |
|
126 |
nonViralName.getTitleCache(); |
|
127 |
nonViralName.getFullTitleCache(); |
|
128 |
//team-or-person caches |
|
129 |
}else if(TeamOrPersonBase.class.isAssignableFrom(entityClazz)){ |
|
130 |
TeamOrPersonBase<?> teamOrPerson = (TeamOrPersonBase<?>)entity; |
|
131 |
String nomTitle = teamOrPerson.getNomenclaturalTitle(); |
|
132 |
if (teamOrPerson instanceof Team){ |
|
133 |
Team team =CdmBase.deproxy(teamOrPerson, Team.class); |
|
134 |
team.setNomenclaturalTitle(nomTitle, team.isProtectedNomenclaturalTitleCache()); //nomTitle is not necessarily cached when it is created |
|
135 |
}else{ |
|
136 |
teamOrPerson.setNomenclaturalTitle(nomTitle); |
|
137 |
} |
|
138 |
String titleCache = teamOrPerson.getTitleCache(); |
|
139 |
if (! teamOrPerson.isProtectedTitleCache()){ |
|
140 |
teamOrPerson.setTitleCache(titleCache, false); |
|
141 |
} |
|
142 |
|
|
143 |
//reference caches |
|
144 |
}else if(Reference.class.isAssignableFrom(entityClazz)){ |
|
145 |
Reference<?> ref = (Reference<?>)entity; |
|
146 |
ref.getAbbrevTitleCache(); |
|
147 |
ref.getTitleCache(); |
|
148 |
//title cache |
|
149 |
}else if(IdentifiableEntity.class.isAssignableFrom(entityClazz)) { |
|
150 |
IdentifiableEntity<?> identifiableEntity = (IdentifiableEntity)entity; |
|
151 |
identifiableEntity.getTitleCache(); |
|
152 |
}else if(Amplification.class.isAssignableFrom(entityClazz)) { |
|
153 |
Amplification amplification = (Amplification)entity; |
|
154 |
amplification.updateCache(); |
|
155 |
} |
|
156 |
|
|
157 |
} |
|
158 |
} |
|
159 |
|
|
160 |
/** |
|
161 |
* @param event |
|
162 |
* @param node |
|
163 |
*/ |
|
164 |
private static <T extends ITreeNode> void reindex(T node) { |
|
165 |
String oldChildIndex = node.treeIndex(); |
|
166 |
ITreeNode<?> parent = node.getParent(); |
|
167 |
String parentIndex = (parent == null) ? (sep + pref + node.treeId() + sep) : parent.treeIndex(); //TODO |
|
168 |
if (node.getId() > 0){ //TODO |
|
169 |
String newChildIndex = parentIndex + node.getId() + sep; |
|
170 |
if (oldChildIndex == null || ! oldChildIndex.equals(newChildIndex)){ |
|
171 |
node.setTreeIndex(newChildIndex); |
|
172 |
|
|
173 |
//TODO this is a greedy implementation, better use update by replace string |
|
174 |
//either using and improving the below code or by using native SQL |
|
175 |
//The current approach may run out of memory for large descendant sets. |
|
176 |
List<T> childNodes = node.getChildNodes(); |
|
177 |
for (T child : childNodes){ |
|
178 |
if (child != null && ! child.equals(node)){ //node should not be it's own child, however just in case |
|
179 |
reindex(child); |
|
180 |
} |
|
181 |
} |
|
182 |
|
|
183 |
// String className = event.getEntityName(); |
|
184 |
// String updateQuery = " UPDATE %s tn " + |
|
185 |
// " SET tn.treeIndex = Replace(tn.treeIndex, '%s', '%s') " + |
|
186 |
// " WHERE tn.id <> "+ node.getId()+" "; |
|
187 |
// updateQuery = String.format(updateQuery, className, oldChildIndex, parentIndex); //dummy |
|
188 |
// System.out.println(updateQuery); |
|
189 |
// EventSource session = event.getSession(); |
|
190 |
// Query query = session.createQuery(updateQuery); |
|
191 |
// query.executeUpdate(); |
|
192 |
} |
|
193 |
} |
|
194 |
} |
|
195 |
|
|
80 | 196 |
} |
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/CdmSecurityHibernateInterceptor.java | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (C) 2011 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 |
package eu.etaxonomy.cdm.persistence.hibernate; |
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
import java.io.Serializable; |
|
14 |
import java.util.EnumSet; |
|
15 |
import java.util.HashMap; |
|
16 |
import java.util.HashSet; |
|
17 |
import java.util.Map; |
|
18 |
import java.util.Set; |
|
19 |
|
|
20 |
import org.apache.commons.lang.ArrayUtils; |
|
21 |
import org.apache.log4j.Logger; |
|
22 |
import org.hibernate.EmptyInterceptor; |
|
23 |
import org.hibernate.type.Type; |
|
24 |
import org.springframework.security.core.context.SecurityContextHolder; |
|
25 |
import org.springframework.stereotype.Component; |
|
26 |
|
|
27 |
import eu.etaxonomy.cdm.database.PermissionDeniedException; |
|
28 |
import eu.etaxonomy.cdm.model.CdmBaseType; |
|
29 |
import eu.etaxonomy.cdm.model.common.CdmBase; |
|
30 |
import eu.etaxonomy.cdm.model.common.IPublishable; |
|
31 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD; |
|
32 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator; |
|
33 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation; |
|
34 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.Role; |
|
35 |
/** |
|
36 |
* @author k.luther |
|
37 |
* @author a.kohlbecker |
|
38 |
* |
|
39 |
*/ |
|
40 |
@Component |
|
41 |
public class CdmSecurityHibernateInterceptor extends EmptyInterceptor { |
|
42 |
|
|
43 |
private static final long serialVersionUID = 8477758472369568074L; |
|
44 |
|
|
45 |
public static final Logger logger = Logger.getLogger(CdmSecurityHibernateInterceptor.class); |
|
46 |
|
|
47 |
|
|
48 |
private CdmPermissionEvaluator permissionEvaluator; |
|
49 |
|
|
50 |
public CdmPermissionEvaluator getPermissionEvaluator() { |
|
51 |
return permissionEvaluator; |
|
52 |
} |
|
53 |
|
|
54 |
public void setPermissionEvaluator(CdmPermissionEvaluator permissionEvaluator) { |
|
55 |
this.permissionEvaluator = permissionEvaluator; |
|
56 |
} |
|
57 |
|
|
58 |
/** |
|
59 |
* The exculdeMap must map every property to the CdmBase type !!! |
|
60 |
*/ |
|
61 |
public static final Map<Class<? extends CdmBase>, Set<String>> exculdeMap = new HashMap<Class<? extends CdmBase>, Set<String>>(); |
|
62 |
|
|
63 |
static{ |
|
64 |
// disabled since no longer needed, see https://dev.e-taxonomy.eu/trac/ticket/4111#comment:8 |
|
65 |
// exculdeMap.put(TaxonNameBase.class, new HashSet<String>()); |
|
66 |
|
|
67 |
/* |
|
68 |
* default fields required for each type for which excludes are defined |
|
69 |
*/ |
|
70 |
// exculdeMap.get(TaxonNameBase.class).add("updatedBy"); |
|
71 |
// exculdeMap.get(TaxonNameBase.class).add("created"); |
|
72 |
// exculdeMap.get(TaxonNameBase.class).add("updated"); |
|
73 |
|
|
74 |
/* |
|
75 |
* the specific excludes |
|
76 |
*/ |
|
77 |
// exculdeMap.get(TaxonNameBase.class).add("taxonBases"); |
|
78 |
} |
|
79 |
|
|
80 |
|
|
81 |
/* (non-Javadoc) |
|
82 |
* @see org.hibernate.EmptyInterceptor#onSave(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.String[], org.hibernate.type.Type[]) |
|
83 |
*/ |
|
84 |
@Override |
|
85 |
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] type) { |
|
86 |
|
|
87 |
if (SecurityContextHolder.getContext().getAuthentication() == null || !(entity instanceof CdmBase)) { |
|
88 |
return true; |
|
89 |
} |
|
90 |
// evaluate throws EvaluationFailedException |
|
91 |
checkPermissions((CdmBase) entity, Operation.CREATE); |
|
92 |
logger.debug("permission check suceeded - object creation granted"); |
|
93 |
return true; |
|
94 |
} |
|
95 |
|
|
96 |
|
|
97 |
/* (non-Javadoc) |
|
98 |
* @see org.hibernate.EmptyInterceptor#onFlushDirty(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.Object[], java.lang.String[], org.hibernate.type.Type[]) |
|
99 |
*/ |
|
100 |
@Override |
|
101 |
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { |
|
102 |
|
|
103 |
if (SecurityContextHolder.getContext().getAuthentication() == null || !(entity instanceof CdmBase)) { |
|
104 |
return true; |
|
105 |
} |
|
106 |
CdmBase cdmEntity = (CdmBase) entity; |
|
107 |
if (previousState == null){ |
|
108 |
return onSave(cdmEntity, id, currentState, propertyNames, null); |
|
109 |
} |
|
110 |
if (isModified(currentState, previousState, propertyNames, exculdeMap.get(CdmBaseType.baseTypeFor(cdmEntity.getClass())))) { |
|
111 |
// evaluate throws EvaluationFailedException |
|
112 |
checkPermissions(cdmEntity, Operation.UPDATE); |
|
113 |
logger.debug("Operation.UPDATE permission check suceeded - object update granted"); |
|
114 |
|
|
115 |
if(IPublishable.class.isAssignableFrom(entity.getClass())){ |
|
116 |
if(namedPropertyIsModified(currentState, previousState, propertyNames, "publish")){ |
|
117 |
checkRoles(Role.ROLE_PUBLISH, Role.ROLE_ADMIN); |
|
118 |
logger.debug("Role.ROLE_PUBLISH permission check suceeded - object update granted"); |
|
119 |
} |
|
120 |
} |
|
121 |
} |
|
122 |
return true; |
|
123 |
} |
|
124 |
|
|
125 |
|
|
126 |
|
|
127 |
/* (non-Javadoc) |
|
128 |
* @see org.hibernate.EmptyInterceptor#onDelete(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.String[], org.hibernate.type.Type[]) |
|
129 |
*/ |
|
130 |
@Override |
|
131 |
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { |
|
132 |
|
|
133 |
if (SecurityContextHolder.getContext().getAuthentication() == null || !(entity instanceof CdmBase)) { |
|
134 |
return; |
|
135 |
} |
|
136 |
CdmBase cdmEntity = (CdmBase) entity; |
|
137 |
// evaluate throws EvaluationFailedException |
|
138 |
checkPermissions(cdmEntity, Operation.DELETE); |
|
139 |
logger.debug("permission check suceeded - object update granted"); |
|
140 |
return; |
|
141 |
} |
|
142 |
|
|
143 |
/** |
|
144 |
* checks if the current authentication has the <code>expectedPermission</code> on the supplied <code>entity</code>. |
|
145 |
* Throws an {@link PermissionDeniedException} if the evaluation fails. |
|
146 |
* |
|
147 |
* @param entity |
|
148 |
* @param expectedOperation |
|
149 |
*/ |
|
150 |
private void checkPermissions(CdmBase entity, EnumSet<CRUD> expectedOperation) { |
|
151 |
|
|
152 |
if (!permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), entity, expectedOperation)){ |
|
153 |
throw new PermissionDeniedException(SecurityContextHolder.getContext().getAuthentication(), entity, expectedOperation); |
|
154 |
} |
|
155 |
} |
|
156 |
|
|
157 |
/** |
|
158 |
* checks if the current authentication has at least one of the <code>roles</code>. |
|
159 |
* Throws an {@link PermissionDeniedException} if the evaluation fails. |
|
160 |
* @param roles |
|
161 |
*/ |
|
162 |
private void checkRoles(Role ... roles) { |
|
163 |
|
|
164 |
if (!permissionEvaluator.hasOneOfRoles(SecurityContextHolder.getContext().getAuthentication(), roles)){ |
|
165 |
throw new PermissionDeniedException(SecurityContextHolder.getContext().getAuthentication(), roles); |
|
166 |
} |
|
167 |
} |
|
168 |
|
|
169 |
/** |
|
170 |
* Checks if the CDM entity as been modified by comparing the current with the previous state. |
|
171 |
* |
|
172 |
* @param currentState |
|
173 |
* @param previousState |
|
174 |
* @return true if the currentState and previousState differ. |
|
175 |
*/ |
|
176 |
private boolean isModified(Object[] currentState, Object[] previousState, String[] propertyNames, Set<String> excludes) { |
|
177 |
|
|
178 |
Set<Integer> excludeIds = null; |
|
179 |
|
|
180 |
if(excludes != null && excludes.size() > 0) { |
|
181 |
excludeIds = new HashSet<Integer>(excludes.size()); |
|
182 |
int i = 0; |
|
183 |
for(String prop : propertyNames){ |
|
184 |
if(excludes.contains(prop)){ |
|
185 |
excludeIds.add(i); |
|
186 |
} |
|
187 |
if(excludeIds.size() == excludes.size()){ |
|
188 |
// all ids found |
|
189 |
break; |
|
190 |
} |
|
191 |
i++; |
|
192 |
} |
|
193 |
} |
|
194 |
|
|
195 |
for (int i = 0; i<currentState.length; i++){ |
|
196 |
if((excludeIds == null || !excludeIds.contains(i))){ |
|
197 |
if(propertyIsModified(currentState, previousState, i)){ |
|
198 |
if(logger.isDebugEnabled()){ |
|
199 |
logger.debug("modified property found: " + propertyNames[i] + ", previousState: " + previousState[i] + ", currentState: " + currentState[i] ); |
|
200 |
} |
|
201 |
return true; |
|
202 |
} |
|
203 |
} |
|
204 |
} |
|
205 |
|
|
206 |
return false; |
|
207 |
} |
|
208 |
|
|
209 |
/** |
|
210 |
* Compares the object states at the property denoted by the key parameter and returns true if they differ in this property |
|
211 |
* |
|
212 |
* @param currentState |
|
213 |
* @param previousState |
|
214 |
* @param isModified |
|
215 |
* @param key |
|
216 |
* @return |
|
217 |
*/ |
|
218 |
private boolean propertyIsModified(Object[] currentState, Object[] previousState, int key) { |
|
219 |
if (currentState[key]== null ) { |
|
220 |
if ( previousState[key]!= null) { |
|
221 |
return true; |
|
222 |
} |
|
223 |
} |
|
224 |
if (currentState[key]!= null ){ |
|
225 |
if (previousState[key] == null){ |
|
226 |
return true; |
|
227 |
} |
|
228 |
} |
|
229 |
if (currentState[key]!= null && previousState[key] != null){ |
|
230 |
if (!currentState[key].equals(previousState[key])) { |
|
231 |
return true; |
|
232 |
} |
|
233 |
} |
|
234 |
return false; |
|
235 |
} |
|
236 |
|
|
237 |
private boolean namedPropertyIsModified(Object[] currentState, Object[] previousState, String[] propertyNames, String propertyNameToTest) { |
|
238 |
|
|
239 |
int key = ArrayUtils.indexOf(propertyNames, propertyNameToTest); |
|
240 |
return propertyIsModified(currentState, previousState, key); |
|
241 |
} |
|
242 |
|
|
243 |
|
|
244 |
} |
|
1 |
/** |
|
2 |
* Copyright (C) 2011 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 |
package eu.etaxonomy.cdm.persistence.hibernate; |
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
import java.io.Serializable; |
|
14 |
import java.util.EnumSet; |
|
15 |
import java.util.HashMap; |
|
16 |
import java.util.HashSet; |
|
17 |
import java.util.Map; |
|
18 |
import java.util.Set; |
|
19 |
|
|
20 |
import org.apache.commons.lang.ArrayUtils; |
|
21 |
import org.apache.log4j.Logger; |
|
22 |
import org.hibernate.EmptyInterceptor; |
|
23 |
import org.hibernate.type.Type; |
|
24 |
import org.springframework.security.core.context.SecurityContextHolder; |
|
25 |
import org.springframework.stereotype.Component; |
|
26 |
|
|
27 |
import eu.etaxonomy.cdm.database.PermissionDeniedException; |
|
28 |
import eu.etaxonomy.cdm.model.CdmBaseType; |
|
29 |
import eu.etaxonomy.cdm.model.common.CdmBase; |
|
30 |
import eu.etaxonomy.cdm.model.common.IPublishable; |
|
31 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD; |
|
32 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator; |
|
33 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation; |
|
34 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.Role; |
|
35 |
/** |
|
36 |
* @author k.luther |
|
37 |
* @author a.kohlbecker |
|
38 |
* |
|
39 |
*/ |
|
40 |
@Component |
|
41 |
public class CdmSecurityHibernateInterceptor extends EmptyInterceptor { |
|
42 |
|
|
43 |
private static final long serialVersionUID = 8477758472369568074L; |
|
44 |
|
|
45 |
public static final Logger logger = Logger.getLogger(CdmSecurityHibernateInterceptor.class); |
|
46 |
|
|
47 |
|
|
48 |
private CdmPermissionEvaluator permissionEvaluator; |
|
49 |
|
|
50 |
public CdmPermissionEvaluator getPermissionEvaluator() { |
|
51 |
return permissionEvaluator; |
|
52 |
} |
|
53 |
|
|
54 |
public void setPermissionEvaluator(CdmPermissionEvaluator permissionEvaluator) { |
|
55 |
this.permissionEvaluator = permissionEvaluator; |
|
56 |
} |
|
57 |
|
|
58 |
/** |
|
59 |
* The exculdeMap must map every property to the CdmBase type !!! |
|
60 |
*/ |
|
61 |
public static final Map<Class<? extends CdmBase>, Set<String>> exculdeMap = new HashMap<Class<? extends CdmBase>, Set<String>>(); |
|
62 |
|
|
63 |
static{ |
|
64 |
// disabled since no longer needed, see https://dev.e-taxonomy.eu/trac/ticket/4111#comment:8 |
|
65 |
// exculdeMap.put(TaxonNameBase.class, new HashSet<String>()); |
|
66 |
|
|
67 |
Set<String> defaultExculdes = new HashSet<String>(); |
|
68 |
defaultExculdes.add("createdBy"); |
|
69 |
|
|
70 |
for ( CdmBaseType type: CdmBaseType.values()){ |
|
71 |
exculdeMap.put(type.getBaseClass(), new HashSet<String>()); |
|
72 |
exculdeMap.get(type.getBaseClass()).addAll(defaultExculdes); |
|
73 |
} |
|
74 |
exculdeMap.put(CdmBase.class, new HashSet<String>()); |
|
75 |
exculdeMap.get(CdmBase.class).addAll(defaultExculdes); |
|
76 |
|
|
77 |
|
|
78 |
/* |
|
79 |
* default fields required for each type for which excludes are defined |
|
80 |
*/ |
|
81 |
// exculdeMap.get(TaxonNameBase.class).add("updatedBy"); |
|
82 |
// exculdeMap.get(TaxonNameBase.class).add("created"); |
|
83 |
// exculdeMap.get(TaxonNameBase.class).add("updated"); |
|
84 |
|
|
85 |
/* |
|
86 |
* the specific excludes |
|
87 |
*/ |
|
88 |
// exculdeMap.get(TaxonNameBase.class).add("taxonBases"); |
|
89 |
} |
|
90 |
|
|
91 |
|
|
92 |
/* (non-Javadoc) |
|
93 |
* @see org.hibernate.EmptyInterceptor#onSave(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.String[], org.hibernate.type.Type[]) |
|
94 |
*/ |
|
95 |
@Override |
|
96 |
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] type) { |
|
97 |
|
|
98 |
if (SecurityContextHolder.getContext().getAuthentication() == null || !(entity instanceof CdmBase)) { |
|
99 |
return true; |
|
100 |
} |
|
101 |
// evaluate throws EvaluationFailedException |
|
102 |
checkPermissions((CdmBase) entity, Operation.CREATE); |
|
103 |
logger.debug("permission check suceeded - object creation granted"); |
|
104 |
return true; |
|
105 |
} |
|
106 |
|
|
107 |
|
|
108 |
/* (non-Javadoc) |
|
109 |
* @see org.hibernate.EmptyInterceptor#onFlushDirty(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.Object[], java.lang.String[], org.hibernate.type.Type[]) |
|
110 |
*/ |
|
111 |
@Override |
|
112 |
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { |
|
113 |
|
|
114 |
if (SecurityContextHolder.getContext().getAuthentication() == null || !(entity instanceof CdmBase)) { |
|
115 |
return true; |
|
116 |
} |
|
117 |
CdmBase cdmEntity = (CdmBase) entity; |
|
118 |
if (previousState == null){ |
|
119 |
return onSave(cdmEntity, id, currentState, propertyNames, null); |
|
120 |
} |
|
121 |
if (isModified(currentState, previousState, propertyNames, exculdeMap.get(baseType(cdmEntity)))) { |
|
122 |
// evaluate throws EvaluationFailedException |
|
123 |
checkPermissions(cdmEntity, Operation.UPDATE); |
|
124 |
logger.debug("Operation.UPDATE permission check suceeded - object update granted"); |
|
125 |
|
|
126 |
if(IPublishable.class.isAssignableFrom(entity.getClass())){ |
|
127 |
if(namedPropertyIsModified(currentState, previousState, propertyNames, "publish")){ |
|
128 |
checkRoles(Role.ROLE_PUBLISH, Role.ROLE_ADMIN); |
|
129 |
logger.debug("Role.ROLE_PUBLISH permission check suceeded - object update granted"); |
|
130 |
} |
|
131 |
} |
|
132 |
} |
|
133 |
return true; |
|
134 |
} |
|
135 |
|
|
136 |
private Class<? extends CdmBase> baseType(CdmBase cdmEntity) { |
|
137 |
Class<? extends CdmBase> basetype = CdmBaseType.baseTypeFor(cdmEntity.getClass()); |
|
138 |
return basetype == null ? CdmBase.class : basetype; |
|
139 |
} |
|
140 |
|
|
141 |
|
|
142 |
|
|
143 |
/* (non-Javadoc) |
|
144 |
* @see org.hibernate.EmptyInterceptor#onDelete(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.String[], org.hibernate.type.Type[]) |
|
145 |
*/ |
|
146 |
@Override |
|
147 |
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { |
|
148 |
|
|
149 |
if (SecurityContextHolder.getContext().getAuthentication() == null || !(entity instanceof CdmBase)) { |
|
150 |
return; |
|
151 |
} |
|
152 |
CdmBase cdmEntity = (CdmBase) entity; |
|
153 |
// evaluate throws EvaluationFailedException |
|
154 |
checkPermissions(cdmEntity, Operation.DELETE); |
|
155 |
logger.debug("permission check suceeded - object update granted"); |
|
156 |
return; |
|
157 |
} |
|
158 |
|
|
159 |
/** |
|
160 |
* checks if the current authentication has the <code>expectedPermission</code> on the supplied <code>entity</code>. |
|
161 |
* Throws an {@link PermissionDeniedException} if the evaluation fails. |
|
162 |
* |
|
163 |
* @param entity |
|
164 |
* @param expectedOperation |
|
165 |
*/ |
|
166 |
private void checkPermissions(CdmBase entity, EnumSet<CRUD> expectedOperation) { |
|
167 |
|
|
168 |
if (!permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), entity, expectedOperation)){ |
|
169 |
throw new PermissionDeniedException(SecurityContextHolder.getContext().getAuthentication(), entity, expectedOperation); |
|
170 |
} |
|
171 |
} |
|
172 |
|
|
173 |
/** |
|
174 |
* checks if the current authentication has at least one of the <code>roles</code>. |
|
175 |
* Throws an {@link PermissionDeniedException} if the evaluation fails. |
|
176 |
* @param roles |
|
177 |
*/ |
|
178 |
private void checkRoles(Role ... roles) { |
|
179 |
|
|
180 |
if (!permissionEvaluator.hasOneOfRoles(SecurityContextHolder.getContext().getAuthentication(), roles)){ |
|
181 |
throw new PermissionDeniedException(SecurityContextHolder.getContext().getAuthentication(), roles); |
|
182 |
} |
|
183 |
} |
|
184 |
|
|
185 |
/** |
|
186 |
* Checks if the CDM entity as been modified by comparing the current with the previous state. |
|
187 |
* |
|
188 |
* @param currentState |
|
189 |
* @param previousState |
|
190 |
* @return true if the currentState and previousState differ. |
|
191 |
*/ |
|
192 |
private boolean isModified(Object[] currentState, Object[] previousState, String[] propertyNames, Set<String> excludes) { |
|
193 |
|
|
194 |
Set<Integer> excludeIds = null; |
|
195 |
|
|
196 |
if(excludes != null && excludes.size() > 0) { |
|
197 |
excludeIds = new HashSet<Integer>(excludes.size()); |
|
198 |
int i = 0; |
|
199 |
for(String prop : propertyNames){ |
|
200 |
if(excludes.contains(prop)){ |
|
201 |
excludeIds.add(i); |
|
202 |
} |
|
203 |
if(excludeIds.size() == excludes.size()){ |
|
204 |
// all ids found |
|
205 |
break; |
|
206 |
} |
|
207 |
i++; |
|
208 |
} |
|
209 |
} |
|
210 |
|
|
211 |
for (int i = 0; i<currentState.length; i++){ |
|
212 |
if((excludeIds == null || !excludeIds.contains(i))){ |
|
213 |
if(propertyIsModified(currentState, previousState, i)){ |
|
214 |
if(logger.isDebugEnabled()){ |
|
215 |
logger.debug("modified property found: " + propertyNames[i] + ", previousState: " + previousState[i] + ", currentState: " + currentState[i] ); |
|
216 |
} |
|
217 |
return true; |
|
218 |
} |
|
219 |
} |
|
220 |
} |
|
221 |
|
|
222 |
return false; |
|
223 |
} |
|
224 |
|
|
225 |
/** |
|
226 |
* Compares the object states at the property denoted by the key parameter and returns true if they differ in this property |
|
227 |
* |
|
228 |
* @param currentState |
|
229 |
* @param previousState |
|
230 |
* @param isModified |
|
231 |
* @param key |
|
232 |
* @return |
|
233 |
*/ |
|
234 |
private boolean propertyIsModified(Object[] currentState, Object[] previousState, int key) { |
|
235 |
if (currentState[key]== null ) { |
|
236 |
if ( previousState[key]!= null) { |
|
237 |
return true; |
|
238 |
} |
|
239 |
} |
|
240 |
if (currentState[key]!= null ){ |
|
241 |
if (previousState[key] == null){ |
|
242 |
return true; |
|
243 |
} |
|
244 |
} |
|
245 |
if (currentState[key]!= null && previousState[key] != null){ |
|
246 |
if (!currentState[key].equals(previousState[key])) { |
|
247 |
return true; |
|
248 |
} |
|
249 |
} |
|
250 |
return false; |
|
251 |
} |
|
252 |
|
|
253 |
private boolean namedPropertyIsModified(Object[] currentState, Object[] previousState, String[] propertyNames, String propertyNameToTest) { |
|
254 |
|
|
255 |
int key = ArrayUtils.indexOf(propertyNames, propertyNameToTest); |
|
256 |
return propertyIsModified(currentState, previousState, key); |
|
257 |
} |
|
258 |
|
|
259 |
|
|
260 |
} |
cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/hibernate/SaveOrUpdateorMergeEntityListener.java | ||
---|---|---|
19 | 19 |
import org.hibernate.event.spi.SaveOrUpdateEvent; |
20 | 20 |
import org.hibernate.event.spi.SaveOrUpdateEventListener; |
21 | 21 |
|
22 |
import eu.etaxonomy.cdm.model.common.CdmBase; |
|
23 | 22 |
import eu.etaxonomy.cdm.model.common.ITreeNode; |
24 |
import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent; |
|
25 | 23 |
|
26 | 24 |
|
27 | 25 |
@SuppressWarnings("serial") |
... | ... | |
34 | 32 |
saveOrUpdateOrMerge(entity, event.getSession()); |
35 | 33 |
} |
36 | 34 |
|
37 |
/* (non-Javadoc) |
|
38 |
* @see org.hibernate.event.spi.MergeEventListener#onMerge(org.hibernate.event.spi.MergeEvent) |
|
39 |
*/ |
|
40 | 35 |
@Override |
41 | 36 |
public void onMerge(MergeEvent event) throws HibernateException { |
42 | 37 |
Object entity = event.getOriginal(); |
43 | 38 |
saveOrUpdateOrMerge(entity,event.getSession()); |
44 | 39 |
} |
45 | 40 |
|
46 |
/* (non-Javadoc) |
|
47 |
* @see org.hibernate.event.spi.MergeEventListener#onMerge(org.hibernate.event.spi.MergeEvent, java.util.Map) |
|
48 |
*/ |
|
49 | 41 |
@Override |
50 | 42 |
public void onMerge(MergeEvent event, Map copiedAlready) throws HibernateException { |
51 | 43 |
|
... | ... | |
53 | 45 |
|
54 | 46 |
private void saveOrUpdateOrMerge(Object entity, Session session) { |
55 | 47 |
|
56 |
if(entity != null && CdmBase.class.isAssignableFrom(entity.getClass())){ |
|
57 |
|
|
58 |
if (entity instanceof ITreeNode) { |
|
59 |
ITreeNode<?> node = (ITreeNode<?>)entity; |
|
60 |
reindex(node); |
|
61 |
|
|
62 |
} |
|
63 |
|
|
64 |
if (entity instanceof DeterminationEvent) { |
|
65 |
DeterminationEvent detEv = (DeterminationEvent)entity; |
|
66 |
if (detEv.getTaxon() != null && detEv.getTaxonName() == null && detEv.getTaxon().getName() != null){ |
|
67 |
detEv.setTaxonName(detEv.getTaxon().getName()); |
|
68 |
} |
|
69 |
} |
|
70 |
} |
|
48 |
//moved to CdmPreDataChangeObservableListener |
|
49 |
// if(entity != null && CdmBase.class.isAssignableFrom(entity.getClass())){ |
|
50 |
// |
|
51 |
// if (entity instanceof ITreeNode) { |
|
52 |
// ITreeNode<?> node = (ITreeNode<?>)entity; |
|
53 |
// reindex(node); |
|
54 |
// |
|
55 |
// } |
|
56 |
// |
|
57 |
// if (entity instanceof DeterminationEvent) { |
|
58 |
// DeterminationEvent detEv = (DeterminationEvent)entity; |
|
59 |
// if (detEv.getTaxon() != null && detEv.getTaxonName() == null && detEv.getTaxon().getName() != null){ |
|
60 |
// detEv.setTaxonName(detEv.getTaxon().getName()); |
|
61 |
// } |
|
62 |
// } |
|
63 |
// } |
|
71 | 64 |
} |
72 | 65 |
|
73 | 66 |
static String sep = ITreeNode.separator; |
cdmlib-persistence/src/test/resources/eu/etaxonomy/cdm/persistence/dao/hibernate/description/DescriptionElementDaoHibernateImplTest.testChangeLanguageString-result.xml | ||
---|---|---|
1 |
<?xml version='1.0' encoding='UTF-8'?>
|
|
1 |
<?xml version='1.0' encoding='UTF-8'?> |
|
2 | 2 |
<dataset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../dataset.xsd"> |
3 |
<DESCRIPTIONELEMENTBASE DTYPE="TextData" ID="34" INDESCRIPTION_ID="1" CREATED="2008-12-10 09:56:07.0" UUID="31a0160a-51b2-4565-85cf-2be58cb561d6" FEATURE_ID="922"/>
|
|
4 |
<DESCRIPTIONELEMENTBASE_LANGUAGESTRING DESCRIPTIONELEMENTBASE_ID="34" MULTILANGUAGETEXT_MAPKEY_ID="406"/>
|
|
5 |
<LANGUAGESTRING ID="1" CREATED="2008-12-10 09:56:07.0" UUID="2a5ceebb-4830-4524-b330-78461bf8cb6b" UPDATED="2008-12-10 09:56:07.253" LANGUAGE_ID="406" TEXT="A new English text"/>
|
|
6 |
<LANGUAGESTRING ID="2" CREATED="2008-12-10 09:56:07.0" UUID="373e7154-9372-4985-b77e-68df28e3f84b" UPDATED="2008-12-10 09:56:07.253" LANGUAGE_ID="406" TEXT="Praesent vitae turpis vitae sapien sodales sagittis."/>
|
|
7 |
<LANGUAGESTRING ID="3" CREATED="2008-12-10 09:56:07.0" UUID="f72f17d8-58c2-4c4e-b052-89d9016b6d02" UPDATED="2008-12-10 09:56:07.253" LANGUAGE_ID="406" TEXT="Maecenas congue ligula ut nulla. Nullam commodo euismod dolor."/>
|
|
8 |
|
|
3 |
<DESCRIPTIONELEMENTBASE DTYPE="TextData" ID="34" INDESCRIPTION_ID="1" CREATED="2008-12-10 09:56:07.0" UUID="31a0160a-51b2-4565-85cf-2be58cb561d6" FEATURE_ID="922"/> |
|
4 |
<DESCRIPTIONELEMENTBASE_LANGUAGESTRING DESCRIPTIONELEMENTBASE_ID="34" MULTILANGUAGETEXT_MAPKEY_ID="406"/> |
|
5 |
<LANGUAGESTRING ID="1" CREATED="2008-12-10 09:56:07.0" UUID="2a5ceebb-4830-4524-b330-78461bf8cb6b" LANGUAGE_ID="406" TEXT="A new English text"/>
|
|
6 |
<LANGUAGESTRING ID="2" CREATED="2008-12-10 09:56:07.0" UUID="373e7154-9372-4985-b77e-68df28e3f84b" UPDATED="2008-12-10 09:56:07.253" LANGUAGE_ID="406" TEXT="Praesent vitae turpis vitae sapien sodales sagittis."/> |
|
7 |
<LANGUAGESTRING ID="3" CREATED="2008-12-10 09:56:07.0" UUID="f72f17d8-58c2-4c4e-b052-89d9016b6d02" UPDATED="2008-12-10 09:56:07.253" LANGUAGE_ID="406" TEXT="Maecenas congue ligula ut nulla. Nullam commodo euismod dolor."/> |
|
8 |
|
|
9 | 9 |
</dataset> |
cdmlib-persistence/src/test/resources/eu/etaxonomy/cdm/persistence/dao/hibernate/taxon/TaxonDaoHibernateImplTest.testAddChild-result.xml | ||
---|---|---|
125 | 125 |
<TAXONBASE DTYPE="Taxon" ID="33" CREATED="2007-12-10 09:56:07.0" UUID="2c41e444-b160-4c6a-a1be-d5317d97d68d" UPDATED="2008-12-10 09:56:07.253" PROTECTEDTITLECACHE="true" TITLECACHE="Manduca bergarmatipes (Clark, 1927) sec. cate-sphingidae.org" DOUBTFUL="false" TAXONOMICCHILDRENCOUNT="0" NAME_ID="33" SEC_ID="2"/> |
126 | 126 |
<TAXONBASE DTYPE="Taxon" ID="34" CREATED="2009-12-10 09:56:07.0" UUID="7fe66bfd-235b-4164-8f0a-d054b5e962ba" UPDATED="2008-12-10 09:56:07.253" PROTECTEDTITLECACHE="true" TITLECACHE="Manduca chinchilla (Gehlen, 1942) sec. cate-sphingidae.org" DOUBTFUL="false" TAXONOMICCHILDRENCOUNT="0" NAME_ID="34" SEC_ID="2"/> |
127 | 127 |
<TAXONBASE DTYPE="Taxon" ID="35" CREATED="2002-12-10 09:56:07.0" UUID="4cab3cc5-eb80-477c-ac1b-be3c3d0a5a85" UPDATED="2008-12-10 09:56:07.253" PROTECTEDTITLECACHE="true" TITLECACHE="Acherontia atropos (Linnaeus, 1758) sec. cate-sphingidae.org" DOUBTFUL="false" TAXONOMICCHILDRENCOUNT="0" NAME_ID="35" SEC_ID="2"/> |
128 |
<TAXONBASE DTYPE="Taxon" ID="36" CREATED="2003-04-10 09:56:07.0" UUID="b04cc9cb-2b4a-4cc4-a94a-3c93a2158b06" UPDATED="2008-12-10 09:56:07.253" PROTECTEDTITLECACHE="true" TITLECACHE="Acherontia lachesis (Fabricius, 1798) sec. cate-sphingidae.org" DOUBTFUL="false" TAXONOMICCHILDRENCOUNT="1" NAME_ID="36" SEC_ID="2"/>
|
|
128 |
<TAXONBASE DTYPE="Taxon" ID="36" CREATED="2003-04-10 09:56:07.0" UUID="b04cc9cb-2b4a-4cc4-a94a-3c93a2158b06" PROTECTEDTITLECACHE="true" TITLECACHE="Acherontia lachesis (Fabricius, 1798) sec. cate-sphingidae.org" DOUBTFUL="false" TAXONOMICCHILDRENCOUNT="1" NAME_ID="36" SEC_ID="2"/> |
|
129 | 129 |
<TAXONBASE DTYPE="Taxon" ID="37" CREATED="2003-08-10 09:56:07.0" UUID="7b8b5cb3-37ba-4dba-91ac-4c6ffd6ac331" UPDATED="2008-12-10 09:56:07.253" PROTECTEDTITLECACHE="true" TITLECACHE="Acherontia styx Westwood, 1847 sec. cate-sphingidae.org" DOUBTFUL="false" TAXONOMICCHILDRENCOUNT="1" NAME_ID="37" SEC_ID="2"/> |
130 | 130 |
<TAXONBASE DTYPE="Taxon" ID="38" CREATED="2008-12-10 09:56:07.0" UUID="bc09aca6-06fd-4905-b1e7-cbf7cc65d783" UPDATED="2008-12-10 09:56:07.253" PROTECTEDTITLECACHE="true" TITLECACHE="Cryptocoryne x purpurea nothovar borneoensis N.Jacobsen, Bastm. & Yuji Sasaki sec. cate-sphingidae.org" DOUBTFUL="false" TAXONOMICCHILDRENCOUNT="0" NAME_ID="38" SEC_ID="3"/> |
131 | 131 |
<TAXONBASE DTYPE="Taxon" PROTECTEDTITLECACHE="true" TITLECACHE="Acherontia lachesis diehli Eitschberger, 2003" DOUBTFUL="false" TAXONOMICCHILDRENCOUNT="0" TAXONOMICPARENTCACHE_ID="36"/> |
cdmlib-persistence/src/test/resources/eu/etaxonomy/cdm/persistence/hibernate/replace/ReferringObjectMetadataFactoryTest.testReplaceToOneProperty-result.xml | ||
---|---|---|
1 | 1 |
<?xml version='1.0' encoding='UTF-8'?> |
2 | 2 |
<dataset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../dao/hibernate/dataset.xsd"> |
3 |
<AGENTBASE DTYPE="Person" ID="1" CREATED="2008-12-10 09:56:07.0" UUID="e4ec436a-3e8c-4166-a834-3bb84c2b5ad6" UPDATED="2008-12-10 09:56:07.253" PROTECTEDTITLECACHE="true" TITLECACHE="H.C.J. Godfray" COLLECTORTITLE="[NULL]" PROTECTEDCOLLECTORTITLECACHE="FALSE" />
|
|
4 |
<AGENTBASE DTYPE="Person" ID="2" CREATED="2008-12-10 09:56:07.0" UUID="ed6ac546-8c6c-48c4-9b91-40b1157c05c6" UPDATED="2008-12-10 09:56:07.253" PROTECTEDTITLECACHE="true" TITLECACHE="B.R. Clark" FIRSTNAME="Ben" LASTNAME="Clark" COLLECTORTITLE="[NULL]" PROTECTEDCOLLECTORTITLECACHE="FALSE" />
|
|
3 |
<AGENTBASE DTYPE="Person" ID="1" CREATED="2008-12-10 09:56:07.0" UUID="e4ec436a-3e8c-4166-a834-3bb84c2b5ad6" PROTECTEDTITLECACHE="true" TITLECACHE="H.C.J. Godfray" COLLECTORTITLE="[NULL]" PROTECTEDCOLLECTORTITLECACHE="FALSE" /> |
|
4 |
<AGENTBASE DTYPE="Person" ID="2" CREATED="2008-12-10 09:56:07.0" UUID="ed6ac546-8c6c-48c4-9b91-40b1157c05c6" PROTECTEDTITLECACHE="true" TITLECACHE="B.R. Clark" FIRSTNAME="Ben" LASTNAME="Clark" COLLECTORTITLE="[NULL]" PROTECTEDCOLLECTORTITLECACHE="FALSE" /> |
|
5 | 5 |
<AGENTBASE DTYPE="Person" ID="3" CREATED="2008-12-10 09:56:07.0" UUID="746e872b-3f61-442c-b093-6b4d15c87694" UPDATED="2008-12-10 09:56:07.253" PROTECTEDTITLECACHE="true" TITLECACHE="I.J. Kitching" COLLECTORTITLE="[NULL]" PROTECTEDCOLLECTORTITLECACHE="FALSE" /> |
6 | 6 |
<AGENTBASE DTYPE="Person" ID="4" CREATED="2008-12-10 09:56:07.0" UUID="c62cd389-d787-47f4-99c3-b80eb12a1ef2" UPDATED="2008-12-10 09:56:07.253" PROTECTEDTITLECACHE="true" TITLECACHE="S.J. Mayo" COLLECTORTITLE="[NULL]" PROTECTEDCOLLECTORTITLECACHE="FALSE" /> |
7 | 7 |
<AGENTBASE DTYPE="Person" ID="5" CREATED="2008-12-10 09:56:07.0" UUID="dbaa601e-806b-40aa-a3cd-c2e179ddbd9a" UPDATED="2008-12-10 09:56:07.253" PROTECTEDTITLECACHE="true" TITLECACHE="M.J. Scoble" COLLECTORTITLE="[NULL]" PROTECTEDCOLLECTORTITLECACHE="FALSE" /> |
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/SecurityTest.java | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (C) 2011 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 |
package eu.etaxonomy.cdm.api.service; |
|
10 |
|
|
11 |
import static org.junit.Assert.assertEquals; |
|
12 |
import static org.junit.Assert.assertFalse; |
|
13 |
import static org.junit.Assert.assertTrue; |
|
14 |
|
|
15 |
import java.io.FileNotFoundException; |
|
16 |
import java.util.Collection; |
|
17 |
import java.util.EnumSet; |
|
18 |
import java.util.HashSet; |
|
19 |
import java.util.List; |
|
20 |
import java.util.Set; |
|
21 |
import java.util.UUID; |
|
22 |
|
|
23 |
import javax.sql.DataSource; |
|
24 |
|
|
25 |
import org.apache.log4j.Logger; |
|
26 |
import org.junit.Assert; |
|
27 |
import org.junit.Ignore; |
|
28 |
import org.junit.Test; |
|
29 |
import org.springframework.security.access.AccessDeniedException; |
|
30 |
import org.springframework.security.authentication.AuthenticationManager; |
|
31 |
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
|
32 |
import org.springframework.security.authentication.dao.SaltSource; |
|
33 |
import org.springframework.security.authentication.encoding.PasswordEncoder; |
|
34 |
import org.springframework.security.core.Authentication; |
|
35 |
import org.springframework.security.core.GrantedAuthority; |
|
36 |
import org.springframework.security.core.context.SecurityContext; |
|
37 |
import org.springframework.security.core.context.SecurityContextHolder; |
|
38 |
import org.unitils.database.annotations.TestDataSource; |
|
39 |
import org.unitils.dbunit.annotation.DataSet; |
|
40 |
import org.unitils.spring.annotation.SpringBean; |
|
41 |
import org.unitils.spring.annotation.SpringBeanByType; |
|
42 |
|
|
43 |
import sun.security.provider.PolicyParser.ParsingException; |
|
44 |
import eu.etaxonomy.cdm.database.PermissionDeniedException; |
|
45 |
import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl; |
|
46 |
import eu.etaxonomy.cdm.model.common.User; |
|
47 |
import eu.etaxonomy.cdm.model.description.DescriptionElementBase; |
|
48 |
import eu.etaxonomy.cdm.model.description.Feature; |
|
49 |
import eu.etaxonomy.cdm.model.description.TaxonDescription; |
|
50 |
import eu.etaxonomy.cdm.model.description.TextData; |
|
51 |
import eu.etaxonomy.cdm.model.name.BotanicalName; |
|
52 |
import eu.etaxonomy.cdm.model.name.Rank; |
|
53 |
import eu.etaxonomy.cdm.model.name.TaxonNameBase; |
|
54 |
import eu.etaxonomy.cdm.model.name.ZoologicalName; |
|
55 |
import eu.etaxonomy.cdm.model.reference.Reference; |
|
56 |
import eu.etaxonomy.cdm.model.reference.ReferenceFactory; |
|
57 |
import eu.etaxonomy.cdm.model.taxon.Classification; |
|
58 |
import eu.etaxonomy.cdm.model.taxon.Synonym; |
|
59 |
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType; |
|
60 |
import eu.etaxonomy.cdm.model.taxon.Taxon; |
|
61 |
import eu.etaxonomy.cdm.model.taxon.TaxonBase; |
|
62 |
import eu.etaxonomy.cdm.model.taxon.TaxonNode; |
|
63 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD; |
|
64 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority; |
|
65 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionClass; |
|
66 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator; |
|
67 |
import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation; |
|
68 |
import eu.etaxonomy.cdm.persistence.query.MatchMode; |
|
69 |
|
|
70 |
|
|
71 |
@DataSet |
|
72 |
public class SecurityTest extends AbstractSecurityTestBase{ |
|
73 |
|
|
74 |
|
|
75 |
private static final Logger logger = Logger.getLogger(SecurityTest.class); |
|
76 |
|
|
77 |
@SpringBeanByType |
|
78 |
private ITaxonService taxonService; |
|
79 |
|
|
80 |
@SpringBeanByType |
|
81 |
private INameService nameService; |
|
82 |
|
|
83 |
@SpringBeanByType |
|
84 |
private IReferenceService referenceService; |
|
85 |
|
|
86 |
@SpringBeanByType |
|
87 |
private ITaxonNodeService taxonNodeService; |
|
88 |
|
|
89 |
@SpringBeanByType |
|
90 |
private IDescriptionService descriptionService; |
|
91 |
|
|
92 |
@SpringBeanByType |
|
93 |
private IUserService userService; |
|
94 |
|
|
95 |
@SpringBeanByType |
|
96 |
private IClassificationService classificationService; |
|
97 |
|
|
98 |
@SpringBeanByType |
|
99 |
private AuthenticationManager authenticationManager; |
|
100 |
|
|
101 |
@SpringBeanByType |
|
102 |
private SaltSource saltSource; |
|
103 |
|
|
104 |
@SpringBeanByType |
|
105 |
private PasswordEncoder passwordEncoder; |
|
106 |
|
|
107 |
@SpringBean("cdmPermissionEvaluator") |
|
108 |
private CdmPermissionEvaluator permissionEvaluator; |
|
109 |
|
|
110 |
@TestDataSource |
|
111 |
protected DataSource dataSource; |
|
112 |
|
|
113 |
private Authentication authentication; |
|
114 |
|
|
115 |
|
|
116 |
/** |
|
117 |
* no assertions in this test, since it is only used to create password hashes for test data |
|
118 |
*/ |
|
119 |
@Test |
|
120 |
public void testEncryptPassword(){ |
|
121 |
|
|
122 |
String password = PASSWORD_ADMIN; |
|
123 |
User user = User.NewInstance("userManager", ""); |
|
124 |
|
|
125 |
Object salt = this.saltSource.getSalt(user); |
|
126 |
String passwordEncrypted = passwordEncoder.encodePassword(password, salt); |
|
127 |
logger.info("encrypted password: " + passwordEncrypted ); |
|
128 |
} |
|
129 |
|
|
130 |
@Test |
|
131 |
@DataSet |
|
132 |
public void testHasPermission(){ |
|
133 |
|
|
134 |
Taxon taxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()),null); |
|
135 |
|
|
136 |
authentication = authenticationManager.authenticate(tokenForTaxonomist); |
|
137 |
boolean hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.UPDATE); |
|
138 |
assertTrue(hasPermission); |
|
139 |
|
|
140 |
authentication = authenticationManager.authenticate(tokenForDescriptionEditor); |
|
141 |
hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.UPDATE); |
|
142 |
assertFalse(hasPermission); |
|
143 |
} |
|
144 |
|
|
145 |
@Test |
|
146 |
@DataSet |
|
147 |
public void testListByUsernameAllow(){ |
|
148 |
|
|
149 |
authentication = authenticationManager.authenticate(tokenForTaxonomist); |
|
150 |
SecurityContext context = SecurityContextHolder.getContext(); |
|
151 |
context.setAuthentication(authentication); |
|
152 |
|
|
153 |
List<User> userList = userService.listByUsername("Editor", MatchMode.ANYWHERE, null, null, 0, null, null); |
|
154 |
Assert.assertTrue("The user list must have elements", userList.size() > 0 ); |
|
155 |
} |
|
156 |
|
|
157 |
@Test |
|
158 |
@DataSet |
|
159 |
public void testUserService_CreateDeny(){ |
|
160 |
|
|
161 |
authentication = authenticationManager.authenticate(tokenForTaxonomist); |
|
162 |
SecurityContext context = SecurityContextHolder.getContext(); |
|
163 |
context.setAuthentication(authentication); |
|
164 |
|
|
165 |
RuntimeException exception = null; |
|
166 |
try { |
|
167 |
userService.createUser(User.NewInstance("new guy", "alkjdsfalkj")); |
|
168 |
commitAndStartNewTransaction(null); |
|
169 |
} catch (AccessDeniedException e){ |
|
170 |
logger.debug("Expected failure of evaluation.", e); |
|
171 |
exception = e; |
|
172 |
} catch (RuntimeException e){ |
|
173 |
exception = findThrowableOfTypeIn(PermissionDeniedException.class, e); |
|
174 |
logger.debug("Expected failure of evaluation.", e); |
|
175 |
} finally { |
|
176 |
// needed in case saveOrUpdate was interrupted by the RuntimeException |
|
177 |
// commitAndStartNewTransaction() would raise an UnexpectedRollbackException |
|
178 |
endTransaction(); |
|
179 |
startNewTransaction(); |
|
180 |
} |
|
181 |
Assert.assertNotNull("Must fail here!", exception); |
|
182 |
|
|
183 |
} |
|
184 |
|
|
185 |
@Test |
|
186 |
@DataSet |
|
187 |
public void testUserService_CreateAllow(){ |
|
188 |
|
|
189 |
authentication = authenticationManager.authenticate(tokenForUserManager); |
|
190 |
SecurityContext context = SecurityContextHolder.getContext(); |
|
191 |
context.setAuthentication(authentication); |
|
192 |
|
|
193 |
RuntimeException exception = null; |
|
194 |
try { |
|
195 |
userService.createUser(User.NewInstance("new guy", "alkjdsfalkj")); |
|
196 |
commitAndStartNewTransaction(null); |
|
197 |
} catch (AccessDeniedException e){ |
|
198 |
logger.error("Unexpected failure of evaluation.", e); |
|
199 |
exception = e; |
|
200 |
} catch (RuntimeException e){ |
|
201 |
exception = findThrowableOfTypeIn(PermissionDeniedException.class, e); |
|
202 |
logger.error("unexpected failure of evaluation.", exception); |
|
203 |
} finally { |
|
204 |
// needed in case saveOrUpdate was interrupted by the RuntimeException |
|
205 |
// commitAndStartNewTransaction() would raise an UnexpectedRollbackException |
|
206 |
endTransaction(); |
|
207 |
startNewTransaction(); |
|
208 |
} |
|
209 |
Assert.assertNull("Must not fail here!", exception); |
|
210 |
|
|
211 |
} |
|
212 |
|
|
213 |
|
|
214 |
@Test |
|
215 |
@DataSet |
|
216 |
@Ignore // FIXME http://dev.e-taxonomy.eu/trac/ticket/3098 |
|
217 |
public void testHasPermissions(){ |
|
218 |
|
|
219 |
Taxon taxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()),null); |
|
220 |
|
|
221 |
authentication = authenticationManager.authenticate(tokenForTaxonomist); |
|
222 |
boolean hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.ALL); |
|
223 |
assertTrue(hasPermission); |
|
224 |
} |
|
225 |
|
|
226 |
|
|
227 |
/** |
|
228 |
* Test method for {@link eu.etaxonomy.cdm.api.service.TaxonServiceImpl#saveTaxon(eu.etaxonomy.cdm.model.taxon.TaxonBase)}. |
|
229 |
*/ |
|
230 |
@Test |
|
231 |
public final void testSaveTaxon() { |
|
232 |
|
|
233 |
authentication = authenticationManager.authenticate(tokenForAdmin); |
|
234 |
SecurityContext context = SecurityContextHolder.getContext(); |
|
235 |
context.setAuthentication(authentication); |
|
236 |
|
|
237 |
Taxon expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null); |
|
238 |
expectedTaxon.getName().setTitleCache("Newby admin", true); |
|
239 |
UUID uuid = taxonService.save(expectedTaxon).getUuid(); |
|
240 |
commitAndStartNewTransaction(null); |
|
241 |
TaxonBase<?> actualTaxon = taxonService.load(uuid); |
|
242 |
assertEquals(expectedTaxon, actualTaxon); |
|
243 |
|
|
244 |
authentication = authenticationManager.authenticate(tokenForTaxonEditor); |
|
245 |
context = SecurityContextHolder.getContext(); |
|
246 |
context.setAuthentication(authentication); |
|
247 |
expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()), null); |
|
248 |
expectedTaxon.getName().setTitleCache("Newby taxonEditor", true); |
|
249 |
uuid = taxonService.saveOrUpdate(expectedTaxon); |
|
250 |
commitAndStartNewTransaction(null); |
|
251 |
actualTaxon = taxonService.load(uuid); |
|
252 |
assertEquals(expectedTaxon, actualTaxon); |
|
253 |
|
|
254 |
} |
|
255 |
|
|
256 |
@Test |
|
257 |
public final void testSaveNameAllow() { |
|
258 |
|
|
259 |
authentication = authenticationManager.authenticate(tokenForTaxonEditor); |
|
260 |
SecurityContext context = SecurityContextHolder.getContext(); |
|
261 |
context.setAuthentication(authentication); |
|
262 |
|
|
263 |
ZoologicalName newName = ZoologicalName.NewInstance(Rank.SPECIES()); |
|
264 |
newName.setTitleCache("Newby taxonEditor", true); |
|
265 |
UUID uuid = nameService.saveOrUpdate(newName); |
|
266 |
commitAndStartNewTransaction(null); |
|
267 |
TaxonNameBase savedName = nameService.load(uuid); |
|
268 |
assertEquals(newName, savedName); |
|
269 |
} |
|
270 |
|
|
271 |
|
Also available in: Unified diff
Adapt listeners and tests to new pre-insert strategy #5066