View Javadoc
1   package net.sumaris.core.dao.data;
2   
3   /*-
4    * #%L
5    * SUMARiS:: Core
6    * %%
7    * Copyright (C) 2018 - 2019 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.Sets;
26  import net.sumaris.core.config.SumarisConfiguration;
27  import net.sumaris.core.dao.technical.SortDirection;
28  import net.sumaris.core.dao.technical.hibernate.HibernateDaoSupport;
29  import net.sumaris.core.dao.technical.model.IEntity;
30  import net.sumaris.core.exception.SumarisTechnicalException;
31  import net.sumaris.core.model.administration.programStrategy.Program;
32  import net.sumaris.core.model.administration.user.Department;
33  import net.sumaris.core.model.administration.user.Person;
34  import net.sumaris.core.model.data.*;
35  import net.sumaris.core.model.referential.QualityFlag;
36  import net.sumaris.core.util.Beans;
37  import net.sumaris.core.vo.administration.user.DepartmentVO;
38  import net.sumaris.core.vo.administration.user.PersonVO;
39  import net.sumaris.core.vo.data.IDataVO;
40  import net.sumaris.core.vo.data.IRootDataVO;
41  import net.sumaris.core.vo.data.VesselSnapshotVO;
42  import org.apache.commons.collections4.CollectionUtils;
43  import org.apache.commons.collections4.MapUtils;
44  import org.apache.commons.lang3.StringUtils;
45  
46  import javax.persistence.criteria.*;
47  import java.io.Serializable;
48  import java.util.Map;
49  import java.util.Objects;
50  import java.util.Set;
51  
52  /**
53   * @author Benoit Lavenier <benoit.lavenier@e-is.pro>*
54   */
55  public abstract class BaseDataDaoImpl extends HibernateDaoSupport {
56  
57      public <T extends Serializable> void copyRootDataProperties(IRootDataVO<T> source,
58                                                                  IRootDataEntity<T> target,
59                                                                  boolean copyIfNull) {
60  
61          // Copy root data properties without exception
62          copyRootDataProperties(source, target, copyIfNull, (String) null);
63      }
64  
65      public <T extends Serializable> void copyRootDataProperties(IRootDataVO<T> source,
66                                                                  IRootDataEntity<T> target,
67                                                                  boolean copyIfNull,
68                                                                  String... exceptProperties) {
69  
70          // Copy data properties except some properties if specified
71          copyDataProperties(source, target, copyIfNull, exceptProperties);
72  
73          // Recorder person
74          copyRecorderPerson(source, target, copyIfNull);
75  
76          // Program
77          copyProgram(source, target, copyIfNull);
78      }
79  
80      public <T extends Serializable> void copyDataProperties(IDataVO<T> source,
81                                                              IDataEntity<T> target,
82                                                              boolean copyIfNull) {
83  
84          // Copy data properties without exception
85          copyDataProperties(source, target, copyIfNull, (String) null);
86      }
87  
88      public <T extends Serializable> void copyDataProperties(IDataVO<T> source,
89                                                              IDataEntity<T> target,
90                                                              boolean copyIfNull,
91                                                              String... exceptProperties) {
92  
93          // Copy bean properties except some properties if specified
94          Beans.copyProperties(source, target, exceptProperties);
95  
96          // Recorder department
97          copyRecorderDepartment(source, target, copyIfNull);
98  
99          // Quality flag
100         copyQualityFlag(source, target, copyIfNull);
101     }
102 
103     public <T extends Serializable> void copyRecorderDepartment(IWithRecorderDepartmentEntity<T, DepartmentVO> source,
104                                                                 IWithRecorderDepartmentEntity<T, Department> target,
105                                                                 boolean copyIfNull) {
106         // Recorder department
107         if (copyIfNull || source.getRecorderDepartment() != null) {
108             if (source.getRecorderDepartment() == null || source.getRecorderDepartment().getId() == null) {
109                 target.setRecorderDepartment(null);
110             } else {
111                 target.setRecorderDepartment(load(Department.class, source.getRecorderDepartment().getId()));
112             }
113         }
114     }
115 
116     public <T extends Serializable> void copyRecorderPerson(IWithRecorderPersonEntity<T, PersonVO> source,
117                                                             IWithRecorderPersonEntity<T, Person> target,
118                                                             boolean copyIfNull) {
119         if (copyIfNull || source.getRecorderPerson() != null) {
120             if (source.getRecorderPerson() == null || source.getRecorderPerson().getId() == null) {
121                 target.setRecorderPerson(null);
122             } else {
123                 target.setRecorderPerson(load(Person.class, source.getRecorderPerson().getId()));
124             }
125         }
126     }
127 
128     public <T extends Serializable> void copyObservers(IWithObserversEntity<T, PersonVO> source,
129                                                        IWithObserversEntity<T, Person> target,
130                                                        boolean copyIfNull) {
131         // Observers
132         if (copyIfNull || source.getObservers() != null) {
133             if (CollectionUtils.isEmpty(source.getObservers())) {
134                 if (target.getId() != null && CollectionUtils.isNotEmpty(target.getObservers())) {
135                     target.getObservers().clear();
136                 }
137             } else {
138                 Set<Person> observers = target.getId() != null ? target.getObservers() : Sets.newHashSet();
139                 Map<Integer, Person> observersToRemove = Beans.splitById(observers);
140                 source.getObservers().stream()
141                         .map(IEntity::getId)
142                         .filter(Objects::nonNull)
143                         .forEach(personId -> {
144                             if (observersToRemove.remove(personId) == null) {
145                                 // Add new item
146                                 observers.add(load(Person.class, personId));
147                             }
148                         });
149 
150                 // Remove deleted tableNames
151                 if (MapUtils.isNotEmpty(observersToRemove)) {
152                     observers.removeAll(observersToRemove.values());
153                 }
154                 target.setObservers(observers);
155             }
156         }
157     }
158 
159     public void copyVessel(IWithVesselSnapshotEntity<Integer, VesselSnapshotVO> source,
160                            IWithVesselEntity<Integer, Vessel> target,
161                            boolean copyIfNull) {
162         // Vessel
163         if (copyIfNull || (source.getVesselSnapshot() != null && source.getVesselSnapshot().getId() != null)) {
164             if (source.getVesselSnapshot() == null || source.getVesselSnapshot().getId() == null) {
165                 target.setVessel(null);
166             } else {
167                 target.setVessel(load(Vessel.class, source.getVesselSnapshot().getId()));
168             }
169         }
170     }
171 
172     public <T extends Serializable> void copyQualityFlag(IDataVO<T> source,
173                                                          IDataEntity<T> target,
174                                                          boolean copyIfNull) {
175         // Quality flag
176         if (copyIfNull || source.getQualityFlagId() != null) {
177             if (source.getQualityFlagId() == null) {
178                 target.setQualityFlag(load(QualityFlag.class, SumarisConfiguration.getInstance().getDefaultQualityFlagId()));
179             } else {
180                 target.setQualityFlag(load(QualityFlag.class, source.getQualityFlagId()));
181             }
182         }
183     }
184 
185     public <T extends Serializable> void copyProgram(IRootDataVO<T> source,
186                                                      IRootDataEntity<T> target,
187                                                      boolean copyIfNull) {
188         // Program
189         if (copyIfNull || (source.getProgram() != null && (source.getProgram().getId() != null || source.getProgram().getLabel() != null))) {
190             if (source.getProgram() == null || (source.getProgram().getId() == null && source.getProgram().getLabel() == null)) {
191                 target.setProgram(null);
192             }
193             // Load by id
194             else if (source.getProgram().getId() != null) {
195                 target.setProgram(load(Program.class, source.getProgram().getId()));
196             }
197             // Load by label
198             else {
199                 throw new SumarisTechnicalException("Missing program.id !");
200             }
201         }
202     }
203 
204     /**
205      * Add a orderBy on query
206      *
207      * @param query the query
208      * @param cb criteria builder
209      * @param root the root of the query
210      * @param sortAttribute the sort attribute (can be a nested attribute)
211      * @param sortDirection the direction
212      * @param <T> type of query
213      * @return the query itself
214      */
215     protected <T> CriteriaQuery<T> addSorting(CriteriaQuery<T> query,
216                                               CriteriaBuilder cb,
217                                               Root<?> root, String sortAttribute, SortDirection sortDirection) {
218         // Add sorting
219         if (StringUtils.isNotBlank(sortAttribute)) {
220             Expression<?> sortExpression = composePath(root, sortAttribute);
221             query.orderBy(SortDirection.DESC.equals(sortDirection) ?
222                 cb.desc(sortExpression) :
223                 cb.asc(sortExpression)
224             );
225         }
226         return query;
227     }
228 
229     /**
230      * Compose a Path from root, accepting nested property name
231      *
232      * @param root the root expression
233      * @param attributePath the attribute path, can contains '.'
234      * @param <X> Type of Path
235      * @return the composed Path
236      */
237     protected <X> Path<X> composePath(Root<?> root, String attributePath) {
238 
239         String[] paths = attributePath.split("\\.");
240         From<?, ?> from = root; // starting from root
241         Path<X> result = null;
242 
243         for (int i = 0; i < paths.length; i++) {
244             String path = paths[i];
245 
246             if (i == paths.length - 1) {
247                 // last path, get it
248                 result = from.get(path);
249             } else {
250                 // need a join (find it from existing joins of from)
251                 Join join = from.getJoins().stream()
252                     .filter(j -> j.getAttribute().getName().equals(path))
253                     .findFirst().orElse(null);
254                 if (join == null) {
255                     throw new IllegalArgumentException(String.format("the join %s from %s doesn't exists", path, from.getClass().getSimpleName()));
256                 }
257                 from = join;
258             }
259         }
260 
261         return result;
262     }
263 }