Using countByReferenceTitle() instead of countByTitle()
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / IdentifiableServiceBase.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.util.ArrayList;
14 import java.util.List;
15
16 import org.apache.log4j.Logger;
17 import org.hibernate.criterion.Criterion;
18 import org.springframework.transaction.annotation.Transactional;
19
20 import eu.etaxonomy.cdm.api.service.config.IIdentifiableEntityServiceConfigurator;
21 import eu.etaxonomy.cdm.api.service.pager.Pager;
22 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
23 import eu.etaxonomy.cdm.model.common.CdmBase;
24 import eu.etaxonomy.cdm.model.common.ISourceable;
25 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
26 import eu.etaxonomy.cdm.model.common.IdentifiableSource;
27 import eu.etaxonomy.cdm.model.common.LSID;
28 import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;
29 import eu.etaxonomy.cdm.model.media.Rights;
30 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
31 import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
32 import eu.etaxonomy.cdm.persistence.dao.common.IIdentifiableDao;
33 import eu.etaxonomy.cdm.persistence.query.MatchMode;
34 import eu.etaxonomy.cdm.persistence.query.OrderHint;
35 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
36
37 public abstract class IdentifiableServiceBase<T extends IdentifiableEntity,DAO extends IIdentifiableDao<T>> extends AnnotatableServiceBase<T,DAO>
38 implements IIdentifiableEntityService<T>{
39
40 protected static final int UPDATE_TITLE_CACHE_DEFAULT_STEP_SIZE = 1000;
41 protected static final Logger logger = Logger.getLogger(IdentifiableServiceBase.class);
42
43 @Transactional(readOnly = true)
44 public Pager<Rights> getRights(T t, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
45 Integer numberOfResults = dao.countRights(t);
46
47 List<Rights> results = new ArrayList<Rights>();
48 if(numberOfResults > 0) { // no point checking again
49 results = dao.getRights(t, pageSize, pageNumber,propertyPaths);
50 }
51
52 return new DefaultPagerImpl<Rights>(pageNumber, numberOfResults, pageSize, results);
53 }
54
55 @Transactional(readOnly = true)
56 public Pager<IdentifiableSource> getSources(T t, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
57 Integer numberOfResults = dao.countSources(t);
58
59 List<IdentifiableSource> results = new ArrayList<IdentifiableSource>();
60 if(numberOfResults > 0) { // no point checking again
61 results = dao.getSources(t, pageSize, pageNumber,propertyPaths);
62 }
63
64 return new DefaultPagerImpl<IdentifiableSource>(pageNumber, numberOfResults, pageSize, results);
65 }
66
67 @Transactional(readOnly = true)
68 protected List<T> findByTitle(IIdentifiableEntityServiceConfigurator config){
69 return ((IIdentifiableDao)dao).findByTitle(config.getTitleSearchString(),
70 config.getMatchMode(), 0, -1, null);
71 // TODO: Implement parameters pageSize, pageNumber, and criteria
72 }
73
74 @Transactional(readOnly = false)
75 public T replace(T x, T y) {
76 return dao.replace(x, y);
77 }
78 /**
79 * FIXME Candidate for harmonization
80 * Given that this method is strongly typed, and generic, could we not simply expose it as
81 * List<T> findByTitle(String title) as it is somewhat less cumbersome. Admittedly, I don't
82 * understand what is going on with the configurators etc. so maybe there is a good reason for
83 * the design of this method.
84 * @param title
85 * @return
86 */
87 @Transactional(readOnly = true)
88 protected List<T> findCdmObjectsByTitle(String title){
89 return ((IIdentifiableDao)dao).findByTitle(title);
90 }
91
92 @Transactional(readOnly = true)
93 protected List<T> findCdmObjectsByTitle(String title, Class<T> clazz){
94 return ((IIdentifiableDao)dao).findByTitleAndClass(title, clazz);
95 }
96 @Transactional(readOnly = true)
97 protected List<T> findCdmObjectsByTitle(String title, CdmBase sessionObject){
98 return ((IIdentifiableDao)dao).findByTitle(title, sessionObject);
99 }
100
101 /*
102 * TODO - Migrated from CommonServiceBase
103 * (non-Javadoc)
104 * @see eu.etaxonomy.cdm.api.service.ICommonService#getSourcedObjectById(java.lang.String, java.lang.String)
105 */
106 @Transactional(readOnly = true)
107 public ISourceable getSourcedObjectByIdInSource(Class clazz, String idInSource, String idNamespace) {
108 ISourceable result = null;
109
110 List<T> list = dao.findOriginalSourceByIdInSource(idInSource, idNamespace);
111 if (! list.isEmpty()){
112 result = list.get(0);
113 }
114 return result;
115 }
116
117 /* (non-Javadoc)
118 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#getUuidAndTitleCache()
119 */
120 @Transactional(readOnly = true)
121 public List<UuidAndTitleCache<T>> getUuidAndTitleCache() {
122 return dao.getUuidAndTitleCache();
123 }
124
125 @Transactional(readOnly = true)
126 public Pager<T> findByTitle(Class<? extends T> clazz, String queryString,MatchMode matchmode, List<Criterion> criteria, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
127 Integer numberOfResults = dao.countByTitle(clazz, queryString, matchmode, criteria);
128
129 List<T> results = new ArrayList<T>();
130 if(numberOfResults > 0) { // no point checking again
131 results = dao.findByTitle(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths);
132 }
133
134 return new DefaultPagerImpl<T>(pageNumber, numberOfResults, pageSize, results);
135 }
136
137 @Transactional(readOnly = true)
138 public List<T> listByTitle(Class<? extends T> clazz, String queryString,MatchMode matchmode, List<Criterion> criteria, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
139 Integer numberOfResults = dao.countByTitle(clazz, queryString, matchmode, criteria);
140
141 List<T> results = new ArrayList<T>();
142 if(numberOfResults > 0) { // no point checking again
143 results = dao.findByTitle(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths);
144 }
145 return results;
146 }
147
148 @Transactional(readOnly = true)
149 public List<T> listByReferenceTitle(Class<? extends T> clazz, String queryString,MatchMode matchmode, List<Criterion> criteria, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
150 Integer numberOfResults = dao.countByReferenceTitle(clazz, queryString, matchmode, criteria);
151
152 List<T> results = new ArrayList<T>();
153 if(numberOfResults > 0) { // no point checking again
154 results = dao.findByReferenceTitle(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths);
155 }
156 return results;
157 }
158
159 @Transactional(readOnly = true)
160 public T find(LSID lsid) {
161 return dao.find(lsid);
162 }
163
164 @Transactional(readOnly = true)
165 public Pager<T> search(Class<? extends T> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
166 Integer numberOfResults = dao.count(clazz,queryString);
167
168 List<T> results = new ArrayList<T>();
169 if(numberOfResults > 0) { // no point checking again
170 results = dao.search(clazz,queryString, pageSize, pageNumber, orderHints, propertyPaths);
171 }
172
173 return new DefaultPagerImpl<T>(pageNumber, numberOfResults, pageSize, results);
174 }
175
176 @Transactional(readOnly = false)
177 public void updateTitleCache(Class<? extends T> clazz) {
178 IIdentifiableEntityCacheStrategy<T> cacheStrategy = null;
179 updateTitleCache(clazz, UPDATE_TITLE_CACHE_DEFAULT_STEP_SIZE, cacheStrategy);
180 }
181
182
183 @Transactional(readOnly = false) //TODO check transactional behaviour, e.g. what happens with the session if count is very large
184 public void updateTitleCache(Class<? extends T> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<T> cacheStrategy) {
185 if (stepSize == null){
186 stepSize = UPDATE_TITLE_CACHE_DEFAULT_STEP_SIZE;
187 }
188
189 int count = dao.count(clazz);
190 for(int i = 0 ; i < count ; i = i + stepSize){
191 // not sure if such strict ordering is necessary here, but for safety reasons I do it
192 ArrayList<OrderHint> orderHints = new ArrayList<OrderHint>();
193 orderHints.add( new OrderHint("id", OrderHint.SortOrder.ASCENDING));
194 List<T> list = this.list(clazz, stepSize, i, orderHints, null);
195 List<T> entitiesToUpdate = new ArrayList<T>();
196 for (T entity : list){
197 if (entity.isProtectedTitleCache() == false){
198 IIdentifiableEntityCacheStrategy entityCacheStrategy = cacheStrategy;
199 if (entityCacheStrategy == null){
200 entityCacheStrategy = entity.getCacheStrategy();
201 //FIXME find out why the wrong cache strategy is loaded here, see #1876
202 if (entity instanceof ReferenceBase){
203 entityCacheStrategy = ReferenceFactory.newReference(((ReferenceBase)entity).getType()).getCacheStrategy();
204 }
205 }
206 entity.setCacheStrategy(entityCacheStrategy);
207 //TODO this won't work for those classes that always generate the title cache new
208 String titleCache = entity.getTitleCache();
209 setOtherCachesNull(entity); //TODO find better solution
210 String newTitleCache = entityCacheStrategy.getTitleCache(entity);
211 if (titleCache == null || titleCache != null && ! titleCache.equals(newTitleCache)){
212 entity.setTitleCache(null, false);
213 entity.getTitleCache();
214 entitiesToUpdate.add(entity);
215 }
216 }
217 }
218 saveOrUpdate(entitiesToUpdate);
219
220 }
221 }
222
223 /**
224 * Needs override if not only the title cache should be set to null to
225 * generate the correct new title cache
226 */
227 protected void setOtherCachesNull(T entity) {
228 return;
229 }
230 }
231