Add support for localName based filtering in PfReferenceTimestamp key.
[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, isRefTimestampKey(someClass));
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                                boolean isRefTimestampKey) {
430         StringBuilder bld = new StringBuilder(filterQueryString);
431         for (String key : filterMap.keySet()) {
432             if (isRefTimestampKey) {
433                 bld.append("c.key.referenceKey." + key + "= :" + key + AND);
434             } else {
435                 bld.append("c." + key + "= :" + key + AND);
436             }
437         }
438         return bld.toString();
439     }
440
441     @Override
442     public <T extends PfConcept> T get(final Class<T> someClass, final PfConceptKey key) {
443         return genericGet(someClass, key);
444     }
445
446     @Override
447     public <T extends PfConcept> T get(final Class<T> someClass, final PfReferenceKey key) {
448         return genericGet(someClass, key);
449     }
450
451     @Override
452     public <T extends PfConcept> T get(final Class<T> someClass, final PfTimestampKey key) {
453         return genericGet(someClass, key);
454     }
455
456     @Override
457     public <T extends PfConcept> T get(final Class<T> someClass, final PfReferenceTimestampKey key) {
458         return genericGet(someClass, key);
459     }
460
461     private <T extends PfConcept> T genericGet(final Class<T> someClass, final Object key) {
462         if (someClass == null) {
463             return null;
464         }
465         final EntityManager mg = getEntityManager();
466         try {
467             final T t = mg.find(someClass, key);
468             if (t != null) {
469                 mg.refresh(t);
470             }
471             return checkAndReturn(someClass, t);
472         } finally {
473             mg.close();
474         }
475     }
476
477     @Override
478     public <T extends PfConcept> List<T> getAll(final Class<T> someClass) {
479         if (someClass == null) {
480             return Collections.emptyList();
481         }
482         final EntityManager mg = getEntityManager();
483         try {
484             return mg.createQuery(setQueryTable(SELECT_FROM_TABLE, someClass), someClass).getResultList();
485         } finally {
486             mg.close();
487         }
488     }
489
490     @Override
491     public <T extends PfConcept> List<T> getAll(final Class<T> someClass, final PfConceptKey parentKey) {
492         if (someClass == null) {
493             return Collections.emptyList();
494         }
495         final EntityManager mg = getEntityManager();
496         try {
497             // @formatter:off
498             return mg.createQuery(setQueryTable(SELECT_ALL_FOR_PARENT, someClass), someClass)
499                     .setParameter(PARENT_NAME,    parentKey.getName())
500                     .setParameter(PARENT_VERSION, parentKey.getVersion())
501                     .getResultList();
502             // @formatter:on
503         } finally {
504             mg.close();
505         }
506     }
507
508     @Override
509     public <T extends PfConcept> List<T> getAllVersionsByParent(final Class<T> someClass, final String parentKeyName) {
510         if (someClass == null || parentKeyName == null) {
511             return Collections.emptyList();
512         }
513         final EntityManager mg = getEntityManager();
514         try {
515             // @formatter:off
516             return mg.createQuery(setQueryTable(SELECT_ALL_VERSIONS_FOR_PARENT, someClass), someClass)
517                     .setParameter(PARENT_NAME, parentKeyName)
518                     .getResultList();
519             // @formatter:on
520         } finally {
521             mg.close();
522         }
523     }
524
525     @Override
526     public <T extends PfConcept> List<T> getAllVersions(final Class<T> someClass, final String conceptName) {
527         if (someClass == null || conceptName == null) {
528             return Collections.emptyList();
529         }
530         final EntityManager mg = getEntityManager();
531         try {
532             // @formatter:off
533             return mg.createQuery(setQueryTable(SELECT_ALL_VERSIONS, someClass), someClass)
534                     .setParameter(NAME, conceptName)
535                     .getResultList();
536             // @formatter:on
537         } finally {
538             mg.close();
539         }
540     }
541
542     @Override
543     public <T extends PfConcept> T getConcept(final Class<T> someClass, final PfConceptKey key) {
544         if (someClass == null || key == null) {
545             return null;
546         }
547         final EntityManager mg = getEntityManager();
548         List<T> ret;
549         try {
550             // @formatter:off
551             ret = mg.createQuery(setQueryTable(SELECT_BY_CONCEPT_KEY, someClass), someClass)
552                     .setParameter(NAME,    key.getName())
553                     .setParameter(VERSION, key.getVersion())
554                     .getResultList();
555             // @formatter:on
556         } finally {
557             mg.close();
558         }
559
560         return getSingleResult(someClass, key.getId(), ret);
561     }
562
563     @Override
564     public <T extends PfConcept> T getConcept(final Class<T> someClass, final PfReferenceKey key) {
565         if (someClass == null || key == null) {
566             return null;
567         }
568         final EntityManager mg = getEntityManager();
569         List<T> ret;
570         try {
571             // @formatter:off
572             ret = mg.createQuery(setQueryTable(SELECT_BY_REFERENCE_KEY, someClass), someClass)
573                     .setParameter(PARENT_NAME,    key.getParentKeyName())
574                     .setParameter(PARENT_VERSION, key.getParentKeyVersion())
575                     .setParameter(LOCAL_NAME,     key.getLocalName())
576                     .getResultList();
577             // @formatter:on
578         } finally {
579             mg.close();
580         }
581
582         return getSingleResult(someClass, key.getId(), ret);
583     }
584
585     @Override
586     public <T extends PfConcept> T update(final T obj) {
587         final EntityManager mg = getEntityManager();
588         T ret;
589         try {
590             mg.getTransaction().begin();
591             ret = mg.merge(obj);
592             mg.flush();
593             mg.getTransaction().commit();
594         } finally {
595             mg.close();
596         }
597         return ret;
598     }
599
600     @Override
601     public <T extends PfConcept> long size(final Class<T> someClass) {
602         if (someClass == null) {
603             return 0;
604         }
605         final EntityManager mg = getEntityManager();
606         long size = 0;
607         try {
608             size = mg.createQuery("SELECT COUNT(c) FROM " + someClass.getSimpleName() + " c", Long.class)
609                     .getSingleResult();
610         } finally {
611             mg.close();
612         }
613         return size;
614     }
615
616     /**
617      * Add the table to a query string.
618      *
619      * @param queryString the query string
620      * @param tableClass the class name of the table
621      * @return the updated query string
622      */
623     private <T extends PfConcept> String setQueryTable(final String queryString, final Class<T> tableClass) {
624         return queryString.replace(TABLE_TOKEN, tableClass.getSimpleName());
625     }
626
627     /**
628      * Check that a query returned one and only one entry and return that entry.
629      *
630      * @param someClass the class being searched for
631      * @param conceptName the concept name being searched for
632      * @param resultList the result list returned by the query
633      * @return the single unique result
634      */
635     private <T extends PfConcept> T getSingleResult(final Class<T> someClass, final String searchFilter, List<T> ret) {
636         if (ret == null || ret.isEmpty()) {
637             return null;
638         }
639         if (ret.size() > 1) {
640             throw new IllegalArgumentException("More than one result was returned query on " + someClass
641                     + " with filter " + searchFilter + ": " + ret);
642         }
643         return ret.get(0);
644     }
645
646     /**
647      * generate filter string with the filter value in TimestampKey.
648      *
649      * @param inputFilterString current filterString generated from FilterMap
650      * @param name the pdp name the start timeStamp to filter from database, filter rule: startTime <= filteredRecord
651      *        timeStamp <= endTime. null for ignore start time.
652      * @param endTime the end timeStamp to filter from database, filter rule: startTime <= filteredRecord timeStamp <=
653      *        endTime. null for ignore end time
654      * @param isRefTimestampKey boolean value, set to true if the query invoked for pfReferenceTimestampKey
655      * @return the filter string to query database
656      */
657     private String addKeyFilterString(String inputFilterString, final String name, final Instant startTime,
658             final Instant endTime, final boolean isRefTimestampKey) {
659         String filterQueryString;
660         String inputFilter = inputFilterString;
661         if (name != null) {
662             if (isRefTimestampKey) {
663                 inputFilter += PARENT_NAME_REF_FILTER + AND;
664             } else {
665                 inputFilter += NAME_FILTER + AND;
666             }
667         }
668         if (startTime != null) {
669             if (endTime != null) {
670                 filterQueryString = inputFilter + TIMESTAMP_START_FILTER + AND + TIMESTAMP_END_FILTER;
671             } else {
672                 filterQueryString = inputFilter + TIMESTAMP_START_FILTER;
673             }
674         } else {
675             if (endTime != null) {
676                 filterQueryString = inputFilter + TIMESTAMP_END_FILTER;
677             } else {
678                 filterQueryString = inputFilter.substring(0, inputFilter.length() - AND.length());
679             }
680         }
681
682         return filterQueryString;
683     }
684
685     /**
686      * check the result get from database and return the object.
687      *
688      * @param <T> the type of the object to get, a subclass of {@link PfConcept}
689      * @param someClass the class of the object to get, a subclass of {@link PfConcept}
690      * @param t the object that was retrieved from the database
691      * @return the checked object or null
692      */
693     private <T extends PfConcept> T checkAndReturn(final Class<T> someClass, final T objToCheck) {
694         if (objToCheck != null) {
695             try {
696                 return PfUtils.makeCopy(objToCheck);
697             } catch (final Exception e) {
698                 LOGGER.warn(CLONE_ERR_MSG, someClass.getName(), e);
699             }
700         }
701         return null;
702     }
703 }