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 for drools session and pass it in here, or create a new one
45 public JpaDroolsPdpsConnector(EntityManagerFactory emf){
49 public Collection<DroolsPdp> getDroolsPdps() {
50 //return a list of all the DroolsPdps in the database
51 EntityManager em = emf.createEntityManager();
53 em.getTransaction().begin();
54 Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p");
55 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
56 LinkedList<DroolsPdp> droolsPdpsReturnList = new LinkedList<>();
57 for(Object o : droolsPdpsList){
58 if(o instanceof DroolsPdp){
59 //Make sure it is not a cached version
60 em.refresh((DroolsPdpEntity)o);
61 droolsPdpsReturnList.add((DroolsPdp)o);
62 if (logger.isDebugEnabled()) {
63 DroolsPdp droolsPdp = (DroolsPdp)o;
64 logger.debug("getDroolsPdps: PDP= {}"
65 + ", isDesignated= {}"
67 + ", priority= {}", droolsPdp.getPdpId(), droolsPdp.isDesignated(),
68 droolsPdp.getUpdatedDate(), droolsPdp.getPriority());
73 em.getTransaction().commit();
76 ("Cannot commit getDroolsPdps() transaction", e);
78 return droolsPdpsReturnList;
80 cleanup(em, "getDroolsPdps");
84 private boolean nullSafeEquals(Object one, Object two){
85 if(one == null && two == null){
88 if(one != null && two != null){
89 return one.equals(two);
95 public void update(DroolsPdp pdp) {
97 if (logger.isDebugEnabled()) {
98 logger.debug("update: Entering, pdpId={}", pdp.getPdpId());
101 //this is to update our own pdp in the database
102 EntityManager em = emf.createEntityManager();
104 em.getTransaction().begin();
105 Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId");
106 droolsPdpsListQuery.setParameter("pdpId", pdp.getPdpId());
107 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
108 DroolsPdpEntity droolsPdpEntity;
109 if(droolsPdpsList.size() == 1 && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)){
110 droolsPdpEntity = (DroolsPdpEntity)droolsPdpsList.get(0);
111 em.refresh(droolsPdpEntity); //Make sure we have current values
112 Date currentDate = new Date();
113 long difference = currentDate.getTime()-droolsPdpEntity.getUpdatedDate().getTime();
114 //just set some kind of default here
115 long pdpTimeout = 15000;
117 pdpTimeout = Long.parseLong(ActiveStandbyProperties.getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
120 ("Could not get PDP timeout property, using default.", e);
122 boolean isCurrent = difference<pdpTimeout;
123 if (logger.isDebugEnabled()) {
124 logger.debug("update: PDP= {}, isCurrent={}"
126 + ", pdpTimeout= {}, designated= {}",
127 pdp.getPdpId(), isCurrent, difference, pdpTimeout, droolsPdpEntity.isDesignated());
130 if (logger.isDebugEnabled()) {
131 logger.debug("update: For PDP={}"
132 + ", instantiating new DroolsPdpEntity", pdp.getPdpId());
134 droolsPdpEntity = new DroolsPdpEntity();
135 em.persist(droolsPdpEntity);
136 droolsPdpEntity.setPdpId(pdp.getPdpId());
138 if(droolsPdpEntity.getPriority() != pdp.getPriority()){
139 droolsPdpEntity.setPriority(pdp.getPriority());
141 if(!droolsPdpEntity.getUpdatedDate().equals(pdp.getUpdatedDate())){
142 droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate());
144 /*if(!droolsPdpEntity.getDesignatedDate().equals(pdp.getDesignatedDate())){
145 droolsPdpEntity.setDesignatedDate(pdp.getDesignatedDate());
146 } The designated date is only set below when this first becomes designated*/
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(),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(new Date());
165 em.getTransaction().commit();
167 cleanup(em, "update");
170 if (logger.isDebugEnabled()) {
171 logger.debug("update: Exiting");
177 * Note: A side effect of this boolean method is that if the PDP is designated but not current, the
178 * droolspdpentity.DESIGNATED column will be set to false (the PDP will be un-designated, i.e. marked as
179 * being in standby mode)
182 public boolean isPdpCurrent(DroolsPdp pdp) {
184 boolean isCurrent = isCurrent(pdp);
186 EntityManager em = emf.createEntityManager();
188 if(!isCurrent && pdp.isDesignated()){
189 em.getTransaction().begin();
190 Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId");
191 droolsPdpsListQuery.setParameter("pdpId", pdp.getPdpId());
192 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
193 if(droolsPdpsList.size() == 1 && droolsPdpsList.get(0) instanceof DroolsPdpEntity){
194 if (logger.isDebugEnabled()) {
195 logger.debug("isPdpCurrent: PDP={} designated but not current; setting designated to false", pdp.getPdpId());
197 DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity)droolsPdpsList.get(0);
198 droolsPdpEntity.setDesignated(false);
199 em.getTransaction().commit();
201 logger.warn("isPdpCurrent: PDP={} is designated but not current; "
202 + "however it does not have a DB entry, so cannot set DESIGNATED to false!", pdp.getPdpId());
205 if (logger.isDebugEnabled()) {
206 logger.debug("isPdpCurrent: For PDP= {}, "
207 + "designated={}, isCurrent={}", pdp.getPdpId(), pdp.isDesignated(), isCurrent);
212 ("Could not update expired record marked as designated in the database", e);
214 cleanup(em, "isPdpCurrent");
221 public void setDesignated(DroolsPdp pdp, boolean designated) {
223 if (logger.isDebugEnabled()) {
224 logger.debug("setDesignated: Entering, pdpId={}"
225 + ", designated={}", pdp.getPdpId(), designated);
228 EntityManager em = null;
230 em = emf.createEntityManager();
231 em.getTransaction().begin();
232 Query droolsPdpsListQuery = em
233 .createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId");
234 droolsPdpsListQuery.setParameter("pdpId", pdp.getPdpId());
235 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
236 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
237 if (droolsPdpsList.size() == 1
238 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
239 DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList
242 if (logger.isDebugEnabled()) {
243 logger.debug("setDesignated: PDP={}"
244 + " found, designated= {}"
245 + ", setting to {}", pdp.getPdpId(), droolsPdpEntity.isDesignated(),
248 droolsPdpEntity.setDesignated(designated);
250 em.refresh(droolsPdpEntity); //make sure we get the DB value
251 if(!droolsPdpEntity.isDesignated()){
252 droolsPdpEntity.setDesignatedDate(new Date());
256 em.getTransaction().commit();
258 logger.error("setDesignated: PDP={}"
259 + " not in DB; cannot update designation", pdp.getPdpId());
261 } catch (Exception e) {
262 logger.error("setDesignated: Caught Exception", e);
264 cleanup(em, "setDesignated");
267 if (logger.isDebugEnabled()) {
268 logger.debug("setDesignated: Exiting");
275 public void standDownPdp(String pdpId) {
276 if(logger.isDebugEnabled()){
277 logger.debug("standDownPdp: Entering, pdpId={}", pdpId);
280 EntityManager em = null;
285 em = emf.createEntityManager();
286 em.getTransaction().begin();
289 * Get droolspdpentity record for this PDP and mark DESIGNATED as
292 Query droolsPdpsListQuery = em
293 .createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId");
294 droolsPdpsListQuery.setParameter("pdpId", pdpId);
295 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
296 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
297 DroolsPdpEntity droolsPdpEntity;
298 if (droolsPdpsList.size() == 1
299 && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)) {
300 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
301 droolsPdpEntity.setDesignated(false);
302 em.persist(droolsPdpEntity);
303 if(logger.isDebugEnabled()){
304 logger.debug("standDownPdp: PDP={} persisted as non-designated.", pdpId );
307 logger.error("standDownPdp: Missing record in droolspdpentity for pdpId={}"
308 + "; cannot stand down PDP", pdpId);
314 em.getTransaction().commit();
315 cleanup(em, "standDownPdp");
318 // Keep the election handler in sync with the DB
319 DroolsPdpsElectionHandler.setMyPdpDesignated(false);
321 } catch (Exception e) {
322 logger.error("standDownPdp: Unexpected Exception attempting to mark "
323 + "DESIGNATED as false for droolspdpentity, pdpId={}"
324 + ". Cannot stand down PDP; message={}", pdpId, e.getMessage(), e);
326 cleanup(em, "standDownPdp");
328 if(logger.isDebugEnabled()){
329 logger.debug("standDownPdp: Exiting");
335 * Determines whether or not a designated PDP has failed.
337 * Note: The update method, which is run periodically by the
338 * TimerUpdateClass, will un-designate a PDP that is stale.
341 public boolean hasDesignatedPdpFailed(Collection<DroolsPdp> pdps) {
343 if (logger.isDebugEnabled()) {
344 logger.debug("hasDesignatedPdpFailed: Entering, pdps.size()={}", pdps.size());
347 boolean failed = true;
348 boolean foundDesignatedPdp = false;
350 for (DroolsPdp pdp : pdps) {
353 * Normally, the update method will un-designate any stale PDP, but
354 * we check here to see if the PDP has gone stale since the update
357 * Even if we determine that the designated PDP is current, we keep
358 * going (we don't break), so we can get visibility into the other
359 * PDPs, when in DEBUG mode.
361 if (pdp.isDesignated() && isCurrent(pdp)) {
362 if (logger.isDebugEnabled()) {
363 logger.debug("hasDesignatedPdpFailed: Designated PDP={} is current", pdp.getPdpId());
366 foundDesignatedPdp = true;
367 } else if (pdp.isDesignated() && !isCurrent(pdp)) {
368 logger.error("hasDesignatedPdpFailed: Designated PDP={} has failed", pdp.getPdpId());
369 foundDesignatedPdp = true;
371 if (logger.isDebugEnabled()) {
372 logger.debug("hasDesignatedPdpFailed: PDP={} is not designated", pdp.getPdpId());
377 if (logger.isDebugEnabled()) {
378 logger.debug("hasDesignatedPdpFailed: Exiting and returning, foundDesignatedPdp={}",
385 private boolean isCurrent(DroolsPdp pdp) {
387 if (logger.isDebugEnabled()) {
388 logger.debug("isCurrent: Entering, pdpId={}", pdp.getPdpId());
391 boolean current = false;
393 // Return if the current PDP is considered "current" based on whatever
394 // time box that may be.
395 // If the the PDP is not current, we should mark it as not primary in
397 Date currentDate = new Date();
398 long difference = currentDate.getTime()
399 - pdp.getUpdatedDate().getTime();
400 // just set some kind of default here
401 long pdpTimeout = 15000;
403 pdpTimeout = Long.parseLong(ActiveStandbyProperties
404 .getProperty(ActiveStandbyProperties.PDP_TIMEOUT));
405 if (logger.isDebugEnabled()) {
406 logger.debug("isCurrent: pdp.timeout={}", pdpTimeout);
408 } catch (Exception e) {
410 ("isCurrent: Could not get PDP timeout property, using default.", e);
412 current = difference < pdpTimeout;
414 if (logger.isDebugEnabled()) {
415 logger.debug("isCurrent: Exiting, difference={}, pdpTimeout={}"
416 + "; returning current={}", difference, pdpTimeout, current);
424 * Currently this method is only used in a JUnit test environment. Gets a
425 * PDP record from droolspdpentity table.
428 public DroolsPdpEntity getPdp(String pdpId) {
430 if (logger.isDebugEnabled()) {
431 logger.debug("getPdp: Entering and getting PDP with pdpId={}", pdpId);
434 DroolsPdpEntity droolsPdpEntity = null;
436 EntityManager em = null;
438 em = emf.createEntityManager();
439 em.getTransaction().begin();
440 Query droolsPdpsListQuery = em
441 .createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId");
442 droolsPdpsListQuery.setParameter("pdpId", pdpId);
443 List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(
444 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
445 if (droolsPdpsList.size() == 1
446 && droolsPdpsList.get(0) instanceof DroolsPdpEntity) {
447 droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0);
448 if (logger.isDebugEnabled()) {
449 logger.debug("getPdp: PDP={}"
450 + " found, isDesignated={},"
451 + " updatedDate={}, "
452 + "priority={}", pdpId,
453 droolsPdpEntity.isDesignated(), droolsPdpEntity.getUpdatedDate(),
454 droolsPdpEntity.getPriority());
457 // Make sure the droolsPdpEntity is not a cached version
458 em.refresh(droolsPdpEntity);
460 em.getTransaction().commit();
462 logger.error("getPdp: PDP={} not found!?", pdpId);
464 } catch (Exception e) {
466 ("getPdp: Caught Exception attempting to get PDP", e);
468 cleanup(em, "getPdp");
471 if (logger.isDebugEnabled()) {
472 logger.debug("getPdp: Returning droolsPdpEntity={}", droolsPdpEntity);
474 return droolsPdpEntity;
479 * Normally this method should only be used in a JUnit test environment.
480 * Manually inserts a PDP record in droolspdpentity table.
483 public void insertPdp(DroolsPdp pdp) {
484 if(logger.isDebugEnabled()){
485 logger.debug("insertPdp: Entering and manually inserting PDP");
491 EntityManager em = emf.createEntityManager();
493 em.getTransaction().begin();
498 DroolsPdpEntity droolsPdpEntity = new DroolsPdpEntity();
499 em.persist(droolsPdpEntity);
500 droolsPdpEntity.setPdpId(pdp.getPdpId());
501 droolsPdpEntity.setDesignated(pdp.isDesignated());
502 droolsPdpEntity.setPriority(pdp.getPriority());
503 droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate());
504 droolsPdpEntity.setSiteName(pdp.getSiteName());
509 em.getTransaction().commit();
511 cleanup(em, "insertPdp");
513 if(logger.isDebugEnabled()){
514 logger.debug("insertPdp: Exiting");
520 * Normally this method should only be used in a JUnit test environment.
521 * Manually deletes all PDP records in droolspdpentity table.
524 public void deleteAllPdps() {
526 if(logger.isDebugEnabled()){
527 logger.debug("deleteAllPdps: Entering");
533 EntityManager em = emf.createEntityManager();
535 em.getTransaction().begin();
537 Query droolsPdpsListQuery = em
538 .createQuery("SELECT p FROM DroolsPdpEntity p");
539 @SuppressWarnings("unchecked")
540 List<DroolsPdp> droolsPdpsList = droolsPdpsListQuery.setLockMode(
541 LockModeType.NONE).setFlushMode(FlushModeType.COMMIT).getResultList();
542 if(logger.isDebugEnabled()){
543 logger.debug("deleteAllPdps: Deleting {} PDPs", droolsPdpsList.size());
545 for (DroolsPdp droolsPdp : droolsPdpsList) {
546 String pdpId = droolsPdp.getPdpId();
553 em.getTransaction().commit();
555 cleanup(em, "deleteAllPdps");
557 if(logger.isDebugEnabled()){
558 logger.debug("deleteAllPdps: Exiting");
564 * Normally this method should only be used in a JUnit test environment.
565 * Manually deletes a PDP record in droolspdpentity table.
568 public void deletePdp(String pdpId) {
569 if(logger.isDebugEnabled()){
570 logger.debug("deletePdp: Entering and manually deleting pdpId={}", pdpId);
576 EntityManager em = emf.createEntityManager();
578 em.getTransaction().begin();
583 DroolsPdpEntity droolsPdpEntity = em.find(DroolsPdpEntity.class, pdpId);
584 if (droolsPdpEntity != null) {
585 if(logger.isDebugEnabled()){
586 logger.debug("deletePdp: Removing PDP");
588 em.remove(droolsPdpEntity);
590 if(logger.isDebugEnabled()){
591 logger.debug("deletePdp: PDP with ID={} not currently in DB", pdpId);
598 em.getTransaction().commit();
600 cleanup(em, "deletePdp");
602 if(logger.isDebugEnabled()){
603 logger.debug("deletePdp: Exiting");
609 * Close the specified EntityManager, rolling back any pending transaction
611 * @param em the EntityManager to close ('null' is OK)
612 * @param method the invoking Java method (used for log messages)
614 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);