Merge "Aai Simulator for CQ"
[policy/models.git] / models-dao / src / main / java / org / onap / policy / models / dao / impl / DefaultPfDao.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019 Nordix Foundation.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.models.dao.impl;
22
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.List;
26
27 import javax.persistence.EntityManager;
28 import javax.persistence.EntityManagerFactory;
29 import javax.persistence.Persistence;
30 import javax.ws.rs.core.Response;
31
32 import org.onap.policy.models.base.PfConcept;
33 import org.onap.policy.models.base.PfConceptKey;
34 import org.onap.policy.models.base.PfModelException;
35 import org.onap.policy.models.base.PfModelRuntimeException;
36 import org.onap.policy.models.base.PfReferenceKey;
37 import org.onap.policy.models.dao.DaoParameters;
38 import org.onap.policy.models.dao.PfDao;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * The Class DefaultPfDao is an JPA implementation of the {@link PfDao} class for Policy Framework concepts
44  * ({@link PfConcept}). It uses the default JPA implementation in the javax {@link Persistence} class.
45  */
46 public class DefaultPfDao implements PfDao {
47     private static final Logger LOGGER = LoggerFactory.getLogger(DefaultPfDao.class);
48
49     // @formatter:off
50     private static final String NAME           = "name";
51     private static final String VERSION        = "version";
52     private static final String PARENT_NAME    = "parentname";
53     private static final String PARENT_VERSION = "parentversion";
54     private static final String LOCAL_NAME     = "localname";
55
56     private static final String TABLE_TOKEN = "__TABLE__";
57
58     private static final String DELETE_FROM_TABLE = "DELETE FROM __TABLE__ c";
59
60     private static final String SELECT_FROM_TABLE = "SELECT c FROM __TABLE__ c";
61
62     private static final String WHERE      = " WHERE ";
63     private static final String AND        = " AND ";
64
65     private static final String NAME_FILTER           = "c.key.name = :name";
66     private static final String VERSION_FILTER        = "c.key.version = :version";
67     private static final String PARENT_NAME_FILTER    = "c.key.parentKeyName = :parentname";
68     private static final String PARENT_VERSION_FILTER = "c.key.parentKeyVersion = :parentversion";
69     private static final String LOCAL_NAME_FILTER     = "c.key.localName = :localname";
70
71     private static final String DELETE_BY_CONCEPT_KEY =
72             DELETE_FROM_TABLE + WHERE + NAME_FILTER + AND + VERSION_FILTER;
73
74     private static final String DELETE_BY_REFERENCE_KEY =
75             DELETE_FROM_TABLE + WHERE + PARENT_NAME_FILTER + AND + PARENT_VERSION_FILTER + AND + LOCAL_NAME_FILTER;
76
77     private static final String SELECT_ALL_FOR_PARENT =
78             SELECT_FROM_TABLE + WHERE + PARENT_NAME_FILTER + AND + PARENT_VERSION_FILTER;
79
80     private static final String SELECT_ALL_VERSIONS = SELECT_FROM_TABLE + WHERE + NAME_FILTER;
81
82     private static final String SELECT_BY_CONCEPT_KEY =
83             SELECT_FROM_TABLE + WHERE + NAME_FILTER + AND + VERSION_FILTER;
84
85     private static final String SELECT_BY_REFERENCE_KEY =
86             SELECT_FROM_TABLE + WHERE + PARENT_NAME_FILTER + AND + PARENT_VERSION_FILTER + AND + LOCAL_NAME_FILTER;
87     // @formatter:on
88
89     // Entity manager for JPA
90     private EntityManagerFactory emf = null;
91
92     @Override
93     public void init(final DaoParameters daoParameters) throws PfModelException {
94         if (daoParameters == null || daoParameters.getPersistenceUnit() == null) {
95             LOGGER.error("Policy Framework persistence unit parameter not set");
96             throw new PfModelException(Response.Status.INTERNAL_SERVER_ERROR,
97                     "Policy Framework persistence unit parameter not set");
98         }
99
100         LOGGER.debug("Creating Policy Framework persistence unit \"{}\" . . .", daoParameters.getPersistenceUnit());
101         try {
102             emf = Persistence.createEntityManagerFactory(daoParameters.getPersistenceUnit(),
103                     daoParameters.getJdbcProperties());
104         } catch (final Exception ex) {
105             String errorMessage = "Creation of Policy Framework persistence unit \""
106                     + daoParameters.getPersistenceUnit() + "\" failed";
107             LOGGER.warn(errorMessage, ex);
108             throw new PfModelException(Response.Status.INTERNAL_SERVER_ERROR, errorMessage, ex);
109         }
110         LOGGER.debug("Created Policy Framework persistence unit \"{}\"", daoParameters.getPersistenceUnit());
111     }
112
113     /**
114      * Gets the entity manager for this DAO.
115      *
116      * @return the entity manager
117      */
118     protected final synchronized EntityManager getEntityManager() {
119         if (emf == null) {
120             LOGGER.warn("Policy Framework DAO has not been initialized");
121             throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR,
122                     "Policy Framework DAO has not been initialized");
123         }
124
125         return emf.createEntityManager();
126     }
127
128     @Override
129     public final void close() {
130         if (emf != null) {
131             emf.close();
132         }
133     }
134
135     @Override
136     public <T extends PfConcept> void create(final T obj) {
137         if (obj == null) {
138             return;
139         }
140         final EntityManager mg = getEntityManager();
141         try {
142             mg.getTransaction().begin();
143             mg.merge(obj);
144             mg.getTransaction().commit();
145         } finally {
146             mg.close();
147         }
148     }
149
150     @Override
151     public <T extends PfConcept> void delete(final T obj) {
152         if (obj == null) {
153             return;
154         }
155         final EntityManager mg = getEntityManager();
156         try {
157             mg.getTransaction().begin();
158             mg.remove(mg.contains(obj) ? obj : mg.merge(obj));
159             mg.getTransaction().commit();
160         } finally {
161             mg.close();
162         }
163     }
164
165     @Override
166     public <T extends PfConcept> void delete(final Class<T> someClass, final PfConceptKey key) {
167         if (key == null) {
168             return;
169         }
170         final EntityManager mg = getEntityManager();
171         try {
172             // @formatter:off
173             mg.getTransaction().begin();
174             mg.createQuery(setQueryTable(DELETE_BY_CONCEPT_KEY, someClass), someClass)
175                 .setParameter(NAME,    key.getName())
176                 .setParameter(VERSION, key.getVersion())
177                 .executeUpdate();
178             mg.getTransaction().commit();
179             // @formatter:on
180         } finally {
181             mg.close();
182         }
183     }
184
185     @Override
186     public <T extends PfConcept> void delete(final Class<T> someClass, final PfReferenceKey key) {
187         if (key == null) {
188             return;
189         }
190         final EntityManager mg = getEntityManager();
191         try {
192             // @formatter:off
193             mg.getTransaction().begin();
194             mg.createQuery(setQueryTable(DELETE_BY_REFERENCE_KEY, someClass), someClass)
195                 .setParameter(PARENT_NAME,    key.getParentKeyName())
196                 .setParameter(PARENT_VERSION, key.getParentKeyVersion())
197                 .setParameter(LOCAL_NAME,     key.getLocalName())
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 createCollection(final Collection<T> objs) {
208         if (objs == null || objs.isEmpty()) {
209             return;
210         }
211         final EntityManager mg = getEntityManager();
212         try {
213             mg.getTransaction().begin();
214             for (final T t : objs) {
215                 mg.merge(t);
216             }
217             mg.getTransaction().commit();
218         } finally {
219             mg.close();
220         }
221     }
222
223     @Override
224     public <T extends PfConcept> void deleteCollection(final Collection<T> objs) {
225         if (objs == null || objs.isEmpty()) {
226             return;
227         }
228         final EntityManager mg = getEntityManager();
229         try {
230             mg.getTransaction().begin();
231             for (final T t : objs) {
232                 mg.remove(mg.contains(t) ? t : mg.merge(t));
233             }
234             mg.getTransaction().commit();
235         } finally {
236             mg.close();
237         }
238     }
239
240     @Override
241     public <T extends PfConcept> int deleteByConceptKey(final Class<T> someClass, final Collection<PfConceptKey> keys) {
242         if (keys == null || keys.isEmpty()) {
243             return 0;
244         }
245         int deletedCount = 0;
246         final EntityManager mg = getEntityManager();
247         try {
248             // @formatter:off
249             mg.getTransaction().begin();
250             for (final PfConceptKey key : keys) {
251                 deletedCount += mg.createQuery(setQueryTable(DELETE_BY_CONCEPT_KEY, someClass), someClass)
252                     .setParameter(NAME,    key.getName())
253                     .setParameter(VERSION, key.getVersion())
254                     .executeUpdate();
255             }
256             mg.getTransaction().commit();
257             // @formatter:on
258         } finally {
259             mg.close();
260         }
261         return deletedCount;
262     }
263
264     @Override
265     public <T extends PfConcept> int deleteByReferenceKey(final Class<T> someClass,
266             final Collection<PfReferenceKey> keys) {
267         if (keys == null || keys.isEmpty()) {
268             return 0;
269         }
270         int deletedCount = 0;
271         final EntityManager mg = getEntityManager();
272         try {
273             // @formatter:off
274             mg.getTransaction().begin();
275             for (final PfReferenceKey key : keys) {
276                 deletedCount += mg.createQuery(setQueryTable(DELETE_BY_REFERENCE_KEY, someClass), someClass)
277                     .setParameter(PARENT_NAME,    key.getParentKeyName())
278                     .setParameter(PARENT_VERSION, key.getParentKeyVersion())
279                     .setParameter(LOCAL_NAME,     key.getLocalName())
280                     .executeUpdate();
281             }
282             mg.getTransaction().commit();
283             // @formatter:on
284         } finally {
285             mg.close();
286         }
287         return deletedCount;
288     }
289
290     @Override
291     public <T extends PfConcept> void deleteAll(final Class<T> someClass) {
292         final EntityManager mg = getEntityManager();
293         try {
294             mg.getTransaction().begin();
295             mg.createQuery(setQueryTable(DELETE_FROM_TABLE, someClass), someClass).executeUpdate();
296             mg.getTransaction().commit();
297         } finally {
298             mg.close();
299         }
300     }
301
302     @Override
303     public <T extends PfConcept> List<T> getFiltered(final Class<T> someClass, final String name,
304             final String version) {
305         if (name == null) {
306             return getAll(someClass);
307         }
308
309         if (version == null) {
310             return getAllVersions(someClass, name);
311         }
312
313         T foundConcept = get(someClass, new PfConceptKey(name, version));
314
315         return (foundConcept == null ? Collections.emptyList() : Collections.singletonList(foundConcept));
316     }
317
318     @Override
319     public <T extends PfConcept> T get(final Class<T> someClass, final PfConceptKey key) {
320         if (someClass == null) {
321             return null;
322         }
323         final EntityManager mg = getEntityManager();
324         try {
325             final T t = mg.find(someClass, key);
326             if (t != null) {
327                 // This clone is created to force the JPA DAO to recurse down through the object
328                 try {
329                     final T clonedT = someClass.newInstance();
330                     t.copyTo(clonedT);
331                     return clonedT;
332                 } catch (final Exception e) {
333                     LOGGER.warn("Could not clone object of class \"" + someClass.getCanonicalName() + "\"", e);
334                     return null;
335                 }
336             } else {
337                 return null;
338             }
339         } finally {
340             mg.close();
341         }
342     }
343
344     @Override
345     public <T extends PfConcept> T get(final Class<T> someClass, final PfReferenceKey key) {
346         if (someClass == null) {
347             return null;
348         }
349         final EntityManager mg = getEntityManager();
350         try {
351             final T t = mg.find(someClass, key);
352             if (t != null) {
353                 try {
354                     final T clonedT = someClass.newInstance();
355                     t.copyTo(clonedT);
356                     return clonedT;
357                 } catch (final Exception e) {
358                     LOGGER.warn("Could not clone object of class \"" + someClass.getCanonicalName() + "\"", e);
359                     return null;
360                 }
361             } else {
362                 return null;
363             }
364         } finally {
365             mg.close();
366         }
367     }
368
369     @Override
370     public <T extends PfConcept> List<T> getAll(final Class<T> someClass) {
371         if (someClass == null) {
372             return Collections.emptyList();
373         }
374         final EntityManager mg = getEntityManager();
375         try {
376             return mg.createQuery(setQueryTable(SELECT_FROM_TABLE, someClass), someClass).getResultList();
377         } finally {
378             mg.close();
379         }
380     }
381
382     @Override
383     public <T extends PfConcept> List<T> getAll(final Class<T> someClass, final PfConceptKey parentKey) {
384         if (someClass == null) {
385             return Collections.emptyList();
386         }
387         final EntityManager mg = getEntityManager();
388         try {
389             // @formatter:off
390             return mg.createQuery(setQueryTable(SELECT_ALL_FOR_PARENT, someClass), someClass)
391                     .setParameter(PARENT_NAME,    parentKey.getName())
392                     .setParameter(PARENT_VERSION, parentKey.getVersion())
393                     .getResultList();
394             // @formatter:on
395         } finally {
396             mg.close();
397         }
398     }
399
400     @Override
401     public <T extends PfConcept> List<T> getAllVersions(final Class<T> someClass, final String conceptName) {
402         if (someClass == null || conceptName == null) {
403             return Collections.emptyList();
404         }
405         final EntityManager mg = getEntityManager();
406         try {
407             // @formatter:off
408             return mg.createQuery(setQueryTable(SELECT_ALL_VERSIONS, someClass), someClass)
409                     .setParameter(NAME, conceptName)
410                     .getResultList();
411             // @formatter:on
412         } finally {
413             mg.close();
414         }
415     }
416
417     @Override
418     public <T extends PfConcept> T getConcept(final Class<T> someClass, final PfConceptKey key) {
419         if (someClass == null || key == null) {
420             return null;
421         }
422         final EntityManager mg = getEntityManager();
423         List<T> ret;
424         try {
425             // @formatter:off
426             ret = mg.createQuery(setQueryTable(SELECT_BY_CONCEPT_KEY, someClass), someClass)
427                     .setParameter(NAME,    key.getName())
428                     .setParameter(VERSION, key.getVersion())
429                     .getResultList();
430             // @formatter:on
431         } finally {
432             mg.close();
433         }
434
435         return getSingleResult(someClass, key.getId(), ret);
436     }
437
438     @Override
439     public <T extends PfConcept> T getConcept(final Class<T> someClass, final PfReferenceKey key) {
440         if (someClass == null || key == null) {
441             return null;
442         }
443         final EntityManager mg = getEntityManager();
444         List<T> ret;
445         try {
446             // @formatter:off
447             ret = mg.createQuery(setQueryTable(SELECT_BY_REFERENCE_KEY, someClass), someClass)
448                     .setParameter(PARENT_NAME,    key.getParentKeyName())
449                     .setParameter(PARENT_VERSION, key.getParentKeyVersion())
450                     .setParameter(LOCAL_NAME,     key.getLocalName())
451                     .getResultList();
452             // @formatter:on
453         } finally {
454             mg.close();
455         }
456
457         return getSingleResult(someClass, key.getId(), ret);
458     }
459
460     @Override
461     public <T extends PfConcept> T update(final T obj) {
462         final EntityManager mg = getEntityManager();
463         T ret;
464         try {
465             mg.getTransaction().begin();
466             ret = mg.merge(obj);
467             mg.flush();
468             mg.getTransaction().commit();
469         } finally {
470             mg.close();
471         }
472         return ret;
473     }
474
475     @Override
476     public <T extends PfConcept> long size(final Class<T> someClass) {
477         if (someClass == null) {
478             return 0;
479         }
480         final EntityManager mg = getEntityManager();
481         long size = 0;
482         try {
483             size = mg.createQuery("SELECT COUNT(c) FROM " + someClass.getSimpleName() + " c", Long.class)
484                     .getSingleResult();
485         } finally {
486             mg.close();
487         }
488         return size;
489     }
490
491     /**
492      * Add the table to a query string.
493      *
494      * @param queryString the query string
495      * @param tableClass the class name of the table
496      * @return the updated query string
497      */
498     private <T extends PfConcept> String setQueryTable(final String queryString, final Class<T> tableClass) {
499         return queryString.replaceAll(TABLE_TOKEN, tableClass.getSimpleName());
500     }
501
502     /**
503      * Check that a query returned one and only one entry and return that entry.
504      *
505      * @param someClass the class being searched for
506      * @param conceptName the concept name being searched for
507      * @param resultList the result list returned by the query
508      * @return the single unique result
509      */
510     private <T extends PfConcept> T getSingleResult(final Class<T> someClass, final String searchFilter, List<T> ret) {
511         if (ret == null || ret.isEmpty()) {
512             return null;
513         }
514         if (ret.size() > 1) {
515             throw new IllegalArgumentException("More than one result was returned query on " + someClass
516                     + " with filter " + searchFilter + ": " + ret);
517         }
518         return ret.get(0);
519     }
520 }