2 * ============LICENSE_START=======================================================
3 * feature-active-standby-management
4 * ================================================================================
5 * Copyright (C) 2017-2019 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.Date;
25 import java.util.LinkedList;
26 import java.util.List;
28 import javax.persistence.EntityManager;
29 import javax.persistence.EntityManagerFactory;
30 import javax.persistence.FlushModeType;
31 import javax.persistence.LockModeType;
32 import javax.persistence.Query;
33 import org.onap.policy.common.im.MonitorTime;
34 import org.onap.policy.common.utils.time.CurrentTime;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 public class JpaDroolsPdpsConnector implements DroolsPdpsConnector {
40 private static final String SELECT_PDP_BY_ID = "SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId";
41 private static final String PDP_ID_PARAM = "pdpId";
43 // get an instance of logger
44 private static final Logger logger = LoggerFactory.getLogger(JpaDroolsPdpsConnector.class);
45 private EntityManagerFactory emf;
47 private final CurrentTime currentTime = MonitorTime.getInstance();
50 //not sure if we want to use the same entity manager factory
51 //for drools session and pass it in here, or create a new one
52 public JpaDroolsPdpsConnector(EntityManagerFactory emf) {
57 public Collection<DroolsPdp> getDroolsPdps() {
58 //return a list of all the DroolsPdps in the database
59 EntityManager em = emf.createEntityManager();
61 em.getTransaction().begin();
62 Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p");
63 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
64 .setFlushMode(FlushModeType.COMMIT).getResultList();
65 LinkedList<DroolsPdp> droolsPdpsReturnList = new LinkedList<>();
66 for (Object o : droolsPdpsList) {
67 if (!(o instanceof DroolsPdp)) {
70 //Make sure it is not a cached version
71 DroolsPdp droolsPdp = (DroolsPdp)o;
72 em.refresh(droolsPdp);
73 droolsPdpsReturnList.add(droolsPdp);
74 if (logger.isDebugEnabled()) {
75 logger.debug("getDroolsPdps: PDP= {}"
76 + ", isDesignated= {}"
78 + ", priority= {}", droolsPdp.getPdpId(), droolsPdp.isDesignated(),
79 droolsPdp.getUpdatedDate(), droolsPdp.getPriority());
83 em.getTransaction().commit();
84 } catch (Exception e) {
85 logger.error("Cannot commit getDroolsPdps() transaction", e);
87 return droolsPdpsReturnList;
89 cleanup(em, "getDroolsPdps");
93 private boolean nullSafeEquals(Object one, Object two) {
94 if (one == null && two == null) {
97 if (one != null && two != null) {
98 return one.equals(two);
104 public void update(DroolsPdp pdp) {
106 logger.debug("update: Entering, pdpId={}", pdp.getPdpId());
108 //this is to update our own pdp in the database
109 EntityManager em = emf.createEntityManager();
111 em.getTransaction().begin();
112 Query droolsPdpsListQuery = em.createQuery(SELECT_PDP_BY_ID);
113 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
114 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
115 .setFlushMode(FlushModeType.COMMIT).getResultList();
116 DroolsPdpEntity droolsPdpEntity;
117 if (droolsPdpsList.size() == 1 && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)) {
118 droolsPdpEntity = (DroolsPdpEntity)droolsPdpsList.get(0);
119 em.refresh(droolsPdpEntity); //Make sure we have current values
120 Date currentDate = currentTime.getDate();
121 long difference = currentDate.getTime() - droolsPdpEntity.getUpdatedDate().getTime();
122 //just set some kind of default here
123 long pdpTimeout = 15000;
125 pdpTimeout = Long.parseLong(
126 ActiveStandbyProperties.getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
127 } catch (Exception e) {
128 logger.error("Could not get PDP timeout property, using default.", e);
130 boolean isCurrent = difference < pdpTimeout;
131 logger.debug("update: PDP= {}, isCurrent={}"
133 + ", pdpTimeout= {}, designated= {}",
134 pdp.getPdpId(), isCurrent, difference, pdpTimeout, droolsPdpEntity.isDesignated());
136 logger.debug("update: For PDP={}"
137 + ", instantiating new DroolsPdpEntity", pdp.getPdpId());
138 droolsPdpEntity = new DroolsPdpEntity();
139 em.persist(droolsPdpEntity);
140 droolsPdpEntity.setPdpId(pdp.getPdpId());
142 if (droolsPdpEntity.getPriority() != pdp.getPriority()) {
143 droolsPdpEntity.setPriority(pdp.getPriority());
145 if (!droolsPdpEntity.getUpdatedDate().equals(pdp.getUpdatedDate())) {
146 droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate());
148 if (!nullSafeEquals(droolsPdpEntity.getSite(),pdp.getSite())) {
149 droolsPdpEntity.setSite(pdp.getSite());
152 if (droolsPdpEntity.isDesignated() != pdp.isDesignated()) {
153 logger.debug("update: pdpId={}"
154 + ", pdp.isDesignated={}"
155 + ", droolsPdpEntity.pdpId= {}"
156 + ", droolsPdpEntity.isDesignated={}",
157 pdp.getPdpId(), pdp.isDesignated(),
158 droolsPdpEntity.getPdpId(), droolsPdpEntity.isDesignated());
159 droolsPdpEntity.setDesignated(pdp.isDesignated());
160 //The isDesignated value is not the same and the new one == true
161 if (pdp.isDesignated()) {
162 droolsPdpEntity.setDesignatedDate(currentTime.getDate());
165 em.getTransaction().commit();
167 cleanup(em, "update");
170 logger.debug("update: Exiting");
175 * Note: A side effect of this boolean method is that if the PDP is designated but not current, the
176 * droolspdpentity.DESIGNATED column will be set to false (the PDP will be un-designated, i.e. marked as
177 * being in standby mode)
180 public boolean isPdpCurrent(DroolsPdp pdp) {
182 boolean isCurrent = isCurrent(pdp);
184 EntityManager em = emf.createEntityManager();
186 if (!isCurrent && pdp.isDesignated()) {
187 em.getTransaction().begin();
188 Query droolsPdpsListQuery = em.createQuery(SELECT_PDP_BY_ID);
189 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
190 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
191 .setFlushMode(FlushModeType.COMMIT).getResultList();
192 if (droolsPdpsList.size() == 1 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
193 logger.debug("isPdpCurrent: PDP={} designated but not current; setting designated to false",
195 DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity)droolsPdpsList.get(0);
196 droolsPdpEntity.setDesignated(false);
197 em.getTransaction().commit();
199 logger.warn("isPdpCurrent: PDP={} is designated but not current; "
200 + "however it does not have a DB entry, so cannot set DESIGNATED to false!",
204 logger.debug("isPdpCurrent: For PDP= {}, "
205 + "designated={}, isCurrent={}", pdp.getPdpId(), pdp.isDesignated(), isCurrent);
207 } catch (Exception e) {
208 logger.error("Could not update expired record marked as designated in the database", e);
210 cleanup(em, "isPdpCurrent");
217 public void setDesignated(DroolsPdp pdp, boolean designated) {
219 logger.debug("setDesignated: Entering, pdpId={}"
220 + ", designated={}", pdp.getPdpId(), designated);
222 EntityManager em = null;
224 em = emf.createEntityManager();
225 em.getTransaction().begin();
226 Query droolsPdpsListQuery = em
227 .createQuery(SELECT_PDP_BY_ID);
228 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
229 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
230 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
231 if (droolsPdpsList.size() == 1
232 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
233 DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList
236 logger.debug("setDesignated: PDP={}"
237 + " found, designated= {}"
238 + ", setting to {}", pdp.getPdpId(), droolsPdpEntity.isDesignated(),
240 setPdpDesignation(em, droolsPdpEntity, designated);
241 em.getTransaction().commit();
243 logger.error("setDesignated: PDP={}"
244 + " not in DB; cannot update designation", pdp.getPdpId());
246 } catch (Exception e) {
247 logger.error("setDesignated: Caught Exception", e);
249 cleanup(em, "setDesignated");
252 logger.debug("setDesignated: Exiting");
256 private void setPdpDesignation(EntityManager em, DroolsPdpEntity droolsPdpEntity, boolean designated) {
257 droolsPdpEntity.setDesignated(designated);
259 em.refresh(droolsPdpEntity); //make sure we get the DB value
260 if (!droolsPdpEntity.isDesignated()) {
261 droolsPdpEntity.setDesignatedDate(currentTime.getDate());
269 public void standDownPdp(String pdpId) {
270 logger.debug("standDownPdp: Entering, pdpId={}", pdpId);
272 EntityManager em = null;
277 em = emf.createEntityManager();
278 em.getTransaction().begin();
281 * Get droolspdpentity record for this PDP and mark DESIGNATED as
284 Query droolsPdpsListQuery = em
285 .createQuery(SELECT_PDP_BY_ID);
286 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdpId);
287 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
288 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
289 DroolsPdpEntity droolsPdpEntity;
290 if (droolsPdpsList.size() == 1
291 && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)) {
292 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
293 droolsPdpEntity.setDesignated(false);
294 em.persist(droolsPdpEntity);
295 logger.debug("standDownPdp: PDP={} persisted as non-designated.", pdpId );
297 logger.error("standDownPdp: Missing record in droolspdpentity for pdpId={}"
298 + "; cannot stand down PDP", pdpId);
304 em.getTransaction().commit();
305 cleanup(em, "standDownPdp");
308 // Keep the election handler in sync with the DB
309 DroolsPdpsElectionHandler.setMyPdpDesignated(false);
311 } catch (Exception e) {
312 logger.error("standDownPdp: Unexpected Exception attempting to mark "
313 + "DESIGNATED as false for droolspdpentity, pdpId={}"
314 + ". Cannot stand down PDP; message={}", pdpId, e.getMessage(), e);
316 cleanup(em, "standDownPdp");
318 logger.debug("standDownPdp: Exiting");
323 * Determines whether or not a designated PDP has failed.
325 * Note: The update method, which is run periodically by the
326 * TimerUpdateClass, will un-designate a PDP that is stale.
329 public boolean hasDesignatedPdpFailed(Collection<DroolsPdp> pdps) {
331 logger.debug("hasDesignatedPdpFailed: Entering, pdps.size()={}", pdps.size());
333 boolean failed = true;
334 boolean foundDesignatedPdp = false;
336 for (DroolsPdp pdp : pdps) {
339 * Normally, the update method will un-designate any stale PDP, but
340 * we check here to see if the PDP has gone stale since the update
343 * Even if we determine that the designated PDP is current, we keep
344 * going (we don't break), so we can get visibility into the other
345 * PDPs, when in DEBUG mode.
347 if (pdp.isDesignated() && isCurrent(pdp)) {
348 logger.debug("hasDesignatedPdpFailed: Designated PDP={} is current", pdp.getPdpId());
350 foundDesignatedPdp = true;
351 } else if (pdp.isDesignated() && !isCurrent(pdp)) {
352 logger.error("hasDesignatedPdpFailed: Designated PDP={} has failed", pdp.getPdpId());
353 foundDesignatedPdp = true;
355 logger.debug("hasDesignatedPdpFailed: PDP={} is not designated", pdp.getPdpId());
359 logger.debug("hasDesignatedPdpFailed: Exiting and returning, foundDesignatedPdp={}",
365 private boolean isCurrent(DroolsPdp pdp) {
367 logger.debug("isCurrent: Entering, pdpId={}", pdp.getPdpId());
369 boolean current = false;
371 // Return if the current PDP is considered "current" based on whatever
372 // time box that may be.
373 // If the the PDP is not current, we should mark it as not primary in
375 Date currentDate = currentTime.getDate();
376 long difference = currentDate.getTime()
377 - pdp.getUpdatedDate().getTime();
378 // just set some kind of default here
379 long pdpTimeout = 15000;
381 pdpTimeout = Long.parseLong(ActiveStandbyProperties
382 .getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
383 logger.debug("isCurrent: pdp.timeout={}", pdpTimeout);
384 } catch (Exception e) {
385 logger.error("isCurrent: Could not get PDP timeout property, using default.", e);
387 current = difference < pdpTimeout;
389 logger.debug("isCurrent: Exiting, difference={}, pdpTimeout={}"
390 + "; returning current={}", difference, pdpTimeout, current);
397 * Currently this method is only used in a JUnit test environment. Gets a
398 * PDP record from droolspdpentity table.
401 public DroolsPdpEntity getPdp(String pdpId) {
403 logger.debug("getPdp: Entering and getting PDP with pdpId={}", pdpId);
405 DroolsPdpEntity droolsPdpEntity = null;
407 EntityManager em = null;
409 em = emf.createEntityManager();
410 em.getTransaction().begin();
411 Query droolsPdpsListQuery = em
412 .createQuery(SELECT_PDP_BY_ID);
413 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdpId);
414 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
415 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
416 if (droolsPdpsList.size() == 1
417 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
418 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
419 logger.debug("getPdp: PDP={}"
420 + " found, isDesignated={},"
421 + " updatedDate={}, "
422 + "priority={}", pdpId,
423 droolsPdpEntity.isDesignated(), droolsPdpEntity.getUpdatedDate(),
424 droolsPdpEntity.getPriority());
426 // Make sure the droolsPdpEntity is not a cached version
427 em.refresh(droolsPdpEntity);
429 em.getTransaction().commit();
431 logger.error("getPdp: PDP={} not found!?", pdpId);
433 } catch (Exception e) {
434 logger.error("getPdp: Caught Exception attempting to get PDP", e);
436 cleanup(em, "getPdp");
439 logger.debug("getPdp: Returning droolsPdpEntity={}", droolsPdpEntity);
440 return droolsPdpEntity;
445 * Normally this method should only be used in a JUnit test environment.
446 * Manually inserts a PDP record in droolspdpentity table.
449 public void insertPdp(DroolsPdp pdp) {
450 logger.debug("insertPdp: Entering and manually inserting PDP");
455 EntityManager em = emf.createEntityManager();
457 em.getTransaction().begin();
462 DroolsPdpEntity droolsPdpEntity = new DroolsPdpEntity();
463 em.persist(droolsPdpEntity);
464 droolsPdpEntity.setPdpId(pdp.getPdpId());
465 droolsPdpEntity.setDesignated(pdp.isDesignated());
466 droolsPdpEntity.setPriority(pdp.getPriority());
467 droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate());
468 droolsPdpEntity.setSite(pdp.getSite());
473 em.getTransaction().commit();
475 cleanup(em, "insertPdp");
477 logger.debug("insertPdp: Exiting");
482 * Normally this method should only be used in a JUnit test environment.
483 * Manually deletes all PDP records in droolspdpentity table.
486 public void deleteAllPdps() {
488 logger.debug("deleteAllPdps: Entering");
493 EntityManager em = emf.createEntityManager();
495 em.getTransaction().begin();
497 Query droolsPdpsListQuery = em
498 .createQuery("SELECT p FROM DroolsPdpEntity p");
499 @SuppressWarnings("unchecked")
500 List<DroolsPdp> droolsPdpsList = droolsPdpsListQuery.setLockMode(
501 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
502 logger.debug("deleteAllPdps: Deleting {} PDPs", droolsPdpsList.size());
503 for (DroolsPdp droolsPdp : droolsPdpsList) {
504 String pdpId = droolsPdp.getPdpId();
511 em.getTransaction().commit();
513 cleanup(em, "deleteAllPdps");
515 logger.debug("deleteAllPdps: Exiting");
520 * Normally this method should only be used in a JUnit test environment.
521 * Manually deletes a PDP record in droolspdpentity table.
524 public void deletePdp(String pdpId) {
525 logger.debug("deletePdp: Entering and manually deleting pdpId={}", pdpId);
530 EntityManager em = emf.createEntityManager();
532 em.getTransaction().begin();
537 DroolsPdpEntity droolsPdpEntity = em.find(DroolsPdpEntity.class, pdpId);
538 if (droolsPdpEntity != null) {
539 logger.debug("deletePdp: Removing PDP");
540 em.remove(droolsPdpEntity);
542 logger.debug("deletePdp: PDP with ID={} not currently in DB", pdpId);
548 em.getTransaction().commit();
550 cleanup(em, "deletePdp");
552 logger.debug("deletePdp: Exiting");
557 * Close the specified EntityManager, rolling back any pending transaction
559 * @param em the EntityManager to close ('null' is OK)
560 * @param method the invoking Java method (used for log messages)
562 private static void cleanup(EntityManager em, String method) {
563 if (em != null && em.isOpen()) {
564 if (em.getTransaction().isActive()) {
565 // there is an active EntityTransaction -- roll it back
567 em.getTransaction().rollback();
568 } catch (Exception e) {
569 logger.error(method + ": Caught Exception attempting to rollback EntityTransaction,", e);
573 // now, close the EntityManager
576 } catch (Exception e) {
577 logger.error(method + ": Caught Exception attempting to close EntityManager, ", e);