Fix Reference Key columns persistence issue in db
[policy/models.git] / models-dao / src / main / java / org / onap / policy / models / dao / impl / DefaultPfDao.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019-2021 Nordix Foundation.
4  *  Modifications Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.models.dao.impl;
23
24 import java.sql.Timestamp;
25 import java.time.Instant;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Map;
30 import javax.persistence.EntityManager;
31 import javax.persistence.EntityManagerFactory;
32 import javax.persistence.Persistence;
33 import javax.persistence.TypedQuery;
34 import javax.ws.rs.core.Response;
35 import org.onap.policy.models.base.PfConcept;
36 import org.onap.policy.models.base.PfConceptKey;
37 import org.onap.policy.models.base.PfModelException;
38 import org.onap.policy.models.base.PfModelRuntimeException;
39 import org.onap.policy.models.base.PfReferenceKey;
40 import org.onap.policy.models.base.PfReferenceTimestampKey;
41 import org.onap.policy.models.base.PfTimestampKey;
42 import org.onap.policy.models.base.PfUtils;
43 import org.onap.policy.models.dao.DaoParameters;
44 import org.onap.policy.models.dao.PfDao;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 /**
49  * The Class DefaultPfDao is an JPA implementation of the {@link PfDao} class for Policy Framework concepts
50  * ({@link PfConcept}). It uses the default JPA implementation in the javax {@link Persistence} class.
51  */
52 public class DefaultPfDao implements PfDao {
53     private static final Logger LOGGER = LoggerFactory.getLogger(DefaultPfDao.class);
54
55     // @formatter:off
56     private static final String NAME           = "name";
57     private static final String VERSION        = "version";
58     private static final String TIMESTAMP      = "timeStamp";
59     private static final String PARENT_NAME    = "parentname";
60     private static final String PARENT_VERSION = "parentversion";
61     private static final String LOCAL_NAME     = "localname";
62
63     private static final String TABLE_TOKEN = "__TABLE__";
64
65     private static final String DELETE_FROM_TABLE = "DELETE FROM __TABLE__ c";
66
67     private static final String SELECT_FROM_TABLE = "SELECT c FROM __TABLE__ c";
68
69     private static final String WHERE      = " WHERE ";
70     private static final String AND        = " AND ";
71     private static final String ORDER      = " ORDER BY ";
72
73     private static final String NAME_FILTER            = "c.key.name = :name";
74     private static final String VERSION_FILTER         = "c.key.version = :version";
75     private static final String TIMESTAMP_FILTER       = "c.key.timeStamp = :timeStamp";
76     private static final String TIMESTAMP_START_FILTER = "c.key.timeStamp >= :startTime";
77     private static final String TIMESTAMP_END_FILTER   = "c.key.timeStamp <= :endTime";
78     private static final String PARENT_NAME_FILTER     = "c.key.parentKeyName = :parentname";
79     private static final String PARENT_VERSION_FILTER  = "c.key.parentKeyVersion = :parentversion";
80     private static final String LOCAL_NAME_FILTER      = "c.key.localName = :localname";
81
82     private static final String PARENT_NAME_REF_FILTER     = "c.key.referenceKey.parentKeyName = :parentKeyName";
83
84     private static final String CLONE_ERR_MSG = "Could not clone object of class \"{}\"";
85
86     private static final String DELETE_BY_CONCEPT_KEY =
87             DELETE_FROM_TABLE + WHERE + NAME_FILTER + AND + VERSION_FILTER;
88
89     private static final String DELETE_BY_TIMESTAMP_KEY =
90             DELETE_FROM_TABLE + WHERE + NAME_FILTER + AND + VERSION_FILTER  + AND + TIMESTAMP_FILTER;
91
92     private static final String DELETE_BY_REFERENCE_KEY =
93             DELETE_FROM_TABLE + WHERE + PARENT_NAME_FILTER + AND + PARENT_VERSION_FILTER + AND + LOCAL_NAME_FILTER;
94
95     private static final String SELECT_ALL_FOR_PARENT =
96             SELECT_FROM_TABLE + WHERE + PARENT_NAME_FILTER + AND + PARENT_VERSION_FILTER;
97
98     private static final String SELECT_ALL_VERSIONS_FOR_PARENT =
99             SELECT_FROM_TABLE + WHERE + PARENT_NAME_FILTER;
100
101     private static final String SELECT_ALL_VERSIONS = SELECT_FROM_TABLE + WHERE + NAME_FILTER;
102
103     private static final String SELECT_BY_CONCEPT_KEY =
104             SELECT_FROM_TABLE + WHERE + NAME_FILTER + AND + VERSION_FILTER;
105
106     private static final String SELECT_BY_REFERENCE_KEY =
107             SELECT_FROM_TABLE + WHERE + PARENT_NAME_FILTER + AND + PARENT_VERSION_FILTER + AND + LOCAL_NAME_FILTER;
108     // @formatter:on
109
110     // Entity manager for JPA
111     private EntityManagerFactory emf = null;
112
113     @Override
114     public void init(final DaoParameters daoParameters) throws PfModelException {
115         if (daoParameters == null || daoParameters.getPersistenceUnit() == null) {
116             LOGGER.error("Policy Framework persistence unit parameter not set");
117             throw new PfModelException(Response.Status.INTERNAL_SERVER_ERROR,
118                     "Policy Framework persistence unit parameter not set");
119         }
120
121         LOGGER.debug("Creating Policy Framework persistence unit \"{}\" . . .", daoParameters.getPersistenceUnit());
122         try {
123             emf = Persistence.createEntityManagerFactory(daoParameters.getPersistenceUnit(),
124                     daoParameters.getJdbcProperties());
125         } catch (final Exception ex) {
126             String errorMessage = "Creation of Policy Framework persistence unit \""
127                     + daoParameters.getPersistenceUnit() + "\" failed";
128             LOGGER.warn(errorMessage);
129             throw new PfModelException(Response.Status.INTERNAL_SERVER_ERROR, errorMessage, ex);
130         }
131         LOGGER.debug("Created Policy Framework persistence unit \"{}\"", daoParameters.getPersistenceUnit());
132     }
133
134     /**
135      * Gets the entity manager for this DAO.
136      *
137      * @return the entity manager
138      */
139     protected final synchronized EntityManager getEntityManager() {
140         if (emf == null) {
141             LOGGER.warn("Policy Framework DAO has not been initialized");
142             throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR,
143                     "Policy Framework DAO has not been initialized");
144         }
145
146         return emf.createEntityManager();
147     }
148
149     @Override
150     public final void close() {
151         if (emf != null) {
152             emf.close();
153         }
154     }
155
156     @Override
157     public <T extends PfConcept> void create(final T obj) {
158         if (obj == null) {
159             return;
160         }
161         final EntityManager mg = getEntityManager();
162         try {
163             mg.getTransaction().begin();
164             mg.merge(obj);
165             mg.getTransaction().commit();
166         } finally {
167             mg.close();
168         }
169     }
170
171     @Override
172     public <T extends PfConcept> void delete(final T obj) {
173         if (obj == null) {
174             return;
175         }
176         final EntityManager mg = getEntityManager();
177         try {
178             mg.getTransaction().begin();
179             mg.remove(mg.contains(obj) ? obj : mg.merge(obj));
180             mg.getTransaction().commit();
181         } finally {
182             mg.close();
183         }
184     }
185
186     @Override
187     public <T extends PfConcept> void delete(final Class<T> someClass, final PfConceptKey key) {
188         if (key == null) {
189             return;
190         }
191         final EntityManager mg = getEntityManager();
192         try {
193             // @formatter:off
194             mg.getTransaction().begin();
195             mg.createQuery(setQueryTable(DELETE_BY_CONCEPT_KEY, someClass), someClass)
196                 .setParameter(NAME,    key.getName())
197                 .setParameter(VERSION, key.getVersion())
198                 .executeUpdate();
199             mg.getTransaction().commit();
200             // @formatter:on
201         } finally {
202             mg.close();
203         }
204     }
205
206     @Override
207     public <T extends PfConcept> void delete(final Class<T> someClass, final PfReferenceKey key) {
208         if (key == null) {
209             return;
210         }
211         final EntityManager mg = getEntityManager();
212         try {
213             // @formatter:off
214             mg.getTransaction().begin();
215             mg.createQuery(setQueryTable(DELETE_BY_REFERENCE_KEY, someClass), someClass)
216                 .setParameter(PARENT_NAME,    key.getParentKeyName())
217                 .setParameter(PARENT_VERSION, key.getParentKeyVersion())
218                 .setParameter(LOCAL_NAME,     key.getLocalName())
219                 .executeUpdate();
220             mg.getTransaction().commit();
221             // @formatter:on
222         } finally {
223             mg.close();
224         }
225     }
226
227     @Override
228     public <T extends PfConcept> void delete(final Class<T> someClass, final PfTimestampKey key) {
229         if (key == null) {
230             return;
231         }
232         final EntityManager mg = getEntityManager();
233         try {
234             // @formatter:off
235             mg.getTransaction().begin();
236             mg.createQuery(setQueryTable(DELETE_BY_TIMESTAMP_KEY, someClass), someClass)
237                     .setParameter(NAME,    key.getName())
238                     .setParameter(VERSION, key.getVersion())
239                     .setParameter(TIMESTAMP, key.getTimeStamp())
240                     .executeUpdate();
241             mg.getTransaction().commit();
242             // @formatter:on
243         } finally {
244             mg.close();
245         }
246     }
247
248     @Override
249     public <T extends PfConcept> void createCollection(final Collection<T> objs) {
250         if (objs == null || objs.isEmpty()) {
251             return;
252         }
253         final EntityManager mg = getEntityManager();
254         try {
255             mg.getTransaction().begin();
256             for (final T t : objs) {
257                 mg.merge(t);
258             }
259             mg.getTransaction().commit();
260         } finally {
261             mg.close();
262         }
263     }
264
265     @Override
266     public <T extends PfConcept> void deleteCollection(final Collection<T> objs) {
267         if (objs == null || objs.isEmpty()) {
268             return;
269         }
270         final EntityManager mg = getEntityManager();
271         try {
272             mg.getTransaction().begin();
273             for (final T t : objs) {
274                 mg.remove(mg.contains(t) ? t : mg.merge(t));
275             }
276             mg.getTransaction().commit();
277         } finally {
278             mg.close();
279         }
280     }
281
282     @Override
283     public <T extends PfConcept> int deleteByConceptKey(final Class<T> someClass, final Collection<PfConceptKey> keys) {
284         if (keys == null || keys.isEmpty()) {
285             return 0;
286         }
287         int deletedCount = 0;
288         final EntityManager mg = getEntityManager();
289         try {
290             // @formatter:off
291             mg.getTransaction().begin();
292             for (final PfConceptKey key : keys) {
293                 deletedCount += mg.createQuery(setQueryTable(DELETE_BY_CONCEPT_KEY, someClass), someClass)
294                     .setParameter(NAME,    key.getName())
295                     .setParameter(VERSION, key.getVersion())
296                     .executeUpdate();
297             }
298             mg.getTransaction().commit();
299             // @formatter:on
300         } finally {
301             mg.close();
302         }
303         return deletedCount;
304     }
305
306     @Override
307     public <T extends PfConcept> int deleteByReferenceKey(final Class<T> someClass,
308             final Collection<PfReferenceKey> keys) {
309         if (keys == null || keys.isEmpty()) {
310             return 0;
311         }
312         int deletedCount = 0;
313         final EntityManager mg = getEntityManager();
314         try {
315             // @formatter:off
316             mg.getTransaction().begin();
317             for (final PfReferenceKey key : keys) {
318                 deletedCount += mg.createQuery(setQueryTable(DELETE_BY_REFERENCE_KEY, someClass), someClass)
319                     .setParameter(PARENT_NAME,    key.getParentKeyName())
320                     .setParameter(PARENT_VERSION, key.getParentKeyVersion())
321                     .setParameter(LOCAL_NAME,     key.getLocalName())
322                     .executeUpdate();
323             }
324             mg.getTransaction().commit();
325             // @formatter:on
326         } finally {
327             mg.close();
328         }
329         return deletedCount;
330     }
331
332     @Override
333     public <T extends PfConcept> void deleteAll(final Class<T> someClass) {
334         final EntityManager mg = getEntityManager();
335         try {
336             mg.getTransaction().begin();
337             mg.createQuery(setQueryTable(DELETE_FROM_TABLE, someClass), someClass).executeUpdate();
338             mg.getTransaction().commit();
339         } finally {
340             mg.close();
341         }
342     }
343
344     @Override
345     public <T extends PfConcept> List<T> getFiltered(final Class<T> someClass, final String name,
346             final String version) {
347         if (name == null) {
348             return getAll(someClass);
349         }
350
351         if (version == null) {
352             return getAllVersions(someClass, name);
353         }
354
355         T foundConcept = get(someClass, new PfConceptKey(name, version));
356
357         return (foundConcept == null ? Collections.emptyList() : Collections.singletonList(foundConcept));
358     }
359
360     @Override
361     public <T extends PfConcept> List<T> getFiltered(final Class<T> someClass, final String name, final String version,
362             final Instant startTime, final Instant endTime, final Map<String, Object> filterMap, final String sortOrder,
363             final int getRecordNum) {
364         final EntityManager mg = getEntityManager();
365
366         String filterQueryString = SELECT_FROM_TABLE + WHERE;
367
368         try {
369             if (filterMap != null) {
370                 filterQueryString = buildFilter(filterMap, filterQueryString);
371             }
372             filterQueryString = addKeyFilterString(filterQueryString, name, startTime, endTime,
373                 isRefTimestampKey(someClass));
374             if (getRecordNum > 0) {
375                 filterQueryString += ORDER + " c.key.timeStamp " + sortOrder;
376             }
377             TypedQuery<T> query = mg.createQuery(setQueryTable(filterQueryString, someClass), someClass);
378
379             if (filterMap != null) {
380                 for (Map.Entry<String, Object> entry : filterMap.entrySet()) {
381                     query.setParameter(entry.getKey(), entry.getValue());
382                 }
383             }
384             if (name != null) {
385                 if (isRefTimestampKey(someClass)) {
386                     query.setParameter("parentKeyName", name);
387                 } else {
388                     query.setParameter("name", name);
389                 }
390             }
391             if (startTime != null) {
392                 if (endTime != null) {
393                     query.setParameter("startTime", Timestamp.from(startTime));
394                     query.setParameter("endTime", Timestamp.from(endTime));
395                 } else {
396                     query.setParameter("startTime", Timestamp.from(startTime));
397                 }
398             } else {
399                 if (endTime != null) {
400                     query.setParameter("endTime", Timestamp.from(endTime));
401                 }
402             }
403             if (getRecordNum > 0) {
404                 query.setMaxResults(getRecordNum);
405             }
406
407             LOGGER.debug("filterQueryString is  \"{}\"", filterQueryString);
408             return query.getResultList();
409         }  finally {
410             mg.close();
411         }
412     }
413
414     /**
415      * This method checks if the class invoking the DAO is using PfReferenceTimestamp Key.
416      * @param someClass class that invoked Dao
417      * @return true if the key is PfReferenceTimestampKey.
418      */
419     private <T extends PfConcept> boolean isRefTimestampKey(final Class<T> someClass) {
420         try {
421             return PfReferenceTimestampKey.class.isAssignableFrom(someClass.getDeclaredField("key").getType());
422         } catch (NoSuchFieldException e) {
423             LOGGER.error("Error verifying the key for reference timestamp:", e);
424             return false;
425         }
426     }
427
428     private String buildFilter(final Map<String, Object> filterMap, String filterQueryString) {
429         StringBuilder bld = new StringBuilder(filterQueryString);
430         for (String key : filterMap.keySet()) {
431             bld.append("c." + key + "= :" + key + AND);
432         }
433         return bld.toString();
434     }
435
436     @Override
437     public <T extends PfConcept> T get(final Class<T> someClass, final PfConceptKey key) {
438         return genericGet(someClass, key);
439     }
440
441     @Override
442     public <T extends PfConcept> T get(final Class<T> someClass, final PfReferenceKey key) {
443         return genericGet(someClass, key);
444     }
445
446     @Override
447     public <T extends PfConcept> T get(final Class<T> someClass, final PfTimestampKey key) {
448         return genericGet(someClass, key);
449     }
450
451     @Override
452     public <T extends PfConcept> T get(final Class<T> someClass, final PfReferenceTimestampKey key) {
453         return genericGet(someClass, key);
454     }
455
456     private <T extends PfConcept> T genericGet(final Class<T> someClass, final Object key) {
457         if (someClass == null) {
458             return null;
459         }
460         final EntityManager mg = getEntityManager();
461         try {
462             final T t = mg.find(someClass, key);
463             if (t != null) {
464                 mg.refresh(t);
465             }
466             return checkAndReturn(someClass, t);
467         } finally {
468             mg.close();
469         }
470     }
471
472     @Override
473     public <T extends PfConcept> List<T> getAll(final Class<T> someClass) {
474         if (someClass == null) {
475             return Collections.emptyList();
476         }
477         final EntityManager mg = getEntityManager();
478         try {
479             return mg.createQuery(setQueryTable(SELECT_FROM_TABLE, someClass), someClass).getResultList();
480         } finally {
481             mg.close();
482         }
483     }
484
485     @Override
486     public <T extends PfConcept> List<T> getAll(final Class<T> someClass, final PfConceptKey parentKey) {
487         if (someClass == null) {
488             return Collections.emptyList();
489         }
490         final EntityManager mg = getEntityManager();
491         try {
492             // @formatter:off
493             return mg.createQuery(setQueryTable(SELECT_ALL_FOR_PARENT, someClass), someClass)
494                     .setParameter(PARENT_NAME,    parentKey.getName())
495                     .setParameter(PARENT_VERSION, parentKey.getVersion())
496                     .getResultList();
497             // @formatter:on
498         } finally {
499             mg.close();
500         }
501     }
502
503     @Override
504     public <T extends PfConcept> List<T> getAllVersionsByParent(final Class<T> someClass, final String parentKeyName) {
505         if (someClass == null || parentKeyName == null) {
506             return Collections.emptyList();
507         }
508         final EntityManager mg = getEntityManager();
509         try {
510             // @formatter:off
511             return mg.createQuery(setQueryTable(SELECT_ALL_VERSIONS_FOR_PARENT, someClass), someClass)
512                     .setParameter(PARENT_NAME, parentKeyName)
513                     .getResultList();
514             // @formatter:on
515         } finally {
516             mg.close();
517         }
518     }
519
520     @Override
521     public <T extends PfConcept> List<T> getAllVersions(final Class<T> someClass, final String conceptName) {
522         if (someClass == null || conceptName == null) {
523             return Collections.emptyList();
524         }
525         final EntityManager mg = getEntityManager();
526         try {
527             // @formatter:off
528             return mg.createQuery(setQueryTable(SELECT_ALL_VERSIONS, someClass), someClass)
529                     .setParameter(NAME, conceptName)
530                     .getResultList();
531             // @formatter:on
532         } finally {
533             mg.close();
534         }
535     }
536
537     @Override
538     public <T extends PfConcept> T getConcept(final Class<T> someClass, final PfConceptKey key) {
539         if (someClass == null || key == null) {
540             return null;
541         }
542         final EntityManager mg = getEntityManager();
543         List<T> ret;
544         try {
545             // @formatter:off
546             ret = mg.createQuery(setQueryTable(SELECT_BY_CONCEPT_KEY, someClass), someClass)
547                     .setParameter(NAME,    key.getName())
548                     .setParameter(VERSION, key.getVersion())
549                     .getResultList();
550             // @formatter:on
551         } finally {
552             mg.close();
553         }
554
555         return getSingleResult(someClass, key.getId(), ret);
556     }
557
558     @Override
559     public <T extends PfConcept> T getConcept(final Class<T> someClass, final PfReferenceKey key) {
560         if (someClass == null || key == null) {
561             return null;
562         }
563         final EntityManager mg = getEntityManager();
564         List<T> ret;
565         try {
566             // @formatter:off
567             ret = mg.createQuery(setQueryTable(SELECT_BY_REFERENCE_KEY, someClass), someClass)
568                     .setParameter(PARENT_NAME,    key.getParentKeyName())
569                     .setParameter(PARENT_VERSION, key.getParentKeyVersion())
570                     .setParameter(LOCAL_NAME,     key.getLocalName())
571                     .getResultList();
572             // @formatter:on
573         } finally {
574             mg.close();
575         }
576
577         return getSingleResult(someClass, key.getId(), ret);
578     }
579
580     @Override
581     public <T extends PfConcept> T update(final T obj) {
582         final EntityManager mg = getEntityManager();
583         T ret;
584         try {
585             mg.getTransaction().begin();
586             ret = mg.merge(obj);
587             mg.flush();
588             mg.getTransaction().commit();
589         } finally {
590             mg.close();
591         }
592         return ret;
593     }
594
595     @Override
596     public <T extends PfConcept> long size(final Class<T> someClass) {
597         if (someClass == null) {
598             return 0;
599         }
600         final EntityManager mg = getEntityManager();
601         long size = 0;
602         try {
603             size = mg.createQuery("SELECT COUNT(c) FROM " + someClass.getSimpleName() + " c", Long.class)
604                     .getSingleResult();
605         } finally {
606             mg.close();
607         }
608         return size;
609     }
610
611     /**
612      * Add the table to a query string.
613      *
614      * @param queryString the query string
615      * @param tableClass the class name of the table
616      * @return the updated query string
617      */
618     private <T extends PfConcept> String setQueryTable(final String queryString, final Class<T> tableClass) {
619         return queryString.replace(TABLE_TOKEN, tableClass.getSimpleName());
620     }
621
622     /**
623      * Check that a query returned one and only one entry and return that entry.
624      *
625      * @param someClass the class being searched for
626      * @param conceptName the concept name being searched for
627      * @param resultList the result list returned by the query
628      * @return the single unique result
629      */
630     private <T extends PfConcept> T getSingleResult(final Class<T> someClass, final String searchFilter, List<T> ret) {
631         if (ret == null || ret.isEmpty()) {
632             return null;
633         }
634         if (ret.size() > 1) {
635             throw new IllegalArgumentException("More than one result was returned query on " + someClass
636                     + " with filter " + searchFilter + ": " + ret);
637         }
638         return ret.get(0);
639     }
640
641     /**
642      * generate filter string with the filter value in TimestampKey.
643      *
644      * @param inputFilterString current filterString generated from FilterMap
645      * @param name the pdp name the start timeStamp to filter from database, filter rule: startTime <= filteredRecord
646      *        timeStamp <= endTime. null for ignore start time.
647      * @param endTime the end timeStamp to filter from database, filter rule: startTime <= filteredRecord timeStamp <=
648      *        endTime. null for ignore end time
649      * @param isRefTimestampKey boolean value, set to true if the query invoked for pfReferenceTimestampKey
650      * @return the filter string to query database
651      */
652     private String addKeyFilterString(String inputFilterString, final String name, final Instant startTime,
653             final Instant endTime, final boolean isRefTimestampKey) {
654         String filterQueryString;
655         String inputFilter = inputFilterString;
656         if (name != null) {
657             if (isRefTimestampKey) {
658                 inputFilter += PARENT_NAME_REF_FILTER + AND;
659             } else {
660                 inputFilter += NAME_FILTER + AND;
661             }
662         }
663         if (startTime != null) {
664             if (endTime != null) {
665                 filterQueryString = inputFilter + TIMESTAMP_START_FILTER + AND + TIMESTAMP_END_FILTER;
666             } else {
667                 filterQueryString = inputFilter + TIMESTAMP_START_FILTER;
668             }
669         } else {
670             if (endTime != null) {
671                 filterQueryString = inputFilter + TIMESTAMP_END_FILTER;
672             } else {
673                 filterQueryString = inputFilter.substring(0, inputFilter.length() - AND.length());
674             }
675         }
676
677         return filterQueryString;
678     }
679
680     /**
681      * check the result get from database and return the object.
682      *
683      * @param <T> the type of the object to get, a subclass of {@link PfConcept}
684      * @param someClass the class of the object to get, a subclass of {@link PfConcept}
685      * @param t the object that was retrieved from the database
686      * @return the checked object or null
687      */
688     private <T extends PfConcept> T checkAndReturn(final Class<T> someClass, final T objToCheck) {
689         if (objToCheck != null) {
690             try {
691                 return PfUtils.makeCopy(objToCheck);
692             } catch (final Exception e) {
693                 LOGGER.warn(CLONE_ERR_MSG, someClass.getName(), e);
694             }
695         }
696         return null;
697     }
698 }