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