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;
34 import org.slf4j.Logger;
35 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;
47 //not sure if we want to use the same entity manager factory
48 //for drools session and pass it in here, or create a new one
49 public JpaDroolsPdpsConnector(EntityManagerFactory emf) {
54 public Collection<DroolsPdp> getDroolsPdps() {
55 //return a list of all the DroolsPdps in the database
56 EntityManager em = emf.createEntityManager();
58 em.getTransaction().begin();
59 Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p");
60 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
61 .setFlushMode(FlushModeType.COMMIT).getResultList();
62 LinkedList<DroolsPdp> droolsPdpsReturnList = new LinkedList<>();
63 for (Object o : droolsPdpsList) {
64 if (!(o instanceof DroolsPdp)) {
67 //Make sure it is not a cached version
68 DroolsPdp droolsPdp = (DroolsPdp)o;
69 em.refresh(droolsPdp);
70 droolsPdpsReturnList.add(droolsPdp);
71 if (logger.isDebugEnabled()) {
72 logger.debug("getDroolsPdps: PDP= {}"
73 + ", isDesignated= {}"
75 + ", priority= {}", droolsPdp.getPdpId(), droolsPdp.isDesignated(),
76 droolsPdp.getUpdatedDate(), droolsPdp.getPriority());
80 em.getTransaction().commit();
81 } catch (Exception e) {
82 logger.error("Cannot commit getDroolsPdps() transaction", e);
84 return droolsPdpsReturnList;
86 cleanup(em, "getDroolsPdps");
90 private boolean nullSafeEquals(Object one, Object two) {
91 if (one == null && two == null) {
94 if (one != null && two != null) {
95 return one.equals(two);
101 public void update(DroolsPdp pdp) {
103 logger.debug("update: Entering, pdpId={}", pdp.getPdpId());
105 //this is to update our own pdp in the database
106 EntityManager em = emf.createEntityManager();
108 em.getTransaction().begin();
109 Query droolsPdpsListQuery = em.createQuery(SELECT_PDP_BY_ID);
110 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
111 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
112 .setFlushMode(FlushModeType.COMMIT).getResultList();
113 DroolsPdpEntity droolsPdpEntity;
114 if (droolsPdpsList.size() == 1 && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)) {
115 droolsPdpEntity = (DroolsPdpEntity)droolsPdpsList.get(0);
116 em.refresh(droolsPdpEntity); //Make sure we have current values
117 Date currentDate = new Date();
118 long difference = currentDate.getTime() - droolsPdpEntity.getUpdatedDate().getTime();
119 //just set some kind of default here
120 long pdpTimeout = 15000;
122 pdpTimeout = Long.parseLong(
123 ActiveStandbyProperties.getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
124 } catch (Exception e) {
125 logger.error("Could not get PDP timeout property, using default.", e);
127 boolean isCurrent = difference < pdpTimeout;
128 logger.debug("update: PDP= {}, isCurrent={}"
130 + ", pdpTimeout= {}, designated= {}",
131 pdp.getPdpId(), isCurrent, difference, pdpTimeout, droolsPdpEntity.isDesignated());
133 logger.debug("update: For PDP={}"
134 + ", instantiating new DroolsPdpEntity", pdp.getPdpId());
135 droolsPdpEntity = new DroolsPdpEntity();
136 em.persist(droolsPdpEntity);
137 droolsPdpEntity.setPdpId(pdp.getPdpId());
139 if (droolsPdpEntity.getPriority() != pdp.getPriority()) {
140 droolsPdpEntity.setPriority(pdp.getPriority());
142 if (!droolsPdpEntity.getUpdatedDate().equals(pdp.getUpdatedDate())) {
143 droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate());
145 if (!nullSafeEquals(droolsPdpEntity.getSite(),pdp.getSite())) {
146 droolsPdpEntity.setSite(pdp.getSite());
149 if (droolsPdpEntity.isDesignated() != pdp.isDesignated()) {
150 logger.debug("update: pdpId={}"
151 + ", pdp.isDesignated={}"
152 + ", droolsPdpEntity.pdpId= {}"
153 + ", droolsPdpEntity.isDesignated={}",
154 pdp.getPdpId(), pdp.isDesignated(),
155 droolsPdpEntity.getPdpId(), droolsPdpEntity.isDesignated());
156 droolsPdpEntity.setDesignated(pdp.isDesignated());
157 //The isDesignated value is not the same and the new one == true
158 if (pdp.isDesignated()) {
159 droolsPdpEntity.setDesignatedDate(new Date());
162 em.getTransaction().commit();
164 cleanup(em, "update");
167 logger.debug("update: Exiting");
172 * Note: A side effect of this boolean method is that if the PDP is designated but not current, the
173 * droolspdpentity.DESIGNATED column will be set to false (the PDP will be un-designated, i.e. marked as
174 * being in standby mode)
177 public boolean isPdpCurrent(DroolsPdp pdp) {
179 boolean isCurrent = isCurrent(pdp);
181 EntityManager em = emf.createEntityManager();
183 if (!isCurrent && pdp.isDesignated()) {
184 em.getTransaction().begin();
185 Query droolsPdpsListQuery = em.createQuery(SELECT_PDP_BY_ID);
186 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
187 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
188 .setFlushMode(FlushModeType.COMMIT).getResultList();
189 if (droolsPdpsList.size() == 1 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
190 logger.debug("isPdpCurrent: PDP={} designated but not current; setting designated to false",
192 DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity)droolsPdpsList.get(0);
193 droolsPdpEntity.setDesignated(false);
194 em.getTransaction().commit();
196 logger.warn("isPdpCurrent: PDP={} is designated but not current; "
197 + "however it does not have a DB entry, so cannot set DESIGNATED to false!",
201 logger.debug("isPdpCurrent: For PDP= {}, "
202 + "designated={}, isCurrent={}", pdp.getPdpId(), pdp.isDesignated(), isCurrent);
204 } catch (Exception e) {
205 logger.error("Could not update expired record marked as designated in the database", e);
207 cleanup(em, "isPdpCurrent");
214 public void setDesignated(DroolsPdp pdp, boolean designated) {
216 logger.debug("setDesignated: Entering, pdpId={}"
217 + ", designated={}", pdp.getPdpId(), designated);
219 EntityManager em = null;
221 em = emf.createEntityManager();
222 em.getTransaction().begin();
223 Query droolsPdpsListQuery = em
224 .createQuery(SELECT_PDP_BY_ID);
225 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
226 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
227 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
228 if (droolsPdpsList.size() == 1
229 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
230 DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList
233 logger.debug("setDesignated: PDP={}"
234 + " found, designated= {}"
235 + ", setting to {}", pdp.getPdpId(), droolsPdpEntity.isDesignated(),
237 setPdpDesignation(em, droolsPdpEntity, designated);
238 em.getTransaction().commit();
240 logger.error("setDesignated: PDP={}"
241 + " not in DB; cannot update designation", pdp.getPdpId());
243 } catch (Exception e) {
244 logger.error("setDesignated: Caught Exception", e);
246 cleanup(em, "setDesignated");
249 logger.debug("setDesignated: Exiting");
253 private void setPdpDesignation(EntityManager em, DroolsPdpEntity droolsPdpEntity, boolean designated) {
254 droolsPdpEntity.setDesignated(designated);
256 em.refresh(droolsPdpEntity); //make sure we get the DB value
257 if (!droolsPdpEntity.isDesignated()) {
258 droolsPdpEntity.setDesignatedDate(new Date());
266 public void standDownPdp(String pdpId) {
267 logger.debug("standDownPdp: Entering, pdpId={}", pdpId);
269 EntityManager em = null;
274 em = emf.createEntityManager();
275 em.getTransaction().begin();
278 * Get droolspdpentity record for this PDP and mark DESIGNATED as
281 Query droolsPdpsListQuery = em
282 .createQuery(SELECT_PDP_BY_ID);
283 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdpId);
284 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
285 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
286 DroolsPdpEntity droolsPdpEntity;
287 if (droolsPdpsList.size() == 1
288 && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)) {
289 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
290 droolsPdpEntity.setDesignated(false);
291 em.persist(droolsPdpEntity);
292 logger.debug("standDownPdp: PDP={} persisted as non-designated.", pdpId );
294 logger.error("standDownPdp: Missing record in droolspdpentity for pdpId={}"
295 + "; cannot stand down PDP", pdpId);
301 em.getTransaction().commit();
302 cleanup(em, "standDownPdp");
305 // Keep the election handler in sync with the DB
306 DroolsPdpsElectionHandler.setMyPdpDesignated(false);
308 } catch (Exception e) {
309 logger.error("standDownPdp: Unexpected Exception attempting to mark "
310 + "DESIGNATED as false for droolspdpentity, pdpId={}"
311 + ". Cannot stand down PDP; message={}", pdpId, e.getMessage(), e);
313 cleanup(em, "standDownPdp");
315 logger.debug("standDownPdp: Exiting");
320 * Determines whether or not a designated PDP has failed.
322 * Note: The update method, which is run periodically by the
323 * TimerUpdateClass, will un-designate a PDP that is stale.
326 public boolean hasDesignatedPdpFailed(Collection<DroolsPdp> pdps) {
328 logger.debug("hasDesignatedPdpFailed: Entering, pdps.size()={}", pdps.size());
330 boolean failed = true;
331 boolean foundDesignatedPdp = false;
333 for (DroolsPdp pdp : pdps) {
336 * Normally, the update method will un-designate any stale PDP, but
337 * we check here to see if the PDP has gone stale since the update
340 * Even if we determine that the designated PDP is current, we keep
341 * going (we don't break), so we can get visibility into the other
342 * PDPs, when in DEBUG mode.
344 if (pdp.isDesignated() && isCurrent(pdp)) {
345 logger.debug("hasDesignatedPdpFailed: Designated PDP={} is current", pdp.getPdpId());
347 foundDesignatedPdp = true;
348 } else if (pdp.isDesignated() && !isCurrent(pdp)) {
349 logger.error("hasDesignatedPdpFailed: Designated PDP={} has failed", pdp.getPdpId());
350 foundDesignatedPdp = true;
352 logger.debug("hasDesignatedPdpFailed: PDP={} is not designated", pdp.getPdpId());
356 logger.debug("hasDesignatedPdpFailed: Exiting and returning, foundDesignatedPdp={}",
362 private boolean isCurrent(DroolsPdp pdp) {
364 logger.debug("isCurrent: Entering, pdpId={}", pdp.getPdpId());
366 boolean current = false;
368 // Return if the current PDP is considered "current" based on whatever
369 // time box that may be.
370 // If the the PDP is not current, we should mark it as not primary in
372 Date currentDate = new Date();
373 long difference = currentDate.getTime()
374 - pdp.getUpdatedDate().getTime();
375 // just set some kind of default here
376 long pdpTimeout = 15000;
378 pdpTimeout = Long.parseLong(ActiveStandbyProperties
379 .getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
380 logger.debug("isCurrent: pdp.timeout={}", pdpTimeout);
381 } catch (Exception e) {
382 logger.error("isCurrent: Could not get PDP timeout property, using default.", e);
384 current = difference < pdpTimeout;
386 logger.debug("isCurrent: Exiting, difference={}, pdpTimeout={}"
387 + "; returning current={}", difference, pdpTimeout, current);
394 * Currently this method is only used in a JUnit test environment. Gets a
395 * PDP record from droolspdpentity table.
398 public DroolsPdpEntity getPdp(String pdpId) {
400 logger.debug("getPdp: Entering and getting PDP with pdpId={}", pdpId);
402 DroolsPdpEntity droolsPdpEntity = null;
404 EntityManager em = null;
406 em = emf.createEntityManager();
407 em.getTransaction().begin();
408 Query droolsPdpsListQuery = em
409 .createQuery(SELECT_PDP_BY_ID);
410 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdpId);
411 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
412 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
413 if (droolsPdpsList.size() == 1
414 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
415 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
416 logger.debug("getPdp: PDP={}"
417 + " found, isDesignated={},"
418 + " updatedDate={}, "
419 + "priority={}", pdpId,
420 droolsPdpEntity.isDesignated(), droolsPdpEntity.getUpdatedDate(),
421 droolsPdpEntity.getPriority());
423 // Make sure the droolsPdpEntity is not a cached version
424 em.refresh(droolsPdpEntity);
426 em.getTransaction().commit();
428 logger.error("getPdp: PDP={} not found!?", pdpId);
430 } catch (Exception e) {
431 logger.error("getPdp: Caught Exception attempting to get PDP", e);
433 cleanup(em, "getPdp");
436 logger.debug("getPdp: Returning droolsPdpEntity={}", droolsPdpEntity);
437 return droolsPdpEntity;
442 * Normally this method should only be used in a JUnit test environment.
443 * Manually inserts a PDP record in droolspdpentity table.
446 public void insertPdp(DroolsPdp pdp) {
447 logger.debug("insertPdp: Entering and manually inserting PDP");
452 EntityManager em = emf.createEntityManager();
454 em.getTransaction().begin();
459 DroolsPdpEntity droolsPdpEntity = new DroolsPdpEntity();
460 em.persist(droolsPdpEntity);
461 droolsPdpEntity.setPdpId(pdp.getPdpId());
462 droolsPdpEntity.setDesignated(pdp.isDesignated());
463 droolsPdpEntity.setPriority(pdp.getPriority());
464 droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate());
465 droolsPdpEntity.setSite(pdp.getSite());
470 em.getTransaction().commit();
472 cleanup(em, "insertPdp");
474 logger.debug("insertPdp: Exiting");
479 * Normally this method should only be used in a JUnit test environment.
480 * Manually deletes all PDP records in droolspdpentity table.
483 public void deleteAllPdps() {
485 logger.debug("deleteAllPdps: Entering");
490 EntityManager em = emf.createEntityManager();
492 em.getTransaction().begin();
494 Query droolsPdpsListQuery = em
495 .createQuery("SELECT p FROM DroolsPdpEntity p");
496 @SuppressWarnings("unchecked")
497 List<DroolsPdp> droolsPdpsList = droolsPdpsListQuery.setLockMode(
498 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
499 logger.debug("deleteAllPdps: Deleting {} PDPs", droolsPdpsList.size());
500 for (DroolsPdp droolsPdp : droolsPdpsList) {
501 String pdpId = droolsPdp.getPdpId();
508 em.getTransaction().commit();
510 cleanup(em, "deleteAllPdps");
512 logger.debug("deleteAllPdps: Exiting");
517 * Normally this method should only be used in a JUnit test environment.
518 * Manually deletes a PDP record in droolspdpentity table.
521 public void deletePdp(String pdpId) {
522 logger.debug("deletePdp: Entering and manually deleting pdpId={}", pdpId);
527 EntityManager em = emf.createEntityManager();
529 em.getTransaction().begin();
534 DroolsPdpEntity droolsPdpEntity = em.find(DroolsPdpEntity.class, pdpId);
535 if (droolsPdpEntity != null) {
536 logger.debug("deletePdp: Removing PDP");
537 em.remove(droolsPdpEntity);
539 logger.debug("deletePdp: PDP with ID={} not currently in DB", pdpId);
545 em.getTransaction().commit();
547 cleanup(em, "deletePdp");
549 logger.debug("deletePdp: Exiting");
554 * Close the specified EntityManager, rolling back any pending transaction
556 * @param em the EntityManager to close ('null' is OK)
557 * @param method the invoking Java method (used for log messages)
559 private static void cleanup(EntityManager em, String method) {
560 if (em != null && em.isOpen()) {
561 if (em.getTransaction().isActive()) {
562 // there is an active EntityTransaction -- roll it back
564 em.getTransaction().rollback();
565 } catch (Exception e) {
566 logger.error(method + ": Caught Exception attempting to rollback EntityTransaction,", e);
570 // now, close the EntityManager
573 } catch (Exception e) {
574 logger.error(method + ": Caught Exception attempting to close EntityManager, ", e);