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