2 * ============LICENSE_START=======================================================
3 * feature-active-standby-management
4 * ================================================================================
5 * Copyright (C) 2017-2020 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;
27 import javax.persistence.EntityManager;
28 import javax.persistence.EntityManagerFactory;
29 import javax.persistence.FlushModeType;
30 import javax.persistence.LockModeType;
31 import javax.persistence.Query;
32 import org.onap.policy.common.im.MonitorTime;
33 import org.onap.policy.common.utils.time.CurrentTime;
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;
46 private final CurrentTime currentTime = MonitorTime.getInstance();
49 //not sure if we want to use the same entity manager factory
50 //for drools session and pass it in here, or create a new one
51 public JpaDroolsPdpsConnector(EntityManagerFactory emf) {
56 public Collection<DroolsPdp> getDroolsPdps() {
57 //return a list of all the DroolsPdps in the database
58 EntityManager em = emf.createEntityManager();
60 em.getTransaction().begin();
61 Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p");
62 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
63 .setFlushMode(FlushModeType.COMMIT).getResultList();
64 LinkedList<DroolsPdp> droolsPdpsReturnList = new LinkedList<>();
65 for (Object o : droolsPdpsList) {
66 if (!(o instanceof DroolsPdp)) {
69 //Make sure it is not a cached version
70 DroolsPdp droolsPdp = (DroolsPdp) o;
71 em.refresh(droolsPdp);
72 droolsPdpsReturnList.add(droolsPdp);
73 if (logger.isDebugEnabled()) {
74 logger.debug("getDroolsPdps: PDP= {}"
75 + ", isDesignated= {}"
77 + ", priority= {}", droolsPdp.getPdpId(), droolsPdp.isDesignated(),
78 droolsPdp.getUpdatedDate(), droolsPdp.getPriority());
82 em.getTransaction().commit();
83 } catch (Exception e) {
84 logger.error("Cannot commit getDroolsPdps() transaction", e);
86 return droolsPdpsReturnList;
88 cleanup(em, "getDroolsPdps");
92 private boolean nullSafeEquals(Object one, Object two) {
93 if (one == null && two == null) {
96 if (one != null && two != null) {
97 return one.equals(two);
103 public void update(DroolsPdp pdp) {
105 logger.debug("update: Entering, pdpId={}", pdp.getPdpId());
107 //this is to update our own pdp in the database
108 EntityManager em = emf.createEntityManager();
110 em.getTransaction().begin();
111 Query droolsPdpsListQuery = em.createQuery(SELECT_PDP_BY_ID);
112 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
113 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
114 .setFlushMode(FlushModeType.COMMIT).getResultList();
115 DroolsPdpEntity droolsPdpEntity;
116 if (droolsPdpsList.size() == 1 && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)) {
117 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
118 em.refresh(droolsPdpEntity); //Make sure we have current values
119 Date currentDate = currentTime.getDate();
120 long difference = currentDate.getTime() - droolsPdpEntity.getUpdatedDate().getTime();
121 //just set some kind of default here
122 long pdpTimeout = 15000;
124 pdpTimeout = Long.parseLong(
125 ActiveStandbyProperties.getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
126 } catch (Exception e) {
127 logger.error("Could not get PDP timeout property, using default.", e);
129 boolean isCurrent = difference < pdpTimeout;
130 logger.debug("update: PDP= {}, isCurrent={}"
132 + ", pdpTimeout= {}, designated= {}",
133 pdp.getPdpId(), isCurrent, difference, pdpTimeout, droolsPdpEntity.isDesignated());
135 logger.debug("update: For PDP={}"
136 + ", instantiating new DroolsPdpEntity", pdp.getPdpId());
137 droolsPdpEntity = new DroolsPdpEntity();
138 em.persist(droolsPdpEntity);
139 droolsPdpEntity.setPdpId(pdp.getPdpId());
141 if (droolsPdpEntity.getPriority() != pdp.getPriority()) {
142 droolsPdpEntity.setPriority(pdp.getPriority());
144 if (!droolsPdpEntity.getUpdatedDate().equals(pdp.getUpdatedDate())) {
145 droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate());
147 if (!nullSafeEquals(droolsPdpEntity.getSite(), pdp.getSite())) {
148 droolsPdpEntity.setSite(pdp.getSite());
151 if (droolsPdpEntity.isDesignated() != pdp.isDesignated()) {
152 logger.debug("update: pdpId={}"
153 + ", pdp.isDesignated={}"
154 + ", droolsPdpEntity.pdpId= {}"
155 + ", droolsPdpEntity.isDesignated={}",
156 pdp.getPdpId(), pdp.isDesignated(),
157 droolsPdpEntity.getPdpId(), droolsPdpEntity.isDesignated());
158 droolsPdpEntity.setDesignated(pdp.isDesignated());
159 //The isDesignated value is not the same and the new one == true
160 if (pdp.isDesignated()) {
161 droolsPdpEntity.setDesignatedDate(currentTime.getDate());
164 em.getTransaction().commit();
166 cleanup(em, "update");
169 logger.debug("update: Exiting");
174 * Note: A side effect of this boolean method is that if the PDP is designated but not current, the
175 * droolspdpentity.DESIGNATED column will be set to false (the PDP will be un-designated, i.e. marked as
176 * being in standby mode)
179 public boolean isPdpCurrent(DroolsPdp pdp) {
181 boolean isCurrent = isCurrent(pdp);
183 EntityManager em = emf.createEntityManager();
185 if (!isCurrent && pdp.isDesignated()) {
186 em.getTransaction().begin();
187 Query droolsPdpsListQuery = em.createQuery(SELECT_PDP_BY_ID);
188 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
189 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
190 .setFlushMode(FlushModeType.COMMIT).getResultList();
191 if (droolsPdpsList.size() == 1 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
192 logger.debug("isPdpCurrent: PDP={} designated but not current; setting designated to false",
194 DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
195 droolsPdpEntity.setDesignated(false);
196 em.getTransaction().commit();
198 logger.warn("isPdpCurrent: PDP={} is designated but not current; "
199 + "however it does not have a DB entry, so cannot set DESIGNATED to false!",
203 logger.debug("isPdpCurrent: For PDP= {}, "
204 + "designated={}, isCurrent={}", pdp.getPdpId(), pdp.isDesignated(), isCurrent);
206 } catch (Exception e) {
207 logger.error("Could not update expired record marked as designated in the database", e);
209 cleanup(em, "isPdpCurrent");
216 public void setDesignated(DroolsPdp pdp, boolean designated) {
218 logger.debug("setDesignated: Entering, pdpId={}"
219 + ", designated={}", pdp.getPdpId(), designated);
221 EntityManager em = null;
223 em = emf.createEntityManager();
224 em.getTransaction().begin();
225 Query droolsPdpsListQuery = em
226 .createQuery(SELECT_PDP_BY_ID);
227 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdp.getPdpId());
228 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
229 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
230 if (droolsPdpsList.size() == 1
231 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
232 DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList
235 logger.debug("setDesignated: PDP={}"
236 + " found, designated= {}"
237 + ", setting to {}", pdp.getPdpId(), droolsPdpEntity.isDesignated(),
239 setPdpDesignation(em, droolsPdpEntity, designated);
240 em.getTransaction().commit();
242 logger.error("setDesignated: PDP={}"
243 + " not in DB; cannot update designation", pdp.getPdpId());
245 } catch (Exception e) {
246 logger.error("setDesignated: Caught Exception", e);
248 cleanup(em, "setDesignated");
251 logger.debug("setDesignated: Exiting");
255 private void setPdpDesignation(EntityManager em, DroolsPdpEntity droolsPdpEntity, boolean designated) {
256 droolsPdpEntity.setDesignated(designated);
258 em.refresh(droolsPdpEntity); //make sure we get the DB value
259 if (!droolsPdpEntity.isDesignated()) {
260 droolsPdpEntity.setDesignatedDate(currentTime.getDate());
268 public void standDownPdp(String pdpId) {
269 logger.debug("standDownPdp: Entering, pdpId={}", pdpId);
271 EntityManager em = null;
276 em = emf.createEntityManager();
277 em.getTransaction().begin();
280 * Get droolspdpentity record for this PDP and mark DESIGNATED as
283 Query droolsPdpsListQuery = em
284 .createQuery(SELECT_PDP_BY_ID);
285 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdpId);
286 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
287 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
288 DroolsPdpEntity droolsPdpEntity;
289 if (droolsPdpsList.size() == 1
290 && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)) {
291 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
292 droolsPdpEntity.setDesignated(false);
293 em.persist(droolsPdpEntity);
294 logger.debug("standDownPdp: PDP={} persisted as non-designated.", pdpId);
296 logger.error("standDownPdp: Missing record in droolspdpentity for pdpId={}"
297 + "; cannot stand down PDP", pdpId);
303 em.getTransaction().commit();
304 cleanup(em, "standDownPdp");
307 // Keep the election handler in sync with the DB
308 DroolsPdpsElectionHandler.setMyPdpDesignated(false);
310 } catch (Exception e) {
311 logger.error("standDownPdp: Unexpected Exception attempting to mark "
312 + "DESIGNATED as false for droolspdpentity, pdpId={}"
313 + ". Cannot stand down PDP; message={}", pdpId, e.getMessage(), e);
315 cleanup(em, "standDownPdp");
317 logger.debug("standDownPdp: Exiting");
322 * Determines whether or not a designated PDP has failed.
324 * Note: The update method, which is run periodically by the
325 * TimerUpdateClass, will un-designate a PDP that is stale.
328 public boolean hasDesignatedPdpFailed(Collection<DroolsPdp> pdps) {
330 logger.debug("hasDesignatedPdpFailed: Entering, pdps.size()={}", pdps.size());
332 boolean failed = true;
333 boolean foundDesignatedPdp = false;
335 for (DroolsPdp pdp : pdps) {
338 * Normally, the update method will un-designate any stale PDP, but
339 * we check here to see if the PDP has gone stale since the update
342 * Even if we determine that the designated PDP is current, we keep
343 * going (we don't break), so we can get visibility into the other
344 * PDPs, when in DEBUG mode.
346 if (pdp.isDesignated() && isCurrent(pdp)) {
347 logger.debug("hasDesignatedPdpFailed: Designated PDP={} is current", pdp.getPdpId());
349 foundDesignatedPdp = true;
350 } else if (pdp.isDesignated() && !isCurrent(pdp)) {
351 logger.error("hasDesignatedPdpFailed: Designated PDP={} has failed", pdp.getPdpId());
352 foundDesignatedPdp = true;
354 logger.debug("hasDesignatedPdpFailed: PDP={} is not designated", pdp.getPdpId());
358 logger.debug("hasDesignatedPdpFailed: Exiting and returning, foundDesignatedPdp={}",
364 private boolean isCurrent(DroolsPdp pdp) {
366 logger.debug("isCurrent: Entering, pdpId={}", pdp.getPdpId());
368 boolean current = false;
370 // Return if the current PDP is considered "current" based on whatever
371 // time box that may be.
372 // If the the PDP is not current, we should mark it as not primary in
374 Date currentDate = currentTime.getDate();
375 long difference = currentDate.getTime()
376 - pdp.getUpdatedDate().getTime();
377 // just set some kind of default here
378 long pdpTimeout = 15000;
380 pdpTimeout = Long.parseLong(ActiveStandbyProperties
381 .getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
382 logger.debug("isCurrent: pdp.timeout={}", pdpTimeout);
383 } catch (Exception e) {
384 logger.error("isCurrent: Could not get PDP timeout property, using default.", e);
386 current = difference < pdpTimeout;
388 logger.debug("isCurrent: Exiting, difference={}, pdpTimeout={}"
389 + "; returning current={}", difference, pdpTimeout, current);
396 * Currently this method is only used in a JUnit test environment. Gets a
397 * PDP record from droolspdpentity table.
400 public DroolsPdpEntity getPdp(String pdpId) {
402 logger.debug("getPdp: Entering and getting PDP with pdpId={}", pdpId);
404 DroolsPdpEntity droolsPdpEntity = null;
406 EntityManager em = null;
408 em = emf.createEntityManager();
409 em.getTransaction().begin();
410 Query droolsPdpsListQuery = em
411 .createQuery(SELECT_PDP_BY_ID);
412 droolsPdpsListQuery.setParameter(PDP_ID_PARAM, pdpId);
413 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
414 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
415 if (droolsPdpsList.size() == 1
416 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
417 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
418 logger.debug("getPdp: PDP={}"
419 + " found, isDesignated={},"
420 + " updatedDate={}, "
421 + "priority={}", pdpId,
422 droolsPdpEntity.isDesignated(), droolsPdpEntity.getUpdatedDate(),
423 droolsPdpEntity.getPriority());
425 // Make sure the droolsPdpEntity is not a cached version
426 em.refresh(droolsPdpEntity);
428 em.getTransaction().commit();
430 logger.error("getPdp: PDP={} not found!?", pdpId);
432 } catch (Exception e) {
433 logger.error("getPdp: Caught Exception attempting to get PDP", e);
435 cleanup(em, "getPdp");
438 logger.debug("getPdp: Returning droolsPdpEntity={}", droolsPdpEntity);
439 return droolsPdpEntity;
444 * Normally this method should only be used in a JUnit test environment.
445 * Manually inserts a PDP record in droolspdpentity table.
448 public void insertPdp(DroolsPdp pdp) {
449 logger.debug("insertPdp: Entering and manually inserting PDP");
454 EntityManager em = emf.createEntityManager();
456 em.getTransaction().begin();
461 DroolsPdpEntity droolsPdpEntity = new DroolsPdpEntity();
462 em.persist(droolsPdpEntity);
463 droolsPdpEntity.setPdpId(pdp.getPdpId());
464 droolsPdpEntity.setDesignated(pdp.isDesignated());
465 droolsPdpEntity.setPriority(pdp.getPriority());
466 droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate());
467 droolsPdpEntity.setSite(pdp.getSite());
472 em.getTransaction().commit();
474 cleanup(em, "insertPdp");
476 logger.debug("insertPdp: Exiting");
481 * Normally this method should only be used in a JUnit test environment.
482 * Manually deletes all PDP records in droolspdpentity table.
485 public void deleteAllPdps() {
487 logger.debug("deleteAllPdps: Entering");
492 EntityManager em = emf.createEntityManager();
494 em.getTransaction().begin();
496 Query droolsPdpsListQuery = em
497 .createQuery("SELECT p FROM DroolsPdpEntity p");
498 @SuppressWarnings("unchecked")
499 List<DroolsPdp> droolsPdpsList = droolsPdpsListQuery.setLockMode(
500 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
501 logger.debug("deleteAllPdps: Deleting {} PDPs", droolsPdpsList.size());
502 for (DroolsPdp droolsPdp : droolsPdpsList) {
503 String pdpId = droolsPdp.getPdpId();
510 em.getTransaction().commit();
512 cleanup(em, "deleteAllPdps");
514 logger.debug("deleteAllPdps: Exiting");
519 * Normally this method should only be used in a JUnit test environment.
520 * Manually deletes a PDP record in droolspdpentity table.
523 public void deletePdp(String pdpId) {
524 logger.debug("deletePdp: Entering and manually deleting pdpId={}", pdpId);
529 EntityManager em = emf.createEntityManager();
531 em.getTransaction().begin();
536 DroolsPdpEntity droolsPdpEntity = em.find(DroolsPdpEntity.class, pdpId);
537 if (droolsPdpEntity != null) {
538 logger.debug("deletePdp: Removing PDP");
539 em.remove(droolsPdpEntity);
541 logger.debug("deletePdp: PDP with ID={} not currently in DB", pdpId);
547 em.getTransaction().commit();
549 cleanup(em, "deletePdp");
551 logger.debug("deletePdp: Exiting");
556 * Close the specified EntityManager, rolling back any pending transaction
558 * @param em the EntityManager to close ('null' is OK)
559 * @param method the invoking Java method (used for log messages)
561 private static void cleanup(EntityManager em, String method) {
562 if (em != null && em.isOpen()) {
563 if (em.getTransaction().isActive()) {
564 // there is an active EntityTransaction -- roll it back
566 em.getTransaction().rollback();
567 } catch (Exception e) {
568 logger.error("{}: Caught Exception attempting to rollback EntityTransaction", method, e);
572 // now, close the EntityManager
575 } catch (Exception e) {
576 logger.error("{}: Caught Exception attempting to close EntityManager", method, e);