2 * ============LICENSE_START=======================================================
3 * feature-active-standby-management
4 * ================================================================================
5 * Copyright (C) 2017-2021 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.drools.activestandby;
23 import java.util.Collection;
24 import java.util.LinkedList;
25 import java.util.List;
26 import javax.persistence.EntityManager;
27 import javax.persistence.EntityManagerFactory;
28 import javax.persistence.FlushModeType;
29 import javax.persistence.LockModeType;
30 import lombok.AllArgsConstructor;
31 import org.onap.policy.common.im.MonitorTime;
32 import org.onap.policy.common.utils.time.CurrentTime;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
37 public class JpaDroolsPdpsConnector implements DroolsPdpsConnector {
39 private static final String SELECT_PDP_BY_ID = "SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId";
40 private static final String PDP_ID_PARAM = "pdpId";
42 // get an instance of logger
43 private static final Logger logger = LoggerFactory.getLogger(JpaDroolsPdpsConnector.class);
44 private EntityManagerFactory emf;
46 private final CurrentTime currentTime = MonitorTime.getInstance();
49 public Collection<DroolsPdp> getDroolsPdps() {
50 //return a list of all the DroolsPdps in the database
51 var em = emf.createEntityManager();
53 em.getTransaction().begin();
54 var droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p", DroolsPdp.class);
55 List<DroolsPdp> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
56 .setFlushMode(FlushModeType.COMMIT).getResultList();
57 LinkedList<DroolsPdp> droolsPdpsReturnList = new LinkedList<>();
58 for (DroolsPdp droolsPdp : droolsPdpsList) {
59 //Make sure it is not a cached version
60 em.refresh(droolsPdp);
61 droolsPdpsReturnList.add(droolsPdp);
62 if (logger.isDebugEnabled()) {
63 logger.debug("getDroolsPdps: PDP= {}"
64 + ", isDesignated= {}"
66 + ", priority= {}", droolsPdp.getPdpId(), droolsPdp.isDesignated(),
67 droolsPdp.getUpdatedDate(), droolsPdp.getPriority());
71 em.getTransaction().commit();
72 } catch (Exception e) {
73 logger.error("Cannot commit getDroolsPdps() transaction", e);
75 return droolsPdpsReturnList;
77 cleanup(em, "getDroolsPdps");
81 private boolean nullSafeEquals(Object one, Object two) {
82 if (one == null && two == null) {
85 if (one != null && two != null) {
86 return one.equals(two);
92 public void update(DroolsPdp pdp) {
94 logger.debug("update: Entering, pdpId={}", pdp.getPdpId());
96 //this is to update our own pdp in the database
97 var em = emf.createEntityManager();
99 em.getTransaction().begin();
100 var droolsPdpsListQuery = em.createQuery(SELECT_PDP_BY_ID, DroolsPdpEntity.class);
101 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
102 List<DroolsPdpEntity> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
103 .setFlushMode(FlushModeType.COMMIT).getResultList();
104 DroolsPdpEntity droolsPdpEntity;
105 if (droolsPdpsList.size() == 1) {
106 droolsPdpEntity = droolsPdpsList.get(0);
107 em.refresh(droolsPdpEntity); //Make sure we have current values
108 var currentDate = currentTime.getDate();
109 long difference = currentDate.getTime() - droolsPdpEntity.getUpdatedDate().getTime();
110 //just set some kind of default here
111 long pdpTimeout = 15000;
113 pdpTimeout = Long.parseLong(
114 ActiveStandbyProperties.getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
115 } catch (Exception e) {
116 logger.error("Could not get PDP timeout property, using default.", e);
118 boolean isCurrent = difference < pdpTimeout;
119 logger.debug("update: PDP= {}, isCurrent={}"
121 + ", pdpTimeout= {}, designated= {}",
122 pdp.getPdpId(), isCurrent, difference, pdpTimeout, droolsPdpEntity.isDesignated());
124 logger.debug("update: For PDP={}"
125 + ", instantiating new DroolsPdpEntity", pdp.getPdpId());
126 droolsPdpEntity = new DroolsPdpEntity();
127 em.persist(droolsPdpEntity);
128 droolsPdpEntity.setPdpId(pdp.getPdpId());
130 if (droolsPdpEntity.getPriority() != pdp.getPriority()) {
131 droolsPdpEntity.setPriority(pdp.getPriority());
133 if (!droolsPdpEntity.getUpdatedDate().equals(pdp.getUpdatedDate())) {
134 droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate());
136 if (!nullSafeEquals(droolsPdpEntity.getSite(), pdp.getSite())) {
137 droolsPdpEntity.setSite(pdp.getSite());
140 if (droolsPdpEntity.isDesignated() != pdp.isDesignated()) {
141 logger.debug("update: pdpId={}"
142 + ", pdp.isDesignated={}"
143 + ", droolsPdpEntity.pdpId= {}"
144 + ", droolsPdpEntity.isDesignated={}",
145 pdp.getPdpId(), pdp.isDesignated(),
146 droolsPdpEntity.getPdpId(), droolsPdpEntity.isDesignated());
147 droolsPdpEntity.setDesignated(pdp.isDesignated());
148 //The isDesignated value is not the same and the new one == true
149 if (pdp.isDesignated()) {
150 droolsPdpEntity.setDesignatedDate(currentTime.getDate());
153 em.getTransaction().commit();
155 cleanup(em, "update");
158 logger.debug("update: Exiting");
163 * Note: A side effect of this boolean method is that if the PDP is designated but not current, the
164 * droolspdpentity.DESIGNATED column will be set to false (the PDP will be un-designated, i.e. marked as
165 * being in standby mode)
168 public boolean isPdpCurrent(DroolsPdp pdp) {
170 boolean isCurrent = isCurrent(pdp);
172 var em = emf.createEntityManager();
174 if (!isCurrent && pdp.isDesignated()) {
175 em.getTransaction().begin();
176 var droolsPdpsListQuery = em.createQuery(SELECT_PDP_BY_ID, DroolsPdpEntity.class);
177 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
178 List<DroolsPdpEntity> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
179 .setFlushMode(FlushModeType.COMMIT).getResultList();
180 if (droolsPdpsList.size() == 1) {
181 logger.debug("isPdpCurrent: PDP={} designated but not current; setting designated to false",
183 var droolsPdpEntity = droolsPdpsList.get(0);
184 droolsPdpEntity.setDesignated(false);
185 em.getTransaction().commit();
187 logger.warn("isPdpCurrent: PDP={} is designated but not current; "
188 + "however it does not have a DB entry, so cannot set DESIGNATED to false!",
192 logger.debug("isPdpCurrent: For PDP= {}, "
193 + "designated={}, isCurrent={}", pdp.getPdpId(), pdp.isDesignated(), isCurrent);
195 } catch (Exception e) {
196 logger.error("Could not update expired record marked as designated in the database", e);
198 cleanup(em, "isPdpCurrent");
205 public void setDesignated(DroolsPdp pdp, boolean designated) {
207 logger.debug("setDesignated: Entering, pdpId={}"
208 + ", designated={}", pdp.getPdpId(), designated);
210 EntityManager em = null;
212 em = emf.createEntityManager();
213 em.getTransaction().begin();
214 var droolsPdpsListQuery = em
215 .createQuery(SELECT_PDP_BY_ID, DroolsPdpEntity.class);
216 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
217 List<DroolsPdpEntity> droolsPdpsList = droolsPdpsListQuery.setLockMode(
218 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
219 if (droolsPdpsList.size() == 1) {
220 var droolsPdpEntity = droolsPdpsList.get(0);
222 logger.debug("setDesignated: PDP={}"
223 + " found, designated= {}"
224 + ", setting to {}", pdp.getPdpId(), droolsPdpEntity.isDesignated(),
226 setPdpDesignation(em, droolsPdpEntity, designated);
227 em.getTransaction().commit();
229 logger.error("setDesignated: PDP={}"
230 + " not in DB; cannot update designation", pdp.getPdpId());
232 } catch (Exception e) {
233 logger.error("setDesignated: Caught Exception", e);
235 cleanup(em, "setDesignated");
238 logger.debug("setDesignated: Exiting");
242 private void setPdpDesignation(EntityManager em, DroolsPdpEntity droolsPdpEntity, boolean designated) {
243 droolsPdpEntity.setDesignated(designated);
245 em.refresh(droolsPdpEntity); //make sure we get the DB value
246 if (!droolsPdpEntity.isDesignated()) {
247 droolsPdpEntity.setDesignatedDate(currentTime.getDate());
255 public void standDownPdp(String pdpId) {
256 logger.debug("standDownPdp: Entering, pdpId={}", pdpId);
258 EntityManager em = null;
263 em = emf.createEntityManager();
264 em.getTransaction().begin();
267 * Get droolspdpentity record for this PDP and mark DESIGNATED as
270 var droolsPdpsListQuery = em
271 .createQuery(SELECT_PDP_BY_ID, DroolsPdpEntity.class);
272 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdpId);
273 List<DroolsPdpEntity> droolsPdpsList = droolsPdpsListQuery.setLockMode(
274 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
275 if (droolsPdpsList.size() == 1) {
276 var droolsPdpEntity = droolsPdpsList.get(0);
277 droolsPdpEntity.setDesignated(false);
278 em.persist(droolsPdpEntity);
279 logger.debug("standDownPdp: PDP={} persisted as non-designated.", pdpId);
281 logger.error("standDownPdp: Missing record in droolspdpentity for pdpId={}"
282 + "; cannot stand down PDP", pdpId);
288 em.getTransaction().commit();
289 cleanup(em, "standDownPdp");
292 // Keep the election handler in sync with the DB
293 DroolsPdpsElectionHandler.setMyPdpDesignated(false);
295 } catch (Exception e) {
296 logger.error("standDownPdp: Unexpected Exception attempting to mark "
297 + "DESIGNATED as false for droolspdpentity, pdpId={}"
298 + ". Cannot stand down PDP; message={}", pdpId, e.getMessage(), e);
300 cleanup(em, "standDownPdp");
302 logger.debug("standDownPdp: Exiting");
307 * Determines whether or not a designated PDP has failed.
309 * Note: The update method, which is run periodically by the
310 * TimerUpdateClass, will un-designate a PDP that is stale.
313 public boolean hasDesignatedPdpFailed(Collection<DroolsPdp> pdps) {
315 logger.debug("hasDesignatedPdpFailed: Entering, pdps.size()={}", pdps.size());
318 var foundDesignatedPdp = false;
320 for (DroolsPdp pdp : pdps) {
323 * Normally, the update method will un-designate any stale PDP, but
324 * we check here to see if the PDP has gone stale since the update
327 * Even if we determine that the designated PDP is current, we keep
328 * going (we don't break), so we can get visibility into the other
329 * PDPs, when in DEBUG mode.
331 if (pdp.isDesignated() && isCurrent(pdp)) {
332 logger.debug("hasDesignatedPdpFailed: Designated PDP={} is current", pdp.getPdpId());
334 foundDesignatedPdp = true;
335 } else if (pdp.isDesignated() && !isCurrent(pdp)) {
336 logger.error("hasDesignatedPdpFailed: Designated PDP={} has failed", pdp.getPdpId());
337 foundDesignatedPdp = true;
339 logger.debug("hasDesignatedPdpFailed: PDP={} is not designated", pdp.getPdpId());
343 logger.debug("hasDesignatedPdpFailed: Exiting and returning, foundDesignatedPdp={}",
349 private boolean isCurrent(DroolsPdp pdp) {
351 logger.debug("isCurrent: Entering, pdpId={}", pdp.getPdpId());
355 // Return if the current PDP is considered "current" based on whatever
356 // time box that may be.
357 // If the the PDP is not current, we should mark it as not primary in
359 var currentDate = currentTime.getDate();
360 long difference = currentDate.getTime()
361 - pdp.getUpdatedDate().getTime();
362 // just set some kind of default here
363 long pdpTimeout = 15000;
365 pdpTimeout = Long.parseLong(ActiveStandbyProperties
366 .getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
367 logger.debug("isCurrent: pdp.timeout={}", pdpTimeout);
368 } catch (Exception e) {
369 logger.error("isCurrent: Could not get PDP timeout property, using default.", e);
371 current = difference < pdpTimeout;
373 logger.debug("isCurrent: Exiting, difference={}, pdpTimeout={}"
374 + "; returning current={}", difference, pdpTimeout, current);
381 * Currently this method is only used in a JUnit test environment. Gets a
382 * PDP record from droolspdpentity table.
385 public DroolsPdpEntity getPdp(String pdpId) {
387 logger.debug("getPdp: Entering and getting PDP with pdpId={}", pdpId);
389 DroolsPdpEntity droolsPdpEntity = null;
391 EntityManager em = null;
393 em = emf.createEntityManager();
394 em.getTransaction().begin();
395 var droolsPdpsListQuery = em
396 .createQuery(SELECT_PDP_BY_ID);
397 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdpId);
398 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
399 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
400 if (droolsPdpsList.size() == 1
401 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
402 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
403 logger.debug("getPdp: PDP={}"
404 + " found, isDesignated={},"
405 + " updatedDate={}, "
406 + "priority={}", pdpId,
407 droolsPdpEntity.isDesignated(), droolsPdpEntity.getUpdatedDate(),
408 droolsPdpEntity.getPriority());
410 // Make sure the droolsPdpEntity is not a cached version
411 em.refresh(droolsPdpEntity);
413 em.getTransaction().commit();
415 logger.error("getPdp: PDP={} not found!?", pdpId);
417 } catch (Exception e) {
418 logger.error("getPdp: Caught Exception attempting to get PDP", e);
420 cleanup(em, "getPdp");
423 logger.debug("getPdp: Returning droolsPdpEntity={}", droolsPdpEntity);
424 return droolsPdpEntity;
429 * Normally this method should only be used in a JUnit test environment.
430 * Manually inserts a PDP record in droolspdpentity table.
433 public void insertPdp(DroolsPdp pdp) {
434 logger.debug("insertPdp: Entering and manually inserting PDP");
439 var em = emf.createEntityManager();
441 em.getTransaction().begin();
446 var droolsPdpEntity = new DroolsPdpEntity();
447 em.persist(droolsPdpEntity);
448 droolsPdpEntity.setPdpId(pdp.getPdpId());
449 droolsPdpEntity.setDesignated(pdp.isDesignated());
450 droolsPdpEntity.setPriority(pdp.getPriority());
451 droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate());
452 droolsPdpEntity.setSite(pdp.getSite());
457 em.getTransaction().commit();
459 cleanup(em, "insertPdp");
461 logger.debug("insertPdp: Exiting");
466 * Normally this method should only be used in a JUnit test environment.
467 * Manually deletes all PDP records in droolspdpentity table.
470 public void deleteAllPdps() {
472 logger.debug("deleteAllPdps: Entering");
477 var em = emf.createEntityManager();
479 em.getTransaction().begin();
481 var droolsPdpsListQuery = em
482 .createQuery("SELECT p FROM DroolsPdpEntity p");
483 @SuppressWarnings("unchecked")
484 List<DroolsPdp> droolsPdpsList = droolsPdpsListQuery.setLockMode(
485 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
486 logger.debug("deleteAllPdps: Deleting {} PDPs", droolsPdpsList.size());
487 for (DroolsPdp droolsPdp : droolsPdpsList) {
488 String pdpId = droolsPdp.getPdpId();
495 em.getTransaction().commit();
497 cleanup(em, "deleteAllPdps");
499 logger.debug("deleteAllPdps: Exiting");
504 * Normally this method should only be used in a JUnit test environment.
505 * Manually deletes a PDP record in droolspdpentity table.
508 public void deletePdp(String pdpId) {
509 logger.debug("deletePdp: Entering and manually deleting pdpId={}", pdpId);
514 var em = emf.createEntityManager();
516 em.getTransaction().begin();
521 var droolsPdpEntity = em.find(DroolsPdpEntity.class, pdpId);
522 if (droolsPdpEntity != null) {
523 logger.debug("deletePdp: Removing PDP");
524 em.remove(droolsPdpEntity);
526 logger.debug("deletePdp: PDP with ID={} not currently in DB", pdpId);
532 em.getTransaction().commit();
534 cleanup(em, "deletePdp");
536 logger.debug("deletePdp: Exiting");
541 * Close the specified EntityManager, rolling back any pending transaction
543 * @param em the EntityManager to close ('null' is OK)
544 * @param method the invoking Java method (used for log messages)
546 private static void cleanup(EntityManager em, String method) {
547 if (em != null && em.isOpen()) {
548 if (em.getTransaction().isActive()) {
549 // there is an active EntityTransaction -- roll it back
551 em.getTransaction().rollback();
552 } catch (Exception e) {
553 logger.error("{}: Caught Exception attempting to rollback EntityTransaction", method, e);
557 // now, close the EntityManager
560 } catch (Exception e) {
561 logger.error("{}: Caught Exception attempting to close EntityManager", method, e);