2 * ============LICENSE_START=======================================================
3 * feature-active-standby-management
4 * ================================================================================
5 * Copyright (C) 2017-2018 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 // get an instance of logger
40 private static final Logger logger = LoggerFactory.getLogger(JpaDroolsPdpsConnector.class);
41 private EntityManagerFactory emf;
44 //not sure if we want to use the same entity manager factory
45 //for drools session and pass it in here, or create a new one
46 public JpaDroolsPdpsConnector(EntityManagerFactory emf) {
51 public Collection<DroolsPdp> getDroolsPdps() {
52 //return a list of all the DroolsPdps in the database
53 EntityManager em = emf.createEntityManager();
55 em.getTransaction().begin();
56 Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p");
57 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
58 .setFlushMode(FlushModeType.COMMIT).getResultList();
59 LinkedList<DroolsPdp> droolsPdpsReturnList = new LinkedList<>();
60 for (Object o : droolsPdpsList) {
61 if (o instanceof DroolsPdp) {
62 //Make sure it is not a cached version
63 em.refresh((DroolsPdpEntity)o);
64 droolsPdpsReturnList.add((DroolsPdp)o);
65 if (logger.isDebugEnabled()) {
66 DroolsPdp droolsPdp = (DroolsPdp)o;
67 logger.debug("getDroolsPdps: PDP= {}"
68 + ", isDesignated= {}"
70 + ", priority= {}", droolsPdp.getPdpId(), droolsPdp.isDesignated(),
71 droolsPdp.getUpdatedDate(), droolsPdp.getPriority());
76 em.getTransaction().commit();
77 } catch (Exception e) {
78 logger.error("Cannot commit getDroolsPdps() transaction", e);
80 return droolsPdpsReturnList;
82 cleanup(em, "getDroolsPdps");
86 private boolean nullSafeEquals(Object one, Object two) {
87 if (one == null && two == null) {
90 if (one != null && two != null) {
91 return one.equals(two);
97 public void update(DroolsPdp pdp) {
99 if (logger.isDebugEnabled()) {
100 logger.debug("update: Entering, pdpId={}", pdp.getPdpId());
103 //this is to update our own pdp in the database
104 EntityManager em = emf.createEntityManager();
106 em.getTransaction().begin();
107 Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId");
108 droolsPdpsListQuery.setParameter("pdpId", pdp.getPdpId());
109 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
110 .setFlushMode(FlushModeType.COMMIT).getResultList();
111 DroolsPdpEntity droolsPdpEntity;
112 if (droolsPdpsList.size() == 1 && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)) {
113 droolsPdpEntity = (DroolsPdpEntity)droolsPdpsList.get(0);
114 em.refresh(droolsPdpEntity); //Make sure we have current values
115 Date currentDate = new Date();
116 long difference = currentDate.getTime() - droolsPdpEntity.getUpdatedDate().getTime();
117 //just set some kind of default here
118 long pdpTimeout = 15000;
120 pdpTimeout = Long.parseLong(
121 ActiveStandbyProperties.getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
122 } catch (Exception e) {
123 logger.error("Could not get PDP timeout property, using default.", e);
125 boolean isCurrent = difference < pdpTimeout;
126 if (logger.isDebugEnabled()) {
127 logger.debug("update: PDP= {}, isCurrent={}"
129 + ", pdpTimeout= {}, designated= {}",
130 pdp.getPdpId(), isCurrent, difference, pdpTimeout, droolsPdpEntity.isDesignated());
133 if (logger.isDebugEnabled()) {
134 logger.debug("update: For PDP={}"
135 + ", 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.getSiteName(),pdp.getSiteName())) {
148 droolsPdpEntity.setSiteName(pdp.getSiteName());
151 if (droolsPdpEntity.isDesignated() != pdp.isDesignated()) {
152 if (logger.isDebugEnabled()) {
153 logger.debug("update: pdpId={}"
154 + ", pdp.isDesignated={}"
155 + ", droolsPdpEntity.pdpId= {}"
156 + ", droolsPdpEntity.isDesignated={}",
157 pdp.getPdpId(), pdp.isDesignated(),
158 droolsPdpEntity.getPdpId(), droolsPdpEntity.isDesignated());
160 droolsPdpEntity.setDesignated(pdp.isDesignated());
161 //The isDesignated value is not the same and the new one == true
162 if (pdp.isDesignated()) {
163 droolsPdpEntity.setDesignatedDate(new Date());
166 em.getTransaction().commit();
168 cleanup(em, "update");
171 if (logger.isDebugEnabled()) {
172 logger.debug("update: Exiting");
178 * Note: A side effect of this boolean method is that if the PDP is designated but not current, the
179 * droolspdpentity.DESIGNATED column will be set to false (the PDP will be un-designated, i.e. marked as
180 * being in standby mode)
183 public boolean isPdpCurrent(DroolsPdp pdp) {
185 boolean isCurrent = isCurrent(pdp);
187 EntityManager em = emf.createEntityManager();
189 if (!isCurrent && pdp.isDesignated()) {
190 em.getTransaction().begin();
191 Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId");
192 droolsPdpsListQuery.setParameter("pdpId", pdp.getPdpId());
193 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE)
194 .setFlushMode(FlushModeType.COMMIT).getResultList();
195 if (droolsPdpsList.size() == 1 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
196 if (logger.isDebugEnabled()) {
197 logger.debug("isPdpCurrent: PDP={} designated but not current; setting designated to false",
200 DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity)droolsPdpsList.get(0);
201 droolsPdpEntity.setDesignated(false);
202 em.getTransaction().commit();
204 logger.warn("isPdpCurrent: PDP={} is designated but not current; "
205 + "however it does not have a DB entry, so cannot set DESIGNATED to false!",
209 if (logger.isDebugEnabled()) {
210 logger.debug("isPdpCurrent: For PDP= {}, "
211 + "designated={}, isCurrent={}", pdp.getPdpId(), pdp.isDesignated(), isCurrent);
214 } catch (Exception e) {
215 logger.error("Could not update expired record marked as designated in the database", e);
217 cleanup(em, "isPdpCurrent");
224 public void setDesignated(DroolsPdp pdp, boolean designated) {
226 if (logger.isDebugEnabled()) {
227 logger.debug("setDesignated: Entering, pdpId={}"
228 + ", designated={}", pdp.getPdpId(), designated);
231 EntityManager em = null;
233 em = emf.createEntityManager();
234 em.getTransaction().begin();
235 Query droolsPdpsListQuery = em
236 .createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId");
237 droolsPdpsListQuery.setParameter("pdpId", pdp.getPdpId());
238 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
239 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
240 if (droolsPdpsList.size() == 1
241 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
242 DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList
245 if (logger.isDebugEnabled()) {
246 logger.debug("setDesignated: PDP={}"
247 + " found, designated= {}"
248 + ", setting to {}", pdp.getPdpId(), droolsPdpEntity.isDesignated(),
251 droolsPdpEntity.setDesignated(designated);
253 em.refresh(droolsPdpEntity); //make sure we get the DB value
254 if (!droolsPdpEntity.isDesignated()) {
255 droolsPdpEntity.setDesignatedDate(new Date());
259 em.getTransaction().commit();
261 logger.error("setDesignated: PDP={}"
262 + " not in DB; cannot update designation", pdp.getPdpId());
264 } catch (Exception e) {
265 logger.error("setDesignated: Caught Exception", e);
267 cleanup(em, "setDesignated");
270 if (logger.isDebugEnabled()) {
271 logger.debug("setDesignated: Exiting");
278 public void standDownPdp(String pdpId) {
279 if (logger.isDebugEnabled()) {
280 logger.debug("standDownPdp: Entering, pdpId={}", pdpId);
283 EntityManager em = null;
288 em = emf.createEntityManager();
289 em.getTransaction().begin();
292 * Get droolspdpentity record for this PDP and mark DESIGNATED as
295 Query droolsPdpsListQuery = em
296 .createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId");
297 droolsPdpsListQuery.setParameter("pdpId", pdpId);
298 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
299 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
300 DroolsPdpEntity droolsPdpEntity;
301 if (droolsPdpsList.size() == 1
302 && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)) {
303 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
304 droolsPdpEntity.setDesignated(false);
305 em.persist(droolsPdpEntity);
306 if (logger.isDebugEnabled()) {
307 logger.debug("standDownPdp: PDP={} persisted as non-designated.", pdpId );
310 logger.error("standDownPdp: Missing record in droolspdpentity for pdpId={}"
311 + "; cannot stand down PDP", pdpId);
317 em.getTransaction().commit();
318 cleanup(em, "standDownPdp");
321 // Keep the election handler in sync with the DB
322 DroolsPdpsElectionHandler.setMyPdpDesignated(false);
324 } catch (Exception e) {
325 logger.error("standDownPdp: Unexpected Exception attempting to mark "
326 + "DESIGNATED as false for droolspdpentity, pdpId={}"
327 + ". Cannot stand down PDP; message={}", pdpId, e.getMessage(), e);
329 cleanup(em, "standDownPdp");
331 if (logger.isDebugEnabled()) {
332 logger.debug("standDownPdp: Exiting");
338 * Determines whether or not a designated PDP has failed.
340 * Note: The update method, which is run periodically by the
341 * TimerUpdateClass, will un-designate a PDP that is stale.
344 public boolean hasDesignatedPdpFailed(Collection<DroolsPdp> pdps) {
346 if (logger.isDebugEnabled()) {
347 logger.debug("hasDesignatedPdpFailed: Entering, pdps.size()={}", pdps.size());
350 boolean failed = true;
351 boolean foundDesignatedPdp = false;
353 for (DroolsPdp pdp : pdps) {
356 * Normally, the update method will un-designate any stale PDP, but
357 * we check here to see if the PDP has gone stale since the update
360 * Even if we determine that the designated PDP is current, we keep
361 * going (we don't break), so we can get visibility into the other
362 * PDPs, when in DEBUG mode.
364 if (pdp.isDesignated() && isCurrent(pdp)) {
365 if (logger.isDebugEnabled()) {
366 logger.debug("hasDesignatedPdpFailed: Designated PDP={} is current", pdp.getPdpId());
369 foundDesignatedPdp = true;
370 } else if (pdp.isDesignated() && !isCurrent(pdp)) {
371 logger.error("hasDesignatedPdpFailed: Designated PDP={} has failed", pdp.getPdpId());
372 foundDesignatedPdp = true;
374 if (logger.isDebugEnabled()) {
375 logger.debug("hasDesignatedPdpFailed: PDP={} is not designated", pdp.getPdpId());
380 if (logger.isDebugEnabled()) {
381 logger.debug("hasDesignatedPdpFailed: Exiting and returning, foundDesignatedPdp={}",
388 private boolean isCurrent(DroolsPdp pdp) {
390 if (logger.isDebugEnabled()) {
391 logger.debug("isCurrent: Entering, pdpId={}", pdp.getPdpId());
394 boolean current = false;
396 // Return if the current PDP is considered "current" based on whatever
397 // time box that may be.
398 // If the the PDP is not current, we should mark it as not primary in
400 Date currentDate = new Date();
401 long difference = currentDate.getTime()
402 - pdp.getUpdatedDate().getTime();
403 // just set some kind of default here
404 long pdpTimeout = 15000;
406 pdpTimeout = Long.parseLong(ActiveStandbyProperties
407 .getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
408 if (logger.isDebugEnabled()) {
409 logger.debug("isCurrent: pdp.timeout={}", pdpTimeout);
411 } catch (Exception e) {
412 logger.error("isCurrent: Could not get PDP timeout property, using default.", e);
414 current = difference < pdpTimeout;
416 if (logger.isDebugEnabled()) {
417 logger.debug("isCurrent: Exiting, difference={}, pdpTimeout={}"
418 + "; returning current={}", difference, pdpTimeout, current);
426 * Currently this method is only used in a JUnit test environment. Gets a
427 * PDP record from droolspdpentity table.
430 public DroolsPdpEntity getPdp(String pdpId) {
432 if (logger.isDebugEnabled()) {
433 logger.debug("getPdp: Entering and getting PDP with pdpId={}", pdpId);
436 DroolsPdpEntity droolsPdpEntity = null;
438 EntityManager em = null;
440 em = emf.createEntityManager();
441 em.getTransaction().begin();
442 Query droolsPdpsListQuery = em
443 .createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId");
444 droolsPdpsListQuery.setParameter("pdpId", pdpId);
445 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
446 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
447 if (droolsPdpsList.size() == 1
448 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
449 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
450 if (logger.isDebugEnabled()) {
451 logger.debug("getPdp: PDP={}"
452 + " found, isDesignated={},"
453 + " updatedDate={}, "
454 + "priority={}", pdpId,
455 droolsPdpEntity.isDesignated(), droolsPdpEntity.getUpdatedDate(),
456 droolsPdpEntity.getPriority());
459 // Make sure the droolsPdpEntity is not a cached version
460 em.refresh(droolsPdpEntity);
462 em.getTransaction().commit();
464 logger.error("getPdp: PDP={} not found!?", pdpId);
466 } catch (Exception e) {
467 logger.error("getPdp: Caught Exception attempting to get PDP", e);
469 cleanup(em, "getPdp");
472 if (logger.isDebugEnabled()) {
473 logger.debug("getPdp: Returning droolsPdpEntity={}", droolsPdpEntity);
475 return droolsPdpEntity;
480 * Normally this method should only be used in a JUnit test environment.
481 * Manually inserts a PDP record in droolspdpentity table.
484 public void insertPdp(DroolsPdp pdp) {
485 if (logger.isDebugEnabled()) {
486 logger.debug("insertPdp: Entering and manually inserting PDP");
492 EntityManager em = emf.createEntityManager();
494 em.getTransaction().begin();
499 DroolsPdpEntity droolsPdpEntity = new DroolsPdpEntity();
500 em.persist(droolsPdpEntity);
501 droolsPdpEntity.setPdpId(pdp.getPdpId());
502 droolsPdpEntity.setDesignated(pdp.isDesignated());
503 droolsPdpEntity.setPriority(pdp.getPriority());
504 droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate());
505 droolsPdpEntity.setSiteName(pdp.getSiteName());
510 em.getTransaction().commit();
512 cleanup(em, "insertPdp");
514 if (logger.isDebugEnabled()) {
515 logger.debug("insertPdp: Exiting");
521 * Normally this method should only be used in a JUnit test environment.
522 * Manually deletes all PDP records in droolspdpentity table.
525 public void deleteAllPdps() {
527 if (logger.isDebugEnabled()) {
528 logger.debug("deleteAllPdps: Entering");
534 EntityManager em = emf.createEntityManager();
536 em.getTransaction().begin();
538 Query droolsPdpsListQuery = em
539 .createQuery("SELECT p FROM DroolsPdpEntity p");
540 @SuppressWarnings("unchecked")
541 List<DroolsPdp> droolsPdpsList = droolsPdpsListQuery.setLockMode(
542 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
543 if (logger.isDebugEnabled()) {
544 logger.debug("deleteAllPdps: Deleting {} PDPs", droolsPdpsList.size());
546 for (DroolsPdp droolsPdp : droolsPdpsList) {
547 String pdpId = droolsPdp.getPdpId();
554 em.getTransaction().commit();
556 cleanup(em, "deleteAllPdps");
558 if (logger.isDebugEnabled()) {
559 logger.debug("deleteAllPdps: Exiting");
565 * Normally this method should only be used in a JUnit test environment.
566 * Manually deletes a PDP record in droolspdpentity table.
569 public void deletePdp(String pdpId) {
570 if (logger.isDebugEnabled()) {
571 logger.debug("deletePdp: Entering and manually deleting pdpId={}", pdpId);
577 EntityManager em = emf.createEntityManager();
579 em.getTransaction().begin();
584 DroolsPdpEntity droolsPdpEntity = em.find(DroolsPdpEntity.class, pdpId);
585 if (droolsPdpEntity != null) {
586 if (logger.isDebugEnabled()) {
587 logger.debug("deletePdp: Removing PDP");
589 em.remove(droolsPdpEntity);
591 if (logger.isDebugEnabled()) {
592 logger.debug("deletePdp: PDP with ID={} not currently in DB", pdpId);
599 em.getTransaction().commit();
601 cleanup(em, "deletePdp");
603 if (logger.isDebugEnabled()) {
604 logger.debug("deletePdp: Exiting");
610 * Close the specified EntityManager, rolling back any pending transaction
612 * @param em the EntityManager to close ('null' is OK)
613 * @param method the invoking Java method (used for log messages)
615 private static void cleanup(EntityManager em, String method) {
616 if (em != null && em.isOpen()) {
617 if (em.getTransaction().isActive()) {
618 // there is an active EntityTransaction -- roll it back
620 em.getTransaction().rollback();
621 } catch (Exception e) {
622 logger.error(method + ": Caught Exception attempting to rollback EntityTransaction,", e);
626 // now, close the EntityManager
629 } catch (Exception e) {
630 logger.error(method + ": Caught Exception attempting to close EntityManager, ", e);