View Javadoc
1   package net.sumaris.core.dao.referential.taxon;
2   
3   /*-
4    * #%L
5    * SUMARiS:: Core
6    * %%
7    * Copyright (C) 2018 SUMARiS Consortium
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/gpl-3.0.html>.
22   * #L%
23   */
24  
25  import com.google.common.collect.ImmutableList;
26  import net.sumaris.core.dao.referential.ReferentialDao;
27  import net.sumaris.core.dao.technical.SortDirection;
28  import net.sumaris.core.dao.technical.hibernate.HibernateDaoSupport;
29  import net.sumaris.core.model.referential.taxon.*;
30  import net.sumaris.core.model.technical.optimization.taxon.TaxonGroup2TaxonHierarchy;
31  import net.sumaris.core.util.Beans;
32  import net.sumaris.core.vo.filter.TaxonNameFilterVO;
33  import net.sumaris.core.vo.referential.TaxonNameVO;
34  import org.apache.commons.collections4.CollectionUtils;
35  import org.apache.commons.lang3.ArrayUtils;
36  import org.apache.commons.lang3.StringUtils;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  import org.springframework.beans.factory.annotation.Autowired;
40  import org.springframework.stereotype.Repository;
41  
42  import javax.persistence.EntityManager;
43  import javax.persistence.TypedQuery;
44  import javax.persistence.criteria.*;
45  import java.util.Collection;
46  import java.util.List;
47  import java.util.stream.Collectors;
48  
49  @Repository("taxonNameDao")
50  public class TaxonNameDaoImpl extends HibernateDaoSupport implements TaxonNameDao {
51  
52      /** Logger. */
53      private static final Logger log =
54              LoggerFactory.getLogger(TaxonNameDaoImpl.class);
55  
56      @Autowired
57      private ReferentialDao referentialDao;
58  
59      @Override
60      public List<TaxonNameVO> findByFilter(TaxonNameFilterVO filter, int offset, int size,
61                                            String sortAttribute, SortDirection sortDirection) {
62          EntityManager em = getEntityManager();
63          CriteriaBuilder builder = em.getCriteriaBuilder();
64  
65          // With synonym
66          boolean withSynonyms = filter.getWithSynonyms() != null ? filter.getWithSynonyms() : false;
67  
68          // Taxon group
69          ParameterExpression<Collection> taxonGroupIdsParam = builder.parameter(Collection.class);
70  
71          // Where clause visitor
72          ReferentialDao.QueryVisitor<TaxonName> queryVisitor = (query, root) -> {
73  
74              Expression<Boolean> whereClause = null;
75              if (!withSynonyms) {
76                  whereClause = builder.equal(root.get(TaxonName.Fields.IS_REFERENT), Boolean.TRUE);
77              }
78  
79              Expression<Boolean> taxonGroupClause = null;
80              if (ArrayUtils.isNotEmpty(filter.getTaxonGroupIds())) {
81                  Join<TaxonName, ReferenceTaxon> rt = root.join(TaxonName.Fields.REFERENCE_TAXON, JoinType.INNER);
82                  ListJoin<ReferenceTaxon, TaxonGroup2TaxonHierarchy> tgh = rt.joinList(ReferenceTaxon.Fields.PARENT_TAXON_GROUPS, JoinType.INNER);
83                  taxonGroupClause = builder.in(tgh.get(TaxonGroup2TaxonHierarchy.Fields.PARENT_TAXON_GROUP).get(TaxonGroup.Fields.ID))
84                          .value(taxonGroupIdsParam);
85                  whereClause = whereClause == null ?  taxonGroupClause : builder.and(whereClause, taxonGroupClause);
86              }
87  
88              return whereClause;
89          };
90  
91          TypedQuery<TaxonName> typedQuery = referentialDao.createFindQuery(TaxonName.class,
92                  null,
93                  filter.getTaxonomicLevelIds(),
94                  StringUtils.trimToNull(filter.getSearchText()),
95                  StringUtils.trimToNull(filter.getSearchAttribute()),
96                  filter.getStatusIds(),
97                  sortAttribute,
98                  sortDirection,
99                  queryVisitor);
100 
101         if (ArrayUtils.isNotEmpty(filter.getTaxonGroupIds())) {
102             typedQuery.setParameter(taxonGroupIdsParam,  ImmutableList.copyOf(filter.getTaxonGroupIds()));
103         }
104 
105          return typedQuery.getResultStream()
106                 .map(this::toTaxonNameVO)
107                 .collect(Collectors.toList());
108     }
109 
110     @Override
111     public List<TaxonNameVO> getAll(boolean withSynonyms) {
112         EntityManager em = getEntityManager();
113         CriteriaBuilder builder = em.getCriteriaBuilder();
114         CriteriaQuery<TaxonName> query = builder.createQuery(TaxonName.class);
115         Root<TaxonName> root = query.from(TaxonName.class);
116 
117         ParameterExpression<Boolean> withSynonymParam = builder.parameter(Boolean.class);
118 
119         query.select(root)
120                 .where(builder.and(
121                         // Filter on taxonomic level (species+ subspecies)
122                         builder.in(root.get(TaxonName.Fields.TAXONOMIC_LEVEL).get(TaxonomicLevel.Fields.ID))
123                                .value(ImmutableList.of(TaxonomicLevelId.SPECIES.getId(), TaxonomicLevelId.SUBSPECIES.getId())),
124                         // Filter on is_referent
125                         builder.or(
126                                 builder.isNull(withSynonymParam),
127                                 builder.equal(root.get(TaxonName.Fields.IS_REFERENT), Boolean.TRUE)
128                         )
129                 ));
130 
131         return em.createQuery(query)
132                 .setParameter(withSynonymParam, withSynonyms ? null : false)
133                 .getResultStream()
134                 .map(this::toTaxonNameVO)
135                 .collect(Collectors.toList());
136     }
137 
138     @Override
139     public TaxonNameVO getTaxonNameReferent(Integer referenceTaxonId) {
140         EntityManager em = getEntityManager();
141         CriteriaBuilder builder = em.getCriteriaBuilder();
142         CriteriaQuery<TaxonName> query = builder.createQuery(TaxonName.class);
143         Root<TaxonName> root = query.from(TaxonName.class);
144 
145         ParameterExpression<Integer> idParam = builder.parameter(Integer.class);
146 
147         query.select(root)
148                 .where(builder.equal(root.get(TaxonName.Fields.REFERENCE_TAXON).get(ReferenceTaxon.Fields.ID), idParam));
149 
150         TypedQuery<TaxonName> q = em.createQuery(query)
151                 .setParameter(idParam, referenceTaxonId);
152         List<TaxonName> referenceTaxons = q.getResultList();
153         if (CollectionUtils.isEmpty(referenceTaxons)) return null;
154         if (referenceTaxons.size() > 1)  {
155             log.warn(String.format("ReferenceTaxon {id=%} has more than one TaxonNames, with IS_REFERENT=1. Will use the first found.", referenceTaxonId));
156         }
157 
158         return toTaxonNameVO(referenceTaxons.get(0));
159     }
160 
161     @Override
162     public List<TaxonName> getAllTaxonNameByParentIds(Collection<Integer> taxonNameParentIds) {
163         CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
164         CriteriaQuery<TaxonName> query = builder.createQuery(TaxonName.class);
165         Root<TaxonName> root = query.from(TaxonName.class);
166 
167         ParameterExpression<Collection> parentIdsParam = builder.parameter(Collection.class);
168 
169         query.where(builder.in(root.get(TaxonName.Fields.PARENT_TAXON_NAME).get(TaxonName.Fields.ID)).value(parentIdsParam));
170 
171         return getEntityManager().createQuery(query)
172                 .setParameter(parentIdsParam, taxonNameParentIds)
173                 .getResultList();
174     }
175 
176     @Override
177     public List<TaxonNameVO> getAllByTaxonGroupId(Integer taxonGroupId) {
178         EntityManager em = getEntityManager();
179         CriteriaBuilder builder = em.getCriteriaBuilder();
180         CriteriaQuery<TaxonName> query = builder.createQuery(TaxonName.class);
181         Root<TaxonGroup2TaxonHierarchy> root = query.from(TaxonGroup2TaxonHierarchy.class);
182 
183         ParameterExpression<Integer> taxonGroupIdParam = builder.parameter(Integer.class);
184 
185         Join<TaxonGroup2TaxonHierarchy, ReferenceTaxon> rt = root.join(TaxonGroup2TaxonHierarchy.Fields.CHILD_REFERENCE_TAXON, JoinType.INNER);
186         Join<ReferenceTaxon, TaxonName> tn = rt.joinList(ReferenceTaxon.Fields.TAXON_NAMES, JoinType.INNER);
187 
188         query.select(tn)
189                 .where(builder.and(
190                         // Filter on taxon_group
191                         builder.equal(root.get(TaxonGroup2TaxonHierarchy.Fields.PARENT_TAXON_GROUP).get(TaxonGroup.Fields.ID), taxonGroupIdParam),
192                         // Filter on taxonomic level (species and subspecies)
193                         builder.in(tn.get(TaxonName.Fields.TAXONOMIC_LEVEL).get(TaxonomicLevel.Fields.ID))
194                                 .value(ImmutableList.of(TaxonomicLevelId.SPECIES.getId(), TaxonomicLevelId.SUBSPECIES.getId())),
195                         // Filter on is_referent
196                         builder.equal(tn.get(TaxonName.Fields.IS_REFERENT), Boolean.TRUE)
197                 ));
198 
199         return em.createQuery(query)
200                 .setParameter(taxonGroupIdParam, taxonGroupId)
201                 .getResultStream()
202                 .map(this::toTaxonNameVO)
203                 .collect(Collectors.toList());
204     }
205 
206     /* -- protected methods -- */
207 
208     protected List<TaxonNameVO> toTaxonNameVOs(List<TaxonName> source) {
209         return source.stream().map(this::toTaxonNameVO).collect(Collectors.toList());
210     }
211 
212     protected TaxonNameVO toTaxonNameVO(TaxonName source) {
213         if (source == null) return null;
214 
215         TaxonNameVOtial/TaxonNameVO.html#TaxonNameVO">TaxonNameVO target = new TaxonNameVO();
216 
217         Beans.copyProperties(source, target);
218 
219         // Reference taxon
220         target.setReferenceTaxonId(source.getReferenceTaxon().getId());
221         return target;
222     }
223 }