ref #4311 fix collectorTitleCache handling in Team an in person2Team
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / AgentServiceImpl.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 package eu.etaxonomy.cdm.api.service;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.UUID;
14
15 import org.apache.commons.lang3.StringUtils;
16 import org.apache.log4j.Logger;
17 import org.springframework.beans.factory.annotation.Autowired;
18 import org.springframework.stereotype.Service;
19 import org.springframework.transaction.annotation.Transactional;
20
21 import eu.etaxonomy.cdm.api.service.config.IIdentifiableEntityServiceConfigurator;
22 import eu.etaxonomy.cdm.api.service.pager.Pager;
23 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
24 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
25 import eu.etaxonomy.cdm.model.agent.Address;
26 import eu.etaxonomy.cdm.model.agent.AgentBase;
27 import eu.etaxonomy.cdm.model.agent.Institution;
28 import eu.etaxonomy.cdm.model.agent.InstitutionalMembership;
29 import eu.etaxonomy.cdm.model.agent.Person;
30 import eu.etaxonomy.cdm.model.agent.Team;
31 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
32 import eu.etaxonomy.cdm.model.common.CdmBase;
33 import eu.etaxonomy.cdm.persistence.dao.agent.IAgentDao;
34 import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
35 import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
36 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
37 import eu.etaxonomy.cdm.strategy.merge.ConvertMergeStrategy;
38 import eu.etaxonomy.cdm.strategy.merge.DefaultMergeStrategy;
39 import eu.etaxonomy.cdm.strategy.merge.IMergeStrategy;
40 import eu.etaxonomy.cdm.strategy.merge.MergeException;
41 import eu.etaxonomy.cdm.strategy.merge.MergeMode;
42
43 /**
44 * @author a.mueller
45 */
46 @Service
47 @Transactional(readOnly = true)
48 public class AgentServiceImpl
49 extends IdentifiableServiceBase<AgentBase,IAgentDao>
50 implements IAgentService {
51
52 private static final Logger logger = Logger.getLogger(AgentServiceImpl.class);
53
54 @Autowired
55 private ICdmGenericDao genericDao;
56
57 @Override
58 @Autowired
59 protected void setDao(IAgentDao dao) {
60 assert dao != null;
61 this.dao = dao;
62 }
63
64 /**
65 * Constructor
66 */
67 public AgentServiceImpl(){
68 if (logger.isDebugEnabled()) { logger.debug("Load AgentService Bean"); }
69 }
70
71 @Override
72 @Transactional(readOnly = false)
73 public UpdateResult updateCaches(Class<? extends AgentBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<AgentBase> cacheStrategy, IProgressMonitor monitor) {
74 if (clazz == null){
75 clazz = AgentBase.class;
76 }
77 return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
78 }
79
80 @Override
81 public List<Institution> searchInstitutionByCode(String code) {
82 return dao.getInstitutionByCode(code);
83 }
84
85 @Override
86 public Pager<InstitutionalMembership> getInstitutionalMemberships(Person person, Integer pageSize, Integer pageNumber) {
87 long numberOfResults = dao.countInstitutionalMemberships(person);
88
89 List<InstitutionalMembership> results = new ArrayList<>();
90 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
91 results = dao.getInstitutionalMemberships(person, pageSize, pageNumber);
92 }
93
94 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
95 }
96
97 @Override
98 public Pager<Person> getMembers(Team team, Integer pageSize, Integer pageNumber) {
99 long numberOfResults = dao.countMembers(team);
100
101 List<Person> results = new ArrayList<>();
102 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
103 results = dao.getMembers(team, pageSize, pageNumber);
104 }
105
106 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
107 }
108
109 @Override
110 public Pager<Address> getAddresses(AgentBase agent, Integer pageSize, Integer pageNumber) {
111 long numberOfResults = dao.countAddresses(agent);
112
113 List<Address> results = new ArrayList<>();
114 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
115 results = dao.getAddresses(agent, pageSize, pageNumber);
116 }
117
118 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
119 }
120
121 @Override
122 public List<UuidAndTitleCache<Team>> getTeamUuidAndNomenclaturalTitle() {
123 return dao.getTeamUuidAndNomenclaturalTitle();
124 }
125
126 @Override
127 public List<UuidAndTitleCache<Person>> getPersonUuidAndTitleCache() {
128 return dao.getPersonUuidAndTitleCache();
129 }
130
131 @Override
132 public List<UuidAndTitleCache<Team>> getTeamUuidAndTitleCache() {
133 return dao.getTeamUuidAndTitleCache();
134 }
135
136 @Override
137 public List<UuidAndTitleCache<Institution>> getInstitutionUuidAndTitleCache(Integer limit, String pattern) {
138 return dao.getUuidAndAbbrevTitleCache(Institution.class, limit, pattern);
139 }
140
141 @Override
142 @Transactional(readOnly = false)
143 public DeleteResult delete(UUID agentUUID){
144 DeleteResult result = new DeleteResult();
145 if (agentUUID == null){
146 result.setAbort();
147 result.addException(new Exception("Can't delete object without UUID."));
148 return result;
149 }
150 AgentBase base = dao.load(agentUUID);
151 result = isDeletable(agentUUID, null);
152
153 if (result.isOk()){
154 if (base instanceof Team){
155 Team baseTeam = (Team) base;
156 List<Person> members = baseTeam.getTeamMembers();
157 List<Person> temp = new ArrayList<>();
158 for (Person member:members){
159 temp.add(member);
160 }
161 for (Person member: temp){
162 members.remove(member);
163 }
164 }
165 saveOrUpdate(base);
166
167 dao.delete(base);
168 result.addDeletedObject(base);
169
170 }
171
172 return result;
173 }
174
175 @Override
176 public DeleteResult delete(AgentBase agent){
177 return delete(agent.getUuid());
178 }
179
180 @Override
181 @Transactional(readOnly = false)
182 public UpdateResult convertTeam2Person(UUID teamUuid) throws MergeException {
183 Team team = CdmBase.deproxy(dao.load(teamUuid), Team.class);
184 return convertTeam2Person(team);
185 }
186
187 @Override
188 public UpdateResult convertTeam2Person(Team team) throws MergeException {
189 UpdateResult result = new UpdateResult();
190 Person newPerson = null;
191 team = CdmBase.deproxy(team, Team.class);
192 if (team.getTeamMembers().size() > 1){
193 throw new IllegalArgumentException("Team must not have more than 1 member to be convertable into a person");
194 }else if (team.getTeamMembers().size() == 1){
195 newPerson = team.getTeamMembers().get(0);
196 IMergeStrategy strategy = DefaultMergeStrategy.NewInstance(TeamOrPersonBase.class);
197 strategy.setDefaultCollectionMergeMode(MergeMode.FIRST);
198 genericDao.merge(newPerson, team, strategy);
199 }else if (team.getTeamMembers().isEmpty()){
200 newPerson = Person.NewInstance();
201 genericDao.save(newPerson);
202 IMergeStrategy strategy = DefaultMergeStrategy.NewInstance(TeamOrPersonBase.class);
203 strategy.setDefaultMergeMode(MergeMode.SECOND);
204 strategy.setDefaultCollectionMergeMode(MergeMode.SECOND);
205 genericDao.merge(newPerson, team, strategy);
206 }else{
207 throw new IllegalStateException("Unhandled state of team members collection");
208 }
209 result.setCdmEntity(newPerson);
210 return result;
211 }
212
213 @Override
214 @Transactional(readOnly = false)
215 public UpdateResult convertPerson2Team(UUID personUuid) throws MergeException, IllegalArgumentException {
216 Person person = CdmBase.deproxy(dao.load(personUuid), Person.class);
217 return convertPerson2Team(person);
218 }
219
220 @Override
221 public UpdateResult convertPerson2Team(Person person) throws MergeException, IllegalArgumentException {
222 if (person == null){
223 throw new IllegalArgumentException("Person does not exist.");
224 }
225 UpdateResult result = new UpdateResult();
226 Team team = Team.NewInstance();
227 ConvertMergeStrategy strategy = ConvertMergeStrategy.NewInstance(TeamOrPersonBase.class);
228 strategy.setDefaultMergeMode(MergeMode.SECOND);
229 strategy.setDefaultCollectionMergeMode(MergeMode.SECOND);
230 if (person.isProtectedTitleCache() || !person.getTitleCache().startsWith("Person#")){ //the later is for checking if the person is empty, this can be done better
231 team.setTitleCache(person.getTitleCache(), true); //as there are no members we set the titleCache to protected (as long as titleCache does not take the protected nomenclatural title but results in '-empty team-' in this situation); for some reason it is necessary to also set the title cache as well here, otherwise it is recomputed during the merge
232 }
233 strategy.setMergeMode("protectedTitleCache", MergeMode.FIRST); //as we do not add team members, the titleCache of the new team should be always protected
234 strategy.setDeleteSecondObject(true);
235 if (StringUtils.isNotBlank(person.getNomenclaturalTitle())){
236 team.setNomenclaturalTitleCache(person.getNomenclaturalTitle(), true); //sets the protected flag always to true, this is necessary as long as person does not have a nomenclatural title cache; maybe setting the protected title itself is not necessary but does no harm
237 }
238 if (StringUtils.isNotBlank(person.getCollectorTitle())){
239 team.setCollectorTitleCache(person.getCollectorTitle(), true); //sets the protected flag always to true, this is necessary as long as person does not have a collector title cache; maybe setting the protected title itself is not necessary but does no harm
240 }
241
242 if (! genericDao.isMergeable(team, person, strategy)){
243 throw new MergeException("Person can not be transformed into team.");
244 }
245 try {
246 team = this.save(team);
247 genericDao.merge(team, person, strategy);
248
249 //Note: we decided never add the old person as (first) member of the team as there are not many usecases for this.
250 //But we may try to parse the old person into members which may handle the case that teams have been stored as unparsed persons
251
252 } catch (Exception e) {
253 throw new MergeException("Unhandled merge exception", e);
254 }
255 result.setCdmEntity(team);
256 result.addUpdatedObject(team);
257 return result;
258 }
259
260 @Override
261 public <T extends AgentBase> List<UuidAndTitleCache<T>> getUuidAndAbbrevTitleCache(Class<T> clazz, Integer limit, String pattern) {
262 return dao.getUuidAndAbbrevTitleCache(clazz, null, pattern);
263 }
264
265 @Override
266 public <T extends AgentBase<?>> List<T> findByTitleAndAbbrevTitle(IIdentifiableEntityServiceConfigurator<T> config){
267 return dao.findByTitleAndAbbrevTitle(config.getClazz(),config.getTitleSearchStringSqlized(), config.getMatchMode(), config.getCriteria(), config.getPageSize(), config.getPageNumber(), config.getOrderHints(), config.getPropertyPaths());
268 }
269 }