#5054 Add delete method call with uuid
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / TermServiceImpl.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 package eu.etaxonomy.cdm.api.service;
12
13 import java.net.URI;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Enumeration;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Locale;
20 import java.util.Set;
21 import java.util.UUID;
22
23 import org.apache.commons.lang.StringUtils;
24 import org.apache.log4j.Logger;
25 import org.springframework.beans.factory.annotation.Autowired;
26 import org.springframework.beans.factory.annotation.Qualifier;
27 import org.springframework.stereotype.Service;
28 import org.springframework.transaction.annotation.Transactional;
29
30 import eu.etaxonomy.cdm.api.service.UpdateResult.Status;
31 import eu.etaxonomy.cdm.api.service.config.TermDeletionConfigurator;
32 import eu.etaxonomy.cdm.api.service.exception.DataChangeNoRollbackException;
33 import eu.etaxonomy.cdm.api.service.pager.Pager;
34 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
35 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
36 import eu.etaxonomy.cdm.model.common.CdmBase;
37 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
38 import eu.etaxonomy.cdm.model.common.Language;
39 import eu.etaxonomy.cdm.model.common.LanguageString;
40 import eu.etaxonomy.cdm.model.common.LanguageStringBase;
41 import eu.etaxonomy.cdm.model.common.Representation;
42 import eu.etaxonomy.cdm.model.common.TermType;
43 import eu.etaxonomy.cdm.model.common.TermVocabulary;
44 import eu.etaxonomy.cdm.model.location.NamedArea;
45 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
46 import eu.etaxonomy.cdm.model.location.NamedAreaType;
47 import eu.etaxonomy.cdm.model.media.Media;
48 import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
49 import eu.etaxonomy.cdm.persistence.dao.common.ILanguageStringBaseDao;
50 import eu.etaxonomy.cdm.persistence.dao.common.ILanguageStringDao;
51 import eu.etaxonomy.cdm.persistence.dao.common.IRepresentationDao;
52 import eu.etaxonomy.cdm.persistence.query.OrderHint;
53 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
54
55 @Service
56 @Transactional(readOnly = true)
57 public class TermServiceImpl extends IdentifiableServiceBase<DefinedTermBase,IDefinedTermDao> implements ITermService{
58 @SuppressWarnings("unused")
59 private static final Logger logger = Logger.getLogger(TermServiceImpl.class);
60
61 private ILanguageStringDao languageStringDao;
62
63 @Autowired
64 @Qualifier("langStrBaseDao")
65 private ILanguageStringBaseDao languageStringBaseDao;
66 private IRepresentationDao representationDao;
67
68 @Autowired
69 public void setLanguageStringDao(ILanguageStringDao languageStringDao) {
70 this.languageStringDao = languageStringDao;
71 }
72
73 @Autowired
74 public void setRepresentationDao(IRepresentationDao representationDao) {
75 this.representationDao = representationDao;
76 }
77
78 @Override
79 @Autowired
80 protected void setDao(IDefinedTermDao dao) {
81 this.dao = dao;
82 }
83
84 /* (non-Javadoc)
85 * @see eu.etaxonomy.cdm.api.service.ITermService#listByTermType(eu.etaxonomy.cdm.model.common.TermType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
86 */
87 @Override
88 public List<DefinedTermBase<?>> listByTermType(TermType termType, Integer limit, Integer start,
89 List<OrderHint> orderHints, List<String> propertyPaths) {
90 return dao.listByTermType(termType, limit, start, orderHints, propertyPaths);
91 }
92
93 @Override
94 public DefinedTermBase getByUri(URI uri) {
95 return dao.findByUri(uri);
96 }
97
98 @Override
99 public Language getLanguageByIso(String iso639) {
100 return dao.getLanguageByIso(iso639);
101 }
102
103 @Override
104 public List<Language> getLanguagesByLocale(Enumeration<Locale> locales){
105 return dao.getLanguagesByLocale(locales);
106 }
107
108 @Override
109 public <TERM extends DefinedTermBase> TERM findByIdInVocabulary(String id, UUID vocabularyUuid, Class<TERM> clazz) throws IllegalArgumentException {
110 List<TERM> list = dao.getDefinedTermByIdInVocabulary(id, vocabularyUuid, clazz, null, null);
111 if (list.isEmpty()){
112 return null;
113 }else if (list.size() == 1){
114 return list.get(0);
115 }else{
116 String message = "There is more then 1 (%d) term with the same id in vocabulary. This is forbidden. Check the state of your database.";
117 throw new IllegalStateException(String.format(message, list.size()));
118 }
119 }
120
121
122 @Override
123 public NamedArea getAreaByTdwgAbbreviation(String tdwgAbbreviation) {
124 if (StringUtils.isBlank(tdwgAbbreviation)){ //TDWG areas should always have a label
125 return null;
126 }
127 List<NamedArea> list = dao.getDefinedTermByIdInVocabulary(tdwgAbbreviation, NamedArea.uuidTdwgAreaVocabulary, NamedArea.class, null, null);
128 if (list.isEmpty()){
129 return null;
130 }else if (list.size() == 1){
131 return list.get(0);
132 }else{
133 String message = "There is more then 1 (%d) TDWG area with the same abbreviated label. This is forbidden. Check the state of your database.";
134 throw new IllegalStateException(String.format(message, list.size()));
135 }
136
137 }
138
139 @Override
140 public <T extends DefinedTermBase> Pager<T> getGeneralizationOf(T definedTerm, Integer pageSize, Integer pageNumber) {
141 Integer numberOfResults = dao.countGeneralizationOf(definedTerm);
142
143 List<T> results = new ArrayList<T>();
144 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
145 results = dao.getGeneralizationOf(definedTerm, pageSize, pageNumber);
146 }
147
148 return new DefaultPagerImpl<T>(pageNumber, numberOfResults, pageSize, results);
149 }
150
151 @Override
152 public <T extends DefinedTermBase> Pager<T> getIncludes(Collection<T> definedTerms, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
153 Integer numberOfResults = dao.countIncludes(definedTerms);
154
155 List<T> results = new ArrayList<T>();
156 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
157 results = dao.getIncludes(definedTerms, pageSize, pageNumber,propertyPaths);
158 }
159
160 return new DefaultPagerImpl<T>(pageNumber, numberOfResults, pageSize, results);
161 }
162
163 @Override
164 public Pager<Media> getMedia(DefinedTermBase definedTerm, Integer pageSize, Integer pageNumber) {
165 Integer numberOfResults = dao.countMedia(definedTerm);
166
167 List<Media> results = new ArrayList<Media>();
168 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
169 results = dao.getMedia(definedTerm, pageSize, pageNumber);
170 }
171
172 return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
173 }
174
175 @Override
176 public <T extends DefinedTermBase> Pager<T> getPartOf(Set<T> definedTerms,Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
177 Integer numberOfResults = dao.countPartOf(definedTerms);
178
179 List<T> results = new ArrayList<T>();
180 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
181 results = dao.getPartOf(definedTerms, pageSize, pageNumber, propertyPaths);
182 }
183
184 return new DefaultPagerImpl<T>(pageNumber, numberOfResults, pageSize, results);
185 }
186
187 @Override
188 public Pager<NamedArea> list(NamedAreaLevel level, NamedAreaType type, Integer pageSize, Integer pageNumber,
189 List<OrderHint> orderHints, List<String> propertyPaths) {
190 Integer numberOfResults = dao.count(level, type);
191
192 List<NamedArea> results = new ArrayList<NamedArea>();
193 if (numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
194 results = dao.list(level, type, pageSize, pageNumber, orderHints, propertyPaths);
195 }
196
197 return new DefaultPagerImpl<NamedArea>(pageNumber, numberOfResults, pageSize, results);
198 }
199
200 @Override
201 public <T extends DefinedTermBase> Pager<T> findByRepresentationText(String label, Class<T> clazz, Integer pageSize, Integer pageNumber) {
202 Integer numberOfResults = dao.countDefinedTermByRepresentationText(label,clazz);
203
204 List<T> results = new ArrayList<T>();
205 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
206 results = dao.getDefinedTermByRepresentationText(label, clazz, pageSize, pageNumber);
207 }
208
209 return new DefaultPagerImpl<T>(pageNumber, numberOfResults, pageSize, results);
210 }
211
212 @Override
213 public <T extends DefinedTermBase> Pager<T> findByRepresentationAbbreviation(String abbrev, Class<T> clazz, Integer pageSize, Integer pageNumber) {
214 Integer numberOfResults = dao.countDefinedTermByRepresentationAbbrev(abbrev,clazz);
215
216 List<T> results = new ArrayList<T>();
217 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
218 results = dao.getDefinedTermByRepresentationAbbrev(abbrev, clazz, pageSize, pageNumber);
219 }
220
221 return new DefaultPagerImpl<T>(pageNumber, numberOfResults, pageSize, results);
222 }
223
224 @Override
225 public List<LanguageString> getAllLanguageStrings(int limit, int start) {
226 return languageStringDao.list(limit, start);
227 }
228
229 @Override
230 public List<Representation> getAllRepresentations(int limit, int start) {
231 return representationDao.list(limit,start);
232 }
233
234 @Override
235 public UUID saveLanguageData(LanguageStringBase languageData) {
236 return languageStringBaseDao.save(languageData).getUuid();
237 }
238
239 /* (non-Javadoc)
240 * @see eu.etaxonomy.cdm.api.service.ServiceBase#delete(eu.etaxonomy.cdm.model.common.CdmBase)
241 */
242 /** @deprecated use {@link #delete(DefinedTermBase, TermDeletionConfigurator)} instead
243 * to allow DeleteResult return type*/
244 @Override
245 @Deprecated
246 public DeleteResult delete(DefinedTermBase term){
247 DeleteResult result = new DeleteResult();
248
249 TermDeletionConfigurator defaultConfig = new TermDeletionConfigurator();
250 result = delete(term, defaultConfig);
251 return result;
252 }
253
254 @Override
255 @Deprecated
256 @Transactional(readOnly = false)
257 public DeleteResult delete(UUID termUuid){
258 DeleteResult result = new DeleteResult();
259
260 TermDeletionConfigurator defaultConfig = new TermDeletionConfigurator();
261 result = delete(dao.load(termUuid), defaultConfig);
262 return result;
263 }
264
265 @Override
266 public DeleteResult delete(DefinedTermBase term, TermDeletionConfigurator config){
267 if (config == null){
268 config = new TermDeletionConfigurator();
269 }
270 // boolean isInternal = config.isInternal();
271 DeleteResult result = new DeleteResult();
272 Set<DefinedTermBase> termsToSave = new HashSet<DefinedTermBase>();
273 CdmBase.deproxy(dao.merge(term), DefinedTermBase.class);
274
275 try {
276 //generalization of
277 Set<DefinedTermBase> specificTerms = term.getGeneralizationOf();
278 if (specificTerms.size()>0){
279 if (config.isDeleteGeneralizationOfRelations()){
280 DefinedTermBase generalTerm = term.getKindOf();
281 for (DefinedTermBase specificTerm: specificTerms){
282 term.removeGeneralization(specificTerm);
283 if (generalTerm != null){
284 generalTerm.addGeneralizationOf(specificTerm);
285 termsToSave.add(generalTerm);
286 }
287 }
288 }else{
289 //TODO Exception type
290 String message = "This term has specifing terms. Move or delete specifiing terms prior to delete or change delete configuration.";
291 result.addRelatedObjects(specificTerms);
292 result.setAbort();
293 Exception ex = new DataChangeNoRollbackException(message);
294 result.addException(ex);
295 }
296 }
297
298 //kind of
299 DefinedTermBase generalTerm = term.getKindOf();
300 if (generalTerm != null){
301 if (config.isDeleteKindOfRelations()){
302 generalTerm.removeGeneralization(term);
303 }else{
304 //TODO Exception type
305 String message = "This term is kind of another term. Move or delete kind of relationship prior to delete or change delete configuration.";
306 result.addRelatedObject(generalTerm);
307 result.setAbort();
308 DataChangeNoRollbackException ex = new DataChangeNoRollbackException(message);
309 result.addException(ex);
310 throw ex;
311 }
312 }
313
314 //part of
315 DefinedTermBase parentTerm = term.getPartOf();
316 if (parentTerm != null){
317 if (! config.isDeletePartOfRelations()){
318 //TODO Exception type
319 String message = "This term is included in another term. Remove from parent term prior to delete or change delete configuration.";
320 result.addRelatedObject(parentTerm);
321 result.setAbort();
322 DataChangeNoRollbackException ex = new DataChangeNoRollbackException(message);
323 result.addException(ex);
324 }
325 }
326
327
328 //included in
329 Set<DefinedTermBase> includedTerms = term.getIncludes();
330 if (includedTerms.size()> 0){
331 // if (config.isDeleteIncludedTerms()){
332 // for (DefinedTermBase includedTerm: includedTerms){
333 // config.setCheck(true);
334 // DeleteResult includedResult = this.delete(includedTerm, config);
335 //// config.setCheck(isCheck);
336 // result.includeResult(includedResult);
337 // }
338 // }else
339 if (config.isDeleteIncludedRelations()){
340 DefinedTermBase parent = term.getPartOf();
341 for (DefinedTermBase includedTerm: includedTerms){
342 term.removeIncludes(includedTerm);
343 if (parent != null){
344 parent.addIncludes(includedTerm);
345 termsToSave.add(parent);
346 }
347 }
348 }else{
349 //TODO Exception type
350 String message = "This term includes other terms. Move or delete included terms prior to delete or change delete configuration.";
351 result.addRelatedObjects(includedTerms);
352 result.setAbort();
353 Exception ex = new DataChangeNoRollbackException(message);
354 result.addException(ex);
355 }
356 }
357
358 //part of
359 if (parentTerm != null){
360 if (config.isDeletePartOfRelations()){
361 parentTerm.removeIncludes(term);
362 termsToSave.add(parentTerm);
363 }else{
364 //handelede before "included in"
365 }
366 }
367
368 // relatedObjects;
369
370
371 if (result.isOk()){
372 TermVocabulary voc = term.getVocabulary();
373 if (voc!= null){
374 voc.removeTerm(term);
375 }
376 //TODO save voc
377 if (true /*!config.isInternal()*/){
378 dao.delete(term);
379 dao.saveOrUpdateAll(termsToSave);
380 // for (DeleteResult.PersistPair persistPair : result.getObjectsToDelete()){
381 // persistPair.dao.delete(persistPair.objectToPersist);
382 // }
383 // for (DeleteResult.PersistPair persistPair : result.getObjectsToSave()){
384 // persistPair.dao.saveOrUpdate(persistPair.objectToPersist);
385 // }
386
387 }
388 }
389 } catch (DataChangeNoRollbackException e) {
390 result.setStatus(Status.ERROR);
391 }
392 return result;
393 }
394
395 @Override
396 @Transactional(readOnly = false)
397 public DeleteResult delete(UUID termUuid, TermDeletionConfigurator config){
398 return delete(dao.load(termUuid), config);
399 }
400
401 @Override
402 @Transactional(readOnly = false)
403 public void updateTitleCache(Class<? extends DefinedTermBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<DefinedTermBase> cacheStrategy, IProgressMonitor monitor) {
404 //TODO shouldnt this be TermBase instead of DefinedTermBase
405 if (clazz == null){
406 clazz = DefinedTermBase.class;
407 }
408 super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
409 }
410
411 }